blob: f03aeacffb9fe770223b551a42e0979452984875 [file] [log] [blame]
San Mehat9d2bd732009-09-22 16:44:22 -07001/*
2 * linux/drivers/mmc/host/msm_sdcc.c - Qualcomm MSM 7X00A SDCC Driver
3 *
4 * Copyright (C) 2007 Google Inc,
5 * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
Krishna Konda941604a2012-01-10 17:46:34 -08006 * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
San Mehat9d2bd732009-09-22 16:44:22 -07007 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * Based on mmci.c
13 *
14 * Author: San Mehat (san@android.com)
15 *
16 */
17
18#include <linux/module.h>
19#include <linux/moduleparam.h>
20#include <linux/init.h>
21#include <linux/ioport.h>
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +053022#include <linux/of.h>
San Mehat9d2bd732009-09-22 16:44:22 -070023#include <linux/device.h>
24#include <linux/interrupt.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070025#include <linux/irq.h>
San Mehat9d2bd732009-09-22 16:44:22 -070026#include <linux/delay.h>
27#include <linux/err.h>
28#include <linux/highmem.h>
29#include <linux/log2.h>
30#include <linux/mmc/host.h>
31#include <linux/mmc/card.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070032#include <linux/mmc/mmc.h>
San Mehatb3fa5792009-11-02 18:46:09 -080033#include <linux/mmc/sdio.h>
San Mehat9d2bd732009-09-22 16:44:22 -070034#include <linux/clk.h>
35#include <linux/scatterlist.h>
36#include <linux/platform_device.h>
37#include <linux/dma-mapping.h>
38#include <linux/debugfs.h>
39#include <linux/io.h>
40#include <linux/memory.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070041#include <linux/pm_runtime.h>
42#include <linux/wakelock.h>
Sahitya Tummala7a892482011-01-18 11:22:49 +053043#include <linux/gpio.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070044#include <linux/regulator/consumer.h>
45#include <linux/slab.h>
Subhash Jadavani933e6a62011-12-26 18:05:04 +053046#include <linux/pm_qos_params.h>
San Mehat9d2bd732009-09-22 16:44:22 -070047
48#include <asm/cacheflush.h>
49#include <asm/div64.h>
50#include <asm/sizes.h>
51
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070052#include <asm/mach/mmc.h>
San Mehat9d2bd732009-09-22 16:44:22 -070053#include <mach/msm_iomap.h>
Sahitya Tummalab08bb352010-12-08 15:03:05 +053054#include <mach/clk.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070055#include <mach/dma.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070056#include <mach/sdio_al.h>
San Mehat9d2bd732009-09-22 16:44:22 -070057
San Mehat9d2bd732009-09-22 16:44:22 -070058#include "msm_sdcc.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070059#include "msm_sdcc_dml.h"
San Mehat9d2bd732009-09-22 16:44:22 -070060
61#define DRIVER_NAME "msm-sdcc"
62
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070063#define DBG(host, fmt, args...) \
64 pr_debug("%s: %s: " fmt "\n", mmc_hostname(host->mmc), __func__ , args)
65
66#define IRQ_DEBUG 0
67#define SPS_SDCC_PRODUCER_PIPE_INDEX 1
68#define SPS_SDCC_CONSUMER_PIPE_INDEX 2
69#define SPS_CONS_PERIPHERAL 0
70#define SPS_PROD_PERIPHERAL 1
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070071
72#if defined(CONFIG_DEBUG_FS)
73static void msmsdcc_dbg_createhost(struct msmsdcc_host *);
74static struct dentry *debugfs_dir;
75static struct dentry *debugfs_file;
76static int msmsdcc_dbg_init(void);
77#endif
78
Subhash Jadavani8766e352011-11-30 11:30:32 +053079static u64 dma_mask = DMA_BIT_MASK(32);
San Mehat9d2bd732009-09-22 16:44:22 -070080static unsigned int msmsdcc_pwrsave = 1;
San Mehat9d2bd732009-09-22 16:44:22 -070081
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070082static struct mmc_command dummy52cmd;
83static struct mmc_request dummy52mrq = {
84 .cmd = &dummy52cmd,
85 .data = NULL,
86 .stop = NULL,
87};
88static struct mmc_command dummy52cmd = {
89 .opcode = SD_IO_RW_DIRECT,
90 .flags = MMC_RSP_PRESENT,
91 .data = NULL,
92 .mrq = &dummy52mrq,
93};
94/*
95 * An array holding the Tuning pattern to compare with when
96 * executing a tuning cycle.
97 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +053098static const u32 tuning_block_64[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070099 0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
100 0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
101 0xF0FFF0FF, 0x3CCCFC0F, 0xCFCC33CC, 0xEEFFEFFF,
102 0xFDFFFDFF, 0xFFBFFFDF, 0xFFF7FFBB, 0xDE7B7FF7
103};
San Mehat865c8062009-11-13 13:42:06 -0800104
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +0530105static const u32 tuning_block_128[] = {
106 0xFF00FFFF, 0x0000FFFF, 0xCCCCFFFF, 0xCCCC33CC,
107 0xCC3333CC, 0xFFFFCCCC, 0xFFFFEEFF, 0xFFEEEEFF,
108 0xFFDDFFFF, 0xDDDDFFFF, 0xBBFFFFFF, 0xBBFFFFFF,
109 0xFFFFFFBB, 0xFFFFFF77, 0x77FF7777, 0xFFEEDDBB,
110 0x00FFFFFF, 0x00FFFFFF, 0xCCFFFF00, 0xCC33CCCC,
111 0x3333CCCC, 0xFFCCCCCC, 0xFFEEFFFF, 0xEEEEFFFF,
112 0xDDFFFFFF, 0xDDFFFFFF, 0xFFFFFFDD, 0xFFFFFFBB,
113 0xFFFFBBBB, 0xFFFF77FF, 0xFF7777FF, 0xEEDDBB77
114};
115
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700116#if IRQ_DEBUG == 1
117static char *irq_status_bits[] = { "cmdcrcfail", "datcrcfail", "cmdtimeout",
118 "dattimeout", "txunderrun", "rxoverrun",
119 "cmdrespend", "cmdsent", "dataend", NULL,
120 "datablkend", "cmdactive", "txactive",
121 "rxactive", "txhalfempty", "rxhalffull",
122 "txfifofull", "rxfifofull", "txfifoempty",
123 "rxfifoempty", "txdataavlbl", "rxdataavlbl",
124 "sdiointr", "progdone", "atacmdcompl",
125 "sdiointrope", "ccstimeout", NULL, NULL,
126 NULL, NULL, NULL };
127
128static void
129msmsdcc_print_status(struct msmsdcc_host *host, char *hdr, uint32_t status)
San Mehat865c8062009-11-13 13:42:06 -0800130{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700131 int i;
San Mehat8b1c2ba2009-11-16 10:17:30 -0800132
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700133 pr_debug("%s-%s ", mmc_hostname(host->mmc), hdr);
134 for (i = 0; i < 32; i++) {
135 if (status & (1 << i))
136 pr_debug("%s ", irq_status_bits[i]);
San Mehat865c8062009-11-13 13:42:06 -0800137 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700138 pr_debug("\n");
San Mehatc7fc9372009-11-22 17:19:07 -0800139}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700140#endif
San Mehat865c8062009-11-13 13:42:06 -0800141
San Mehat9d2bd732009-09-22 16:44:22 -0700142static void
143msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
144 u32 c);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530145static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530146static inline void msmsdcc_delay(struct msmsdcc_host *host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530147static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -0800148static void msmsdcc_sg_start(struct msmsdcc_host *host);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -0800149static int msmsdcc_vreg_reset(struct msmsdcc_host *host);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530150
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530151static inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
152{
153 unsigned short ret = NR_SG;
154
155 if (host->is_sps_mode) {
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +0530156 ret = SPS_MAX_DESCS;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530157 } else { /* DMA or PIO mode */
158 if (NR_SG > MAX_NR_SG_DMA_PIO)
159 ret = MAX_NR_SG_DMA_PIO;
160 }
161
162 return ret;
163}
164
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530165/* Prevent idle power collapse(pc) while operating in peripheral mode */
166static void msmsdcc_pm_qos_update_latency(struct msmsdcc_host *host, int vote)
167{
168 u32 swfi_latency = 0;
169
170 if (!host->plat->swfi_latency)
171 return;
172
173 swfi_latency = host->plat->swfi_latency + 1;
174
175 if (vote)
176 pm_qos_update_request(&host->pm_qos_req_dma,
177 swfi_latency);
178 else
179 pm_qos_update_request(&host->pm_qos_req_dma,
180 PM_QOS_DEFAULT_VALUE);
181}
182
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700183#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
184static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
185 struct msmsdcc_sps_ep_conn_data *ep);
186static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
187 struct msmsdcc_sps_ep_conn_data *ep);
188#else
189static inline int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
190 struct msmsdcc_sps_ep_conn_data *ep,
191 bool is_producer) { return 0; }
192static inline void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
193 struct msmsdcc_sps_ep_conn_data *ep) { }
194static inline int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
195 struct msmsdcc_sps_ep_conn_data *ep)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530196{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700197 return 0;
198}
199static inline int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
200 struct msmsdcc_sps_ep_conn_data *ep)
201{
202 return 0;
203}
204static inline int msmsdcc_sps_init(struct msmsdcc_host *host) { return 0; }
205static inline void msmsdcc_sps_exit(struct msmsdcc_host *host) {}
206#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530207
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700208/**
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530209 * Apply soft reset to all SDCC BAM pipes
210 *
211 * This function applies soft reset to SDCC BAM pipe.
212 *
213 * This function should be called to recover from error
214 * conditions encountered during CMD/DATA tranfsers with card.
215 *
216 * @host - Pointer to driver's host structure
217 *
218 */
219static void msmsdcc_sps_pipes_reset_and_restore(struct msmsdcc_host *host)
220{
221 int rc;
222
223 /* Reset all SDCC BAM pipes */
224 rc = msmsdcc_sps_reset_ep(host, &host->sps.prod);
225 if (rc)
226 pr_err("%s:msmsdcc_sps_reset_ep(prod) error=%d\n",
227 mmc_hostname(host->mmc), rc);
228 rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
229 if (rc)
230 pr_err("%s:msmsdcc_sps_reset_ep(cons) error=%d\n",
231 mmc_hostname(host->mmc), rc);
232
233 /* Restore all BAM pipes connections */
234 rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
235 if (rc)
236 pr_err("%s:msmsdcc_sps_restore_ep(prod) error=%d\n",
237 mmc_hostname(host->mmc), rc);
238 rc = msmsdcc_sps_restore_ep(host, &host->sps.cons);
239 if (rc)
240 pr_err("%s:msmsdcc_sps_restore_ep(cons) error=%d\n",
241 mmc_hostname(host->mmc), rc);
242}
243
244/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700245 * Apply soft reset
246 *
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530247 * This function applies soft reset to SDCC core and DML core.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700248 *
249 * This function should be called to recover from error
250 * conditions encountered with CMD/DATA tranfsers with card.
251 *
252 * Soft reset should only be used with SDCC controller v4.
253 *
254 * @host - Pointer to driver's host structure
255 *
256 */
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530257static void msmsdcc_soft_reset(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700258{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700259 /*
260 * Reset SDCC controller's DPSM (data path state machine
261 * and CPSM (command path state machine).
262 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700263 writel_relaxed(0, host->base + MMCICOMMAND);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530264 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700265 writel_relaxed(0, host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530266 msmsdcc_sync_reg_wr(host);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530267}
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530268
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530269static void msmsdcc_hard_reset(struct msmsdcc_host *host)
270{
271 int ret;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530272
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530273 /* Reset the controller */
274 ret = clk_reset(host->clk, CLK_RESET_ASSERT);
275 if (ret)
276 pr_err("%s: Clock assert failed at %u Hz"
277 " with err %d\n", mmc_hostname(host->mmc),
278 host->clk_rate, ret);
279
280 ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
281 if (ret)
282 pr_err("%s: Clock deassert failed at %u Hz"
283 " with err %d\n", mmc_hostname(host->mmc),
284 host->clk_rate, ret);
285
Subhash Jadavanidd432952012-03-28 11:25:56 +0530286 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530287 /* Give some delay for clock reset to propogate to controller */
288 msmsdcc_delay(host);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530289}
290
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700291static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
292{
Pratibhasagar V1c11da62011-11-14 12:36:35 +0530293 if (host->sdcc_version) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530294 if (host->is_sps_mode) {
295 /* Reset DML first */
296 msmsdcc_dml_reset(host);
297 /*
298 * delay the SPS pipe reset in thread context as
299 * sps_connect/sps_disconnect APIs can be called
300 * only from non-atomic context.
301 */
302 host->sps.pipe_reset_pending = true;
303 }
304 mb();
305 msmsdcc_soft_reset(host);
306
307 pr_debug("%s: Applied soft reset to Controller\n",
308 mmc_hostname(host->mmc));
309
310 if (host->is_sps_mode)
311 msmsdcc_dml_init(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700312 } else {
313 /* Give Clock reset (hard reset) to controller */
314 u32 mci_clk = 0;
315 u32 mci_mask0 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700316
317 /* Save the controller state */
318 mci_clk = readl_relaxed(host->base + MMCICLOCK);
319 mci_mask0 = readl_relaxed(host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +0530320 host->pwr = readl_relaxed(host->base + MMCIPOWER);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700321 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700322
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530323 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700324 pr_debug("%s: Controller has been reinitialized\n",
325 mmc_hostname(host->mmc));
326
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700327 /* Restore the contoller state */
328 writel_relaxed(host->pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530329 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700330 writel_relaxed(mci_clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530331 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700332 writel_relaxed(mci_mask0, host->base + MMCIMASK0);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530333 mb(); /* no delay required after writing to MASK0 register */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700334 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530335
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700336 if (host->dummy_52_needed)
337 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700338}
339
340static int
San Mehat9d2bd732009-09-22 16:44:22 -0700341msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
342{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700343 int retval = 0;
344
San Mehat9d2bd732009-09-22 16:44:22 -0700345 BUG_ON(host->curr.data);
346
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700347 del_timer(&host->req_tout_timer);
348
San Mehat9d2bd732009-09-22 16:44:22 -0700349 if (mrq->data)
350 mrq->data->bytes_xfered = host->curr.data_xfered;
351 if (mrq->cmd->error == -ETIMEDOUT)
352 mdelay(5);
353
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530354 /* Clear current request information as current request has ended */
355 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
356
San Mehat9d2bd732009-09-22 16:44:22 -0700357 /*
358 * Need to drop the host lock here; mmc_request_done may call
359 * back into the driver...
360 */
361 spin_unlock(&host->lock);
362 mmc_request_done(host->mmc, mrq);
363 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700364
365 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700366}
367
368static void
369msmsdcc_stop_data(struct msmsdcc_host *host)
370{
San Mehat9d2bd732009-09-22 16:44:22 -0700371 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530372 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530373 host->curr.wait_for_auto_prog_done = 0;
374 host->curr.got_auto_prog_done = 0;
Krishna Konda3f5d48f2011-07-27 10:47:31 -0700375 writel_relaxed(readl_relaxed(host->base + MMCIDATACTRL) &
376 (~(MCI_DPSM_ENABLE)), host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530377 msmsdcc_sync_reg_wr(host); /* Allow the DPSM to be reset */
San Mehat9d2bd732009-09-22 16:44:22 -0700378}
379
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700380static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700381{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700382 return host->core_memres->start + MMCIFIFO;
383}
384
385static inline unsigned int msmsdcc_get_min_sup_clk_rate(
386 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530387
Subhash Jadavanidd432952012-03-28 11:25:56 +0530388static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700389{
390 mb();
Subhash Jadavanidd432952012-03-28 11:25:56 +0530391 if (!host->sdcc_version)
392 udelay(host->reg_write_delay);
393 else if (readl_relaxed(host->base + MCI_STATUS2) &
394 MCI_MCLK_REG_WR_ACTIVE) {
395 ktime_t start, diff;
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530396
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530397 start = ktime_get();
398 while (readl_relaxed(host->base + MCI_STATUS2) &
399 MCI_MCLK_REG_WR_ACTIVE) {
400 diff = ktime_sub(ktime_get(), start);
401 /* poll for max. 1 ms */
402 if (ktime_to_us(diff) > 1000) {
403 pr_warning("%s: previous reg. write is"
404 " still active\n",
405 mmc_hostname(host->mmc));
406 break;
407 }
408 }
409 }
San Mehat9d2bd732009-09-22 16:44:22 -0700410}
411
Subhash Jadavanidd432952012-03-28 11:25:56 +0530412static inline void msmsdcc_delay(struct msmsdcc_host *host)
413{
414 udelay(host->reg_write_delay);
415
416}
417
San Mehat56a8b5b2009-11-21 12:29:46 -0800418static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700419msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
420{
421 writel_relaxed(arg, host->base + MMCIARGUMENT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700422 writel_relaxed(c, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530423 /*
424 * As after sending the command, we don't write any of the
425 * controller registers and just wait for the
426 * CMD_RESPOND_END/CMD_SENT/Command failure notication
427 * from Controller.
428 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700429 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800430}
431
432static void
433msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
434{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700435 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800436
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700437 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
438 writel_relaxed((unsigned int)host->curr.xfer_size,
439 host->base + MMCIDATALENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700440 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530441 msmsdcc_sync_reg_wr(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800442
San Mehat6ac9ea62009-12-02 17:24:58 -0800443 if (host->cmd_cmd) {
444 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700445 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800446 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800447}
448
San Mehat9d2bd732009-09-22 16:44:22 -0700449static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530450msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700451{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530452 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700453 unsigned long flags;
454 struct mmc_request *mrq;
455
456 spin_lock_irqsave(&host->lock, flags);
457 mrq = host->curr.mrq;
458 BUG_ON(!mrq);
459
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530460 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700461 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700462 goto out;
463 }
464
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530465 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700466 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700467 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700468 } else {
469 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530470 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700471 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530472 mmc_hostname(host->mmc), host->dma.result);
473 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700474 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530475 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530476 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700477 host->dma.err.flush[0], host->dma.err.flush[1],
478 host->dma.err.flush[2], host->dma.err.flush[3],
479 host->dma.err.flush[4],
480 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530481 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700482 if (!mrq->data->error)
483 mrq->data->error = -EIO;
484 }
San Mehat9d2bd732009-09-22 16:44:22 -0700485 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents,
486 host->dma.dir);
487
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700488 if (host->curr.user_pages) {
489 struct scatterlist *sg = host->dma.sg;
490 int i;
491
492 for (i = 0; i < host->dma.num_ents; i++, sg++)
493 flush_dcache_page(sg_page(sg));
494 }
495
San Mehat9d2bd732009-09-22 16:44:22 -0700496 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800497 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700498
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530499 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
500 (host->curr.wait_for_auto_prog_done &&
501 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700502 /*
503 * If we've already gotten our DATAEND / DATABLKEND
504 * for this request, then complete it through here.
505 */
San Mehat9d2bd732009-09-22 16:44:22 -0700506
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700507 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700508 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700509 host->curr.xfer_remain -= host->curr.xfer_size;
510 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700511 if (host->dummy_52_needed) {
512 mrq->data->bytes_xfered = host->curr.data_xfered;
513 host->dummy_52_sent = 1;
514 msmsdcc_start_command(host, &dummy52cmd,
515 MCI_CPSM_PROGENA);
516 goto out;
517 }
518 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530519 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530520 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700521 mrq->data->bytes_xfered = host->curr.data_xfered;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700522 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530523 /*
524 * Clear current request information as current
525 * request has ended
526 */
527 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
San Mehat9d2bd732009-09-22 16:44:22 -0700528 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700529
San Mehat9d2bd732009-09-22 16:44:22 -0700530 mmc_request_done(host->mmc, mrq);
531 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530532 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
533 || !mrq->sbc)) {
534 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530535 }
San Mehat9d2bd732009-09-22 16:44:22 -0700536 }
537
538out:
539 spin_unlock_irqrestore(&host->lock, flags);
540 return;
541}
542
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700543#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
544/**
545 * Callback notification from SPS driver
546 *
547 * This callback function gets triggered called from
548 * SPS driver when requested SPS data transfer is
549 * completed.
550 *
551 * SPS driver invokes this callback in BAM irq context so
552 * SDCC driver schedule a tasklet for further processing
553 * this callback notification at later point of time in
554 * tasklet context and immediately returns control back
555 * to SPS driver.
556 *
557 * @nofity - Pointer to sps event notify sturcture
558 *
559 */
560static void
561msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
562{
563 struct msmsdcc_host *host =
564 (struct msmsdcc_host *)
565 ((struct sps_event_notify *)notify)->user;
566
567 host->sps.notify = *notify;
568 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
569 mmc_hostname(host->mmc), __func__, notify->event_id,
570 notify->data.transfer.iovec.addr,
571 notify->data.transfer.iovec.size,
572 notify->data.transfer.iovec.flags);
573 /* Schedule a tasklet for completing data transfer */
574 tasklet_schedule(&host->sps.tlet);
575}
576
577/**
578 * Tasklet handler for processing SPS callback event
579 *
580 * This function processing SPS event notification and
581 * checks if the SPS transfer is completed or not and
582 * then accordingly notifies status to MMC core layer.
583 *
584 * This function is called in tasklet context.
585 *
586 * @data - Pointer to sdcc driver data
587 *
588 */
589static void msmsdcc_sps_complete_tlet(unsigned long data)
590{
591 unsigned long flags;
592 int i, rc;
593 u32 data_xfered = 0;
594 struct mmc_request *mrq;
595 struct sps_iovec iovec;
596 struct sps_pipe *sps_pipe_handle;
597 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
598 struct sps_event_notify *notify = &host->sps.notify;
599
600 spin_lock_irqsave(&host->lock, flags);
601 if (host->sps.dir == DMA_FROM_DEVICE)
602 sps_pipe_handle = host->sps.prod.pipe_handle;
603 else
604 sps_pipe_handle = host->sps.cons.pipe_handle;
605 mrq = host->curr.mrq;
606
607 if (!mrq) {
608 spin_unlock_irqrestore(&host->lock, flags);
609 return;
610 }
611
612 pr_debug("%s: %s: sps event_id=%d\n",
613 mmc_hostname(host->mmc), __func__,
614 notify->event_id);
615
616 if (msmsdcc_is_dml_busy(host)) {
617 /* oops !!! this should never happen. */
618 pr_err("%s: %s: Received SPS EOT event"
619 " but DML HW is still busy !!!\n",
620 mmc_hostname(host->mmc), __func__);
621 }
622 /*
623 * Got End of transfer event!!! Check if all of the data
624 * has been transferred?
625 */
626 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
627 rc = sps_get_iovec(sps_pipe_handle, &iovec);
628 if (rc) {
629 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
630 mmc_hostname(host->mmc), __func__, rc, i);
631 break;
632 }
633 data_xfered += iovec.size;
634 }
635
636 if (data_xfered == host->curr.xfer_size) {
637 host->curr.data_xfered = host->curr.xfer_size;
638 host->curr.xfer_remain -= host->curr.xfer_size;
639 pr_debug("%s: Data xfer success. data_xfered=0x%x",
640 mmc_hostname(host->mmc),
641 host->curr.xfer_size);
642 } else {
643 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
644 " xfer_size=%d", mmc_hostname(host->mmc),
645 data_xfered, host->curr.xfer_size);
646 msmsdcc_reset_and_restore(host);
647 if (!mrq->data->error)
648 mrq->data->error = -EIO;
649 }
650
651 /* Unmap sg buffers */
652 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
653 host->sps.dir);
654
655 host->sps.sg = NULL;
656 host->sps.busy = 0;
657
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530658 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
659 (host->curr.wait_for_auto_prog_done &&
660 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700661 /*
662 * If we've already gotten our DATAEND / DATABLKEND
663 * for this request, then complete it through here.
664 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700665
666 if (!mrq->data->error) {
667 host->curr.data_xfered = host->curr.xfer_size;
668 host->curr.xfer_remain -= host->curr.xfer_size;
669 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700670 if (host->dummy_52_needed) {
671 mrq->data->bytes_xfered = host->curr.data_xfered;
672 host->dummy_52_sent = 1;
673 msmsdcc_start_command(host, &dummy52cmd,
674 MCI_CPSM_PROGENA);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700675 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700676 return;
677 }
678 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530679 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530680 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700681 mrq->data->bytes_xfered = host->curr.data_xfered;
682 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530683 /*
684 * Clear current request information as current
685 * request has ended
686 */
687 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700688 spin_unlock_irqrestore(&host->lock, flags);
689
690 mmc_request_done(host->mmc, mrq);
691 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530692 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
693 || !mrq->sbc)) {
694 msmsdcc_start_command(host, mrq->data->stop, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700695 }
696 }
697 spin_unlock_irqrestore(&host->lock, flags);
698}
699
700/**
701 * Exit from current SPS data transfer
702 *
703 * This function exits from current SPS data transfer.
704 *
705 * This function should be called when error condition
706 * is encountered during data transfer.
707 *
708 * @host - Pointer to sdcc host structure
709 *
710 */
711static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
712{
713 struct mmc_request *mrq;
714
715 mrq = host->curr.mrq;
716 BUG_ON(!mrq);
717
718 msmsdcc_reset_and_restore(host);
719 if (!mrq->data->error)
720 mrq->data->error = -EIO;
721
722 /* Unmap sg buffers */
723 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
724 host->sps.dir);
725
726 host->sps.sg = NULL;
727 host->sps.busy = 0;
728 if (host->curr.data)
729 msmsdcc_stop_data(host);
730
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530731 if (!mrq->data->stop || mrq->cmd->error ||
732 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700733 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530734 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
735 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700736 msmsdcc_start_command(host, mrq->data->stop, 0);
737
738}
739#else
740static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
741static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
742static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
743#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
744
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530745static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700746
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530747static void
748msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
749 unsigned int result,
750 struct msm_dmov_errdata *err)
751{
752 struct msmsdcc_dma_data *dma_data =
753 container_of(cmd, struct msmsdcc_dma_data, hdr);
754 struct msmsdcc_host *host = dma_data->host;
755
756 dma_data->result = result;
757 if (err)
758 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
759
760 tasklet_schedule(&host->dma_tlet);
761}
762
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700763static int msmsdcc_check_dma_op_req(struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700764{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700765 if (((data->blksz * data->blocks) < MCI_FIFOSIZE) ||
766 ((data->blksz * data->blocks) % MCI_FIFOSIZE))
San Mehat9d2bd732009-09-22 16:44:22 -0700767 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700768 else
769 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700770}
771
772static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
773{
774 struct msmsdcc_nc_dmadata *nc;
775 dmov_box *box;
776 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700777 unsigned int n;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530778 int i, err = 0, box_cmd_cnt = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700779 struct scatterlist *sg = data->sg;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530780 unsigned int len, offset;
San Mehat9d2bd732009-09-22 16:44:22 -0700781
Krishna Konda25786ec2011-07-25 16:21:36 -0700782 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700783 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700784
Krishna Konda25786ec2011-07-25 16:21:36 -0700785 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
786
San Mehat9d2bd732009-09-22 16:44:22 -0700787 host->dma.sg = data->sg;
788 host->dma.num_ents = data->sg_len;
789
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530790 /* Prevent memory corruption */
791 BUG_ON(host->dma.num_ents > msmsdcc_get_nr_sg(host));
San Mehat56a8b5b2009-11-21 12:29:46 -0800792
San Mehat9d2bd732009-09-22 16:44:22 -0700793 nc = host->dma.nc;
794
San Mehat9d2bd732009-09-22 16:44:22 -0700795 if (data->flags & MMC_DATA_READ)
796 host->dma.dir = DMA_FROM_DEVICE;
797 else
798 host->dma.dir = DMA_TO_DEVICE;
799
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700800 n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
801 host->dma.num_ents, host->dma.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700802
803 if (n != host->dma.num_ents) {
804 pr_err("%s: Unable to map in all sg elements\n",
805 mmc_hostname(host->mmc));
806 host->dma.sg = NULL;
807 host->dma.num_ents = 0;
808 return -ENOMEM;
San Mehat56a8b5b2009-11-21 12:29:46 -0800809 }
San Mehat9d2bd732009-09-22 16:44:22 -0700810
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530811 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
812 host->curr.user_pages = 0;
813 box = &nc->cmd[0];
814 for (i = 0; i < host->dma.num_ents; i++) {
815 len = sg_dma_len(sg);
816 offset = 0;
817
818 do {
819 /* Check if we can do DMA */
820 if (!len || (box_cmd_cnt >= MMC_MAX_DMA_CMDS)) {
821 err = -ENOTSUPP;
822 goto unmap;
823 }
824
825 box->cmd = CMD_MODE_BOX;
826
827 if (len >= MMC_MAX_DMA_BOX_LENGTH) {
828 len = MMC_MAX_DMA_BOX_LENGTH;
829 len -= len % data->blksz;
830 }
831 rows = (len % MCI_FIFOSIZE) ?
832 (len / MCI_FIFOSIZE) + 1 :
833 (len / MCI_FIFOSIZE);
834
835 if (data->flags & MMC_DATA_READ) {
836 box->src_row_addr = msmsdcc_fifo_addr(host);
837 box->dst_row_addr = sg_dma_address(sg) + offset;
838 box->src_dst_len = (MCI_FIFOSIZE << 16) |
839 (MCI_FIFOSIZE);
840 box->row_offset = MCI_FIFOSIZE;
841 box->num_rows = rows * ((1 << 16) + 1);
842 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
843 } else {
844 box->src_row_addr = sg_dma_address(sg) + offset;
845 box->dst_row_addr = msmsdcc_fifo_addr(host);
846 box->src_dst_len = (MCI_FIFOSIZE << 16) |
847 (MCI_FIFOSIZE);
848 box->row_offset = (MCI_FIFOSIZE << 16);
849 box->num_rows = rows * ((1 << 16) + 1);
850 box->cmd |= CMD_DST_CRCI(host->dma.crci);
851 }
852
853 offset += len;
854 len = sg_dma_len(sg) - offset;
855 box++;
856 box_cmd_cnt++;
857 } while (len);
858 sg++;
859 }
860 /* Mark last command */
861 box--;
862 box->cmd |= CMD_LC;
863
864 /* location of command block must be 64 bit aligned */
865 BUG_ON(host->dma.cmd_busaddr & 0x07);
866
867 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
868 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
869 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
870 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
871
872 /* Flush all data to memory before starting dma */
873 mb();
874
875unmap:
876 if (err) {
877 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
878 host->dma.num_ents, host->dma.dir);
879 pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
880 mmc_hostname(host->mmc), err);
881 }
882
883 return err;
San Mehat9d2bd732009-09-22 16:44:22 -0700884}
885
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700886#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
887/**
888 * Submits data transfer request to SPS driver
889 *
890 * This function make sg (scatter gather) data buffers
891 * DMA ready and then submits them to SPS driver for
892 * transfer.
893 *
894 * @host - Pointer to sdcc host structure
895 * @data - Pointer to mmc_data structure
896 *
897 * @return 0 if success else negative value
898 */
899static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
900 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -0800901{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700902 int rc = 0;
903 u32 flags;
904 int i;
905 u32 addr, len, data_cnt;
906 struct scatterlist *sg = data->sg;
907 struct sps_pipe *sps_pipe_handle;
908
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530909 /* Prevent memory corruption */
910 BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700911
912 host->sps.sg = data->sg;
913 host->sps.num_ents = data->sg_len;
914 host->sps.xfer_req_cnt = 0;
915 if (data->flags & MMC_DATA_READ) {
916 host->sps.dir = DMA_FROM_DEVICE;
917 sps_pipe_handle = host->sps.prod.pipe_handle;
918 } else {
919 host->sps.dir = DMA_TO_DEVICE;
920 sps_pipe_handle = host->sps.cons.pipe_handle;
921 }
922
923 /* Make sg buffers DMA ready */
924 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
925 host->sps.dir);
926
927 if (rc != data->sg_len) {
928 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
929 mmc_hostname(host->mmc), rc);
930 host->sps.sg = NULL;
931 host->sps.num_ents = 0;
932 rc = -ENOMEM;
933 goto dma_map_err;
934 }
935
936 pr_debug("%s: %s: %s: pipe=0x%x, total_xfer=0x%x, sg_len=%d\n",
937 mmc_hostname(host->mmc), __func__,
938 host->sps.dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
939 (u32)sps_pipe_handle, host->curr.xfer_size, data->sg_len);
940
941 for (i = 0; i < data->sg_len; i++) {
942 /*
943 * Check if this is the last buffer to transfer?
944 * If yes then set the INT and EOT flags.
945 */
946 len = sg_dma_len(sg);
947 addr = sg_dma_address(sg);
948 flags = 0;
949 while (len > 0) {
950 if (len > SPS_MAX_DESC_SIZE) {
951 data_cnt = SPS_MAX_DESC_SIZE;
952 } else {
953 data_cnt = len;
954 if (i == data->sg_len - 1)
955 flags = SPS_IOVEC_FLAG_INT |
956 SPS_IOVEC_FLAG_EOT;
957 }
958 rc = sps_transfer_one(sps_pipe_handle, addr,
959 data_cnt, host, flags);
960 if (rc) {
961 pr_err("%s: sps_transfer_one() error! rc=%d,"
962 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
963 mmc_hostname(host->mmc), rc,
964 (u32)sps_pipe_handle, (u32)sg, i);
965 goto dma_map_err;
966 }
967 addr += data_cnt;
968 len -= data_cnt;
969 host->sps.xfer_req_cnt++;
970 }
971 sg++;
972 }
973 goto out;
974
975dma_map_err:
976 /* unmap sg buffers */
977 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
978 host->sps.dir);
979out:
980 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -0700981}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700982#else
983static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
984 struct mmc_data *data) { return 0; }
985#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -0700986
987static void
San Mehat56a8b5b2009-11-21 12:29:46 -0800988msmsdcc_start_command_deferred(struct msmsdcc_host *host,
989 struct mmc_command *cmd, u32 *c)
990{
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530991 DBG(host, "op %02x arg %08x flags %08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700992 cmd->opcode, cmd->arg, cmd->flags);
993
San Mehat56a8b5b2009-11-21 12:29:46 -0800994 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
995
996 if (cmd->flags & MMC_RSP_PRESENT) {
997 if (cmd->flags & MMC_RSP_136)
998 *c |= MCI_CPSM_LONGRSP;
999 *c |= MCI_CPSM_RESPONSE;
1000 }
1001
1002 if (/*interrupt*/0)
1003 *c |= MCI_CPSM_INTERRUPT;
1004
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301005 if (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
1006 cmd->opcode == MMC_READ_MULTIPLE_BLOCK ||
1007 cmd->opcode == MMC_WRITE_BLOCK ||
1008 cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK ||
1009 cmd->opcode == SD_IO_RW_EXTENDED)
San Mehat56a8b5b2009-11-21 12:29:46 -08001010 *c |= MCI_CSPM_DATCMD;
1011
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001012 /* Check if AUTO CMD19 is required or not? */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301013 if (host->tuning_needed &&
1014 !(host->mmc->ios.timing == MMC_TIMING_MMC_HS200)) {
1015
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301016 /*
1017 * For open ended block read operation (without CMD23),
1018 * AUTO_CMD19 bit should be set while sending the READ command.
1019 * For close ended block read operation (with CMD23),
1020 * AUTO_CMD19 bit should be set while sending CMD23.
1021 */
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301022 if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
1023 host->curr.mrq->cmd->opcode ==
1024 MMC_READ_MULTIPLE_BLOCK) ||
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301025 (!host->curr.mrq->sbc &&
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301026 (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
1027 cmd->opcode == MMC_READ_MULTIPLE_BLOCK))) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301028 msmsdcc_enable_cdr_cm_sdc4_dll(host);
1029 *c |= MCI_CSPM_AUTO_CMD19;
1030 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001031 }
1032
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05301033 /* Clear CDR_EN bit for write operations */
1034 if (host->tuning_needed && cmd->mrq->data &&
1035 (cmd->mrq->data->flags & MMC_DATA_WRITE))
1036 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) &
1037 ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
1038
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301039 if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301040 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001041 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301042 }
1043
San Mehat56a8b5b2009-11-21 12:29:46 -08001044 if (cmd == cmd->mrq->stop)
1045 *c |= MCI_CSPM_MCIABORT;
1046
San Mehat56a8b5b2009-11-21 12:29:46 -08001047 if (host->curr.cmd != NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001048 pr_err("%s: Overlapping command requests\n",
1049 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -08001050 }
1051 host->curr.cmd = cmd;
1052}
1053
1054static void
1055msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1056 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001057{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301058 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001059 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001060 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001061 unsigned int pio_irqmask = 0;
1062
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301063 BUG_ON(!data->sg);
1064 BUG_ON(!data->sg_len);
1065
San Mehat9d2bd732009-09-22 16:44:22 -07001066 host->curr.data = data;
1067 host->curr.xfer_size = data->blksz * data->blocks;
1068 host->curr.xfer_remain = host->curr.xfer_size;
1069 host->curr.data_xfered = 0;
1070 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301071 host->curr.got_auto_prog_done = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001072
San Mehat9d2bd732009-09-22 16:44:22 -07001073 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1074
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301075 if (host->curr.wait_for_auto_prog_done)
1076 datactrl |= MCI_AUTO_PROG_DONE;
1077
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001078 if (!msmsdcc_check_dma_op_req(data)) {
1079 if (host->is_dma_mode && !msmsdcc_config_dma(host, data)) {
1080 datactrl |= MCI_DPSM_DMAENABLE;
1081 } else if (host->is_sps_mode) {
1082 if (!msmsdcc_is_dml_busy(host)) {
1083 if (!msmsdcc_sps_start_xfer(host, data)) {
1084 /* Now kick start DML transfer */
1085 mb();
1086 msmsdcc_dml_start_xfer(host, data);
1087 datactrl |= MCI_DPSM_DMAENABLE;
1088 host->sps.busy = 1;
1089 }
1090 } else {
1091 /*
1092 * Can't proceed with new transfer as
1093 * previous trasnfer is already in progress.
1094 * There is no point of going into PIO mode
1095 * as well. Is this a time to do kernel panic?
1096 */
1097 pr_err("%s: %s: DML HW is busy!!!"
1098 " Can't perform new SPS transfers"
1099 " now\n", mmc_hostname(host->mmc),
1100 __func__);
1101 }
1102 }
1103 }
1104
1105 /* Is data transfer in PIO mode required? */
1106 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001107 if (data->flags & MMC_DATA_READ) {
1108 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1109 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1110 pio_irqmask |= MCI_RXDATAAVLBLMASK;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001111 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001112 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1113 MCI_TXFIFOEMPTYMASK;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001114
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001115 msmsdcc_sg_start(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001116 }
1117
1118 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301119 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
San Mehat9d2bd732009-09-22 16:44:22 -07001120
San Mehat56a8b5b2009-11-21 12:29:46 -08001121 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001122 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001123 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -07001124
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001125 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
1126 /* Use ADM (Application Data Mover) HW for Data transfer */
1127 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001128 host->cmd_timeout = timeout;
1129 host->cmd_pio_irqmask = pio_irqmask;
1130 host->cmd_datactrl = datactrl;
1131 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001132
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001133 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1134 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001135 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001136
1137 if (cmd) {
1138 msmsdcc_start_command_deferred(host, cmd, &c);
1139 host->cmd_c = c;
1140 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001141 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1142 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1143 host->base + MMCIMASK0);
1144 mb();
1145 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001146 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001147 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001148 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001149
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001150 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001151
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001152 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1153 (~(MCI_IRQ_PIO))) | pio_irqmask,
1154 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001155 writel_relaxed(datactrl, base + MMCIDATACTRL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001156
1157 if (cmd) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05301158 /* Delay between data/command */
1159 msmsdcc_sync_reg_wr(host);
San Mehat56a8b5b2009-11-21 12:29:46 -08001160 /* Daisy-chain the command if requested */
1161 msmsdcc_start_command(host, cmd, c);
Subhash Jadavanidd432952012-03-28 11:25:56 +05301162 } else {
1163 /*
1164 * We don't need delay after writing to DATA_CTRL
1165 * register if we are not writing to CMD register
1166 * immediately after this. As we already have delay
1167 * before sending the command, we just need mb() here.
1168 */
1169 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001170 }
San Mehat9d2bd732009-09-22 16:44:22 -07001171 }
1172}
1173
1174static void
1175msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1176{
San Mehat56a8b5b2009-11-21 12:29:46 -08001177 msmsdcc_start_command_deferred(host, cmd, &c);
1178 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001179}
1180
1181static void
1182msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1183 unsigned int status)
1184{
1185 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001186 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
Subhash Jadavanib30c9822012-03-27 18:03:16 +05301187 || data->mrq->cmd->opcode == MMC_BUS_TEST_R
1188 || data->mrq->cmd->opcode ==
1189 MMC_SEND_TUNING_BLOCK_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001190 pr_err("%s: Data CRC error\n",
1191 mmc_hostname(host->mmc));
1192 pr_err("%s: opcode 0x%.8x\n", __func__,
1193 data->mrq->cmd->opcode);
1194 pr_err("%s: blksz %d, blocks %d\n", __func__,
1195 data->blksz, data->blocks);
1196 data->error = -EILSEQ;
1197 }
San Mehat9d2bd732009-09-22 16:44:22 -07001198 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001199 /* CRC is optional for the bus test commands, not all
1200 * cards respond back with CRC. However controller
1201 * waits for the CRC and times out. Hence ignore the
1202 * data timeouts during the Bustest.
1203 */
1204 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1205 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301206 pr_err("%s: CMD%d: Data timeout\n",
1207 mmc_hostname(host->mmc),
1208 data->mrq->cmd->opcode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001209 data->error = -ETIMEDOUT;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301210 msmsdcc_dump_sdcc_state(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001211 }
San Mehat9d2bd732009-09-22 16:44:22 -07001212 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001213 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001214 data->error = -EIO;
1215 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001216 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001217 data->error = -EIO;
1218 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001219 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001220 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001221 data->error = -EIO;
1222 }
San Mehat9d2bd732009-09-22 16:44:22 -07001223
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001224 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001225 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001226 host->dummy_52_needed = 0;
1227}
San Mehat9d2bd732009-09-22 16:44:22 -07001228
1229static int
1230msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1231{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001232 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001233 uint32_t *ptr = (uint32_t *) buffer;
1234 int count = 0;
1235
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301236 if (remain % 4)
1237 remain = ((remain >> 2) + 1) << 2;
1238
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001239 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1240
1241 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001242 ptr++;
1243 count += sizeof(uint32_t);
1244
1245 remain -= sizeof(uint32_t);
1246 if (remain == 0)
1247 break;
1248 }
1249 return count;
1250}
1251
1252static int
1253msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001254 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001255{
1256 void __iomem *base = host->base;
1257 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001258 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001259
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001260 while (readl_relaxed(base + MMCISTATUS) &
1261 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1262 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001263
San Mehat9d2bd732009-09-22 16:44:22 -07001264 count = min(remain, maxcnt);
1265
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301266 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1267 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001268 ptr += count;
1269 remain -= count;
1270
1271 if (remain == 0)
1272 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001273 }
1274 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001275
1276 return ptr - buffer;
1277}
1278
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001279/*
1280 * Copy up to a word (4 bytes) between a scatterlist
1281 * and a temporary bounce buffer when the word lies across
1282 * two pages. The temporary buffer can then be read to/
1283 * written from the FIFO once.
1284 */
1285static void _msmsdcc_sg_consume_word(struct msmsdcc_host *host)
1286{
1287 struct msmsdcc_pio_data *pio = &host->pio;
1288 unsigned int bytes_avail;
1289
1290 if (host->curr.data->flags & MMC_DATA_READ)
1291 memcpy(pio->sg_miter.addr, pio->bounce_buf,
1292 pio->bounce_buf_len);
1293 else
1294 memcpy(pio->bounce_buf, pio->sg_miter.addr,
1295 pio->bounce_buf_len);
1296
1297 while (pio->bounce_buf_len != 4) {
1298 if (!sg_miter_next(&pio->sg_miter))
1299 break;
1300 bytes_avail = min_t(unsigned int, pio->sg_miter.length,
1301 4 - pio->bounce_buf_len);
1302 if (host->curr.data->flags & MMC_DATA_READ)
1303 memcpy(pio->sg_miter.addr,
1304 &pio->bounce_buf[pio->bounce_buf_len],
1305 bytes_avail);
1306 else
1307 memcpy(&pio->bounce_buf[pio->bounce_buf_len],
1308 pio->sg_miter.addr, bytes_avail);
1309
1310 pio->sg_miter.consumed = bytes_avail;
1311 pio->bounce_buf_len += bytes_avail;
1312 }
1313}
1314
1315/*
1316 * Use sg_miter_next to return as many 4-byte aligned
1317 * chunks as possible, using a temporary 4 byte buffer
1318 * for alignment if necessary
1319 */
1320static int msmsdcc_sg_next(struct msmsdcc_host *host, char **buf, int *len)
1321{
1322 struct msmsdcc_pio_data *pio = &host->pio;
1323 unsigned int length, rlength;
1324 char *buffer;
1325
1326 if (!sg_miter_next(&pio->sg_miter))
1327 return 0;
1328
1329 buffer = pio->sg_miter.addr;
1330 length = pio->sg_miter.length;
1331
1332 if (length < host->curr.xfer_remain) {
1333 rlength = round_down(length, 4);
1334 if (rlength) {
1335 /*
1336 * We have a 4-byte aligned chunk.
1337 * The rounding will be reflected by
1338 * a call to msmsdcc_sg_consumed
1339 */
1340 length = rlength;
1341 goto sg_next_end;
1342 }
1343 /*
1344 * We have a length less than 4 bytes. Check to
1345 * see if more buffer is available, and combine
1346 * to make 4 bytes if possible.
1347 */
1348 pio->bounce_buf_len = length;
1349 memset(pio->bounce_buf, 0, 4);
1350
1351 /*
1352 * On a read, get 4 bytes from FIFO, and distribute
1353 * (4-bouce_buf_len) bytes into consecutive
1354 * sgl buffers when msmsdcc_sg_consumed is called
1355 */
1356 if (host->curr.data->flags & MMC_DATA_READ) {
1357 buffer = pio->bounce_buf;
1358 length = 4;
1359 goto sg_next_end;
1360 } else {
1361 _msmsdcc_sg_consume_word(host);
1362 buffer = pio->bounce_buf;
1363 length = pio->bounce_buf_len;
1364 }
1365 }
1366
1367sg_next_end:
1368 *buf = buffer;
1369 *len = length;
1370 return 1;
1371}
1372
1373/*
1374 * Update sg_miter.consumed based on how many bytes were
1375 * consumed. If the bounce buffer was used to read from FIFO,
1376 * redistribute into sgls.
1377 */
1378static void msmsdcc_sg_consumed(struct msmsdcc_host *host,
1379 unsigned int length)
1380{
1381 struct msmsdcc_pio_data *pio = &host->pio;
1382
1383 if (host->curr.data->flags & MMC_DATA_READ) {
1384 if (length > pio->sg_miter.consumed)
1385 /*
1386 * consumed 4 bytes, but sgl
1387 * describes < 4 bytes
1388 */
1389 _msmsdcc_sg_consume_word(host);
1390 else
1391 pio->sg_miter.consumed = length;
1392 } else
1393 if (length < pio->sg_miter.consumed)
1394 pio->sg_miter.consumed = length;
1395}
1396
1397static void msmsdcc_sg_start(struct msmsdcc_host *host)
1398{
1399 unsigned int sg_miter_flags = SG_MITER_ATOMIC;
1400
1401 host->pio.bounce_buf_len = 0;
1402
1403 if (host->curr.data->flags & MMC_DATA_READ)
1404 sg_miter_flags |= SG_MITER_TO_SG;
1405 else
1406 sg_miter_flags |= SG_MITER_FROM_SG;
1407
1408 sg_miter_start(&host->pio.sg_miter, host->curr.data->sg,
1409 host->curr.data->sg_len, sg_miter_flags);
1410}
1411
1412static void msmsdcc_sg_stop(struct msmsdcc_host *host)
1413{
1414 sg_miter_stop(&host->pio.sg_miter);
1415}
1416
San Mehat1cd22962010-02-03 12:59:29 -08001417static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001418msmsdcc_pio_irq(int irq, void *dev_id)
1419{
1420 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001421 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001422 uint32_t status;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001423 unsigned long flags;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001424 unsigned int remain;
1425 char *buffer;
San Mehat9d2bd732009-09-22 16:44:22 -07001426
Murali Palnati36448a42011-09-02 15:06:18 +05301427 spin_lock(&host->lock);
1428
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001429 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001430
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001431 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301432 (MCI_IRQ_PIO)) == 0) {
1433 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001434 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301435 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001436#if IRQ_DEBUG
1437 msmsdcc_print_status(host, "irq1-r", status);
1438#endif
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001439 local_irq_save(flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001440
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001441 do {
1442 unsigned int len;
San Mehat9d2bd732009-09-22 16:44:22 -07001443
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001444 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1445 | MCI_RXDATAAVLBL)))
1446 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001447
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001448 if (!msmsdcc_sg_next(host, &buffer, &remain))
1449 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001450
San Mehat9d2bd732009-09-22 16:44:22 -07001451 len = 0;
1452 if (status & MCI_RXACTIVE)
1453 len = msmsdcc_pio_read(host, buffer, remain);
1454 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001455 len = msmsdcc_pio_write(host, buffer, remain);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001456
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301457 /* len might have aligned to 32bits above */
1458 if (len > remain)
1459 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001460
San Mehat9d2bd732009-09-22 16:44:22 -07001461 host->curr.xfer_remain -= len;
1462 host->curr.data_xfered += len;
1463 remain -= len;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001464 msmsdcc_sg_consumed(host, len);
San Mehat9d2bd732009-09-22 16:44:22 -07001465
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001466 if (remain) /* Done with this page? */
1467 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001468
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001469 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001470 } while (1);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001471
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001472 msmsdcc_sg_stop(host);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001473 local_irq_restore(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001474
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001475 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1476 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1477 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1478 host->base + MMCIMASK0);
1479 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301480 /*
1481 * back to back write to MASK0 register don't need
1482 * synchronization delay.
1483 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001484 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1485 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1486 }
1487 mb();
1488 } else if (!host->curr.xfer_remain) {
1489 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1490 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1491 mb();
1492 }
San Mehat9d2bd732009-09-22 16:44:22 -07001493
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001494 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001495
1496 return IRQ_HANDLED;
1497}
1498
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001499static void
1500msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1501
1502static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1503 struct mmc_data *data)
1504{
1505 u32 loop_cnt = 0;
1506
1507 /*
1508 * For read commands with data less than fifo size, it is possible to
1509 * get DATAEND first and RXDATA_AVAIL might be set later because of
1510 * synchronization delay through the asynchronous RX FIFO. Thus, for
1511 * such cases, even after DATAEND interrupt is received software
1512 * should poll for RXDATA_AVAIL until the requested data is read out
1513 * of FIFO. This change is needed to get around this abnormal but
1514 * sometimes expected behavior of SDCC3 controller.
1515 *
1516 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1517 * after the data is loaded into RX FIFO. This would amount to less
1518 * than a microsecond and thus looping for 1000 times is good enough
1519 * for that delay.
1520 */
1521 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1522 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1523 spin_unlock(&host->lock);
1524 msmsdcc_pio_irq(1, host);
1525 spin_lock(&host->lock);
1526 }
1527 }
1528 if (loop_cnt == 1000) {
1529 pr_info("%s: Timed out while polling for Rx Data\n",
1530 mmc_hostname(host->mmc));
1531 data->error = -ETIMEDOUT;
1532 msmsdcc_reset_and_restore(host);
1533 }
1534}
1535
San Mehat9d2bd732009-09-22 16:44:22 -07001536static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1537{
1538 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001539
1540 host->curr.cmd = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001541 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1542 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1543 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1544 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -07001545
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001546 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301547 pr_debug("%s: CMD%d: Command timeout\n",
1548 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001549 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001550 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301551 !host->tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301552 pr_err("%s: CMD%d: Command CRC error\n",
1553 mmc_hostname(host->mmc), cmd->opcode);
1554 msmsdcc_dump_sdcc_state(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001555 cmd->error = -EILSEQ;
1556 }
1557
1558 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001559 if (host->curr.data && host->dma.sg &&
1560 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001561 msm_dmov_stop_cmd(host->dma.channel,
1562 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001563 else if (host->curr.data && host->sps.sg &&
1564 host->is_sps_mode){
1565 /* Stop current SPS transfer */
1566 msmsdcc_sps_exit_curr_xfer(host);
1567 }
San Mehat9d2bd732009-09-22 16:44:22 -07001568 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301569 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001570 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301571 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301572 } else { /* host->data == NULL */
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301573 if (!cmd->error && host->prog_enable) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301574 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001575 host->prog_enable = 0;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301576 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001577 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301578 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301579 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301580 host->prog_enable = 0;
Subhash Jadavanied6b0e42012-03-07 16:36:27 +05301581 host->curr.wait_for_auto_prog_done = 0;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001582 if (host->dummy_52_needed)
1583 host->dummy_52_needed = 0;
1584 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001585 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301586 msmsdcc_request_end(host, cmd->mrq);
1587 }
1588 }
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301589 } else if ((cmd == host->curr.mrq->sbc) && cmd->data) {
1590 if (cmd->data->flags & MMC_DATA_READ)
1591 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1592 else
1593 msmsdcc_request_start(host, host->curr.mrq);
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301594 } else if (cmd->data) {
1595 if (!(cmd->data->flags & MMC_DATA_READ))
1596 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001597 }
1598}
1599
San Mehat9d2bd732009-09-22 16:44:22 -07001600static irqreturn_t
1601msmsdcc_irq(int irq, void *dev_id)
1602{
1603 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001604 u32 status;
1605 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001606 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001607
1608 spin_lock(&host->lock);
1609
1610 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001611 struct mmc_command *cmd;
1612 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001613
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001614 if (timer) {
1615 timer = 0;
1616 msmsdcc_delay(host);
1617 }
San Mehat865c8062009-11-13 13:42:06 -08001618
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001619 if (!host->clks_on) {
1620 pr_debug("%s: %s: SDIO async irq received\n",
1621 mmc_hostname(host->mmc), __func__);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301622
1623 /*
1624 * Only async interrupt can come when clocks are off,
1625 * disable further interrupts and enable them when
1626 * clocks are on.
1627 */
1628 if (!host->sdcc_irq_disabled) {
1629 disable_irq_nosync(irq);
1630 host->sdcc_irq_disabled = 1;
1631 }
1632
1633 /*
1634 * If mmc_card_wake_sdio_irq() is set, mmc core layer
1635 * will take care of signaling sdio irq during
1636 * mmc_sdio_resume().
1637 */
1638 if (host->sdcc_suspended)
1639 /*
1640 * This is a wakeup interrupt so hold wakelock
1641 * until SDCC resume is handled.
1642 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001643 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301644 else
1645 mmc_signal_sdio_irq(host->mmc);
1646 ret = 1;
1647 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001648 }
1649
1650 status = readl_relaxed(host->base + MMCISTATUS);
1651
1652 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1653 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001654 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001655
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001656#if IRQ_DEBUG
1657 msmsdcc_print_status(host, "irq0-r", status);
1658#endif
1659 status &= readl_relaxed(host->base + MMCIMASK0);
1660 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301661 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301662 if (host->clk_rate <=
1663 msmsdcc_get_min_sup_clk_rate(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +05301664 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001665#if IRQ_DEBUG
1666 msmsdcc_print_status(host, "irq0-p", status);
1667#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001668
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001669#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
1670 if (status & MCI_SDIOINTROPE) {
1671 if (host->sdcc_suspending)
1672 wake_lock(&host->sdio_suspend_wlock);
1673 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001674 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001675#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001676 data = host->curr.data;
1677
1678 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001679 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1680 MCI_CMDTIMEOUT)) {
1681 if (status & MCI_CMDTIMEOUT)
1682 pr_debug("%s: dummy CMD52 timeout\n",
1683 mmc_hostname(host->mmc));
1684 if (status & MCI_CMDCRCFAIL)
1685 pr_debug("%s: dummy CMD52 CRC failed\n",
1686 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001687 host->dummy_52_sent = 0;
1688 host->dummy_52_needed = 0;
1689 if (data) {
1690 msmsdcc_stop_data(host);
1691 msmsdcc_request_end(host, data->mrq);
1692 }
1693 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001694 spin_unlock(&host->lock);
1695 return IRQ_HANDLED;
1696 }
1697 break;
1698 }
1699
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001700 /*
1701 * Check for proper command response
1702 */
1703 cmd = host->curr.cmd;
1704 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1705 MCI_CMDTIMEOUT | MCI_PROGDONE |
1706 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1707 msmsdcc_do_cmdirq(host, status);
1708 }
1709
Sathish Ambley081d7842011-11-29 11:19:41 -08001710 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001711 /* Check for data errors */
1712 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1713 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1714 msmsdcc_data_err(host, data, status);
1715 host->curr.data_xfered = 0;
1716 if (host->dma.sg && host->is_dma_mode)
1717 msm_dmov_stop_cmd(host->dma.channel,
1718 &host->dma.hdr, 0);
1719 else if (host->sps.sg && host->is_sps_mode) {
1720 /* Stop current SPS transfer */
1721 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301722 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001723 msmsdcc_reset_and_restore(host);
1724 if (host->curr.data)
1725 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301726 if (!data->stop || (host->curr.mrq->sbc
1727 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001728 timer |=
1729 msmsdcc_request_end(host,
1730 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301731 else if ((host->curr.mrq->sbc
1732 && data->error) ||
1733 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001734 msmsdcc_start_command(host,
1735 data->stop,
1736 0);
1737 timer = 1;
1738 }
1739 }
1740 }
1741
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301742 /* Check for prog done */
1743 if (host->curr.wait_for_auto_prog_done &&
1744 (status & MCI_PROGDONE))
1745 host->curr.got_auto_prog_done = 1;
1746
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001747 /* Check for data done */
1748 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1749 host->curr.got_dataend = 1;
1750
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301751 if (host->curr.got_dataend &&
1752 (!host->curr.wait_for_auto_prog_done ||
1753 (host->curr.wait_for_auto_prog_done &&
1754 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001755 /*
1756 * If DMA is still in progress, we complete
1757 * via the completion handler
1758 */
1759 if (!host->dma.busy && !host->sps.busy) {
1760 /*
1761 * There appears to be an issue in the
1762 * controller where if you request a
1763 * small block transfer (< fifo size),
1764 * you may get your DATAEND/DATABLKEND
1765 * irq without the PIO data irq.
1766 *
1767 * Check to see if theres still data
1768 * to be read, and simulate a PIO irq.
1769 */
1770 if (data->flags & MMC_DATA_READ)
1771 msmsdcc_wait_for_rxdata(host,
1772 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001773 if (!data->error) {
1774 host->curr.data_xfered =
1775 host->curr.xfer_size;
1776 host->curr.xfer_remain -=
1777 host->curr.xfer_size;
1778 }
1779
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001780 if (!host->dummy_52_needed) {
1781 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301782 if (!data->stop ||
1783 (host->curr.mrq->sbc
1784 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001785 msmsdcc_request_end(
1786 host,
1787 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301788 else if ((host->curr.mrq->sbc
1789 && data->error) ||
1790 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001791 msmsdcc_start_command(
1792 host,
1793 data->stop, 0);
1794 timer = 1;
1795 }
1796 } else {
1797 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001798 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001799 &dummy52cmd,
1800 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001801 }
1802 }
1803 }
1804 }
1805
San Mehat9d2bd732009-09-22 16:44:22 -07001806 ret = 1;
1807 } while (status);
1808
1809 spin_unlock(&host->lock);
1810
San Mehat9d2bd732009-09-22 16:44:22 -07001811 return IRQ_RETVAL(ret);
1812}
1813
1814static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001815msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1816{
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301817 if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001818 /* Queue/read data, daisy-chain command when data starts */
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301819 if (mrq->sbc)
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301820 msmsdcc_start_data(host, mrq->data, mrq->sbc, 0);
1821 else
1822 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001823 } else {
1824 msmsdcc_start_command(host, mrq->cmd, 0);
1825 }
1826}
1827
1828static void
San Mehat9d2bd732009-09-22 16:44:22 -07001829msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1830{
1831 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001832 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001833
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001834 /*
1835 * Get the SDIO AL client out of LPM.
1836 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001837 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001838 if (host->plat->is_sdio_al_client)
1839 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001840
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301841 /* check if sps pipe reset is pending? */
1842 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1843 msmsdcc_sps_pipes_reset_and_restore(host);
1844 host->sps.pipe_reset_pending = false;
1845 }
1846
San Mehat9d2bd732009-09-22 16:44:22 -07001847 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001848 WARN(host->curr.mrq, "Request in progress\n");
1849 WARN(!host->pwr, "SDCC power is turned off\n");
1850 WARN(!host->clks_on, "SDCC clocks are turned off\n");
1851 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
San Mehat9d2bd732009-09-22 16:44:22 -07001852
1853 if (host->eject) {
1854 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1855 mrq->cmd->error = 0;
1856 mrq->data->bytes_xfered = mrq->data->blksz *
1857 mrq->data->blocks;
1858 } else
1859 mrq->cmd->error = -ENOMEDIUM;
1860
1861 spin_unlock_irqrestore(&host->lock, flags);
1862 mmc_request_done(mmc, mrq);
1863 return;
1864 }
1865
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301866 /*
1867 * Kick the software command timeout timer here.
1868 * Timer expires in 10 secs.
1869 */
1870 mod_timer(&host->req_tout_timer,
1871 (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
San Mehat9d2bd732009-09-22 16:44:22 -07001872
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301873 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301874 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301875 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
1876 mrq->cmd->opcode == 54) {
Pratibhasagar V1c11da62011-11-14 12:36:35 +05301877 if (!host->sdcc_version)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001878 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301879 else
1880 /*
1881 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
1882 * write operations using CMD53 and CMD54.
1883 * Setting this bit with CMD53 would
1884 * automatically triggers PROG_DONE interrupt
1885 * without the need of sending dummy CMD52.
1886 */
1887 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani758cf8c2011-11-13 11:59:55 +05301888 } else if (mrq->cmd->opcode == MMC_WRITE_BLOCK &&
1889 host->sdcc_version) {
1890 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001891 }
San Mehat9d2bd732009-09-22 16:44:22 -07001892 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301893
Pratibhasagar V00b94332011-10-18 14:57:27 +05301894 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301895 mrq->sbc->mrq = mrq;
1896 mrq->sbc->data = mrq->data;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301897 if (mrq->data->flags & MMC_DATA_WRITE) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301898 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301899 msmsdcc_start_command(host, mrq->sbc, 0);
1900 } else {
1901 msmsdcc_request_start(host, mrq);
1902 }
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301903 } else {
1904 msmsdcc_request_start(host, mrq);
1905 }
1906
San Mehat9d2bd732009-09-22 16:44:22 -07001907 spin_unlock_irqrestore(&host->lock, flags);
1908}
1909
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001910static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1911 int min_uV, int max_uV)
1912{
1913 int rc = 0;
1914
1915 if (vreg->set_voltage_sup) {
1916 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1917 if (rc) {
1918 pr_err("%s: regulator_set_voltage(%s) failed."
1919 " min_uV=%d, max_uV=%d, rc=%d\n",
1920 __func__, vreg->name, min_uV, max_uV, rc);
1921 }
1922 }
1923
1924 return rc;
1925}
1926
1927static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1928 int uA_load)
1929{
1930 int rc = 0;
1931
Krishna Kondafea60182011-11-01 16:01:34 -07001932 /* regulators that do not support regulator_set_voltage also
1933 do not support regulator_set_optimum_mode */
1934 if (vreg->set_voltage_sup) {
1935 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1936 if (rc < 0)
1937 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
1938 "uA_load=%d) failed. rc=%d\n", __func__,
1939 vreg->name, uA_load, rc);
1940 else
1941 /* regulator_set_optimum_mode() can return non zero
1942 * value even for success case.
1943 */
1944 rc = 0;
1945 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001946
1947 return rc;
1948}
1949
1950static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1951 struct device *dev)
1952{
1953 int rc = 0;
1954
1955 /* check if regulator is already initialized? */
1956 if (vreg->reg)
1957 goto out;
1958
1959 /* Get the regulator handle */
1960 vreg->reg = regulator_get(dev, vreg->name);
1961 if (IS_ERR(vreg->reg)) {
1962 rc = PTR_ERR(vreg->reg);
1963 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
1964 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001965 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001966 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001967
1968 if (regulator_count_voltages(vreg->reg) > 0)
1969 vreg->set_voltage_sup = 1;
1970
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001971out:
1972 return rc;
1973}
1974
1975static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
1976{
1977 if (vreg->reg)
1978 regulator_put(vreg->reg);
1979}
1980
1981/* This init function should be called only once for each SDCC slot */
1982static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
1983{
1984 int rc = 0;
1985 struct msm_mmc_slot_reg_data *curr_slot;
1986 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1987 struct device *dev = mmc_dev(host->mmc);
1988
1989 curr_slot = host->plat->vreg_data;
1990 if (!curr_slot)
1991 goto out;
1992
1993 curr_vdd_reg = curr_slot->vdd_data;
1994 curr_vccq_reg = curr_slot->vccq_data;
1995 curr_vddp_reg = curr_slot->vddp_data;
1996
1997 if (is_init) {
1998 /*
1999 * Get the regulator handle from voltage regulator framework
2000 * and then try to set the voltage level for the regulator
2001 */
2002 if (curr_vdd_reg) {
2003 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
2004 if (rc)
2005 goto out;
2006 }
2007 if (curr_vccq_reg) {
2008 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
2009 if (rc)
2010 goto vdd_reg_deinit;
2011 }
2012 if (curr_vddp_reg) {
2013 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
2014 if (rc)
2015 goto vccq_reg_deinit;
2016 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002017 rc = msmsdcc_vreg_reset(host);
2018 if (rc)
2019 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
2020 host->pdev_id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002021 goto out;
2022 } else {
2023 /* Deregister all regulators from regulator framework */
2024 goto vddp_reg_deinit;
2025 }
2026vddp_reg_deinit:
2027 if (curr_vddp_reg)
2028 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
2029vccq_reg_deinit:
2030 if (curr_vccq_reg)
2031 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
2032vdd_reg_deinit:
2033 if (curr_vdd_reg)
2034 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2035out:
2036 return rc;
2037}
2038
2039static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2040{
2041 int rc = 0;
2042
Subhash Jadavanicc922692011-08-01 23:05:01 +05302043 /* Put regulator in HPM (high power mode) */
2044 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2045 if (rc < 0)
2046 goto out;
2047
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002048 if (!vreg->is_enabled) {
2049 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302050 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2051 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002052 if (rc)
2053 goto out;
2054
2055 rc = regulator_enable(vreg->reg);
2056 if (rc) {
2057 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2058 __func__, vreg->name, rc);
2059 goto out;
2060 }
2061 vreg->is_enabled = true;
2062 }
2063
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002064out:
2065 return rc;
2066}
2067
2068static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
2069{
2070 int rc = 0;
2071
2072 /* Never disable regulator marked as always_on */
2073 if (vreg->is_enabled && !vreg->always_on) {
2074 rc = regulator_disable(vreg->reg);
2075 if (rc) {
2076 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2077 __func__, vreg->name, rc);
2078 goto out;
2079 }
2080 vreg->is_enabled = false;
2081
2082 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2083 if (rc < 0)
2084 goto out;
2085
2086 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302087 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002088 if (rc)
2089 goto out;
2090 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
2091 /* Put always_on regulator in LPM (low power mode) */
2092 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2093 if (rc < 0)
2094 goto out;
2095 }
2096out:
2097 return rc;
2098}
2099
2100static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
2101{
2102 int rc = 0, i;
2103 struct msm_mmc_slot_reg_data *curr_slot;
2104 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
2105 struct msm_mmc_reg_data *vreg_table[3];
2106
2107 curr_slot = host->plat->vreg_data;
2108 if (!curr_slot)
2109 goto out;
2110
2111 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
2112 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
2113 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
2114
2115 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2116 if (vreg_table[i]) {
2117 if (enable)
2118 rc = msmsdcc_vreg_enable(vreg_table[i]);
2119 else
2120 rc = msmsdcc_vreg_disable(vreg_table[i]);
2121 if (rc)
2122 goto out;
2123 }
2124 }
2125out:
2126 return rc;
2127}
2128
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002129/*
2130 * Reset vreg by ensuring it is off during probe. A call
2131 * to enable vreg is needed to balance disable vreg
2132 */
2133static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2134{
2135 int rc;
2136
2137 rc = msmsdcc_setup_vreg(host, 1);
2138 if (rc)
2139 return rc;
2140 rc = msmsdcc_setup_vreg(host, 0);
2141 return rc;
2142}
2143
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302144static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002145{
2146 int rc = 0;
2147
2148 if (host->plat->vreg_data) {
2149 struct msm_mmc_reg_data *vddp_reg =
2150 host->plat->vreg_data->vddp_data;
2151
2152 if (vddp_reg && vddp_reg->is_enabled)
2153 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
2154 }
2155
2156 return rc;
2157}
2158
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302159static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
2160{
2161 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2162 int rc = 0;
2163
2164 if (curr_slot && curr_slot->vddp_data) {
2165 rc = msmsdcc_set_vddp_level(host,
2166 curr_slot->vddp_data->low_vol_level);
2167
2168 if (rc)
2169 pr_err("%s: %s: failed to change vddp level to %d",
2170 mmc_hostname(host->mmc), __func__,
2171 curr_slot->vddp_data->low_vol_level);
2172 }
2173
2174 return rc;
2175}
2176
2177static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
2178{
2179 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2180 int rc = 0;
2181
2182 if (curr_slot && curr_slot->vddp_data) {
2183 rc = msmsdcc_set_vddp_level(host,
2184 curr_slot->vddp_data->high_vol_level);
2185
2186 if (rc)
2187 pr_err("%s: %s: failed to change vddp level to %d",
2188 mmc_hostname(host->mmc), __func__,
2189 curr_slot->vddp_data->high_vol_level);
2190 }
2191
2192 return rc;
2193}
2194
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302195static inline int msmsdcc_set_vccq_vol(struct msmsdcc_host *host, int level)
2196{
2197 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2198 int rc = 0;
2199
2200 if (curr_slot && curr_slot->vccq_data) {
2201 rc = msmsdcc_vreg_set_voltage(curr_slot->vccq_data,
2202 level, level);
2203 if (rc)
2204 pr_err("%s: %s: failed to change vccq level to %d",
2205 mmc_hostname(host->mmc), __func__, level);
2206 }
2207
2208 return rc;
2209}
2210
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002211static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2212{
2213 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2214 return 1;
2215 return 0;
2216}
2217
2218static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
2219{
2220 if (enable) {
2221 if (!IS_ERR_OR_NULL(host->dfab_pclk))
2222 clk_enable(host->dfab_pclk);
2223 if (!IS_ERR(host->pclk))
2224 clk_enable(host->pclk);
2225 clk_enable(host->clk);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302226 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302227 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002228 } else {
Subhash Jadavanidd432952012-03-28 11:25:56 +05302229 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302230 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002231 clk_disable(host->clk);
2232 if (!IS_ERR(host->pclk))
2233 clk_disable(host->pclk);
2234 if (!IS_ERR_OR_NULL(host->dfab_pclk))
2235 clk_disable(host->dfab_pclk);
2236 }
2237}
2238
2239static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2240 unsigned int req_clk)
2241{
2242 unsigned int sel_clk = -1;
2243
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302244 if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
2245 sel_clk = msmsdcc_get_min_sup_clk_rate(host);
2246 goto out;
2247 }
2248
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002249 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2250 unsigned char cnt;
2251
2252 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2253 if (host->plat->sup_clk_table[cnt] > req_clk)
2254 break;
2255 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2256 sel_clk = host->plat->sup_clk_table[cnt];
2257 break;
2258 } else
2259 sel_clk = host->plat->sup_clk_table[cnt];
2260 }
2261 } else {
2262 if ((req_clk < host->plat->msmsdcc_fmax) &&
2263 (req_clk > host->plat->msmsdcc_fmid))
2264 sel_clk = host->plat->msmsdcc_fmid;
2265 else
2266 sel_clk = req_clk;
2267 }
2268
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302269out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002270 return sel_clk;
2271}
2272
2273static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2274 struct msmsdcc_host *host)
2275{
2276 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2277 return host->plat->sup_clk_table[0];
2278 else
2279 return host->plat->msmsdcc_fmin;
2280}
2281
2282static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2283 struct msmsdcc_host *host)
2284{
2285 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2286 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2287 else
2288 return host->plat->msmsdcc_fmax;
2289}
2290
2291static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302292{
2293 struct msm_mmc_gpio_data *curr;
2294 int i, rc = 0;
2295
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002296 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302297 for (i = 0; i < curr->size; i++) {
2298 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002299 if (curr->gpio[i].is_always_on &&
2300 curr->gpio[i].is_enabled)
2301 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302302 rc = gpio_request(curr->gpio[i].no,
2303 curr->gpio[i].name);
2304 if (rc) {
2305 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2306 mmc_hostname(host->mmc),
2307 curr->gpio[i].no,
2308 curr->gpio[i].name, rc);
2309 goto free_gpios;
2310 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002311 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302312 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002313 if (curr->gpio[i].is_always_on)
2314 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302315 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002316 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302317 }
2318 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002319 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302320
2321free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002322 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302323 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002324 curr->gpio[i].is_enabled = false;
2325 }
2326out:
2327 return rc;
2328}
2329
2330static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2331{
2332 struct msm_mmc_pad_data *curr;
2333 int i;
2334
2335 curr = host->plat->pin_data->pad_data;
2336 for (i = 0; i < curr->drv->size; i++) {
2337 if (enable)
2338 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2339 curr->drv->on[i].val);
2340 else
2341 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2342 curr->drv->off[i].val);
2343 }
2344
2345 for (i = 0; i < curr->pull->size; i++) {
2346 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002347 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002348 curr->pull->on[i].val);
2349 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002350 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002351 curr->pull->off[i].val);
2352 }
2353
2354 return 0;
2355}
2356
2357static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2358{
2359 int rc = 0;
2360
2361 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2362 return 0;
2363
2364 if (host->plat->pin_data->is_gpio)
2365 rc = msmsdcc_setup_gpio(host, enable);
2366 else
2367 rc = msmsdcc_setup_pad(host, enable);
2368
2369 if (!rc)
2370 host->plat->pin_data->cfg_sts = enable;
2371
2372 return rc;
2373}
2374
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302375static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2376{
2377 u32 pwr = 0;
2378 int ret = 0;
2379 struct mmc_host *mmc = host->mmc;
2380
2381 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2382 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2383 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2384 ret = msmsdcc_setup_vreg(host, !!ios->vdd);
2385
2386 if (ret) {
2387 pr_err("%s: Failed to setup voltage regulators\n",
2388 mmc_hostname(host->mmc));
2389 goto out;
2390 }
2391
2392 switch (ios->power_mode) {
2393 case MMC_POWER_OFF:
2394 pwr = MCI_PWR_OFF;
2395 if (host->plat->cfg_mpm_sdiowakeup)
2396 host->plat->cfg_mpm_sdiowakeup(
2397 mmc_dev(mmc), SDC_DAT1_DISABLE);
2398 /*
2399 * As VDD pad rail is always on, set low voltage for VDD
2400 * pad rail when slot is unused (when card is not present
2401 * or during system suspend).
2402 */
2403 msmsdcc_set_vddp_low_vol(host);
2404 msmsdcc_setup_pins(host, false);
2405 break;
2406 case MMC_POWER_UP:
2407 /* writing PWR_UP bit is redundant */
2408 pwr = MCI_PWR_UP;
2409 if (host->plat->cfg_mpm_sdiowakeup)
2410 host->plat->cfg_mpm_sdiowakeup(
2411 mmc_dev(mmc), SDC_DAT1_ENABLE);
2412
2413 msmsdcc_set_vddp_high_vol(host);
2414 msmsdcc_setup_pins(host, true);
2415 break;
2416 case MMC_POWER_ON:
2417 pwr = MCI_PWR_ON;
2418 break;
2419 }
2420
2421out:
2422 return pwr;
2423}
2424
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002425static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2426{
2427 unsigned int wakeup_irq;
2428
2429 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2430 host->plat->sdiowakeup_irq :
2431 host->core_irqres->start;
2432
2433 if (!host->irq_wake_enabled) {
2434 enable_irq_wake(wakeup_irq);
2435 host->irq_wake_enabled = true;
2436 }
2437}
2438
2439static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2440{
2441 unsigned int wakeup_irq;
2442
2443 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2444 host->plat->sdiowakeup_irq :
2445 host->core_irqres->start;
2446
2447 if (host->irq_wake_enabled) {
2448 disable_irq_wake(wakeup_irq);
2449 host->irq_wake_enabled = false;
2450 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302451}
2452
San Mehat9d2bd732009-09-22 16:44:22 -07002453static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302454msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
2455{
2456 struct mmc_host *mmc = host->mmc;
2457
2458 /*
2459 * SDIO_AL clients has different mechanism of handling LPM through
2460 * sdio_al driver itself. The sdio wakeup interrupt is configured as
2461 * part of that. Here, we are interested only in clients like WLAN.
2462 */
2463 if (!(mmc->card && mmc_card_sdio(mmc->card))
2464 || host->plat->is_sdio_al_client)
2465 goto out;
2466
2467 if (!host->sdcc_suspended) {
2468 /*
2469 * When MSM is not in power collapse and we
2470 * are disabling clocks, enable bit 22 in MASK0
2471 * to handle asynchronous SDIO interrupts.
2472 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302473 if (enable_wakeup_irq) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302474 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302475 mb();
2476 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302477 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302478 msmsdcc_sync_reg_wr(host);
2479 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302480 goto out;
2481 } else if (!mmc_card_wake_sdio_irq(mmc)) {
2482 /*
2483 * Wakeup MSM only if SDIO function drivers set
2484 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
2485 */
2486 goto out;
2487 }
2488
2489 if (enable_wakeup_irq) {
2490 if (!host->plat->sdiowakeup_irq) {
2491 /*
2492 * When there is no gpio line that can be configured
2493 * as wakeup interrupt handle it by configuring
2494 * asynchronous sdio interrupts and DAT1 line.
2495 */
2496 writel_relaxed(MCI_SDIOINTMASK,
2497 host->base + MMCIMASK0);
2498 mb();
2499 if (host->plat->cfg_mpm_sdiowakeup)
2500 host->plat->cfg_mpm_sdiowakeup(
2501 mmc_dev(mmc), SDC_DAT1_ENWAKE);
2502 /* configure sdcc core interrupt as wakeup interrupt */
2503 msmsdcc_enable_irq_wake(host);
2504 } else {
2505 /* Let gpio line handle wakeup interrupt */
2506 writel_relaxed(0, host->base + MMCIMASK0);
2507 mb();
2508 if (host->sdio_wakeupirq_disabled) {
2509 host->sdio_wakeupirq_disabled = 0;
2510 /* configure gpio line as wakeup interrupt */
2511 msmsdcc_enable_irq_wake(host);
2512 enable_irq(host->plat->sdiowakeup_irq);
2513 }
2514 }
2515 } else {
2516 if (!host->plat->sdiowakeup_irq) {
2517 /*
2518 * We may not have cleared bit 22 in the interrupt
2519 * handler as the clocks might be off at that time.
2520 */
2521 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302522 msmsdcc_sync_reg_wr(host);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302523 if (host->plat->cfg_mpm_sdiowakeup)
2524 host->plat->cfg_mpm_sdiowakeup(
2525 mmc_dev(mmc), SDC_DAT1_DISWAKE);
2526 msmsdcc_disable_irq_wake(host);
2527 } else if (!host->sdio_wakeupirq_disabled) {
2528 disable_irq_nosync(host->plat->sdiowakeup_irq);
2529 msmsdcc_disable_irq_wake(host);
2530 host->sdio_wakeupirq_disabled = 1;
2531 }
2532 }
2533out:
2534 return;
2535}
2536
2537static void
San Mehat9d2bd732009-09-22 16:44:22 -07002538msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2539{
2540 struct msmsdcc_host *host = mmc_priv(mmc);
2541 u32 clk = 0, pwr = 0;
2542 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002543 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002544 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002545
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002546 DBG(host, "ios->clock = %u\n", ios->clock);
Sahitya Tummala7a892482011-01-18 11:22:49 +05302547
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302548 /*
2549 * Disable SDCC core interrupt until set_ios is completed.
2550 * This avoids any race conditions with interrupt raised
2551 * when turning on/off the clocks. One possible
2552 * scenario is SDIO operational interrupt while the clock
2553 * is turned off.
2554 */
2555
2556 spin_lock_irqsave(&host->lock, flags);
2557 if (!host->sdcc_irq_disabled) {
2558 spin_unlock_irqrestore(&host->lock, flags);
2559 disable_irq(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002560 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302561 host->sdcc_irq_disabled = 1;
2562 }
2563 spin_unlock_irqrestore(&host->lock, flags);
2564
2565 pwr = msmsdcc_setup_pwr(host, ios);
2566
2567 spin_lock_irqsave(&host->lock, flags);
2568 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002569 if (!host->clks_on) {
2570 msmsdcc_setup_clocks(host, true);
2571 host->clks_on = 1;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302572 writel_relaxed(host->mci_irqenable,
2573 host->base + MMCIMASK0);
2574 mb();
2575 msmsdcc_cfg_sdio_wakeup(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002576 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002577
2578 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2579 /*
2580 * For DDR50 mode, controller needs clock rate to be
2581 * double than what is required on the SD card CLK pin.
2582 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302583 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002584 /*
2585 * Make sure that we don't double the clock if
2586 * doubled clock rate is already set
2587 */
2588 if (!host->ddr_doubled_clk_rate ||
2589 (host->ddr_doubled_clk_rate &&
2590 (host->ddr_doubled_clk_rate != ios->clock))) {
2591 host->ddr_doubled_clk_rate =
2592 msmsdcc_get_sup_clk_rate(
2593 host, (ios->clock * 2));
2594 clock = host->ddr_doubled_clk_rate;
2595 }
2596 } else {
2597 host->ddr_doubled_clk_rate = 0;
2598 }
2599
2600 if (clock != host->clk_rate) {
2601 rc = clk_set_rate(host->clk, clock);
2602 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302603 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002604 mmc_hostname(mmc), clock);
2605 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302606 host->reg_write_delay =
2607 (1 + ((3 * USEC_PER_SEC) /
2608 (host->clk_rate ? host->clk_rate :
2609 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002610 }
2611 /*
2612 * give atleast 2 MCLK cycles delay for clocks
2613 * and SDCC core to stabilize
2614 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302615 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002616 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002617 clk |= MCI_CLK_ENABLE;
2618 }
2619
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002620 if (ios->bus_width == MMC_BUS_WIDTH_8)
2621 clk |= MCI_CLK_WIDEBUS_8;
2622 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2623 clk |= MCI_CLK_WIDEBUS_4;
2624 else
2625 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002626
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002627 if (msmsdcc_is_pwrsave(host))
2628 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002629
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002630 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002631
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002632 host->tuning_needed = 0;
2633 /*
2634 * Select the controller timing mode according
2635 * to current bus speed mode
2636 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302637 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2638 (ios->timing == MMC_TIMING_MMC_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002639 clk |= (4 << 14);
2640 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302641 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002642 clk |= (3 << 14);
2643 } else {
2644 clk |= (2 << 14); /* feedback clock */
2645 }
2646
2647 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2648 clk |= (2 << 23);
2649
Subhash Jadavani00083572012-02-15 16:18:01 +05302650 /* Clear IO_PAD_PWR_SWITCH while powering off the card */
2651 if (!ios->vdd)
2652 host->io_pad_pwr_switch = 0;
2653
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002654 if (host->io_pad_pwr_switch)
2655 clk |= IO_PAD_PWR_SWITCH;
2656
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302657 /* Don't write into registers if clocks are disabled */
2658 if (host->clks_on) {
2659 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
2660 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302661 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002662 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302663 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
2664 host->pwr = pwr;
2665 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302666 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002667 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002668 }
2669
2670 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302671 msmsdcc_cfg_sdio_wakeup(host, true);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002672 msmsdcc_setup_clocks(host, false);
2673 host->clks_on = 0;
2674 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302675
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302676 if (host->tuning_in_progress)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302677 WARN(!host->clks_on,
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302678 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302679
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302680 /* Let interrupts be disabled if the host is powered off */
2681 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
2682 enable_irq(host->core_irqres->start);
2683 host->sdcc_irq_disabled = 0;
2684 }
2685
San Mehat4adbbcc2009-11-08 13:00:37 -08002686 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002687}
2688
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002689int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2690{
2691 struct msmsdcc_host *host = mmc_priv(mmc);
2692 u32 clk;
2693
2694 clk = readl_relaxed(host->base + MMCICLOCK);
2695 pr_debug("Changing to pwr_save=%d", pwrsave);
2696 if (pwrsave && msmsdcc_is_pwrsave(host))
2697 clk |= MCI_CLK_PWRSAVE;
2698 else
2699 clk &= ~MCI_CLK_PWRSAVE;
2700 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302701 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002702
2703 return 0;
2704}
2705
2706static int msmsdcc_get_ro(struct mmc_host *mmc)
2707{
2708 int status = -ENOSYS;
2709 struct msmsdcc_host *host = mmc_priv(mmc);
2710
2711 if (host->plat->wpswitch) {
2712 status = host->plat->wpswitch(mmc_dev(mmc));
2713 } else if (host->plat->wpswitch_gpio) {
2714 status = gpio_request(host->plat->wpswitch_gpio,
2715 "SD_WP_Switch");
2716 if (status) {
2717 pr_err("%s: %s: Failed to request GPIO %d\n",
2718 mmc_hostname(mmc), __func__,
2719 host->plat->wpswitch_gpio);
2720 } else {
2721 status = gpio_direction_input(
2722 host->plat->wpswitch_gpio);
2723 if (!status) {
2724 /*
2725 * Wait for atleast 300ms as debounce
2726 * time for GPIO input to stabilize.
2727 */
2728 msleep(300);
2729 status = gpio_get_value_cansleep(
2730 host->plat->wpswitch_gpio);
2731 status ^= !host->plat->wpswitch_polarity;
2732 }
2733 gpio_free(host->plat->wpswitch_gpio);
2734 }
2735 }
2736
2737 if (status < 0)
2738 status = -ENOSYS;
2739 pr_debug("%s: Card read-only status %d\n", __func__, status);
2740
2741 return status;
2742}
2743
2744#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002745static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2746{
2747 struct msmsdcc_host *host = mmc_priv(mmc);
2748 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002749
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302750 /*
2751 * We may come here with clocks turned off in that case don't
2752 * attempt to write into MASK0 register. While turning on the
2753 * clocks mci_irqenable will be written to MASK0 register.
2754 */
2755
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002756 if (enable) {
2757 spin_lock_irqsave(&host->lock, flags);
2758 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302759 if (host->clks_on) {
2760 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002761 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302762 mb();
2763 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002764 spin_unlock_irqrestore(&host->lock, flags);
2765 } else {
2766 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302767 if (host->clks_on) {
2768 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002769 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302770 mb();
2771 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002772 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002773}
2774#endif /* CONFIG_MMC_MSM_SDIO_SUPPORT */
2775
2776#ifdef CONFIG_PM_RUNTIME
2777static int msmsdcc_enable(struct mmc_host *mmc)
2778{
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302779 int rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002780 struct device *dev = mmc->parent;
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302781 struct msmsdcc_host *host = mmc_priv(mmc);
2782
2783 msmsdcc_pm_qos_update_latency(host, 1);
2784
2785 if (mmc->card && mmc_card_sdio(mmc->card) && host->is_resumed)
2786 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002787
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302788 if (dev->power.runtime_status == RPM_SUSPENDING) {
2789 if (mmc->suspend_task == current) {
2790 pm_runtime_get_noresume(dev);
2791 goto out;
2792 }
2793 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002794
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302795 rc = pm_runtime_get_sync(dev);
2796
2797 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002798 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2799 __func__, rc);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302800 return rc;
2801 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302802
2803 host->is_resumed = true;
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302804out:
2805 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002806}
2807
2808static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2809{
2810 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302811 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002812
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302813 msmsdcc_pm_qos_update_latency(host, 0);
2814
2815 if (mmc->card && mmc_card_sdio(mmc->card))
2816 return 0;
2817
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302818 if (host->plat->disable_runtime_pm)
2819 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002820
2821 rc = pm_runtime_put_sync(mmc->parent);
2822
2823 if (rc < 0)
2824 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2825 __func__, rc);
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302826 else
2827 host->is_resumed = false;
2828
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002829 return rc;
2830}
2831#else
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302832static int msmsdcc_enable(struct mmc_host *mmc)
2833{
2834 struct msmsdcc_host *host = mmc_priv(mmc);
2835 unsigned long flags;
2836
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302837 msmsdcc_pm_qos_update_latency(host, 1);
2838
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302839 spin_lock_irqsave(&host->lock, flags);
2840 if (!host->clks_on) {
2841 msmsdcc_setup_clocks(host, true);
2842 host->clks_on = 1;
2843 }
2844 spin_unlock_irqrestore(&host->lock, flags);
2845
2846 return 0;
2847}
2848
2849static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2850{
2851 struct msmsdcc_host *host = mmc_priv(mmc);
2852 unsigned long flags;
2853
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302854 msmsdcc_pm_qos_update_latency(host, 0);
2855
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302856 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302857 return 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302858
2859 spin_lock_irqsave(&host->lock, flags);
2860 if (host->clks_on) {
2861 msmsdcc_setup_clocks(host, false);
2862 host->clks_on = 0;
2863 }
2864 spin_unlock_irqrestore(&host->lock, flags);
2865
2866 return 0;
2867}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002868#endif
2869
2870static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2871 struct mmc_ios *ios)
2872{
2873 struct msmsdcc_host *host = mmc_priv(mmc);
2874 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302875 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002876
Subhash Jadavani00083572012-02-15 16:18:01 +05302877 spin_lock_irqsave(&host->lock, flags);
2878 host->io_pad_pwr_switch = 0;
2879 spin_unlock_irqrestore(&host->lock, flags);
2880
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302881 /*
2882 * For eMMC cards, VccQ voltage range must be changed
2883 * only if it operates in HS200 SDR 1.2V mode or in
2884 * DDR 1.2V mode.
2885 */
2886 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_120) {
2887 rc = msmsdcc_set_vccq_vol(host, 1200000);
2888 goto out;
2889 }
2890
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002891 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2892 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302893 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002894 goto out;
2895 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2896 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302897 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002898 goto out;
2899 }
San Mehat9d2bd732009-09-22 16:44:22 -07002900
2901 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002902 /*
2903 * If we are here means voltage switch from high voltage to
2904 * low voltage is required
2905 */
2906
2907 /*
2908 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2909 * register until they become all zeros.
2910 */
2911 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302912 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002913 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2914 mmc_hostname(mmc), __func__);
2915 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002916 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002917
2918 /* Stop SD CLK output. */
2919 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2920 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302921 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002922 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002923
2924 /*
2925 * Switch VDDPX from high voltage to low voltage
2926 * to change the VDD of the SD IO pads.
2927 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302928 rc = msmsdcc_set_vddp_low_vol(host);
2929 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002930 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002931
2932 spin_lock_irqsave(&host->lock, flags);
2933 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2934 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302935 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002936 host->io_pad_pwr_switch = 1;
2937 spin_unlock_irqrestore(&host->lock, flags);
2938
2939 /* Wait 5 ms for the voltage regulater in the card to become stable. */
2940 usleep_range(5000, 5500);
2941
2942 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302943 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002944 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2945 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302946 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002947 spin_unlock_irqrestore(&host->lock, flags);
2948
2949 /*
2950 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
2951 * don't become all ones within 1 ms then a Voltage Switch
2952 * sequence has failed and a power cycle to the card is required.
2953 * Otherwise Voltage Switch sequence is completed successfully.
2954 */
2955 usleep_range(1000, 1500);
2956
2957 spin_lock_irqsave(&host->lock, flags);
2958 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
2959 != (0xF << 1)) {
2960 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
2961 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302962 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002963 goto out_unlock;
2964 }
2965
2966out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302967 /* Enable PWRSAVE */
2968 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2969 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302970 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002971 spin_unlock_irqrestore(&host->lock, flags);
2972out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302973 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002974}
2975
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302976static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002977{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002978 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002979
2980 /* Program the MCLK value to MCLK_FREQ bit field */
2981 if (host->clk_rate <= 112000000)
2982 mclk_freq = 0;
2983 else if (host->clk_rate <= 125000000)
2984 mclk_freq = 1;
2985 else if (host->clk_rate <= 137000000)
2986 mclk_freq = 2;
2987 else if (host->clk_rate <= 150000000)
2988 mclk_freq = 3;
2989 else if (host->clk_rate <= 162000000)
2990 mclk_freq = 4;
2991 else if (host->clk_rate <= 175000000)
2992 mclk_freq = 5;
2993 else if (host->clk_rate <= 187000000)
2994 mclk_freq = 6;
2995 else if (host->clk_rate <= 200000000)
2996 mclk_freq = 7;
2997
2998 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2999 & ~(7 << 24)) | (mclk_freq << 24)),
3000 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003001}
3002
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303003/* Initialize the DLL (Programmable Delay Line ) */
3004static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003005{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003006 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303007 unsigned long flags;
3008 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003009
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303010 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003011 /*
3012 * Make sure that clock is always enabled when DLL
3013 * tuning is in progress. Keeping PWRSAVE ON may
3014 * turn off the clock. So let's disable the PWRSAVE
3015 * here and re-enable it once tuning is completed.
3016 */
3017 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3018 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303019 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303020
3021 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3022 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3023 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3024
3025 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3026 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3027 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3028
3029 msmsdcc_cm_sdc4_dll_set_freq(host);
3030
3031 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3032 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3033 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3034
3035 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3036 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3037 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3038
3039 /* Set DLL_EN bit to 1. */
3040 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3041 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3042
3043 /* Set CK_OUT_EN bit to 1. */
3044 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3045 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3046
3047 wait_cnt = 50;
3048 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3049 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3050 /* max. wait for 50us sec for LOCK bit to be set */
3051 if (--wait_cnt == 0) {
3052 pr_err("%s: %s: DLL failed to LOCK\n",
3053 mmc_hostname(host->mmc), __func__);
3054 rc = -ETIMEDOUT;
3055 goto out;
3056 }
3057 /* wait for 1us before polling again */
3058 udelay(1);
3059 }
3060
3061out:
3062 /* re-enable PWRSAVE */
3063 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3064 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303065 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303066 spin_unlock_irqrestore(&host->lock, flags);
3067
3068 return rc;
3069}
3070
3071static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3072 u8 poll)
3073{
3074 int rc = 0;
3075 u32 wait_cnt = 50;
3076 u8 ck_out_en = 0;
3077
3078 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3079 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3080 MCI_CK_OUT_EN);
3081
3082 while (ck_out_en != poll) {
3083 if (--wait_cnt == 0) {
3084 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3085 mmc_hostname(host->mmc), __func__, poll);
3086 rc = -ETIMEDOUT;
3087 goto out;
3088 }
3089 udelay(1);
3090
3091 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3092 MCI_CK_OUT_EN);
3093 }
3094out:
3095 return rc;
3096}
3097
3098/*
3099 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3100 * calibration sequence. This function should be called before
3101 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3102 * commands (CMD17/CMD18).
3103 *
3104 * This function gets called when host spinlock acquired.
3105 */
3106static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3107{
3108 int rc = 0;
3109 u32 config;
3110
3111 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3112 config |= MCI_CDR_EN;
3113 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3114 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3115
3116 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3117 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3118 if (rc)
3119 goto err_out;
3120
3121 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3122 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3123 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3124
3125 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3126 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3127 if (rc)
3128 goto err_out;
3129
3130 goto out;
3131
3132err_out:
3133 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3134out:
3135 return rc;
3136}
3137
3138static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3139 u8 phase)
3140{
3141 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303142 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3143 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3144 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303145 unsigned long flags;
3146 u32 config;
3147
3148 spin_lock_irqsave(&host->lock, flags);
3149
3150 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3151 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3152 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3153 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3154
3155 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3156 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3157 if (rc)
3158 goto err_out;
3159
3160 /*
3161 * Write the selected DLL clock output phase (0 ... 15)
3162 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
3163 */
3164 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3165 & ~(0xF << 20))
3166 | (grey_coded_phase_table[phase] << 20)),
3167 host->base + MCI_DLL_CONFIG);
3168
3169 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3170 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3171 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3172
3173 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3174 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3175 if (rc)
3176 goto err_out;
3177
3178 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3179 config |= MCI_CDR_EN;
3180 config &= ~MCI_CDR_EXT_EN;
3181 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3182 goto out;
3183
3184err_out:
3185 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3186 mmc_hostname(host->mmc), __func__, phase);
3187out:
3188 spin_unlock_irqrestore(&host->lock, flags);
3189 return rc;
3190}
3191
3192/*
3193 * Find out the greatest range of consecuitive selected
3194 * DLL clock output phases that can be used as sampling
3195 * setting for SD3.0 UHS-I card read operation (in SDR104
3196 * timing mode) or for eMMC4.5 card read operation (in HS200
3197 * timing mode).
3198 * Select the 3/4 of the range and configure the DLL with the
3199 * selected DLL clock output phase.
3200*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303201static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303202 u8 *phase_table, u8 total_phases)
3203{
Subhash Jadavani6159c622012-03-15 19:05:55 +05303204 #define MAX_PHASES 16
Subhash Jadavani34187042012-03-02 10:59:49 +05303205 int ret;
Subhash Jadavani6159c622012-03-15 19:05:55 +05303206 u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
3207 u8 phases_per_row[MAX_PHASES] = {0};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303208 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303209 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3210 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303211
Subhash Jadavani6159c622012-03-15 19:05:55 +05303212 if (!total_phases || (total_phases > MAX_PHASES)) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303213 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3214 mmc_hostname(host->mmc), __func__, total_phases);
3215 return -EINVAL;
3216 }
3217
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303218 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303219 ranges[row_index][col_index] = phase_table[cnt];
3220 phases_per_row[row_index] += 1;
3221 col_index++;
3222
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303223 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303224 continue;
3225 /* check if next phase in phase_table is consecutive or not */
3226 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3227 row_index++;
3228 col_index = 0;
3229 }
3230 }
3231
Subhash Jadavani6159c622012-03-15 19:05:55 +05303232 if (row_index >= MAX_PHASES)
3233 return -EINVAL;
3234
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303235 /* Check if phase-0 is present in first valid window? */
3236 if (!ranges[0][0]) {
3237 phase_0_found = true;
3238 phase_0_raw_index = 0;
3239 /* Check if cycle exist between 2 valid windows */
3240 for (cnt = 1; cnt <= row_index; cnt++) {
3241 if (phases_per_row[cnt]) {
Subhash Jadavani6159c622012-03-15 19:05:55 +05303242 for (i = 0; i < phases_per_row[cnt]; i++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303243 if (ranges[cnt][i] == 15) {
3244 phase_15_found = true;
3245 phase_15_raw_index = cnt;
3246 break;
3247 }
3248 }
3249 }
3250 }
3251 }
3252
3253 /* If 2 valid windows form cycle then merge them as single window */
3254 if (phase_0_found && phase_15_found) {
3255 /* number of phases in raw where phase 0 is present */
3256 u8 phases_0 = phases_per_row[phase_0_raw_index];
3257 /* number of phases in raw where phase 15 is present */
3258 u8 phases_15 = phases_per_row[phase_15_raw_index];
3259
Subhash Jadavani6159c622012-03-15 19:05:55 +05303260 if (phases_0 + phases_15 >= MAX_PHASES)
3261 /*
3262 * If there are more than 1 phase windows then total
3263 * number of phases in both the windows should not be
3264 * more than or equal to MAX_PHASES.
3265 */
3266 return -EINVAL;
3267
3268 /* Merge 2 cyclic windows */
3269 i = phases_15;
3270 for (cnt = 0; cnt < phases_0; cnt++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303271 ranges[phase_15_raw_index][i] =
3272 ranges[phase_0_raw_index][cnt];
Subhash Jadavani6159c622012-03-15 19:05:55 +05303273 if (++i >= MAX_PHASES)
3274 break;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303275 }
Subhash Jadavani6159c622012-03-15 19:05:55 +05303276
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303277 phases_per_row[phase_0_raw_index] = 0;
3278 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
3279 }
3280
3281 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303282 if (phases_per_row[cnt] > curr_max) {
3283 curr_max = phases_per_row[cnt];
3284 selected_row_index = cnt;
3285 }
3286 }
3287
Subhash Jadavani6159c622012-03-15 19:05:55 +05303288 i = ((curr_max * 3) / 4);
3289 if (i)
3290 i--;
3291
Subhash Jadavani34187042012-03-02 10:59:49 +05303292 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303293
Subhash Jadavani6159c622012-03-15 19:05:55 +05303294 if (ret >= MAX_PHASES) {
3295 ret = -EINVAL;
3296 pr_err("%s: %s: invalid phase selected=%d\n",
3297 mmc_hostname(host->mmc), __func__, ret);
3298 }
3299
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303300 return ret;
3301}
3302
Girish K Sa3f41692012-02-29 12:00:09 +05303303static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303304{
3305 int rc = 0;
3306 struct msmsdcc_host *host = mmc_priv(mmc);
3307 unsigned long flags;
3308 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303309 const u32 *tuning_block_pattern = tuning_block_64;
3310 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303311
3312 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
3313
3314 /* Tuning is only required for SDR104 modes */
3315 if (!host->tuning_needed) {
3316 rc = 0;
3317 goto exit;
3318 }
3319
3320 spin_lock_irqsave(&host->lock, flags);
3321 WARN(!host->pwr, "SDCC power is turned off\n");
3322 WARN(!host->clks_on, "SDCC clocks are turned off\n");
3323 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
3324
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303325 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303326 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
3327 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
3328 tuning_block_pattern = tuning_block_128;
3329 size = sizeof(tuning_block_128);
3330 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303331 spin_unlock_irqrestore(&host->lock, flags);
3332
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003333 /* first of all reset the tuning block */
3334 rc = msmsdcc_init_cm_sdc4_dll(host);
3335 if (rc)
3336 goto out;
3337
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303338 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003339 if (!data_buf) {
3340 rc = -ENOMEM;
3341 goto out;
3342 }
3343
3344 phase = 0;
3345 do {
3346 struct mmc_command cmd = {0};
3347 struct mmc_data data = {0};
3348 struct mmc_request mrq = {
3349 .cmd = &cmd,
3350 .data = &data
3351 };
3352 struct scatterlist sg;
3353
3354 /* set the phase in delay line hw block */
3355 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3356 if (rc)
3357 goto kfree;
3358
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303359 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003360 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
3361
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303362 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003363 data.blocks = 1;
3364 data.flags = MMC_DATA_READ;
3365 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
3366
3367 data.sg = &sg;
3368 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303369 sg_init_one(&sg, data_buf, size);
3370 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003371 mmc_wait_for_req(mmc, &mrq);
3372
3373 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303374 !memcmp(data_buf, tuning_block_pattern, size)) {
3375 /* tuning is successful at this tuning point */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003376 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303377 pr_debug("%s: %s: found good phase = %d\n",
3378 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003379 }
3380 } while (++phase < 16);
3381
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003382 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303383 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303384 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05303385 if (rc < 0)
3386 goto kfree;
3387 else
3388 phase = (u8)rc;
3389
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003390 /*
3391 * Finally set the selected phase in delay
3392 * line hw block.
3393 */
3394 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3395 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303396 goto kfree;
3397 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
3398 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003399 } else {
3400 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303401 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003402 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303403 msmsdcc_dump_sdcc_state(host);
3404 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003405 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003406
3407kfree:
3408 kfree(data_buf);
3409out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303410 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303411 host->tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303412 spin_unlock_irqrestore(&host->lock, flags);
3413exit:
3414 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003415 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07003416}
3417
3418static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003419 .enable = msmsdcc_enable,
3420 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07003421 .request = msmsdcc_request,
3422 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003423 .get_ro = msmsdcc_get_ro,
3424#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07003425 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003426#endif
3427 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
3428 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07003429};
3430
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003431static unsigned int
3432msmsdcc_slot_status(struct msmsdcc_host *host)
3433{
3434 int status;
3435 unsigned int gpio_no = host->plat->status_gpio;
3436
3437 status = gpio_request(gpio_no, "SD_HW_Detect");
3438 if (status) {
3439 pr_err("%s: %s: Failed to request GPIO %d\n",
3440 mmc_hostname(host->mmc), __func__, gpio_no);
3441 } else {
3442 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003443 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08003444 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003445 if (host->plat->is_status_gpio_active_low)
3446 status = !status;
3447 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003448 gpio_free(gpio_no);
3449 }
3450 return status;
3451}
3452
San Mehat9d2bd732009-09-22 16:44:22 -07003453static void
3454msmsdcc_check_status(unsigned long data)
3455{
3456 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3457 unsigned int status;
3458
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003459 if (host->plat->status || host->plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08003460 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003461 status = host->plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08003462 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003463 status = msmsdcc_slot_status(host);
3464
Krishna Konda941604a2012-01-10 17:46:34 -08003465 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08003466
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003467 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08003468 if (host->plat->status)
3469 pr_info("%s: Slot status change detected "
3470 "(%d -> %d)\n",
3471 mmc_hostname(host->mmc),
3472 host->oldstat, status);
3473 else if (host->plat->is_status_gpio_active_low)
3474 pr_info("%s: Slot status change detected "
3475 "(%d -> %d) and the card detect GPIO"
3476 " is ACTIVE_LOW\n",
3477 mmc_hostname(host->mmc),
3478 host->oldstat, status);
3479 else
3480 pr_info("%s: Slot status change detected "
3481 "(%d -> %d) and the card detect GPIO"
3482 " is ACTIVE_HIGH\n",
3483 mmc_hostname(host->mmc),
3484 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07003485 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003486 }
3487 host->oldstat = status;
3488 } else {
3489 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07003490 }
San Mehat9d2bd732009-09-22 16:44:22 -07003491}
3492
3493static irqreturn_t
3494msmsdcc_platform_status_irq(int irq, void *dev_id)
3495{
3496 struct msmsdcc_host *host = dev_id;
3497
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003498 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07003499 msmsdcc_check_status((unsigned long) host);
3500 return IRQ_HANDLED;
3501}
3502
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003503static irqreturn_t
3504msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
3505{
3506 struct msmsdcc_host *host = dev_id;
3507
3508 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
3509 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303510 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003511 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303512 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003513 wake_lock(&host->sdio_wlock);
3514 msmsdcc_disable_irq_wake(host);
3515 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303516 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003517 }
3518 if (host->plat->is_sdio_al_client) {
3519 if (!host->clks_on) {
3520 msmsdcc_setup_clocks(host, true);
3521 host->clks_on = 1;
3522 }
3523 if (host->sdcc_irq_disabled) {
3524 writel_relaxed(host->mci_irqenable,
3525 host->base + MMCIMASK0);
3526 mb();
3527 enable_irq(host->core_irqres->start);
3528 host->sdcc_irq_disabled = 0;
3529 }
3530 wake_lock(&host->sdio_wlock);
3531 }
3532 spin_unlock(&host->lock);
3533
3534 return IRQ_HANDLED;
3535}
3536
San Mehat9d2bd732009-09-22 16:44:22 -07003537static void
3538msmsdcc_status_notify_cb(int card_present, void *dev_id)
3539{
3540 struct msmsdcc_host *host = dev_id;
3541
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003542 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07003543 card_present);
3544 msmsdcc_check_status((unsigned long) host);
3545}
3546
San Mehat9d2bd732009-09-22 16:44:22 -07003547static int
3548msmsdcc_init_dma(struct msmsdcc_host *host)
3549{
3550 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
3551 host->dma.host = host;
3552 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003553 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003554
3555 if (!host->dmares)
3556 return -ENODEV;
3557
3558 host->dma.nc = dma_alloc_coherent(NULL,
3559 sizeof(struct msmsdcc_nc_dmadata),
3560 &host->dma.nc_busaddr,
3561 GFP_KERNEL);
3562 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003563 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07003564 return -ENOMEM;
3565 }
3566 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
3567 host->dma.cmd_busaddr = host->dma.nc_busaddr;
3568 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
3569 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
3570 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07003571 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07003572
3573 return 0;
3574}
3575
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003576#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
3577/**
3578 * Allocate and Connect a SDCC peripheral's SPS endpoint
3579 *
3580 * This function allocates endpoint context and
3581 * connect it with memory endpoint by calling
3582 * appropriate SPS driver APIs.
3583 *
3584 * Also registers a SPS callback function with
3585 * SPS driver
3586 *
3587 * This function should only be called once typically
3588 * during driver probe.
3589 *
3590 * @host - Pointer to sdcc host structure
3591 * @ep - Pointer to sps endpoint data structure
3592 * @is_produce - 1 means Producer endpoint
3593 * 0 means Consumer endpoint
3594 *
3595 * @return - 0 if successful else negative value.
3596 *
3597 */
3598static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
3599 struct msmsdcc_sps_ep_conn_data *ep,
3600 bool is_producer)
3601{
3602 int rc = 0;
3603 struct sps_pipe *sps_pipe_handle;
3604 struct sps_connect *sps_config = &ep->config;
3605 struct sps_register_event *sps_event = &ep->event;
3606
3607 /* Allocate endpoint context */
3608 sps_pipe_handle = sps_alloc_endpoint();
3609 if (!sps_pipe_handle) {
3610 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
3611 mmc_hostname(host->mmc), is_producer);
3612 rc = -ENOMEM;
3613 goto out;
3614 }
3615
3616 /* Get default connection configuration for an endpoint */
3617 rc = sps_get_config(sps_pipe_handle, sps_config);
3618 if (rc) {
3619 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
3620 " rc=%d", mmc_hostname(host->mmc),
3621 (u32)sps_pipe_handle, rc);
3622 goto get_config_err;
3623 }
3624
3625 /* Modify the default connection configuration */
3626 if (is_producer) {
3627 /*
3628 * For SDCC producer transfer, source should be
3629 * SDCC peripheral where as destination should
3630 * be system memory.
3631 */
3632 sps_config->source = host->sps.bam_handle;
3633 sps_config->destination = SPS_DEV_HANDLE_MEM;
3634 /* Producer pipe will handle this connection */
3635 sps_config->mode = SPS_MODE_SRC;
3636 sps_config->options =
3637 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3638 } else {
3639 /*
3640 * For SDCC consumer transfer, source should be
3641 * system memory where as destination should
3642 * SDCC peripheral
3643 */
3644 sps_config->source = SPS_DEV_HANDLE_MEM;
3645 sps_config->destination = host->sps.bam_handle;
3646 sps_config->mode = SPS_MODE_DEST;
3647 sps_config->options =
3648 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3649 }
3650
3651 /* Producer pipe index */
3652 sps_config->src_pipe_index = host->sps.src_pipe_index;
3653 /* Consumer pipe index */
3654 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
3655 /*
3656 * This event thresold value is only significant for BAM-to-BAM
3657 * transfer. It's ignored for BAM-to-System mode transfer.
3658 */
3659 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05303660
3661 /* Allocate maximum descriptor fifo size */
3662 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
3663 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003664 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
3665 sps_config->desc.size,
3666 &sps_config->desc.phys_base,
3667 GFP_KERNEL);
3668
Pratibhasagar V00b94332011-10-18 14:57:27 +05303669 if (!sps_config->desc.base) {
3670 rc = -ENOMEM;
3671 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3672 , mmc_hostname(host->mmc));
3673 goto get_config_err;
3674 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003675 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3676
3677 /* Establish connection between peripheral and memory endpoint */
3678 rc = sps_connect(sps_pipe_handle, sps_config);
3679 if (rc) {
3680 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3681 " rc=%d", mmc_hostname(host->mmc),
3682 (u32)sps_pipe_handle, rc);
3683 goto sps_connect_err;
3684 }
3685
3686 sps_event->mode = SPS_TRIGGER_CALLBACK;
3687 sps_event->options = SPS_O_EOT;
3688 sps_event->callback = msmsdcc_sps_complete_cb;
3689 sps_event->xfer_done = NULL;
3690 sps_event->user = (void *)host;
3691
3692 /* Register callback event for EOT (End of transfer) event. */
3693 rc = sps_register_event(sps_pipe_handle, sps_event);
3694 if (rc) {
3695 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3696 " rc=%d", mmc_hostname(host->mmc),
3697 (u32)sps_pipe_handle, rc);
3698 goto reg_event_err;
3699 }
3700 /* Now save the sps pipe handle */
3701 ep->pipe_handle = sps_pipe_handle;
3702 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3703 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3704 __func__, is_producer ? "READ" : "WRITE",
3705 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3706 goto out;
3707
3708reg_event_err:
3709 sps_disconnect(sps_pipe_handle);
3710sps_connect_err:
3711 dma_free_coherent(mmc_dev(host->mmc),
3712 sps_config->desc.size,
3713 sps_config->desc.base,
3714 sps_config->desc.phys_base);
3715get_config_err:
3716 sps_free_endpoint(sps_pipe_handle);
3717out:
3718 return rc;
3719}
3720
3721/**
3722 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3723 *
3724 * This function disconnect endpoint and deallocates
3725 * endpoint context.
3726 *
3727 * This function should only be called once typically
3728 * during driver remove.
3729 *
3730 * @host - Pointer to sdcc host structure
3731 * @ep - Pointer to sps endpoint data structure
3732 *
3733 */
3734static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3735 struct msmsdcc_sps_ep_conn_data *ep)
3736{
3737 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3738 struct sps_connect *sps_config = &ep->config;
3739 struct sps_register_event *sps_event = &ep->event;
3740
3741 sps_event->xfer_done = NULL;
3742 sps_event->callback = NULL;
3743 sps_register_event(sps_pipe_handle, sps_event);
3744 sps_disconnect(sps_pipe_handle);
3745 dma_free_coherent(mmc_dev(host->mmc),
3746 sps_config->desc.size,
3747 sps_config->desc.base,
3748 sps_config->desc.phys_base);
3749 sps_free_endpoint(sps_pipe_handle);
3750}
3751
3752/**
3753 * Reset SDCC peripheral's SPS endpoint
3754 *
3755 * This function disconnects an endpoint.
3756 *
3757 * This function should be called for reseting
3758 * SPS endpoint when data transfer error is
3759 * encountered during data transfer. This
3760 * can be considered as soft reset to endpoint.
3761 *
3762 * This function should only be called if
3763 * msmsdcc_sps_init() is already called.
3764 *
3765 * @host - Pointer to sdcc host structure
3766 * @ep - Pointer to sps endpoint data structure
3767 *
3768 * @return - 0 if successful else negative value.
3769 */
3770static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3771 struct msmsdcc_sps_ep_conn_data *ep)
3772{
3773 int rc = 0;
3774 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3775
3776 rc = sps_disconnect(sps_pipe_handle);
3777 if (rc) {
3778 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3779 " rc=%d", mmc_hostname(host->mmc), __func__,
3780 (u32)sps_pipe_handle, rc);
3781 goto out;
3782 }
3783 out:
3784 return rc;
3785}
3786
3787/**
3788 * Restore SDCC peripheral's SPS endpoint
3789 *
3790 * This function connects an endpoint.
3791 *
3792 * This function should be called for restoring
3793 * SPS endpoint after data transfer error is
3794 * encountered during data transfer. This
3795 * can be considered as soft reset to endpoint.
3796 *
3797 * This function should only be called if
3798 * msmsdcc_sps_reset_ep() is called before.
3799 *
3800 * @host - Pointer to sdcc host structure
3801 * @ep - Pointer to sps endpoint data structure
3802 *
3803 * @return - 0 if successful else negative value.
3804 */
3805static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3806 struct msmsdcc_sps_ep_conn_data *ep)
3807{
3808 int rc = 0;
3809 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3810 struct sps_connect *sps_config = &ep->config;
3811 struct sps_register_event *sps_event = &ep->event;
3812
3813 /* Establish connection between peripheral and memory endpoint */
3814 rc = sps_connect(sps_pipe_handle, sps_config);
3815 if (rc) {
3816 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3817 " rc=%d", mmc_hostname(host->mmc), __func__,
3818 (u32)sps_pipe_handle, rc);
3819 goto out;
3820 }
3821
3822 /* Register callback event for EOT (End of transfer) event. */
3823 rc = sps_register_event(sps_pipe_handle, sps_event);
3824 if (rc) {
3825 pr_err("%s: %s: sps_register_event() failed!!!"
3826 " pipe_handle=0x%x, rc=%d",
3827 mmc_hostname(host->mmc), __func__,
3828 (u32)sps_pipe_handle, rc);
3829 goto reg_event_err;
3830 }
3831 goto out;
3832
3833reg_event_err:
3834 sps_disconnect(sps_pipe_handle);
3835out:
3836 return rc;
3837}
3838
3839/**
3840 * Initialize SPS HW connected with SDCC core
3841 *
3842 * This function register BAM HW resources with
3843 * SPS driver and then initialize 2 SPS endpoints
3844 *
3845 * This function should only be called once typically
3846 * during driver probe.
3847 *
3848 * @host - Pointer to sdcc host structure
3849 *
3850 * @return - 0 if successful else negative value.
3851 *
3852 */
3853static int msmsdcc_sps_init(struct msmsdcc_host *host)
3854{
3855 int rc = 0;
3856 struct sps_bam_props bam = {0};
3857
3858 host->bam_base = ioremap(host->bam_memres->start,
3859 resource_size(host->bam_memres));
3860 if (!host->bam_base) {
3861 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3862 " size=0x%x", mmc_hostname(host->mmc),
3863 host->bam_memres->start,
3864 (host->bam_memres->end -
3865 host->bam_memres->start));
3866 rc = -ENOMEM;
3867 goto out;
3868 }
3869
3870 bam.phys_addr = host->bam_memres->start;
3871 bam.virt_addr = host->bam_base;
3872 /*
3873 * This event thresold value is only significant for BAM-to-BAM
3874 * transfer. It's ignored for BAM-to-System mode transfer.
3875 */
3876 bam.event_threshold = 0x10; /* Pipe event threshold */
3877 /*
3878 * This threshold controls when the BAM publish
3879 * the descriptor size on the sideband interface.
3880 * SPS HW will only be used when
3881 * data transfer size > MCI_FIFOSIZE (64 bytes).
3882 * PIO mode will be used when
3883 * data transfer size < MCI_FIFOSIZE (64 bytes).
3884 * So set this thresold value to 64 bytes.
3885 */
3886 bam.summing_threshold = 64;
3887 /* SPS driver wll handle the SDCC BAM IRQ */
3888 bam.irq = (u32)host->bam_irqres->start;
3889 bam.manage = SPS_BAM_MGR_LOCAL;
3890
3891 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3892 (u32)bam.phys_addr);
3893 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3894 (u32)bam.virt_addr);
3895
3896 /* Register SDCC Peripheral BAM device to SPS driver */
3897 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3898 if (rc) {
3899 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3900 mmc_hostname(host->mmc), rc);
3901 goto reg_bam_err;
3902 }
3903 pr_info("%s: BAM device registered. bam_handle=0x%x",
3904 mmc_hostname(host->mmc), host->sps.bam_handle);
3905
3906 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3907 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3908
3909 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3910 SPS_PROD_PERIPHERAL);
3911 if (rc)
3912 goto sps_reset_err;
3913 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3914 SPS_CONS_PERIPHERAL);
3915 if (rc)
3916 goto cons_conn_err;
3917
3918 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3919 mmc_hostname(host->mmc),
3920 (unsigned long long)host->bam_memres->start,
3921 (unsigned int)host->bam_irqres->start);
3922 goto out;
3923
3924cons_conn_err:
3925 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3926sps_reset_err:
3927 sps_deregister_bam_device(host->sps.bam_handle);
3928reg_bam_err:
3929 iounmap(host->bam_base);
3930out:
3931 return rc;
3932}
3933
3934/**
3935 * De-initialize SPS HW connected with SDCC core
3936 *
3937 * This function deinitialize SPS endpoints and then
3938 * deregisters BAM resources from SPS driver.
3939 *
3940 * This function should only be called once typically
3941 * during driver remove.
3942 *
3943 * @host - Pointer to sdcc host structure
3944 *
3945 */
3946static void msmsdcc_sps_exit(struct msmsdcc_host *host)
3947{
3948 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
3949 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3950 sps_deregister_bam_device(host->sps.bam_handle);
3951 iounmap(host->bam_base);
3952}
3953#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
3954
3955static ssize_t
3956show_polling(struct device *dev, struct device_attribute *attr, char *buf)
3957{
3958 struct mmc_host *mmc = dev_get_drvdata(dev);
3959 struct msmsdcc_host *host = mmc_priv(mmc);
3960 int poll;
3961 unsigned long flags;
3962
3963 spin_lock_irqsave(&host->lock, flags);
3964 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
3965 spin_unlock_irqrestore(&host->lock, flags);
3966
3967 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
3968}
3969
3970static ssize_t
3971set_polling(struct device *dev, struct device_attribute *attr,
3972 const char *buf, size_t count)
3973{
3974 struct mmc_host *mmc = dev_get_drvdata(dev);
3975 struct msmsdcc_host *host = mmc_priv(mmc);
3976 int value;
3977 unsigned long flags;
3978
3979 sscanf(buf, "%d", &value);
3980
3981 spin_lock_irqsave(&host->lock, flags);
3982 if (value) {
3983 mmc->caps |= MMC_CAP_NEEDS_POLL;
3984 mmc_detect_change(host->mmc, 0);
3985 } else {
3986 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3987 }
3988#ifdef CONFIG_HAS_EARLYSUSPEND
3989 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
3990#endif
3991 spin_unlock_irqrestore(&host->lock, flags);
3992 return count;
3993}
3994
3995static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
3996 show_polling, set_polling);
3997static struct attribute *dev_attrs[] = {
3998 &dev_attr_polling.attr,
3999 NULL,
4000};
4001static struct attribute_group dev_attr_grp = {
4002 .attrs = dev_attrs,
4003};
4004
4005#ifdef CONFIG_HAS_EARLYSUSPEND
4006static void msmsdcc_early_suspend(struct early_suspend *h)
4007{
4008 struct msmsdcc_host *host =
4009 container_of(h, struct msmsdcc_host, early_suspend);
4010 unsigned long flags;
4011
4012 spin_lock_irqsave(&host->lock, flags);
4013 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
4014 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4015 spin_unlock_irqrestore(&host->lock, flags);
4016};
4017static void msmsdcc_late_resume(struct early_suspend *h)
4018{
4019 struct msmsdcc_host *host =
4020 container_of(h, struct msmsdcc_host, early_suspend);
4021 unsigned long flags;
4022
4023 if (host->polling_enabled) {
4024 spin_lock_irqsave(&host->lock, flags);
4025 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
4026 mmc_detect_change(host->mmc, 0);
4027 spin_unlock_irqrestore(&host->lock, flags);
4028 }
4029};
4030#endif
4031
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304032void msmsdcc_print_regs(const char *name, void __iomem *base,
4033 unsigned int no_of_regs)
4034{
4035 unsigned int i;
4036
4037 if (!base)
4038 return;
4039 pr_info("===== %s: Register Dumps @base=0x%x =====\n",
4040 name, (u32)base);
4041 for (i = 0; i < no_of_regs; i = i + 4) {
4042 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x.\n", i*4,
4043 (u32)readl_relaxed(base + i*4),
4044 (u32)readl_relaxed(base + ((i+1)*4)),
4045 (u32)readl_relaxed(base + ((i+2)*4)),
4046 (u32)readl_relaxed(base + ((i+3)*4)));
4047 }
4048}
4049
4050static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
4051{
4052 /* Dump current state of SDCC clocks, power and irq */
4053 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
4054 (host->pwr ? "ON" : "OFF"));
4055 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
4056 mmc_hostname(host->mmc),
4057 (host->clks_on ? "ON" : "OFF"),
4058 (u32)clk_get_rate(host->clk));
4059 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
4060 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
4061
4062 /* Now dump SDCC registers. Don't print FIFO registers */
4063 if (host->clks_on)
4064 msmsdcc_print_regs("SDCC-CORE", host->base, 28);
4065
4066 if (host->curr.data) {
4067 if (msmsdcc_check_dma_op_req(host->curr.data))
4068 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
4069 else if (host->is_dma_mode)
4070 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
4071 mmc_hostname(host->mmc), host->dma.busy,
4072 host->dma.channel, host->dma.crci);
4073 else if (host->is_sps_mode)
4074 pr_info("%s: SPS mode: busy=%d\n",
4075 mmc_hostname(host->mmc), host->sps.busy);
4076
4077 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
4078 mmc_hostname(host->mmc), host->curr.xfer_size,
4079 host->curr.data_xfered, host->curr.xfer_remain);
4080 pr_info("%s: got_dataend=%d, prog_enable=%d,"
4081 " wait_for_auto_prog_done=%d,"
4082 " got_auto_prog_done=%d\n",
4083 mmc_hostname(host->mmc), host->curr.got_dataend,
4084 host->prog_enable, host->curr.wait_for_auto_prog_done,
4085 host->curr.got_auto_prog_done);
4086 }
4087
4088}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004089static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
4090{
4091 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4092 struct mmc_request *mrq;
4093 unsigned long flags;
4094
4095 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004096 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004097 pr_info("%s: %s: dummy CMD52 timeout\n",
4098 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004099 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004100 }
4101
4102 mrq = host->curr.mrq;
4103
4104 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304105 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
4106 mrq->cmd->opcode);
4107 msmsdcc_dump_sdcc_state(host);
4108
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004109 if (!mrq->cmd->error)
4110 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304111 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004112 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004113 if (mrq->data && !mrq->data->error)
4114 mrq->data->error = -ETIMEDOUT;
4115 host->curr.data_xfered = 0;
4116 if (host->dma.sg && host->is_dma_mode) {
4117 msm_dmov_stop_cmd(host->dma.channel,
4118 &host->dma.hdr, 0);
4119 } else if (host->sps.sg && host->is_sps_mode) {
4120 /* Stop current SPS transfer */
4121 msmsdcc_sps_exit_curr_xfer(host);
4122 } else {
4123 msmsdcc_reset_and_restore(host);
4124 msmsdcc_stop_data(host);
4125 if (mrq->data && mrq->data->stop)
4126 msmsdcc_start_command(host,
4127 mrq->data->stop, 0);
4128 else
4129 msmsdcc_request_end(host, mrq);
4130 }
4131 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304132 host->prog_enable = 0;
Subhash Jadavanied6b0e42012-03-07 16:36:27 +05304133 host->curr.wait_for_auto_prog_done = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004134 msmsdcc_reset_and_restore(host);
4135 msmsdcc_request_end(host, mrq);
4136 }
4137 }
4138 spin_unlock_irqrestore(&host->lock, flags);
4139}
4140
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304141static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
4142{
4143 int i, ret;
4144 struct mmc_platform_data *pdata;
4145 struct device_node *np = dev->of_node;
4146 u32 bus_width = 0;
4147 u32 *clk_table;
4148 int clk_table_len;
4149 u32 *sup_voltages;
4150 int sup_volt_len;
4151
4152 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
4153 if (!pdata) {
4154 dev_err(dev, "could not allocate memory for platform data\n");
4155 goto err;
4156 }
4157
4158 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
4159 if (bus_width == 8) {
4160 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
4161 } else if (bus_width == 4) {
4162 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
4163 } else {
4164 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
4165 pdata->mmc_bus_width = 0;
4166 }
4167
4168 if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
4169 size_t sz;
4170 sz = sup_volt_len / sizeof(*sup_voltages);
4171 if (sz > 0) {
4172 sup_voltages = devm_kzalloc(dev,
4173 sz * sizeof(*sup_voltages), GFP_KERNEL);
4174 if (!sup_voltages) {
4175 dev_err(dev, "No memory for supported voltage\n");
4176 goto err;
4177 }
4178
4179 ret = of_property_read_u32_array(np,
4180 "qcom,sdcc-sup-voltages", sup_voltages, sz);
4181 if (ret < 0) {
4182 dev_err(dev, "error while reading voltage"
4183 "ranges %d\n", ret);
4184 goto err;
4185 }
4186 } else {
4187 dev_err(dev, "No supported voltages\n");
4188 goto err;
4189 }
4190 for (i = 0; i < sz; i += 2) {
4191 u32 mask;
4192
4193 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
4194 sup_voltages[i + 1]);
4195 if (!mask)
4196 dev_err(dev, "Invalide voltage range %d\n", i);
4197 pdata->ocr_mask |= mask;
4198 }
4199 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
4200 } else {
4201 dev_err(dev, "Supported voltage range not specified\n");
4202 }
4203
4204 if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
4205 size_t sz;
4206 sz = clk_table_len / sizeof(*clk_table);
4207
4208 if (sz > 0) {
4209 clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
4210 GFP_KERNEL);
4211 if (!clk_table) {
4212 dev_err(dev, "No memory for clock table\n");
4213 goto err;
4214 }
4215
4216 ret = of_property_read_u32_array(np,
4217 "qcom,sdcc-clk-rates", clk_table, sz);
4218 if (ret < 0) {
4219 dev_err(dev, "error while reading clk"
4220 "table %d\n", ret);
4221 goto err;
4222 }
4223 } else {
4224 dev_err(dev, "clk_table not specified\n");
4225 goto err;
4226 }
4227 pdata->sup_clk_table = clk_table;
4228 pdata->sup_clk_cnt = sz;
4229 } else {
4230 dev_err(dev, "Supported clock rates not specified\n");
4231 }
4232
4233 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
4234 pdata->nonremovable = true;
4235 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
4236 pdata->disable_cmd23 = true;
4237
4238 return pdata;
4239err:
4240 return NULL;
4241}
4242
San Mehat9d2bd732009-09-22 16:44:22 -07004243static int
4244msmsdcc_probe(struct platform_device *pdev)
4245{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304246 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07004247 struct msmsdcc_host *host;
4248 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004249 unsigned long flags;
4250 struct resource *core_irqres = NULL;
4251 struct resource *bam_irqres = NULL;
4252 struct resource *core_memres = NULL;
4253 struct resource *dml_memres = NULL;
4254 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07004255 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07004256 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05304257 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004258 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07004259
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304260 if (pdev->dev.of_node) {
4261 plat = msmsdcc_populate_pdata(&pdev->dev);
4262 of_property_read_u32((&pdev->dev)->of_node,
4263 "cell-index", &pdev->id);
4264 } else {
4265 plat = pdev->dev.platform_data;
4266 }
4267
San Mehat9d2bd732009-09-22 16:44:22 -07004268 /* must have platform data */
4269 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004270 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004271 ret = -EINVAL;
4272 goto out;
4273 }
4274
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004275 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07004276 return -EINVAL;
4277
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304278 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
4279 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
4280 return -EINVAL;
4281 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004282
San Mehat9d2bd732009-09-22 16:44:22 -07004283 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004284 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004285 return -ENXIO;
4286 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304287 if (pdev->dev.of_node) {
4288 /*
4289 * Device tree iomem resources are only accessible by index.
4290 * index = 0 -> SDCC register interface
4291 * index = 1 -> DML register interface
4292 * index = 2 -> BAM register interface
4293 * IRQ resources:
4294 * index = 0 -> SDCC IRQ
4295 * index = 1 -> BAM IRQ
4296 */
4297 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
4298 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
4299 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
4300 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
4301 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
4302 } else {
4303 for (i = 0; i < pdev->num_resources; i++) {
4304 if (pdev->resource[i].flags & IORESOURCE_MEM) {
4305 if (!strncmp(pdev->resource[i].name,
4306 "sdcc_dml_addr",
4307 sizeof("sdcc_dml_addr")))
4308 dml_memres = &pdev->resource[i];
4309 else if (!strncmp(pdev->resource[i].name,
4310 "sdcc_bam_addr",
4311 sizeof("sdcc_bam_addr")))
4312 bam_memres = &pdev->resource[i];
4313 else
4314 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07004315
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304316 }
4317 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
4318 if (!strncmp(pdev->resource[i].name,
4319 "sdcc_bam_irq",
4320 sizeof("sdcc_bam_irq")))
4321 bam_irqres = &pdev->resource[i];
4322 else
4323 core_irqres = &pdev->resource[i];
4324 }
4325 if (pdev->resource[i].flags & IORESOURCE_DMA) {
4326 if (!strncmp(pdev->resource[i].name,
4327 "sdcc_dma_chnl",
4328 sizeof("sdcc_dma_chnl")))
4329 dmares = &pdev->resource[i];
4330 else if (!strncmp(pdev->resource[i].name,
4331 "sdcc_dma_crci",
4332 sizeof("sdcc_dma_crci")))
4333 dma_crci_res = &pdev->resource[i];
4334 }
Krishna Konda25786ec2011-07-25 16:21:36 -07004335 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004336 }
4337
4338 if (!core_irqres || !core_memres) {
4339 pr_err("%s: Invalid sdcc core resource\n", __func__);
4340 return -ENXIO;
4341 }
4342
4343 /*
4344 * Both BAM and DML memory resource should be preset.
4345 * BAM IRQ resource should also be present.
4346 */
4347 if ((bam_memres && !dml_memres) ||
4348 (!bam_memres && dml_memres) ||
4349 ((bam_memres && dml_memres) && !bam_irqres)) {
4350 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004351 return -ENXIO;
4352 }
4353
4354 /*
4355 * Setup our host structure
4356 */
San Mehat9d2bd732009-09-22 16:44:22 -07004357 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
4358 if (!mmc) {
4359 ret = -ENOMEM;
4360 goto out;
4361 }
4362
4363 host = mmc_priv(mmc);
4364 host->pdev_id = pdev->id;
4365 host->plat = plat;
4366 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08004367 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05304368
4369 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004370 host->is_sps_mode = 1;
4371 else if (dmares)
4372 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07004373
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004374 host->base = ioremap(core_memres->start,
4375 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07004376 if (!host->base) {
4377 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004378 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004379 }
4380
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004381 host->core_irqres = core_irqres;
4382 host->bam_irqres = bam_irqres;
4383 host->core_memres = core_memres;
4384 host->dml_memres = dml_memres;
4385 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07004386 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07004387 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07004388 spin_lock_init(&host->lock);
4389
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004390#ifdef CONFIG_MMC_EMBEDDED_SDIO
4391 if (plat->embedded_sdio)
4392 mmc_set_embedded_sdio_data(mmc,
4393 &plat->embedded_sdio->cis,
4394 &plat->embedded_sdio->cccr,
4395 plat->embedded_sdio->funcs,
4396 plat->embedded_sdio->num_funcs);
4397#endif
4398
Sahitya Tummala62612cf2010-12-08 15:03:03 +05304399 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
4400 (unsigned long)host);
4401
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004402 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
4403 (unsigned long)host);
4404 if (host->is_dma_mode) {
4405 /* Setup DMA */
4406 ret = msmsdcc_init_dma(host);
4407 if (ret)
4408 goto ioremap_free;
4409 } else {
4410 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004411 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004412 }
4413
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004414 /*
4415 * Setup SDCC clock if derived from Dayatona
4416 * fabric core clock.
4417 */
4418 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07004419 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004420 if (!IS_ERR(host->dfab_pclk)) {
4421 /* Set the clock rate to 64MHz for max. performance */
4422 ret = clk_set_rate(host->dfab_pclk, 64000000);
4423 if (ret)
4424 goto dfab_pclk_put;
4425 ret = clk_enable(host->dfab_pclk);
4426 if (ret)
4427 goto dfab_pclk_put;
4428 } else
4429 goto dma_free;
4430 }
4431
4432 /*
4433 * Setup main peripheral bus clock
4434 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004435 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004436 if (!IS_ERR(host->pclk)) {
4437 ret = clk_enable(host->pclk);
4438 if (ret)
4439 goto pclk_put;
4440
4441 host->pclk_rate = clk_get_rate(host->pclk);
4442 }
4443
4444 /*
4445 * Setup SDC MMC clock
4446 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004447 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07004448 if (IS_ERR(host->clk)) {
4449 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004450 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07004451 }
4452
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004453 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
4454 if (ret) {
4455 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
4456 goto clk_put;
4457 }
4458
4459 ret = clk_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004460 if (ret)
4461 goto clk_put;
4462
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004463 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304464 if (!host->clk_rate)
4465 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304466
4467 /*
4468 * Lookup the Controller Version, to identify the supported features
4469 * Version number read as 0 would indicate SDCC3 or earlier versions
4470 */
4471 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
4472 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
4473 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304474 /*
4475 * Set the register write delay according to min. clock frequency
4476 * supported and update later when the host->clk_rate changes.
4477 */
4478 host->reg_write_delay =
4479 (1 + ((3 * USEC_PER_SEC) /
4480 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004481
4482 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05304483 /* Apply Hard reset to SDCC to put it in power on default state */
4484 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004485
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304486 /* pm qos request to prevent apps idle power collapse */
4487 if (host->plat->swfi_latency)
4488 pm_qos_add_request(&host->pm_qos_req_dma,
4489 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
4490
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004491 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07004492 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004493 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07004494 goto clk_disable;
4495 }
4496
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004497
4498 /* Clocks has to be running before accessing SPS/DML HW blocks */
4499 if (host->is_sps_mode) {
4500 /* Initialize SPS */
4501 ret = msmsdcc_sps_init(host);
4502 if (ret)
4503 goto vreg_deinit;
4504 /* Initialize DML */
4505 ret = msmsdcc_dml_init(host);
4506 if (ret)
4507 goto sps_exit;
4508 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05304509 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07004510
San Mehat9d2bd732009-09-22 16:44:22 -07004511 /*
4512 * Setup MMC host structure
4513 */
4514 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004515 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
4516 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004517 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004518 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
4519 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07004520
San Mehat9d2bd732009-09-22 16:44:22 -07004521 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05304522 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304523
4524 /*
4525 * If we send the CMD23 before multi block write/read command
4526 * then we need not to send CMD12 at the end of the transfer.
4527 * If we don't send the CMD12 then only way to detect the PROG_DONE
4528 * status is to use the AUTO_PROG_DONE status provided by SDCC4
4529 * controller. So let's enable the CMD23 for SDCC4 only.
4530 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304531 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304532 mmc->caps |= MMC_CAP_CMD23;
4533
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004534 mmc->caps |= plat->uhs_caps;
4535 /*
4536 * XPC controls the maximum current in the default speed mode of SDXC
4537 * card. XPC=0 means 100mA (max.) but speed class is not supported.
4538 * XPC=1 means 150mA (max.) and speed class is supported.
4539 */
4540 if (plat->xpc_cap)
4541 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
4542 MMC_CAP_SET_XPC_180);
4543
Subhash Jadavani0a0c6272012-03-24 23:13:18 +05304544 mmc->caps2 |= MMC_CAP2_BOOTPART_NOACC;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304545 if (pdev->dev.of_node) {
4546 if (of_get_property((&pdev->dev)->of_node,
4547 "qcom,sdcc-hs200", NULL))
4548 mmc->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
4549 }
4550
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004551 if (plat->nonremovable)
4552 mmc->caps |= MMC_CAP_NONREMOVABLE;
4553#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
4554 mmc->caps |= MMC_CAP_SDIO_IRQ;
4555#endif
4556
4557 if (plat->is_sdio_al_client)
4558 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07004559
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304560 mmc->max_segs = msmsdcc_get_nr_sg(host);
4561 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
4562 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07004563
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304564 mmc->max_req_size = MMC_MAX_REQ_SIZE;
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +05304565 mmc->max_seg_size = mmc->max_req_size;
San Mehat9d2bd732009-09-22 16:44:22 -07004566
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004567 writel_relaxed(0, host->base + MMCIMASK0);
4568 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05304569 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004570
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004571 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
4572 mb();
4573 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07004574
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004575 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
4576 DRIVER_NAME " (cmd)", host);
4577 if (ret)
4578 goto dml_exit;
4579
4580 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
4581 DRIVER_NAME " (pio)", host);
4582 if (ret)
4583 goto irq_free;
4584
4585 /*
4586 * Enable SDCC IRQ only when host is powered on. Otherwise, this
4587 * IRQ is un-necessarily being monitored by MPM (Modem power
4588 * management block) during idle-power collapse. The MPM will be
4589 * configured to monitor the DATA1 GPIO line with level-low trigger
4590 * and thus depending on the GPIO status, it prevents TCXO shutdown
4591 * during idle-power collapse.
4592 */
4593 disable_irq(core_irqres->start);
4594 host->sdcc_irq_disabled = 1;
4595
4596 if (plat->sdiowakeup_irq) {
4597 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4598 mmc_hostname(mmc));
4599 ret = request_irq(plat->sdiowakeup_irq,
4600 msmsdcc_platform_sdiowakeup_irq,
4601 IRQF_SHARED | IRQF_TRIGGER_LOW,
4602 DRIVER_NAME "sdiowakeup", host);
4603 if (ret) {
4604 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
4605 plat->sdiowakeup_irq, ret);
4606 goto pio_irq_free;
4607 } else {
4608 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304609 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004610 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304611 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004612 }
4613 spin_unlock_irqrestore(&host->lock, flags);
4614 }
4615 }
4616
4617 if (plat->cfg_mpm_sdiowakeup) {
4618 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4619 mmc_hostname(mmc));
4620 }
4621
4622 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
4623 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004624 /*
4625 * Setup card detect change
4626 */
4627
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004628 if (plat->status || plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08004629 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004630 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08004631 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004632 host->oldstat = msmsdcc_slot_status(host);
Krishna Konda360aa422011-12-06 18:27:41 -08004633
Krishna Konda941604a2012-01-10 17:46:34 -08004634 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004635 }
San Mehat9d2bd732009-09-22 16:44:22 -07004636
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004637 if (plat->status_irq) {
4638 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07004639 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004640 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07004641 DRIVER_NAME " (slot)",
4642 host);
4643 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004644 pr_err("Unable to get slot IRQ %d (%d)\n",
4645 plat->status_irq, ret);
4646 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004647 }
4648 } else if (plat->register_status_notify) {
4649 plat->register_status_notify(msmsdcc_status_notify_cb, host);
4650 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004651 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07004652 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004653
4654 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004655
4656 ret = pm_runtime_set_active(&(pdev)->dev);
4657 if (ret < 0)
4658 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
4659 __func__, ret);
4660 /*
4661 * There is no notion of suspend/resume for SD/MMC/SDIO
4662 * cards. So host can be suspended/resumed with out
4663 * worrying about its children.
4664 */
4665 pm_suspend_ignore_children(&(pdev)->dev, true);
4666
4667 /*
4668 * MMC/SD/SDIO bus suspend/resume operations are defined
4669 * only for the slots that will be used for non-removable
4670 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
4671 * defined. Otherwise, they simply become card removal and
4672 * insertion events during suspend and resume respectively.
4673 * Hence, enable run-time PM only for slots for which bus
4674 * suspend/resume operations are defined.
4675 */
4676#ifdef CONFIG_MMC_UNSAFE_RESUME
4677 /*
4678 * If this capability is set, MMC core will enable/disable host
4679 * for every claim/release operation on a host. We use this
4680 * notification to increment/decrement runtime pm usage count.
4681 */
4682 mmc->caps |= MMC_CAP_DISABLE;
4683 pm_runtime_enable(&(pdev)->dev);
4684#else
4685 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
4686 mmc->caps |= MMC_CAP_DISABLE;
4687 pm_runtime_enable(&(pdev)->dev);
4688 }
4689#endif
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05304690#ifndef CONFIG_PM_RUNTIME
4691 mmc_set_disable_delay(mmc, MSM_MMC_DISABLE_TIMEOUT);
4692#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004693 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
4694 (unsigned long)host);
4695
San Mehat9d2bd732009-09-22 16:44:22 -07004696 mmc_add_host(mmc);
4697
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004698#ifdef CONFIG_HAS_EARLYSUSPEND
4699 host->early_suspend.suspend = msmsdcc_early_suspend;
4700 host->early_suspend.resume = msmsdcc_late_resume;
4701 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
4702 register_early_suspend(&host->early_suspend);
4703#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004704
Krishna Konda25786ec2011-07-25 16:21:36 -07004705 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
4706 " dmacrcri %d\n", mmc_hostname(mmc),
4707 (unsigned long long)core_memres->start,
4708 (unsigned int) core_irqres->start,
4709 (unsigned int) plat->status_irq, host->dma.channel,
4710 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004711
4712 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
4713 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
4714 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
4715 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
4716 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
4717 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
4718 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
4719 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
4720 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
4721 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
4722 host->eject);
4723 pr_info("%s: Power save feature enable = %d\n",
4724 mmc_hostname(mmc), msmsdcc_pwrsave);
4725
Krishna Konda25786ec2011-07-25 16:21:36 -07004726 if (host->is_dma_mode && host->dma.channel != -1
4727 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004728 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004729 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004730 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004731 mmc_hostname(mmc), host->dma.cmd_busaddr,
4732 host->dma.cmdptr_busaddr);
4733 } else if (host->is_sps_mode) {
4734 pr_info("%s: SPS-BAM data transfer mode available\n",
4735 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004736 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004737 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004738
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004739#if defined(CONFIG_DEBUG_FS)
4740 msmsdcc_dbg_createhost(host);
4741#endif
4742 if (!plat->status_irq) {
4743 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
4744 if (ret)
4745 goto platform_irq_free;
4746 }
San Mehat9d2bd732009-09-22 16:44:22 -07004747 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004748
4749 platform_irq_free:
4750 del_timer_sync(&host->req_tout_timer);
4751 pm_runtime_disable(&(pdev)->dev);
4752 pm_runtime_set_suspended(&(pdev)->dev);
4753
4754 if (plat->status_irq)
4755 free_irq(plat->status_irq, host);
4756 sdiowakeup_irq_free:
4757 wake_lock_destroy(&host->sdio_suspend_wlock);
4758 if (plat->sdiowakeup_irq)
4759 free_irq(plat->sdiowakeup_irq, host);
4760 pio_irq_free:
4761 if (plat->sdiowakeup_irq)
4762 wake_lock_destroy(&host->sdio_wlock);
4763 free_irq(core_irqres->start, host);
4764 irq_free:
4765 free_irq(core_irqres->start, host);
4766 dml_exit:
4767 if (host->is_sps_mode)
4768 msmsdcc_dml_exit(host);
4769 sps_exit:
4770 if (host->is_sps_mode)
4771 msmsdcc_sps_exit(host);
4772 vreg_deinit:
4773 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07004774 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004775 clk_disable(host->clk);
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304776 if (host->plat->swfi_latency)
4777 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07004778 clk_put:
4779 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004780 pclk_disable:
4781 if (!IS_ERR(host->pclk))
4782 clk_disable(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07004783 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004784 if (!IS_ERR(host->pclk))
4785 clk_put(host->pclk);
4786 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4787 clk_disable(host->dfab_pclk);
4788 dfab_pclk_put:
4789 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4790 clk_put(host->dfab_pclk);
4791 dma_free:
4792 if (host->is_dma_mode) {
4793 if (host->dmares)
4794 dma_free_coherent(NULL,
4795 sizeof(struct msmsdcc_nc_dmadata),
4796 host->dma.nc, host->dma.nc_busaddr);
4797 }
4798 ioremap_free:
4799 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07004800 host_free:
4801 mmc_free_host(mmc);
4802 out:
4803 return ret;
4804}
4805
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004806static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07004807{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004808 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4809 struct mmc_platform_data *plat;
4810 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004811
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004812 if (!mmc)
4813 return -ENXIO;
4814
4815 if (pm_runtime_suspended(&(pdev)->dev))
4816 pm_runtime_resume(&(pdev)->dev);
4817
4818 host = mmc_priv(mmc);
4819
4820 DBG(host, "Removing SDCC device = %d\n", pdev->id);
4821 plat = host->plat;
4822
4823 if (!plat->status_irq)
4824 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
4825
4826 del_timer_sync(&host->req_tout_timer);
4827 tasklet_kill(&host->dma_tlet);
4828 tasklet_kill(&host->sps.tlet);
4829 mmc_remove_host(mmc);
4830
4831 if (plat->status_irq)
4832 free_irq(plat->status_irq, host);
4833
4834 wake_lock_destroy(&host->sdio_suspend_wlock);
4835 if (plat->sdiowakeup_irq) {
4836 wake_lock_destroy(&host->sdio_wlock);
4837 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
4838 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07004839 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004840
4841 free_irq(host->core_irqres->start, host);
4842 free_irq(host->core_irqres->start, host);
4843
4844 clk_put(host->clk);
4845 if (!IS_ERR(host->pclk))
4846 clk_put(host->pclk);
4847 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4848 clk_put(host->dfab_pclk);
4849
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304850 if (host->plat->swfi_latency)
4851 pm_qos_remove_request(&host->pm_qos_req_dma);
4852
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004853 msmsdcc_vreg_init(host, false);
4854
4855 if (host->is_dma_mode) {
4856 if (host->dmares)
4857 dma_free_coherent(NULL,
4858 sizeof(struct msmsdcc_nc_dmadata),
4859 host->dma.nc, host->dma.nc_busaddr);
4860 }
4861
4862 if (host->is_sps_mode) {
4863 msmsdcc_dml_exit(host);
4864 msmsdcc_sps_exit(host);
4865 }
4866
4867 iounmap(host->base);
4868 mmc_free_host(mmc);
4869
4870#ifdef CONFIG_HAS_EARLYSUSPEND
4871 unregister_early_suspend(&host->early_suspend);
4872#endif
4873 pm_runtime_disable(&(pdev)->dev);
4874 pm_runtime_set_suspended(&(pdev)->dev);
4875
4876 return 0;
4877}
4878
Oluwafemi Adeyemif68d3e62012-03-13 11:46:49 -07004879static void msmsdcc_shutdown(struct platform_device *pdev)
4880{
4881 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4882
4883 mmc_remove_host(mmc);
4884 mmc_free_host(mmc);
4885}
4886
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004887#ifdef CONFIG_MSM_SDIO_AL
4888int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4889{
4890 struct msmsdcc_host *host = mmc_priv(mmc);
4891 unsigned long flags;
4892
4893 spin_lock_irqsave(&host->lock, flags);
4894 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
4895 enable ? "En" : "Dis");
4896
4897 if (enable) {
4898 if (!host->sdcc_irq_disabled) {
4899 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05304900 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004901 host->sdcc_irq_disabled = 1;
4902 }
4903
4904 if (host->clks_on) {
4905 msmsdcc_setup_clocks(host, false);
4906 host->clks_on = 0;
4907 }
4908
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304909 if (host->plat->sdio_lpm_gpio_setup &&
4910 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004911 spin_unlock_irqrestore(&host->lock, flags);
4912 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
4913 spin_lock_irqsave(&host->lock, flags);
4914 host->sdio_gpio_lpm = 1;
4915 }
4916
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304917 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004918 msmsdcc_enable_irq_wake(host);
4919 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304920 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004921 }
4922 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304923 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004924 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304925 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004926 msmsdcc_disable_irq_wake(host);
4927 }
4928
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304929 if (host->plat->sdio_lpm_gpio_setup &&
4930 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004931 spin_unlock_irqrestore(&host->lock, flags);
4932 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
4933 spin_lock_irqsave(&host->lock, flags);
4934 host->sdio_gpio_lpm = 0;
4935 }
4936
4937 if (!host->clks_on) {
4938 msmsdcc_setup_clocks(host, true);
4939 host->clks_on = 1;
4940 }
4941
4942 if (host->sdcc_irq_disabled) {
4943 writel_relaxed(host->mci_irqenable,
4944 host->base + MMCIMASK0);
4945 mb();
4946 enable_irq(host->core_irqres->start);
4947 host->sdcc_irq_disabled = 0;
4948 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004949 }
4950 spin_unlock_irqrestore(&host->lock, flags);
4951 return 0;
4952}
4953#else
4954int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4955{
4956 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004957}
4958#endif
4959
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004960#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07004961static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004962msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004963{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004964 struct mmc_host *mmc = dev_get_drvdata(dev);
4965 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07004966 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304967 unsigned long flags;
4968
San Mehat9d2bd732009-09-22 16:44:22 -07004969
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004970 if (host->plat->is_sdio_al_client)
4971 return 0;
Sahitya Tummala7661a452011-07-18 13:28:35 +05304972 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004973 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004974 host->sdcc_suspending = 1;
4975 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07004976
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004977 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004978 * MMC core thinks that host is disabled by now since
4979 * runtime suspend is scheduled after msmsdcc_disable()
4980 * is called. Thus, MMC core will try to enable the host
4981 * while suspending it. This results in a synchronous
4982 * runtime resume request while in runtime suspending
4983 * context and hence inorder to complete this resume
4984 * requet, it will wait for suspend to be complete,
4985 * but runtime suspend also can not proceed further
4986 * until the host is resumed. Thus, it leads to a hang.
4987 * Hence, increase the pm usage count before suspending
4988 * the host so that any resume requests after this will
4989 * simple become pm usage counter increment operations.
4990 */
4991 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05304992 /* If there is pending detect work abort runtime suspend */
4993 if (unlikely(work_busy(&mmc->detect.work)))
4994 rc = -EAGAIN;
4995 else
4996 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004997 pm_runtime_put_noidle(dev);
4998
4999 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305000 spin_lock_irqsave(&host->lock, flags);
5001 host->sdcc_suspended = true;
5002 spin_unlock_irqrestore(&host->lock, flags);
5003 if (mmc->card && mmc_card_sdio(mmc->card) &&
5004 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005005 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305006 * If SDIO function driver doesn't want
5007 * to power off the card, atleast turn off
5008 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005009 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305010 mmc_host_clk_hold(mmc);
5011 spin_lock_irqsave(&mmc->clk_lock, flags);
5012 mmc->clk_old = mmc->ios.clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005013 mmc->ios.clock = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305014 mmc->clk_gated = true;
5015 spin_unlock_irqrestore(&mmc->clk_lock, flags);
5016 mmc_set_ios(mmc);
5017 mmc_host_clk_release(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005018 }
5019 }
5020 host->sdcc_suspending = 0;
5021 mmc->suspend_task = NULL;
5022 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
5023 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005024 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05305025 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
San Mehat9d2bd732009-09-22 16:44:22 -07005026 return rc;
5027}
5028
5029static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005030msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07005031{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005032 struct mmc_host *mmc = dev_get_drvdata(dev);
5033 struct msmsdcc_host *host = mmc_priv(mmc);
5034 unsigned long flags;
5035
5036 if (host->plat->is_sdio_al_client)
5037 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07005038
Sahitya Tummala7661a452011-07-18 13:28:35 +05305039 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005040 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305041 if (mmc->card && mmc_card_sdio(mmc->card) &&
5042 mmc_card_keep_power(mmc)) {
5043 mmc_host_clk_hold(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305044 mmc->ios.clock = host->clk_rate;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305045 mmc_set_ios(mmc);
5046 mmc_host_clk_release(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305047 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005048
5049 mmc_resume_host(mmc);
5050
5051 /*
5052 * FIXME: Clearing of flags must be handled in clients
5053 * resume handler.
5054 */
5055 spin_lock_irqsave(&host->lock, flags);
5056 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305057 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005058 spin_unlock_irqrestore(&host->lock, flags);
5059
5060 /*
5061 * After resuming the host wait for sometime so that
5062 * the SDIO work will be processed.
5063 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305064 if (mmc->card && mmc_card_sdio(mmc->card)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005065 if ((host->plat->cfg_mpm_sdiowakeup ||
5066 host->plat->sdiowakeup_irq) &&
5067 wake_lock_active(&host->sdio_wlock))
5068 wake_lock_timeout(&host->sdio_wlock, 1);
5069 }
5070
5071 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005072 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05305073 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005074 return 0;
5075}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005076
5077static int msmsdcc_runtime_idle(struct device *dev)
5078{
5079 struct mmc_host *mmc = dev_get_drvdata(dev);
5080 struct msmsdcc_host *host = mmc_priv(mmc);
5081
5082 if (host->plat->is_sdio_al_client)
5083 return 0;
5084
5085 /* Idle timeout is not configurable for now */
5086 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
5087
5088 return -EAGAIN;
5089}
5090
5091static int msmsdcc_pm_suspend(struct device *dev)
5092{
5093 struct mmc_host *mmc = dev_get_drvdata(dev);
5094 struct msmsdcc_host *host = mmc_priv(mmc);
5095 int rc = 0;
5096
5097 if (host->plat->is_sdio_al_client)
5098 return 0;
5099
5100
5101 if (host->plat->status_irq)
5102 disable_irq(host->plat->status_irq);
5103
Subhash Jadavani18702212012-03-19 18:50:18 +05305104 if (!pm_runtime_suspended(dev)) {
5105 if (!(mmc->card && mmc_card_sdio(mmc->card))) {
5106 /*
5107 * decrement power.usage_counter if it's
5108 * not zero earlier
5109 */
5110 pm_runtime_put_noidle(dev);
5111 rc = pm_runtime_suspend(dev);
5112 }
5113
5114 /*
5115 * if device runtime PM status is still not suspended
5116 * then perform suspend here.
5117 */
5118 if (!pm_runtime_suspended(dev))
5119 rc = msmsdcc_runtime_suspend(dev);
5120 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005121
5122 return rc;
5123}
5124
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305125static int msmsdcc_suspend_noirq(struct device *dev)
5126{
5127 struct mmc_host *mmc = dev_get_drvdata(dev);
5128 struct msmsdcc_host *host = mmc_priv(mmc);
5129 int rc = 0;
5130
5131 /*
5132 * After platform suspend there may be active request
5133 * which might have enabled clocks. For example, in SDIO
5134 * case, ksdioirq thread might have scheduled after sdcc
5135 * suspend but before system freeze. In that case abort
5136 * suspend and retry instead of keeping the clocks on
5137 * during suspend and not allowing TCXO.
5138 */
5139
5140 if (host->clks_on) {
5141 pr_warn("%s: clocks are on after suspend, aborting system "
5142 "suspend\n", mmc_hostname(mmc));
5143 rc = -EAGAIN;
5144 }
5145
5146 return rc;
5147}
5148
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005149static int msmsdcc_pm_resume(struct device *dev)
5150{
5151 struct mmc_host *mmc = dev_get_drvdata(dev);
5152 struct msmsdcc_host *host = mmc_priv(mmc);
5153 int rc = 0;
5154
5155 if (host->plat->is_sdio_al_client)
5156 return 0;
5157
Sahitya Tummalafb486372011-09-02 19:01:49 +05305158 if (!pm_runtime_suspended(dev))
5159 rc = msmsdcc_runtime_resume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005160 if (host->plat->status_irq) {
5161 msmsdcc_check_status((unsigned long)host);
5162 enable_irq(host->plat->status_irq);
5163 }
5164
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005165 return rc;
5166}
5167
Daniel Walker08ecfde2010-06-23 12:32:20 -07005168#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005169#define msmsdcc_runtime_suspend NULL
5170#define msmsdcc_runtime_resume NULL
5171#define msmsdcc_runtime_idle NULL
5172#define msmsdcc_pm_suspend NULL
5173#define msmsdcc_pm_resume NULL
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305174#define msmsdcc_suspend_noirq NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07005175#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005176
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005177static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
5178 .runtime_suspend = msmsdcc_runtime_suspend,
5179 .runtime_resume = msmsdcc_runtime_resume,
5180 .runtime_idle = msmsdcc_runtime_idle,
5181 .suspend = msmsdcc_pm_suspend,
5182 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305183 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005184};
5185
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305186static const struct of_device_id msmsdcc_dt_match[] = {
5187 {.compatible = "qcom,msm-sdcc"},
5188
5189};
5190MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
5191
San Mehat9d2bd732009-09-22 16:44:22 -07005192static struct platform_driver msmsdcc_driver = {
5193 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005194 .remove = msmsdcc_remove,
Oluwafemi Adeyemif68d3e62012-03-13 11:46:49 -07005195 .shutdown = msmsdcc_shutdown,
San Mehat9d2bd732009-09-22 16:44:22 -07005196 .driver = {
5197 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005198 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305199 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07005200 },
5201};
5202
5203static int __init msmsdcc_init(void)
5204{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005205#if defined(CONFIG_DEBUG_FS)
5206 int ret = 0;
5207 ret = msmsdcc_dbg_init();
5208 if (ret) {
5209 pr_err("Failed to create debug fs dir \n");
5210 return ret;
5211 }
5212#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005213 return platform_driver_register(&msmsdcc_driver);
5214}
5215
5216static void __exit msmsdcc_exit(void)
5217{
5218 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005219
5220#if defined(CONFIG_DEBUG_FS)
5221 debugfs_remove(debugfs_file);
5222 debugfs_remove(debugfs_dir);
5223#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005224}
5225
5226module_init(msmsdcc_init);
5227module_exit(msmsdcc_exit);
5228
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005229MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07005230MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005231
5232#if defined(CONFIG_DEBUG_FS)
5233
5234static int
5235msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
5236{
5237 file->private_data = inode->i_private;
5238 return 0;
5239}
5240
5241static ssize_t
5242msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
5243 size_t count, loff_t *ppos)
5244{
5245 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08005246 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005247 int max, i;
5248
5249 i = 0;
5250 max = sizeof(buf) - 1;
5251
5252 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
5253 host->curr.cmd, host->curr.data);
5254 if (host->curr.cmd) {
5255 struct mmc_command *cmd = host->curr.cmd;
5256
5257 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
5258 cmd->opcode, cmd->arg, cmd->flags);
5259 }
5260 if (host->curr.data) {
5261 struct mmc_data *data = host->curr.data;
5262 i += scnprintf(buf + i, max - i,
5263 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
5264 data->timeout_ns, data->timeout_clks,
5265 data->blksz, data->blocks, data->error,
5266 data->flags);
5267 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
5268 host->curr.xfer_size, host->curr.xfer_remain,
5269 host->curr.data_xfered, host->dma.sg);
5270 }
5271
5272 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
5273}
5274
5275static const struct file_operations msmsdcc_dbg_state_ops = {
5276 .read = msmsdcc_dbg_state_read,
5277 .open = msmsdcc_dbg_state_open,
5278};
5279
5280static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
5281{
5282 if (debugfs_dir) {
5283 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
5284 0644, debugfs_dir, host,
5285 &msmsdcc_dbg_state_ops);
5286 }
5287}
5288
5289static int __init msmsdcc_dbg_init(void)
5290{
5291 int err;
5292
5293 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
5294 if (IS_ERR(debugfs_dir)) {
5295 err = PTR_ERR(debugfs_dir);
5296 debugfs_dir = NULL;
5297 return err;
5298 }
5299
5300 return 0;
5301}
5302#endif