blob: 9652773a1e04604f3575b7f81bcb88abe3b8394b [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 Jadavani15f29db2011-10-13 09:57:13 +0530145static inline void msmsdcc_delay(struct msmsdcc_host *host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530146static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -0800147static void msmsdcc_sg_start(struct msmsdcc_host *host);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -0800148static int msmsdcc_vreg_reset(struct msmsdcc_host *host);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530149
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530150static inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
151{
152 unsigned short ret = NR_SG;
153
154 if (host->is_sps_mode) {
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +0530155 ret = SPS_MAX_DESCS;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530156 } else { /* DMA or PIO mode */
157 if (NR_SG > MAX_NR_SG_DMA_PIO)
158 ret = MAX_NR_SG_DMA_PIO;
159 }
160
161 return ret;
162}
163
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530164/* Prevent idle power collapse(pc) while operating in peripheral mode */
165static void msmsdcc_pm_qos_update_latency(struct msmsdcc_host *host, int vote)
166{
167 u32 swfi_latency = 0;
168
169 if (!host->plat->swfi_latency)
170 return;
171
172 swfi_latency = host->plat->swfi_latency + 1;
173
174 if (vote)
175 pm_qos_update_request(&host->pm_qos_req_dma,
176 swfi_latency);
177 else
178 pm_qos_update_request(&host->pm_qos_req_dma,
179 PM_QOS_DEFAULT_VALUE);
180}
181
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700182#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
183static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
184 struct msmsdcc_sps_ep_conn_data *ep);
185static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
186 struct msmsdcc_sps_ep_conn_data *ep);
187#else
188static inline int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
189 struct msmsdcc_sps_ep_conn_data *ep,
190 bool is_producer) { return 0; }
191static inline void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
192 struct msmsdcc_sps_ep_conn_data *ep) { }
193static inline int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
194 struct msmsdcc_sps_ep_conn_data *ep)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530195{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700196 return 0;
197}
198static inline int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
199 struct msmsdcc_sps_ep_conn_data *ep)
200{
201 return 0;
202}
203static inline int msmsdcc_sps_init(struct msmsdcc_host *host) { return 0; }
204static inline void msmsdcc_sps_exit(struct msmsdcc_host *host) {}
205#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530206
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700207/**
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530208 * Apply soft reset to all SDCC BAM pipes
209 *
210 * This function applies soft reset to SDCC BAM pipe.
211 *
212 * This function should be called to recover from error
213 * conditions encountered during CMD/DATA tranfsers with card.
214 *
215 * @host - Pointer to driver's host structure
216 *
217 */
218static void msmsdcc_sps_pipes_reset_and_restore(struct msmsdcc_host *host)
219{
220 int rc;
221
222 /* Reset all SDCC BAM pipes */
223 rc = msmsdcc_sps_reset_ep(host, &host->sps.prod);
224 if (rc)
225 pr_err("%s:msmsdcc_sps_reset_ep(prod) error=%d\n",
226 mmc_hostname(host->mmc), rc);
227 rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
228 if (rc)
229 pr_err("%s:msmsdcc_sps_reset_ep(cons) error=%d\n",
230 mmc_hostname(host->mmc), rc);
231
232 /* Restore all BAM pipes connections */
233 rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
234 if (rc)
235 pr_err("%s:msmsdcc_sps_restore_ep(prod) error=%d\n",
236 mmc_hostname(host->mmc), rc);
237 rc = msmsdcc_sps_restore_ep(host, &host->sps.cons);
238 if (rc)
239 pr_err("%s:msmsdcc_sps_restore_ep(cons) error=%d\n",
240 mmc_hostname(host->mmc), rc);
241}
242
243/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700244 * Apply soft reset
245 *
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530246 * This function applies soft reset to SDCC core and DML core.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700247 *
248 * This function should be called to recover from error
249 * conditions encountered with CMD/DATA tranfsers with card.
250 *
251 * Soft reset should only be used with SDCC controller v4.
252 *
253 * @host - Pointer to driver's host structure
254 *
255 */
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530256static void msmsdcc_soft_reset(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700257{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700258 /*
259 * Reset SDCC controller's DPSM (data path state machine
260 * and CPSM (command path state machine).
261 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700262 writel_relaxed(0, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530263 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700264 writel_relaxed(0, host->base + MMCIDATACTRL);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530265 msmsdcc_delay(host);
266}
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530267
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530268static void msmsdcc_hard_reset(struct msmsdcc_host *host)
269{
270 int ret;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530271
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530272 /* Reset the controller */
273 ret = clk_reset(host->clk, CLK_RESET_ASSERT);
274 if (ret)
275 pr_err("%s: Clock assert failed at %u Hz"
276 " with err %d\n", mmc_hostname(host->mmc),
277 host->clk_rate, ret);
278
279 ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
280 if (ret)
281 pr_err("%s: Clock deassert failed at %u Hz"
282 " with err %d\n", mmc_hostname(host->mmc),
283 host->clk_rate, ret);
284
285 /* Give some delay for clock reset to propogate to controller */
286 msmsdcc_delay(host);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530287}
288
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700289static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
290{
Pratibhasagar V1c11da62011-11-14 12:36:35 +0530291 if (host->sdcc_version) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530292 if (host->is_sps_mode) {
293 /* Reset DML first */
294 msmsdcc_dml_reset(host);
295 /*
296 * delay the SPS pipe reset in thread context as
297 * sps_connect/sps_disconnect APIs can be called
298 * only from non-atomic context.
299 */
300 host->sps.pipe_reset_pending = true;
301 }
302 mb();
303 msmsdcc_soft_reset(host);
304
305 pr_debug("%s: Applied soft reset to Controller\n",
306 mmc_hostname(host->mmc));
307
308 if (host->is_sps_mode)
309 msmsdcc_dml_init(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700310 } else {
311 /* Give Clock reset (hard reset) to controller */
312 u32 mci_clk = 0;
313 u32 mci_mask0 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700314
315 /* Save the controller state */
316 mci_clk = readl_relaxed(host->base + MMCICLOCK);
317 mci_mask0 = readl_relaxed(host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +0530318 host->pwr = readl_relaxed(host->base + MMCIPOWER);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700319 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700320
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530321 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700322 pr_debug("%s: Controller has been reinitialized\n",
323 mmc_hostname(host->mmc));
324
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700325 /* Restore the contoller state */
326 writel_relaxed(host->pwr, host->base + MMCIPOWER);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530327 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700328 writel_relaxed(mci_clk, host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530329 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700330 writel_relaxed(mci_mask0, host->base + MMCIMASK0);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530331 mb(); /* no delay required after writing to MASK0 register */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700332 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530333
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700334 if (host->dummy_52_needed)
335 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700336}
337
338static int
San Mehat9d2bd732009-09-22 16:44:22 -0700339msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
340{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700341 int retval = 0;
342
San Mehat9d2bd732009-09-22 16:44:22 -0700343 BUG_ON(host->curr.data);
344
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700345 del_timer(&host->req_tout_timer);
346
San Mehat9d2bd732009-09-22 16:44:22 -0700347 if (mrq->data)
348 mrq->data->bytes_xfered = host->curr.data_xfered;
349 if (mrq->cmd->error == -ETIMEDOUT)
350 mdelay(5);
351
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530352 /* Clear current request information as current request has ended */
353 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
354
San Mehat9d2bd732009-09-22 16:44:22 -0700355 /*
356 * Need to drop the host lock here; mmc_request_done may call
357 * back into the driver...
358 */
359 spin_unlock(&host->lock);
360 mmc_request_done(host->mmc, mrq);
361 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700362
363 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700364}
365
366static void
367msmsdcc_stop_data(struct msmsdcc_host *host)
368{
San Mehat9d2bd732009-09-22 16:44:22 -0700369 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530370 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530371 host->curr.wait_for_auto_prog_done = 0;
372 host->curr.got_auto_prog_done = 0;
Krishna Konda3f5d48f2011-07-27 10:47:31 -0700373 writel_relaxed(readl_relaxed(host->base + MMCIDATACTRL) &
374 (~(MCI_DPSM_ENABLE)), host->base + MMCIDATACTRL);
Krishna Konda3e5c4d02011-07-11 16:31:45 -0700375 msmsdcc_delay(host); /* Allow the DPSM to be reset */
San Mehat9d2bd732009-09-22 16:44:22 -0700376}
377
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700378static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700379{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700380 return host->core_memres->start + MMCIFIFO;
381}
382
383static inline unsigned int msmsdcc_get_min_sup_clk_rate(
384 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530385
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700386static inline void msmsdcc_delay(struct msmsdcc_host *host)
387{
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530388 ktime_t start, diff;
389
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700390 mb();
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +0530391 udelay(host->reg_write_delay);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530392
Pratibhasagar V1c11da62011-11-14 12:36:35 +0530393 if (host->sdcc_version &&
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530394 (readl_relaxed(host->base + MCI_STATUS2) &
395 MCI_MCLK_REG_WR_ACTIVE)) {
396 start = ktime_get();
397 while (readl_relaxed(host->base + MCI_STATUS2) &
398 MCI_MCLK_REG_WR_ACTIVE) {
399 diff = ktime_sub(ktime_get(), start);
400 /* poll for max. 1 ms */
401 if (ktime_to_us(diff) > 1000) {
402 pr_warning("%s: previous reg. write is"
403 " still active\n",
404 mmc_hostname(host->mmc));
405 break;
406 }
407 }
408 }
San Mehat9d2bd732009-09-22 16:44:22 -0700409}
410
San Mehat56a8b5b2009-11-21 12:29:46 -0800411static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700412msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
413{
414 writel_relaxed(arg, host->base + MMCIARGUMENT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700415 writel_relaxed(c, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530416 /*
417 * As after sending the command, we don't write any of the
418 * controller registers and just wait for the
419 * CMD_RESPOND_END/CMD_SENT/Command failure notication
420 * from Controller.
421 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700422 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800423}
424
425static void
426msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
427{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700428 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800429
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700430 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
431 writel_relaxed((unsigned int)host->curr.xfer_size,
432 host->base + MMCIDATALENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700433 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
434 msmsdcc_delay(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800435
San Mehat6ac9ea62009-12-02 17:24:58 -0800436 if (host->cmd_cmd) {
437 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700438 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800439 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800440}
441
San Mehat9d2bd732009-09-22 16:44:22 -0700442static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530443msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700444{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530445 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700446 unsigned long flags;
447 struct mmc_request *mrq;
448
449 spin_lock_irqsave(&host->lock, flags);
450 mrq = host->curr.mrq;
451 BUG_ON(!mrq);
452
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530453 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700454 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700455 goto out;
456 }
457
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530458 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700459 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700460 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700461 } else {
462 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530463 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700464 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530465 mmc_hostname(host->mmc), host->dma.result);
466 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700467 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530468 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530469 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700470 host->dma.err.flush[0], host->dma.err.flush[1],
471 host->dma.err.flush[2], host->dma.err.flush[3],
472 host->dma.err.flush[4],
473 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530474 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700475 if (!mrq->data->error)
476 mrq->data->error = -EIO;
477 }
San Mehat9d2bd732009-09-22 16:44:22 -0700478 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents,
479 host->dma.dir);
480
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700481 if (host->curr.user_pages) {
482 struct scatterlist *sg = host->dma.sg;
483 int i;
484
485 for (i = 0; i < host->dma.num_ents; i++, sg++)
486 flush_dcache_page(sg_page(sg));
487 }
488
San Mehat9d2bd732009-09-22 16:44:22 -0700489 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800490 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700491
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530492 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
493 (host->curr.wait_for_auto_prog_done &&
494 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700495 /*
496 * If we've already gotten our DATAEND / DATABLKEND
497 * for this request, then complete it through here.
498 */
San Mehat9d2bd732009-09-22 16:44:22 -0700499
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700500 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700501 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700502 host->curr.xfer_remain -= host->curr.xfer_size;
503 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700504 if (host->dummy_52_needed) {
505 mrq->data->bytes_xfered = host->curr.data_xfered;
506 host->dummy_52_sent = 1;
507 msmsdcc_start_command(host, &dummy52cmd,
508 MCI_CPSM_PROGENA);
509 goto out;
510 }
511 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530512 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530513 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700514 mrq->data->bytes_xfered = host->curr.data_xfered;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700515 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530516 /*
517 * Clear current request information as current
518 * request has ended
519 */
520 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
San Mehat9d2bd732009-09-22 16:44:22 -0700521 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700522
San Mehat9d2bd732009-09-22 16:44:22 -0700523 mmc_request_done(host->mmc, mrq);
524 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530525 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
526 || !mrq->sbc)) {
527 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530528 }
San Mehat9d2bd732009-09-22 16:44:22 -0700529 }
530
531out:
532 spin_unlock_irqrestore(&host->lock, flags);
533 return;
534}
535
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700536#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
537/**
538 * Callback notification from SPS driver
539 *
540 * This callback function gets triggered called from
541 * SPS driver when requested SPS data transfer is
542 * completed.
543 *
544 * SPS driver invokes this callback in BAM irq context so
545 * SDCC driver schedule a tasklet for further processing
546 * this callback notification at later point of time in
547 * tasklet context and immediately returns control back
548 * to SPS driver.
549 *
550 * @nofity - Pointer to sps event notify sturcture
551 *
552 */
553static void
554msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
555{
556 struct msmsdcc_host *host =
557 (struct msmsdcc_host *)
558 ((struct sps_event_notify *)notify)->user;
559
560 host->sps.notify = *notify;
561 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
562 mmc_hostname(host->mmc), __func__, notify->event_id,
563 notify->data.transfer.iovec.addr,
564 notify->data.transfer.iovec.size,
565 notify->data.transfer.iovec.flags);
566 /* Schedule a tasklet for completing data transfer */
567 tasklet_schedule(&host->sps.tlet);
568}
569
570/**
571 * Tasklet handler for processing SPS callback event
572 *
573 * This function processing SPS event notification and
574 * checks if the SPS transfer is completed or not and
575 * then accordingly notifies status to MMC core layer.
576 *
577 * This function is called in tasklet context.
578 *
579 * @data - Pointer to sdcc driver data
580 *
581 */
582static void msmsdcc_sps_complete_tlet(unsigned long data)
583{
584 unsigned long flags;
585 int i, rc;
586 u32 data_xfered = 0;
587 struct mmc_request *mrq;
588 struct sps_iovec iovec;
589 struct sps_pipe *sps_pipe_handle;
590 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
591 struct sps_event_notify *notify = &host->sps.notify;
592
593 spin_lock_irqsave(&host->lock, flags);
594 if (host->sps.dir == DMA_FROM_DEVICE)
595 sps_pipe_handle = host->sps.prod.pipe_handle;
596 else
597 sps_pipe_handle = host->sps.cons.pipe_handle;
598 mrq = host->curr.mrq;
599
600 if (!mrq) {
601 spin_unlock_irqrestore(&host->lock, flags);
602 return;
603 }
604
605 pr_debug("%s: %s: sps event_id=%d\n",
606 mmc_hostname(host->mmc), __func__,
607 notify->event_id);
608
609 if (msmsdcc_is_dml_busy(host)) {
610 /* oops !!! this should never happen. */
611 pr_err("%s: %s: Received SPS EOT event"
612 " but DML HW is still busy !!!\n",
613 mmc_hostname(host->mmc), __func__);
614 }
615 /*
616 * Got End of transfer event!!! Check if all of the data
617 * has been transferred?
618 */
619 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
620 rc = sps_get_iovec(sps_pipe_handle, &iovec);
621 if (rc) {
622 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
623 mmc_hostname(host->mmc), __func__, rc, i);
624 break;
625 }
626 data_xfered += iovec.size;
627 }
628
629 if (data_xfered == host->curr.xfer_size) {
630 host->curr.data_xfered = host->curr.xfer_size;
631 host->curr.xfer_remain -= host->curr.xfer_size;
632 pr_debug("%s: Data xfer success. data_xfered=0x%x",
633 mmc_hostname(host->mmc),
634 host->curr.xfer_size);
635 } else {
636 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
637 " xfer_size=%d", mmc_hostname(host->mmc),
638 data_xfered, host->curr.xfer_size);
639 msmsdcc_reset_and_restore(host);
640 if (!mrq->data->error)
641 mrq->data->error = -EIO;
642 }
643
644 /* Unmap sg buffers */
645 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
646 host->sps.dir);
647
648 host->sps.sg = NULL;
649 host->sps.busy = 0;
650
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530651 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
652 (host->curr.wait_for_auto_prog_done &&
653 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700654 /*
655 * If we've already gotten our DATAEND / DATABLKEND
656 * for this request, then complete it through here.
657 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700658
659 if (!mrq->data->error) {
660 host->curr.data_xfered = host->curr.xfer_size;
661 host->curr.xfer_remain -= host->curr.xfer_size;
662 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700663 if (host->dummy_52_needed) {
664 mrq->data->bytes_xfered = host->curr.data_xfered;
665 host->dummy_52_sent = 1;
666 msmsdcc_start_command(host, &dummy52cmd,
667 MCI_CPSM_PROGENA);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700668 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700669 return;
670 }
671 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530672 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530673 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700674 mrq->data->bytes_xfered = host->curr.data_xfered;
675 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530676 /*
677 * Clear current request information as current
678 * request has ended
679 */
680 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700681 spin_unlock_irqrestore(&host->lock, flags);
682
683 mmc_request_done(host->mmc, mrq);
684 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530685 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
686 || !mrq->sbc)) {
687 msmsdcc_start_command(host, mrq->data->stop, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700688 }
689 }
690 spin_unlock_irqrestore(&host->lock, flags);
691}
692
693/**
694 * Exit from current SPS data transfer
695 *
696 * This function exits from current SPS data transfer.
697 *
698 * This function should be called when error condition
699 * is encountered during data transfer.
700 *
701 * @host - Pointer to sdcc host structure
702 *
703 */
704static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
705{
706 struct mmc_request *mrq;
707
708 mrq = host->curr.mrq;
709 BUG_ON(!mrq);
710
711 msmsdcc_reset_and_restore(host);
712 if (!mrq->data->error)
713 mrq->data->error = -EIO;
714
715 /* Unmap sg buffers */
716 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
717 host->sps.dir);
718
719 host->sps.sg = NULL;
720 host->sps.busy = 0;
721 if (host->curr.data)
722 msmsdcc_stop_data(host);
723
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530724 if (!mrq->data->stop || mrq->cmd->error ||
725 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700726 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530727 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
728 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700729 msmsdcc_start_command(host, mrq->data->stop, 0);
730
731}
732#else
733static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
734static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
735static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
736#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
737
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530738static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700739
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530740static void
741msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
742 unsigned int result,
743 struct msm_dmov_errdata *err)
744{
745 struct msmsdcc_dma_data *dma_data =
746 container_of(cmd, struct msmsdcc_dma_data, hdr);
747 struct msmsdcc_host *host = dma_data->host;
748
749 dma_data->result = result;
750 if (err)
751 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
752
753 tasklet_schedule(&host->dma_tlet);
754}
755
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700756static int msmsdcc_check_dma_op_req(struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700757{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700758 if (((data->blksz * data->blocks) < MCI_FIFOSIZE) ||
759 ((data->blksz * data->blocks) % MCI_FIFOSIZE))
San Mehat9d2bd732009-09-22 16:44:22 -0700760 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700761 else
762 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700763}
764
765static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
766{
767 struct msmsdcc_nc_dmadata *nc;
768 dmov_box *box;
769 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700770 unsigned int n;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530771 int i, err = 0, box_cmd_cnt = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700772 struct scatterlist *sg = data->sg;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530773 unsigned int len, offset;
San Mehat9d2bd732009-09-22 16:44:22 -0700774
Krishna Konda25786ec2011-07-25 16:21:36 -0700775 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700776 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700777
Krishna Konda25786ec2011-07-25 16:21:36 -0700778 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
779
San Mehat9d2bd732009-09-22 16:44:22 -0700780 host->dma.sg = data->sg;
781 host->dma.num_ents = data->sg_len;
782
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530783 /* Prevent memory corruption */
784 BUG_ON(host->dma.num_ents > msmsdcc_get_nr_sg(host));
San Mehat56a8b5b2009-11-21 12:29:46 -0800785
San Mehat9d2bd732009-09-22 16:44:22 -0700786 nc = host->dma.nc;
787
San Mehat9d2bd732009-09-22 16:44:22 -0700788 if (data->flags & MMC_DATA_READ)
789 host->dma.dir = DMA_FROM_DEVICE;
790 else
791 host->dma.dir = DMA_TO_DEVICE;
792
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700793 n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
794 host->dma.num_ents, host->dma.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700795
796 if (n != host->dma.num_ents) {
797 pr_err("%s: Unable to map in all sg elements\n",
798 mmc_hostname(host->mmc));
799 host->dma.sg = NULL;
800 host->dma.num_ents = 0;
801 return -ENOMEM;
San Mehat56a8b5b2009-11-21 12:29:46 -0800802 }
San Mehat9d2bd732009-09-22 16:44:22 -0700803
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530804 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
805 host->curr.user_pages = 0;
806 box = &nc->cmd[0];
807 for (i = 0; i < host->dma.num_ents; i++) {
808 len = sg_dma_len(sg);
809 offset = 0;
810
811 do {
812 /* Check if we can do DMA */
813 if (!len || (box_cmd_cnt >= MMC_MAX_DMA_CMDS)) {
814 err = -ENOTSUPP;
815 goto unmap;
816 }
817
818 box->cmd = CMD_MODE_BOX;
819
820 if (len >= MMC_MAX_DMA_BOX_LENGTH) {
821 len = MMC_MAX_DMA_BOX_LENGTH;
822 len -= len % data->blksz;
823 }
824 rows = (len % MCI_FIFOSIZE) ?
825 (len / MCI_FIFOSIZE) + 1 :
826 (len / MCI_FIFOSIZE);
827
828 if (data->flags & MMC_DATA_READ) {
829 box->src_row_addr = msmsdcc_fifo_addr(host);
830 box->dst_row_addr = sg_dma_address(sg) + offset;
831 box->src_dst_len = (MCI_FIFOSIZE << 16) |
832 (MCI_FIFOSIZE);
833 box->row_offset = MCI_FIFOSIZE;
834 box->num_rows = rows * ((1 << 16) + 1);
835 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
836 } else {
837 box->src_row_addr = sg_dma_address(sg) + offset;
838 box->dst_row_addr = msmsdcc_fifo_addr(host);
839 box->src_dst_len = (MCI_FIFOSIZE << 16) |
840 (MCI_FIFOSIZE);
841 box->row_offset = (MCI_FIFOSIZE << 16);
842 box->num_rows = rows * ((1 << 16) + 1);
843 box->cmd |= CMD_DST_CRCI(host->dma.crci);
844 }
845
846 offset += len;
847 len = sg_dma_len(sg) - offset;
848 box++;
849 box_cmd_cnt++;
850 } while (len);
851 sg++;
852 }
853 /* Mark last command */
854 box--;
855 box->cmd |= CMD_LC;
856
857 /* location of command block must be 64 bit aligned */
858 BUG_ON(host->dma.cmd_busaddr & 0x07);
859
860 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
861 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
862 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
863 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
864
865 /* Flush all data to memory before starting dma */
866 mb();
867
868unmap:
869 if (err) {
870 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
871 host->dma.num_ents, host->dma.dir);
872 pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
873 mmc_hostname(host->mmc), err);
874 }
875
876 return err;
San Mehat9d2bd732009-09-22 16:44:22 -0700877}
878
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700879#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
880/**
881 * Submits data transfer request to SPS driver
882 *
883 * This function make sg (scatter gather) data buffers
884 * DMA ready and then submits them to SPS driver for
885 * transfer.
886 *
887 * @host - Pointer to sdcc host structure
888 * @data - Pointer to mmc_data structure
889 *
890 * @return 0 if success else negative value
891 */
892static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
893 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -0800894{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700895 int rc = 0;
896 u32 flags;
897 int i;
898 u32 addr, len, data_cnt;
899 struct scatterlist *sg = data->sg;
900 struct sps_pipe *sps_pipe_handle;
901
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530902 /* Prevent memory corruption */
903 BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700904
905 host->sps.sg = data->sg;
906 host->sps.num_ents = data->sg_len;
907 host->sps.xfer_req_cnt = 0;
908 if (data->flags & MMC_DATA_READ) {
909 host->sps.dir = DMA_FROM_DEVICE;
910 sps_pipe_handle = host->sps.prod.pipe_handle;
911 } else {
912 host->sps.dir = DMA_TO_DEVICE;
913 sps_pipe_handle = host->sps.cons.pipe_handle;
914 }
915
916 /* Make sg buffers DMA ready */
917 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
918 host->sps.dir);
919
920 if (rc != data->sg_len) {
921 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
922 mmc_hostname(host->mmc), rc);
923 host->sps.sg = NULL;
924 host->sps.num_ents = 0;
925 rc = -ENOMEM;
926 goto dma_map_err;
927 }
928
929 pr_debug("%s: %s: %s: pipe=0x%x, total_xfer=0x%x, sg_len=%d\n",
930 mmc_hostname(host->mmc), __func__,
931 host->sps.dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
932 (u32)sps_pipe_handle, host->curr.xfer_size, data->sg_len);
933
934 for (i = 0; i < data->sg_len; i++) {
935 /*
936 * Check if this is the last buffer to transfer?
937 * If yes then set the INT and EOT flags.
938 */
939 len = sg_dma_len(sg);
940 addr = sg_dma_address(sg);
941 flags = 0;
942 while (len > 0) {
943 if (len > SPS_MAX_DESC_SIZE) {
944 data_cnt = SPS_MAX_DESC_SIZE;
945 } else {
946 data_cnt = len;
947 if (i == data->sg_len - 1)
948 flags = SPS_IOVEC_FLAG_INT |
949 SPS_IOVEC_FLAG_EOT;
950 }
951 rc = sps_transfer_one(sps_pipe_handle, addr,
952 data_cnt, host, flags);
953 if (rc) {
954 pr_err("%s: sps_transfer_one() error! rc=%d,"
955 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
956 mmc_hostname(host->mmc), rc,
957 (u32)sps_pipe_handle, (u32)sg, i);
958 goto dma_map_err;
959 }
960 addr += data_cnt;
961 len -= data_cnt;
962 host->sps.xfer_req_cnt++;
963 }
964 sg++;
965 }
966 goto out;
967
968dma_map_err:
969 /* unmap sg buffers */
970 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
971 host->sps.dir);
972out:
973 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -0700974}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700975#else
976static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
977 struct mmc_data *data) { return 0; }
978#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -0700979
980static void
San Mehat56a8b5b2009-11-21 12:29:46 -0800981msmsdcc_start_command_deferred(struct msmsdcc_host *host,
982 struct mmc_command *cmd, u32 *c)
983{
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530984 DBG(host, "op %02x arg %08x flags %08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700985 cmd->opcode, cmd->arg, cmd->flags);
986
San Mehat56a8b5b2009-11-21 12:29:46 -0800987 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
988
989 if (cmd->flags & MMC_RSP_PRESENT) {
990 if (cmd->flags & MMC_RSP_136)
991 *c |= MCI_CPSM_LONGRSP;
992 *c |= MCI_CPSM_RESPONSE;
993 }
994
995 if (/*interrupt*/0)
996 *c |= MCI_CPSM_INTERRUPT;
997
Subhash Jadavanide0fc772011-11-13 12:27:52 +0530998 if (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
999 cmd->opcode == MMC_READ_MULTIPLE_BLOCK ||
1000 cmd->opcode == MMC_WRITE_BLOCK ||
1001 cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK ||
1002 cmd->opcode == SD_IO_RW_EXTENDED)
San Mehat56a8b5b2009-11-21 12:29:46 -08001003 *c |= MCI_CSPM_DATCMD;
1004
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001005 /* Check if AUTO CMD19 is required or not? */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301006 if (host->tuning_needed &&
1007 !(host->mmc->ios.timing == MMC_TIMING_MMC_HS200)) {
1008
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301009 /*
1010 * For open ended block read operation (without CMD23),
1011 * AUTO_CMD19 bit should be set while sending the READ command.
1012 * For close ended block read operation (with CMD23),
1013 * AUTO_CMD19 bit should be set while sending CMD23.
1014 */
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301015 if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
1016 host->curr.mrq->cmd->opcode ==
1017 MMC_READ_MULTIPLE_BLOCK) ||
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301018 (!host->curr.mrq->sbc &&
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301019 (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
1020 cmd->opcode == MMC_READ_MULTIPLE_BLOCK))) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301021 msmsdcc_enable_cdr_cm_sdc4_dll(host);
1022 *c |= MCI_CSPM_AUTO_CMD19;
1023 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001024 }
1025
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05301026 /* Clear CDR_EN bit for write operations */
1027 if (host->tuning_needed && cmd->mrq->data &&
1028 (cmd->mrq->data->flags & MMC_DATA_WRITE))
1029 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) &
1030 ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
1031
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301032 if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301033 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001034 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301035 }
1036
San Mehat56a8b5b2009-11-21 12:29:46 -08001037 if (cmd == cmd->mrq->stop)
1038 *c |= MCI_CSPM_MCIABORT;
1039
San Mehat56a8b5b2009-11-21 12:29:46 -08001040 if (host->curr.cmd != NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001041 pr_err("%s: Overlapping command requests\n",
1042 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -08001043 }
1044 host->curr.cmd = cmd;
1045}
1046
1047static void
1048msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1049 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001050{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301051 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001052 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001053 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001054 unsigned int pio_irqmask = 0;
1055
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301056 BUG_ON(!data->sg);
1057 BUG_ON(!data->sg_len);
1058
San Mehat9d2bd732009-09-22 16:44:22 -07001059 host->curr.data = data;
1060 host->curr.xfer_size = data->blksz * data->blocks;
1061 host->curr.xfer_remain = host->curr.xfer_size;
1062 host->curr.data_xfered = 0;
1063 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301064 host->curr.got_auto_prog_done = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001065
San Mehat9d2bd732009-09-22 16:44:22 -07001066 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1067
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301068 if (host->curr.wait_for_auto_prog_done)
1069 datactrl |= MCI_AUTO_PROG_DONE;
1070
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001071 if (!msmsdcc_check_dma_op_req(data)) {
1072 if (host->is_dma_mode && !msmsdcc_config_dma(host, data)) {
1073 datactrl |= MCI_DPSM_DMAENABLE;
1074 } else if (host->is_sps_mode) {
1075 if (!msmsdcc_is_dml_busy(host)) {
1076 if (!msmsdcc_sps_start_xfer(host, data)) {
1077 /* Now kick start DML transfer */
1078 mb();
1079 msmsdcc_dml_start_xfer(host, data);
1080 datactrl |= MCI_DPSM_DMAENABLE;
1081 host->sps.busy = 1;
1082 }
1083 } else {
1084 /*
1085 * Can't proceed with new transfer as
1086 * previous trasnfer is already in progress.
1087 * There is no point of going into PIO mode
1088 * as well. Is this a time to do kernel panic?
1089 */
1090 pr_err("%s: %s: DML HW is busy!!!"
1091 " Can't perform new SPS transfers"
1092 " now\n", mmc_hostname(host->mmc),
1093 __func__);
1094 }
1095 }
1096 }
1097
1098 /* Is data transfer in PIO mode required? */
1099 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001100 if (data->flags & MMC_DATA_READ) {
1101 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1102 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1103 pio_irqmask |= MCI_RXDATAAVLBLMASK;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001104 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001105 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1106 MCI_TXFIFOEMPTYMASK;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001107
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001108 msmsdcc_sg_start(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001109 }
1110
1111 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301112 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
San Mehat9d2bd732009-09-22 16:44:22 -07001113
San Mehat56a8b5b2009-11-21 12:29:46 -08001114 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001115 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001116 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -07001117
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001118 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
1119 /* Use ADM (Application Data Mover) HW for Data transfer */
1120 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001121 host->cmd_timeout = timeout;
1122 host->cmd_pio_irqmask = pio_irqmask;
1123 host->cmd_datactrl = datactrl;
1124 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001125
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001126 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1127 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001128 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001129
1130 if (cmd) {
1131 msmsdcc_start_command_deferred(host, cmd, &c);
1132 host->cmd_c = c;
1133 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001134 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1135 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1136 host->base + MMCIMASK0);
1137 mb();
1138 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001139 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001140 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001141 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001142
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001143 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001144
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001145 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1146 (~(MCI_IRQ_PIO))) | pio_irqmask,
1147 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001148 writel_relaxed(datactrl, base + MMCIDATACTRL);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301149 /*
1150 * We don't need delay after writing to DATA_CTRL register
1151 * if we are not writing to CMD register immediately after
1152 * this. As we already have delay before sending the
1153 * command, we just need mb() here.
1154 */
1155 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001156
1157 if (cmd) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001158 msmsdcc_delay(host); /* Delay between data/command */
San Mehat56a8b5b2009-11-21 12:29:46 -08001159 /* Daisy-chain the command if requested */
1160 msmsdcc_start_command(host, cmd, c);
1161 }
San Mehat9d2bd732009-09-22 16:44:22 -07001162 }
1163}
1164
1165static void
1166msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1167{
San Mehat56a8b5b2009-11-21 12:29:46 -08001168 msmsdcc_start_command_deferred(host, cmd, &c);
1169 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001170}
1171
1172static void
1173msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1174 unsigned int status)
1175{
1176 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001177 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1178 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1179 pr_err("%s: Data CRC error\n",
1180 mmc_hostname(host->mmc));
1181 pr_err("%s: opcode 0x%.8x\n", __func__,
1182 data->mrq->cmd->opcode);
1183 pr_err("%s: blksz %d, blocks %d\n", __func__,
1184 data->blksz, data->blocks);
1185 data->error = -EILSEQ;
1186 }
San Mehat9d2bd732009-09-22 16:44:22 -07001187 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001188 /* CRC is optional for the bus test commands, not all
1189 * cards respond back with CRC. However controller
1190 * waits for the CRC and times out. Hence ignore the
1191 * data timeouts during the Bustest.
1192 */
1193 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1194 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301195 pr_err("%s: CMD%d: Data timeout\n",
1196 mmc_hostname(host->mmc),
1197 data->mrq->cmd->opcode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001198 data->error = -ETIMEDOUT;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301199 msmsdcc_dump_sdcc_state(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001200 }
San Mehat9d2bd732009-09-22 16:44:22 -07001201 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001202 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001203 data->error = -EIO;
1204 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001205 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001206 data->error = -EIO;
1207 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001208 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001209 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001210 data->error = -EIO;
1211 }
San Mehat9d2bd732009-09-22 16:44:22 -07001212
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001213 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001214 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001215 host->dummy_52_needed = 0;
1216}
San Mehat9d2bd732009-09-22 16:44:22 -07001217
1218static int
1219msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1220{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001221 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001222 uint32_t *ptr = (uint32_t *) buffer;
1223 int count = 0;
1224
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301225 if (remain % 4)
1226 remain = ((remain >> 2) + 1) << 2;
1227
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001228 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1229
1230 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001231 ptr++;
1232 count += sizeof(uint32_t);
1233
1234 remain -= sizeof(uint32_t);
1235 if (remain == 0)
1236 break;
1237 }
1238 return count;
1239}
1240
1241static int
1242msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001243 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001244{
1245 void __iomem *base = host->base;
1246 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001247 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001248
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001249 while (readl_relaxed(base + MMCISTATUS) &
1250 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1251 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001252
San Mehat9d2bd732009-09-22 16:44:22 -07001253 count = min(remain, maxcnt);
1254
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301255 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1256 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001257 ptr += count;
1258 remain -= count;
1259
1260 if (remain == 0)
1261 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001262 }
1263 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001264
1265 return ptr - buffer;
1266}
1267
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001268/*
1269 * Copy up to a word (4 bytes) between a scatterlist
1270 * and a temporary bounce buffer when the word lies across
1271 * two pages. The temporary buffer can then be read to/
1272 * written from the FIFO once.
1273 */
1274static void _msmsdcc_sg_consume_word(struct msmsdcc_host *host)
1275{
1276 struct msmsdcc_pio_data *pio = &host->pio;
1277 unsigned int bytes_avail;
1278
1279 if (host->curr.data->flags & MMC_DATA_READ)
1280 memcpy(pio->sg_miter.addr, pio->bounce_buf,
1281 pio->bounce_buf_len);
1282 else
1283 memcpy(pio->bounce_buf, pio->sg_miter.addr,
1284 pio->bounce_buf_len);
1285
1286 while (pio->bounce_buf_len != 4) {
1287 if (!sg_miter_next(&pio->sg_miter))
1288 break;
1289 bytes_avail = min_t(unsigned int, pio->sg_miter.length,
1290 4 - pio->bounce_buf_len);
1291 if (host->curr.data->flags & MMC_DATA_READ)
1292 memcpy(pio->sg_miter.addr,
1293 &pio->bounce_buf[pio->bounce_buf_len],
1294 bytes_avail);
1295 else
1296 memcpy(&pio->bounce_buf[pio->bounce_buf_len],
1297 pio->sg_miter.addr, bytes_avail);
1298
1299 pio->sg_miter.consumed = bytes_avail;
1300 pio->bounce_buf_len += bytes_avail;
1301 }
1302}
1303
1304/*
1305 * Use sg_miter_next to return as many 4-byte aligned
1306 * chunks as possible, using a temporary 4 byte buffer
1307 * for alignment if necessary
1308 */
1309static int msmsdcc_sg_next(struct msmsdcc_host *host, char **buf, int *len)
1310{
1311 struct msmsdcc_pio_data *pio = &host->pio;
1312 unsigned int length, rlength;
1313 char *buffer;
1314
1315 if (!sg_miter_next(&pio->sg_miter))
1316 return 0;
1317
1318 buffer = pio->sg_miter.addr;
1319 length = pio->sg_miter.length;
1320
1321 if (length < host->curr.xfer_remain) {
1322 rlength = round_down(length, 4);
1323 if (rlength) {
1324 /*
1325 * We have a 4-byte aligned chunk.
1326 * The rounding will be reflected by
1327 * a call to msmsdcc_sg_consumed
1328 */
1329 length = rlength;
1330 goto sg_next_end;
1331 }
1332 /*
1333 * We have a length less than 4 bytes. Check to
1334 * see if more buffer is available, and combine
1335 * to make 4 bytes if possible.
1336 */
1337 pio->bounce_buf_len = length;
1338 memset(pio->bounce_buf, 0, 4);
1339
1340 /*
1341 * On a read, get 4 bytes from FIFO, and distribute
1342 * (4-bouce_buf_len) bytes into consecutive
1343 * sgl buffers when msmsdcc_sg_consumed is called
1344 */
1345 if (host->curr.data->flags & MMC_DATA_READ) {
1346 buffer = pio->bounce_buf;
1347 length = 4;
1348 goto sg_next_end;
1349 } else {
1350 _msmsdcc_sg_consume_word(host);
1351 buffer = pio->bounce_buf;
1352 length = pio->bounce_buf_len;
1353 }
1354 }
1355
1356sg_next_end:
1357 *buf = buffer;
1358 *len = length;
1359 return 1;
1360}
1361
1362/*
1363 * Update sg_miter.consumed based on how many bytes were
1364 * consumed. If the bounce buffer was used to read from FIFO,
1365 * redistribute into sgls.
1366 */
1367static void msmsdcc_sg_consumed(struct msmsdcc_host *host,
1368 unsigned int length)
1369{
1370 struct msmsdcc_pio_data *pio = &host->pio;
1371
1372 if (host->curr.data->flags & MMC_DATA_READ) {
1373 if (length > pio->sg_miter.consumed)
1374 /*
1375 * consumed 4 bytes, but sgl
1376 * describes < 4 bytes
1377 */
1378 _msmsdcc_sg_consume_word(host);
1379 else
1380 pio->sg_miter.consumed = length;
1381 } else
1382 if (length < pio->sg_miter.consumed)
1383 pio->sg_miter.consumed = length;
1384}
1385
1386static void msmsdcc_sg_start(struct msmsdcc_host *host)
1387{
1388 unsigned int sg_miter_flags = SG_MITER_ATOMIC;
1389
1390 host->pio.bounce_buf_len = 0;
1391
1392 if (host->curr.data->flags & MMC_DATA_READ)
1393 sg_miter_flags |= SG_MITER_TO_SG;
1394 else
1395 sg_miter_flags |= SG_MITER_FROM_SG;
1396
1397 sg_miter_start(&host->pio.sg_miter, host->curr.data->sg,
1398 host->curr.data->sg_len, sg_miter_flags);
1399}
1400
1401static void msmsdcc_sg_stop(struct msmsdcc_host *host)
1402{
1403 sg_miter_stop(&host->pio.sg_miter);
1404}
1405
San Mehat1cd22962010-02-03 12:59:29 -08001406static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001407msmsdcc_pio_irq(int irq, void *dev_id)
1408{
1409 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001410 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001411 uint32_t status;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001412 unsigned long flags;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001413 unsigned int remain;
1414 char *buffer;
San Mehat9d2bd732009-09-22 16:44:22 -07001415
Murali Palnati36448a42011-09-02 15:06:18 +05301416 spin_lock(&host->lock);
1417
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001418 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001419
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001420 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301421 (MCI_IRQ_PIO)) == 0) {
1422 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001423 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301424 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001425#if IRQ_DEBUG
1426 msmsdcc_print_status(host, "irq1-r", status);
1427#endif
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001428 local_irq_save(flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001429
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001430 do {
1431 unsigned int len;
San Mehat9d2bd732009-09-22 16:44:22 -07001432
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001433 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1434 | MCI_RXDATAAVLBL)))
1435 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001436
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001437 if (!msmsdcc_sg_next(host, &buffer, &remain))
1438 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001439
San Mehat9d2bd732009-09-22 16:44:22 -07001440 len = 0;
1441 if (status & MCI_RXACTIVE)
1442 len = msmsdcc_pio_read(host, buffer, remain);
1443 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001444 len = msmsdcc_pio_write(host, buffer, remain);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001445
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301446 /* len might have aligned to 32bits above */
1447 if (len > remain)
1448 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001449
San Mehat9d2bd732009-09-22 16:44:22 -07001450 host->curr.xfer_remain -= len;
1451 host->curr.data_xfered += len;
1452 remain -= len;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001453 msmsdcc_sg_consumed(host, len);
San Mehat9d2bd732009-09-22 16:44:22 -07001454
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001455 if (remain) /* Done with this page? */
1456 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001457
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001458 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001459 } while (1);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001460
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001461 msmsdcc_sg_stop(host);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001462 local_irq_restore(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001463
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001464 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1465 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1466 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1467 host->base + MMCIMASK0);
1468 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301469 /*
1470 * back to back write to MASK0 register don't need
1471 * synchronization delay.
1472 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001473 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1474 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1475 }
1476 mb();
1477 } else if (!host->curr.xfer_remain) {
1478 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1479 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1480 mb();
1481 }
San Mehat9d2bd732009-09-22 16:44:22 -07001482
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001483 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001484
1485 return IRQ_HANDLED;
1486}
1487
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001488static void
1489msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1490
1491static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1492 struct mmc_data *data)
1493{
1494 u32 loop_cnt = 0;
1495
1496 /*
1497 * For read commands with data less than fifo size, it is possible to
1498 * get DATAEND first and RXDATA_AVAIL might be set later because of
1499 * synchronization delay through the asynchronous RX FIFO. Thus, for
1500 * such cases, even after DATAEND interrupt is received software
1501 * should poll for RXDATA_AVAIL until the requested data is read out
1502 * of FIFO. This change is needed to get around this abnormal but
1503 * sometimes expected behavior of SDCC3 controller.
1504 *
1505 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1506 * after the data is loaded into RX FIFO. This would amount to less
1507 * than a microsecond and thus looping for 1000 times is good enough
1508 * for that delay.
1509 */
1510 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1511 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1512 spin_unlock(&host->lock);
1513 msmsdcc_pio_irq(1, host);
1514 spin_lock(&host->lock);
1515 }
1516 }
1517 if (loop_cnt == 1000) {
1518 pr_info("%s: Timed out while polling for Rx Data\n",
1519 mmc_hostname(host->mmc));
1520 data->error = -ETIMEDOUT;
1521 msmsdcc_reset_and_restore(host);
1522 }
1523}
1524
San Mehat9d2bd732009-09-22 16:44:22 -07001525static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1526{
1527 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001528
1529 host->curr.cmd = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001530 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1531 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1532 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1533 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -07001534
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001535 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301536 pr_debug("%s: CMD%d: Command timeout\n",
1537 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001538 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001539 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301540 !host->tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301541 pr_err("%s: CMD%d: Command CRC error\n",
1542 mmc_hostname(host->mmc), cmd->opcode);
1543 msmsdcc_dump_sdcc_state(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001544 cmd->error = -EILSEQ;
1545 }
1546
1547 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001548 if (host->curr.data && host->dma.sg &&
1549 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001550 msm_dmov_stop_cmd(host->dma.channel,
1551 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001552 else if (host->curr.data && host->sps.sg &&
1553 host->is_sps_mode){
1554 /* Stop current SPS transfer */
1555 msmsdcc_sps_exit_curr_xfer(host);
1556 }
San Mehat9d2bd732009-09-22 16:44:22 -07001557 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301558 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001559 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301560 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301561 } else { /* host->data == NULL */
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301562 if (!cmd->error && host->prog_enable) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301563 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001564 host->prog_enable = 0;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301565 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001566 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301567 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301568 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301569 host->prog_enable = 0;
Subhash Jadavanied6b0e42012-03-07 16:36:27 +05301570 host->curr.wait_for_auto_prog_done = 0;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001571 if (host->dummy_52_needed)
1572 host->dummy_52_needed = 0;
1573 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001574 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301575 msmsdcc_request_end(host, cmd->mrq);
1576 }
1577 }
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301578 } else if ((cmd == host->curr.mrq->sbc) && cmd->data) {
1579 if (cmd->data->flags & MMC_DATA_READ)
1580 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1581 else
1582 msmsdcc_request_start(host, host->curr.mrq);
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301583 } else if (cmd->data) {
1584 if (!(cmd->data->flags & MMC_DATA_READ))
1585 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001586 }
1587}
1588
San Mehat9d2bd732009-09-22 16:44:22 -07001589static irqreturn_t
1590msmsdcc_irq(int irq, void *dev_id)
1591{
1592 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001593 u32 status;
1594 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001595 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001596
1597 spin_lock(&host->lock);
1598
1599 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001600 struct mmc_command *cmd;
1601 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001602
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001603 if (timer) {
1604 timer = 0;
1605 msmsdcc_delay(host);
1606 }
San Mehat865c8062009-11-13 13:42:06 -08001607
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001608 if (!host->clks_on) {
1609 pr_debug("%s: %s: SDIO async irq received\n",
1610 mmc_hostname(host->mmc), __func__);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301611
1612 /*
1613 * Only async interrupt can come when clocks are off,
1614 * disable further interrupts and enable them when
1615 * clocks are on.
1616 */
1617 if (!host->sdcc_irq_disabled) {
1618 disable_irq_nosync(irq);
1619 host->sdcc_irq_disabled = 1;
1620 }
1621
1622 /*
1623 * If mmc_card_wake_sdio_irq() is set, mmc core layer
1624 * will take care of signaling sdio irq during
1625 * mmc_sdio_resume().
1626 */
1627 if (host->sdcc_suspended)
1628 /*
1629 * This is a wakeup interrupt so hold wakelock
1630 * until SDCC resume is handled.
1631 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001632 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301633 else
1634 mmc_signal_sdio_irq(host->mmc);
1635 ret = 1;
1636 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001637 }
1638
1639 status = readl_relaxed(host->base + MMCISTATUS);
1640
1641 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1642 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001643 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001644
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001645#if IRQ_DEBUG
1646 msmsdcc_print_status(host, "irq0-r", status);
1647#endif
1648 status &= readl_relaxed(host->base + MMCIMASK0);
1649 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301650 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301651 if (host->clk_rate <=
1652 msmsdcc_get_min_sup_clk_rate(host))
1653 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001654#if IRQ_DEBUG
1655 msmsdcc_print_status(host, "irq0-p", status);
1656#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001657
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001658#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
1659 if (status & MCI_SDIOINTROPE) {
1660 if (host->sdcc_suspending)
1661 wake_lock(&host->sdio_suspend_wlock);
1662 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001663 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001664#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001665 data = host->curr.data;
1666
1667 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001668 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1669 MCI_CMDTIMEOUT)) {
1670 if (status & MCI_CMDTIMEOUT)
1671 pr_debug("%s: dummy CMD52 timeout\n",
1672 mmc_hostname(host->mmc));
1673 if (status & MCI_CMDCRCFAIL)
1674 pr_debug("%s: dummy CMD52 CRC failed\n",
1675 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001676 host->dummy_52_sent = 0;
1677 host->dummy_52_needed = 0;
1678 if (data) {
1679 msmsdcc_stop_data(host);
1680 msmsdcc_request_end(host, data->mrq);
1681 }
1682 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001683 spin_unlock(&host->lock);
1684 return IRQ_HANDLED;
1685 }
1686 break;
1687 }
1688
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001689 /*
1690 * Check for proper command response
1691 */
1692 cmd = host->curr.cmd;
1693 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1694 MCI_CMDTIMEOUT | MCI_PROGDONE |
1695 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1696 msmsdcc_do_cmdirq(host, status);
1697 }
1698
Sathish Ambley081d7842011-11-29 11:19:41 -08001699 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001700 /* Check for data errors */
1701 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1702 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1703 msmsdcc_data_err(host, data, status);
1704 host->curr.data_xfered = 0;
1705 if (host->dma.sg && host->is_dma_mode)
1706 msm_dmov_stop_cmd(host->dma.channel,
1707 &host->dma.hdr, 0);
1708 else if (host->sps.sg && host->is_sps_mode) {
1709 /* Stop current SPS transfer */
1710 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301711 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001712 msmsdcc_reset_and_restore(host);
1713 if (host->curr.data)
1714 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301715 if (!data->stop || (host->curr.mrq->sbc
1716 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001717 timer |=
1718 msmsdcc_request_end(host,
1719 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301720 else if ((host->curr.mrq->sbc
1721 && data->error) ||
1722 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001723 msmsdcc_start_command(host,
1724 data->stop,
1725 0);
1726 timer = 1;
1727 }
1728 }
1729 }
1730
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301731 /* Check for prog done */
1732 if (host->curr.wait_for_auto_prog_done &&
1733 (status & MCI_PROGDONE))
1734 host->curr.got_auto_prog_done = 1;
1735
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001736 /* Check for data done */
1737 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1738 host->curr.got_dataend = 1;
1739
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301740 if (host->curr.got_dataend &&
1741 (!host->curr.wait_for_auto_prog_done ||
1742 (host->curr.wait_for_auto_prog_done &&
1743 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001744 /*
1745 * If DMA is still in progress, we complete
1746 * via the completion handler
1747 */
1748 if (!host->dma.busy && !host->sps.busy) {
1749 /*
1750 * There appears to be an issue in the
1751 * controller where if you request a
1752 * small block transfer (< fifo size),
1753 * you may get your DATAEND/DATABLKEND
1754 * irq without the PIO data irq.
1755 *
1756 * Check to see if theres still data
1757 * to be read, and simulate a PIO irq.
1758 */
1759 if (data->flags & MMC_DATA_READ)
1760 msmsdcc_wait_for_rxdata(host,
1761 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001762 if (!data->error) {
1763 host->curr.data_xfered =
1764 host->curr.xfer_size;
1765 host->curr.xfer_remain -=
1766 host->curr.xfer_size;
1767 }
1768
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001769 if (!host->dummy_52_needed) {
1770 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301771 if (!data->stop ||
1772 (host->curr.mrq->sbc
1773 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001774 msmsdcc_request_end(
1775 host,
1776 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301777 else if ((host->curr.mrq->sbc
1778 && data->error) ||
1779 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001780 msmsdcc_start_command(
1781 host,
1782 data->stop, 0);
1783 timer = 1;
1784 }
1785 } else {
1786 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001787 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001788 &dummy52cmd,
1789 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001790 }
1791 }
1792 }
1793 }
1794
San Mehat9d2bd732009-09-22 16:44:22 -07001795 ret = 1;
1796 } while (status);
1797
1798 spin_unlock(&host->lock);
1799
San Mehat9d2bd732009-09-22 16:44:22 -07001800 return IRQ_RETVAL(ret);
1801}
1802
1803static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001804msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1805{
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301806 if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001807 /* Queue/read data, daisy-chain command when data starts */
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301808 if (mrq->sbc)
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301809 msmsdcc_start_data(host, mrq->data, mrq->sbc, 0);
1810 else
1811 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001812 } else {
1813 msmsdcc_start_command(host, mrq->cmd, 0);
1814 }
1815}
1816
1817static void
San Mehat9d2bd732009-09-22 16:44:22 -07001818msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1819{
1820 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001821 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001822
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001823 /*
1824 * Get the SDIO AL client out of LPM.
1825 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001826 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001827 if (host->plat->is_sdio_al_client)
1828 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001829
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301830 /* check if sps pipe reset is pending? */
1831 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1832 msmsdcc_sps_pipes_reset_and_restore(host);
1833 host->sps.pipe_reset_pending = false;
1834 }
1835
San Mehat9d2bd732009-09-22 16:44:22 -07001836 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001837 WARN(host->curr.mrq, "Request in progress\n");
1838 WARN(!host->pwr, "SDCC power is turned off\n");
1839 WARN(!host->clks_on, "SDCC clocks are turned off\n");
1840 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
San Mehat9d2bd732009-09-22 16:44:22 -07001841
1842 if (host->eject) {
1843 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1844 mrq->cmd->error = 0;
1845 mrq->data->bytes_xfered = mrq->data->blksz *
1846 mrq->data->blocks;
1847 } else
1848 mrq->cmd->error = -ENOMEDIUM;
1849
1850 spin_unlock_irqrestore(&host->lock, flags);
1851 mmc_request_done(mmc, mrq);
1852 return;
1853 }
1854
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301855 /*
1856 * Kick the software command timeout timer here.
1857 * Timer expires in 10 secs.
1858 */
1859 mod_timer(&host->req_tout_timer,
1860 (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
San Mehat9d2bd732009-09-22 16:44:22 -07001861
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301862 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301863 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301864 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
1865 mrq->cmd->opcode == 54) {
Pratibhasagar V1c11da62011-11-14 12:36:35 +05301866 if (!host->sdcc_version)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001867 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301868 else
1869 /*
1870 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
1871 * write operations using CMD53 and CMD54.
1872 * Setting this bit with CMD53 would
1873 * automatically triggers PROG_DONE interrupt
1874 * without the need of sending dummy CMD52.
1875 */
1876 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani758cf8c2011-11-13 11:59:55 +05301877 } else if (mrq->cmd->opcode == MMC_WRITE_BLOCK &&
1878 host->sdcc_version) {
1879 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001880 }
San Mehat9d2bd732009-09-22 16:44:22 -07001881 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301882
Pratibhasagar V00b94332011-10-18 14:57:27 +05301883 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301884 mrq->sbc->mrq = mrq;
1885 mrq->sbc->data = mrq->data;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301886 if (mrq->data->flags & MMC_DATA_WRITE) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301887 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301888 msmsdcc_start_command(host, mrq->sbc, 0);
1889 } else {
1890 msmsdcc_request_start(host, mrq);
1891 }
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301892 } else {
1893 msmsdcc_request_start(host, mrq);
1894 }
1895
San Mehat9d2bd732009-09-22 16:44:22 -07001896 spin_unlock_irqrestore(&host->lock, flags);
1897}
1898
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001899static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1900 int min_uV, int max_uV)
1901{
1902 int rc = 0;
1903
1904 if (vreg->set_voltage_sup) {
1905 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1906 if (rc) {
1907 pr_err("%s: regulator_set_voltage(%s) failed."
1908 " min_uV=%d, max_uV=%d, rc=%d\n",
1909 __func__, vreg->name, min_uV, max_uV, rc);
1910 }
1911 }
1912
1913 return rc;
1914}
1915
1916static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1917 int uA_load)
1918{
1919 int rc = 0;
1920
Krishna Kondafea60182011-11-01 16:01:34 -07001921 /* regulators that do not support regulator_set_voltage also
1922 do not support regulator_set_optimum_mode */
1923 if (vreg->set_voltage_sup) {
1924 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1925 if (rc < 0)
1926 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
1927 "uA_load=%d) failed. rc=%d\n", __func__,
1928 vreg->name, uA_load, rc);
1929 else
1930 /* regulator_set_optimum_mode() can return non zero
1931 * value even for success case.
1932 */
1933 rc = 0;
1934 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001935
1936 return rc;
1937}
1938
1939static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1940 struct device *dev)
1941{
1942 int rc = 0;
1943
1944 /* check if regulator is already initialized? */
1945 if (vreg->reg)
1946 goto out;
1947
1948 /* Get the regulator handle */
1949 vreg->reg = regulator_get(dev, vreg->name);
1950 if (IS_ERR(vreg->reg)) {
1951 rc = PTR_ERR(vreg->reg);
1952 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
1953 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001954 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001955 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001956
1957 if (regulator_count_voltages(vreg->reg) > 0)
1958 vreg->set_voltage_sup = 1;
1959
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001960out:
1961 return rc;
1962}
1963
1964static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
1965{
1966 if (vreg->reg)
1967 regulator_put(vreg->reg);
1968}
1969
1970/* This init function should be called only once for each SDCC slot */
1971static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
1972{
1973 int rc = 0;
1974 struct msm_mmc_slot_reg_data *curr_slot;
1975 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1976 struct device *dev = mmc_dev(host->mmc);
1977
1978 curr_slot = host->plat->vreg_data;
1979 if (!curr_slot)
1980 goto out;
1981
1982 curr_vdd_reg = curr_slot->vdd_data;
1983 curr_vccq_reg = curr_slot->vccq_data;
1984 curr_vddp_reg = curr_slot->vddp_data;
1985
1986 if (is_init) {
1987 /*
1988 * Get the regulator handle from voltage regulator framework
1989 * and then try to set the voltage level for the regulator
1990 */
1991 if (curr_vdd_reg) {
1992 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
1993 if (rc)
1994 goto out;
1995 }
1996 if (curr_vccq_reg) {
1997 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
1998 if (rc)
1999 goto vdd_reg_deinit;
2000 }
2001 if (curr_vddp_reg) {
2002 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
2003 if (rc)
2004 goto vccq_reg_deinit;
2005 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002006 rc = msmsdcc_vreg_reset(host);
2007 if (rc)
2008 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
2009 host->pdev_id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002010 goto out;
2011 } else {
2012 /* Deregister all regulators from regulator framework */
2013 goto vddp_reg_deinit;
2014 }
2015vddp_reg_deinit:
2016 if (curr_vddp_reg)
2017 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
2018vccq_reg_deinit:
2019 if (curr_vccq_reg)
2020 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
2021vdd_reg_deinit:
2022 if (curr_vdd_reg)
2023 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2024out:
2025 return rc;
2026}
2027
2028static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2029{
2030 int rc = 0;
2031
Subhash Jadavanicc922692011-08-01 23:05:01 +05302032 /* Put regulator in HPM (high power mode) */
2033 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2034 if (rc < 0)
2035 goto out;
2036
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002037 if (!vreg->is_enabled) {
2038 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302039 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2040 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002041 if (rc)
2042 goto out;
2043
2044 rc = regulator_enable(vreg->reg);
2045 if (rc) {
2046 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2047 __func__, vreg->name, rc);
2048 goto out;
2049 }
2050 vreg->is_enabled = true;
2051 }
2052
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002053out:
2054 return rc;
2055}
2056
2057static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
2058{
2059 int rc = 0;
2060
2061 /* Never disable regulator marked as always_on */
2062 if (vreg->is_enabled && !vreg->always_on) {
2063 rc = regulator_disable(vreg->reg);
2064 if (rc) {
2065 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2066 __func__, vreg->name, rc);
2067 goto out;
2068 }
2069 vreg->is_enabled = false;
2070
2071 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2072 if (rc < 0)
2073 goto out;
2074
2075 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302076 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002077 if (rc)
2078 goto out;
2079 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
2080 /* Put always_on regulator in LPM (low power mode) */
2081 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2082 if (rc < 0)
2083 goto out;
2084 }
2085out:
2086 return rc;
2087}
2088
2089static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
2090{
2091 int rc = 0, i;
2092 struct msm_mmc_slot_reg_data *curr_slot;
2093 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
2094 struct msm_mmc_reg_data *vreg_table[3];
2095
2096 curr_slot = host->plat->vreg_data;
2097 if (!curr_slot)
2098 goto out;
2099
2100 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
2101 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
2102 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
2103
2104 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2105 if (vreg_table[i]) {
2106 if (enable)
2107 rc = msmsdcc_vreg_enable(vreg_table[i]);
2108 else
2109 rc = msmsdcc_vreg_disable(vreg_table[i]);
2110 if (rc)
2111 goto out;
2112 }
2113 }
2114out:
2115 return rc;
2116}
2117
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002118/*
2119 * Reset vreg by ensuring it is off during probe. A call
2120 * to enable vreg is needed to balance disable vreg
2121 */
2122static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2123{
2124 int rc;
2125
2126 rc = msmsdcc_setup_vreg(host, 1);
2127 if (rc)
2128 return rc;
2129 rc = msmsdcc_setup_vreg(host, 0);
2130 return rc;
2131}
2132
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302133static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002134{
2135 int rc = 0;
2136
2137 if (host->plat->vreg_data) {
2138 struct msm_mmc_reg_data *vddp_reg =
2139 host->plat->vreg_data->vddp_data;
2140
2141 if (vddp_reg && vddp_reg->is_enabled)
2142 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
2143 }
2144
2145 return rc;
2146}
2147
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302148static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
2149{
2150 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2151 int rc = 0;
2152
2153 if (curr_slot && curr_slot->vddp_data) {
2154 rc = msmsdcc_set_vddp_level(host,
2155 curr_slot->vddp_data->low_vol_level);
2156
2157 if (rc)
2158 pr_err("%s: %s: failed to change vddp level to %d",
2159 mmc_hostname(host->mmc), __func__,
2160 curr_slot->vddp_data->low_vol_level);
2161 }
2162
2163 return rc;
2164}
2165
2166static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
2167{
2168 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2169 int rc = 0;
2170
2171 if (curr_slot && curr_slot->vddp_data) {
2172 rc = msmsdcc_set_vddp_level(host,
2173 curr_slot->vddp_data->high_vol_level);
2174
2175 if (rc)
2176 pr_err("%s: %s: failed to change vddp level to %d",
2177 mmc_hostname(host->mmc), __func__,
2178 curr_slot->vddp_data->high_vol_level);
2179 }
2180
2181 return rc;
2182}
2183
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302184static inline int msmsdcc_set_vccq_vol(struct msmsdcc_host *host, int level)
2185{
2186 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2187 int rc = 0;
2188
2189 if (curr_slot && curr_slot->vccq_data) {
2190 rc = msmsdcc_vreg_set_voltage(curr_slot->vccq_data,
2191 level, level);
2192 if (rc)
2193 pr_err("%s: %s: failed to change vccq level to %d",
2194 mmc_hostname(host->mmc), __func__, level);
2195 }
2196
2197 return rc;
2198}
2199
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002200static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2201{
2202 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2203 return 1;
2204 return 0;
2205}
2206
2207static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
2208{
2209 if (enable) {
2210 if (!IS_ERR_OR_NULL(host->dfab_pclk))
2211 clk_enable(host->dfab_pclk);
2212 if (!IS_ERR(host->pclk))
2213 clk_enable(host->pclk);
2214 clk_enable(host->clk);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302215 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002216 } else {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302217 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002218 clk_disable(host->clk);
2219 if (!IS_ERR(host->pclk))
2220 clk_disable(host->pclk);
2221 if (!IS_ERR_OR_NULL(host->dfab_pclk))
2222 clk_disable(host->dfab_pclk);
2223 }
2224}
2225
2226static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2227 unsigned int req_clk)
2228{
2229 unsigned int sel_clk = -1;
2230
2231 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2232 unsigned char cnt;
2233
2234 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2235 if (host->plat->sup_clk_table[cnt] > req_clk)
2236 break;
2237 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2238 sel_clk = host->plat->sup_clk_table[cnt];
2239 break;
2240 } else
2241 sel_clk = host->plat->sup_clk_table[cnt];
2242 }
2243 } else {
2244 if ((req_clk < host->plat->msmsdcc_fmax) &&
2245 (req_clk > host->plat->msmsdcc_fmid))
2246 sel_clk = host->plat->msmsdcc_fmid;
2247 else
2248 sel_clk = req_clk;
2249 }
2250
2251 return sel_clk;
2252}
2253
2254static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2255 struct msmsdcc_host *host)
2256{
2257 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2258 return host->plat->sup_clk_table[0];
2259 else
2260 return host->plat->msmsdcc_fmin;
2261}
2262
2263static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2264 struct msmsdcc_host *host)
2265{
2266 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2267 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2268 else
2269 return host->plat->msmsdcc_fmax;
2270}
2271
2272static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302273{
2274 struct msm_mmc_gpio_data *curr;
2275 int i, rc = 0;
2276
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002277 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302278 for (i = 0; i < curr->size; i++) {
2279 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002280 if (curr->gpio[i].is_always_on &&
2281 curr->gpio[i].is_enabled)
2282 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302283 rc = gpio_request(curr->gpio[i].no,
2284 curr->gpio[i].name);
2285 if (rc) {
2286 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2287 mmc_hostname(host->mmc),
2288 curr->gpio[i].no,
2289 curr->gpio[i].name, rc);
2290 goto free_gpios;
2291 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002292 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302293 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002294 if (curr->gpio[i].is_always_on)
2295 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302296 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002297 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302298 }
2299 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002300 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302301
2302free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002303 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302304 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002305 curr->gpio[i].is_enabled = false;
2306 }
2307out:
2308 return rc;
2309}
2310
2311static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2312{
2313 struct msm_mmc_pad_data *curr;
2314 int i;
2315
2316 curr = host->plat->pin_data->pad_data;
2317 for (i = 0; i < curr->drv->size; i++) {
2318 if (enable)
2319 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2320 curr->drv->on[i].val);
2321 else
2322 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2323 curr->drv->off[i].val);
2324 }
2325
2326 for (i = 0; i < curr->pull->size; i++) {
2327 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002328 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002329 curr->pull->on[i].val);
2330 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002331 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002332 curr->pull->off[i].val);
2333 }
2334
2335 return 0;
2336}
2337
2338static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2339{
2340 int rc = 0;
2341
2342 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2343 return 0;
2344
2345 if (host->plat->pin_data->is_gpio)
2346 rc = msmsdcc_setup_gpio(host, enable);
2347 else
2348 rc = msmsdcc_setup_pad(host, enable);
2349
2350 if (!rc)
2351 host->plat->pin_data->cfg_sts = enable;
2352
2353 return rc;
2354}
2355
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302356static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2357{
2358 u32 pwr = 0;
2359 int ret = 0;
2360 struct mmc_host *mmc = host->mmc;
2361
2362 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2363 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2364 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2365 ret = msmsdcc_setup_vreg(host, !!ios->vdd);
2366
2367 if (ret) {
2368 pr_err("%s: Failed to setup voltage regulators\n",
2369 mmc_hostname(host->mmc));
2370 goto out;
2371 }
2372
2373 switch (ios->power_mode) {
2374 case MMC_POWER_OFF:
2375 pwr = MCI_PWR_OFF;
2376 if (host->plat->cfg_mpm_sdiowakeup)
2377 host->plat->cfg_mpm_sdiowakeup(
2378 mmc_dev(mmc), SDC_DAT1_DISABLE);
2379 /*
2380 * As VDD pad rail is always on, set low voltage for VDD
2381 * pad rail when slot is unused (when card is not present
2382 * or during system suspend).
2383 */
2384 msmsdcc_set_vddp_low_vol(host);
2385 msmsdcc_setup_pins(host, false);
2386 break;
2387 case MMC_POWER_UP:
2388 /* writing PWR_UP bit is redundant */
2389 pwr = MCI_PWR_UP;
2390 if (host->plat->cfg_mpm_sdiowakeup)
2391 host->plat->cfg_mpm_sdiowakeup(
2392 mmc_dev(mmc), SDC_DAT1_ENABLE);
2393
2394 msmsdcc_set_vddp_high_vol(host);
2395 msmsdcc_setup_pins(host, true);
2396 break;
2397 case MMC_POWER_ON:
2398 pwr = MCI_PWR_ON;
2399 break;
2400 }
2401
2402out:
2403 return pwr;
2404}
2405
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002406static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2407{
2408 unsigned int wakeup_irq;
2409
2410 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2411 host->plat->sdiowakeup_irq :
2412 host->core_irqres->start;
2413
2414 if (!host->irq_wake_enabled) {
2415 enable_irq_wake(wakeup_irq);
2416 host->irq_wake_enabled = true;
2417 }
2418}
2419
2420static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2421{
2422 unsigned int wakeup_irq;
2423
2424 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2425 host->plat->sdiowakeup_irq :
2426 host->core_irqres->start;
2427
2428 if (host->irq_wake_enabled) {
2429 disable_irq_wake(wakeup_irq);
2430 host->irq_wake_enabled = false;
2431 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302432}
2433
San Mehat9d2bd732009-09-22 16:44:22 -07002434static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302435msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
2436{
2437 struct mmc_host *mmc = host->mmc;
2438
2439 /*
2440 * SDIO_AL clients has different mechanism of handling LPM through
2441 * sdio_al driver itself. The sdio wakeup interrupt is configured as
2442 * part of that. Here, we are interested only in clients like WLAN.
2443 */
2444 if (!(mmc->card && mmc_card_sdio(mmc->card))
2445 || host->plat->is_sdio_al_client)
2446 goto out;
2447
2448 if (!host->sdcc_suspended) {
2449 /*
2450 * When MSM is not in power collapse and we
2451 * are disabling clocks, enable bit 22 in MASK0
2452 * to handle asynchronous SDIO interrupts.
2453 */
2454 if (enable_wakeup_irq)
2455 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
2456 else
2457 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
2458 mb();
2459 goto out;
2460 } else if (!mmc_card_wake_sdio_irq(mmc)) {
2461 /*
2462 * Wakeup MSM only if SDIO function drivers set
2463 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
2464 */
2465 goto out;
2466 }
2467
2468 if (enable_wakeup_irq) {
2469 if (!host->plat->sdiowakeup_irq) {
2470 /*
2471 * When there is no gpio line that can be configured
2472 * as wakeup interrupt handle it by configuring
2473 * asynchronous sdio interrupts and DAT1 line.
2474 */
2475 writel_relaxed(MCI_SDIOINTMASK,
2476 host->base + MMCIMASK0);
2477 mb();
2478 if (host->plat->cfg_mpm_sdiowakeup)
2479 host->plat->cfg_mpm_sdiowakeup(
2480 mmc_dev(mmc), SDC_DAT1_ENWAKE);
2481 /* configure sdcc core interrupt as wakeup interrupt */
2482 msmsdcc_enable_irq_wake(host);
2483 } else {
2484 /* Let gpio line handle wakeup interrupt */
2485 writel_relaxed(0, host->base + MMCIMASK0);
2486 mb();
2487 if (host->sdio_wakeupirq_disabled) {
2488 host->sdio_wakeupirq_disabled = 0;
2489 /* configure gpio line as wakeup interrupt */
2490 msmsdcc_enable_irq_wake(host);
2491 enable_irq(host->plat->sdiowakeup_irq);
2492 }
2493 }
2494 } else {
2495 if (!host->plat->sdiowakeup_irq) {
2496 /*
2497 * We may not have cleared bit 22 in the interrupt
2498 * handler as the clocks might be off at that time.
2499 */
2500 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
2501 mb();
2502 if (host->plat->cfg_mpm_sdiowakeup)
2503 host->plat->cfg_mpm_sdiowakeup(
2504 mmc_dev(mmc), SDC_DAT1_DISWAKE);
2505 msmsdcc_disable_irq_wake(host);
2506 } else if (!host->sdio_wakeupirq_disabled) {
2507 disable_irq_nosync(host->plat->sdiowakeup_irq);
2508 msmsdcc_disable_irq_wake(host);
2509 host->sdio_wakeupirq_disabled = 1;
2510 }
2511 }
2512out:
2513 return;
2514}
2515
2516static void
San Mehat9d2bd732009-09-22 16:44:22 -07002517msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2518{
2519 struct msmsdcc_host *host = mmc_priv(mmc);
2520 u32 clk = 0, pwr = 0;
2521 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002522 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002523 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002524
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002525 DBG(host, "ios->clock = %u\n", ios->clock);
Sahitya Tummala7a892482011-01-18 11:22:49 +05302526
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302527 /*
2528 * Disable SDCC core interrupt until set_ios is completed.
2529 * This avoids any race conditions with interrupt raised
2530 * when turning on/off the clocks. One possible
2531 * scenario is SDIO operational interrupt while the clock
2532 * is turned off.
2533 */
2534
2535 spin_lock_irqsave(&host->lock, flags);
2536 if (!host->sdcc_irq_disabled) {
2537 spin_unlock_irqrestore(&host->lock, flags);
2538 disable_irq(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002539 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302540 host->sdcc_irq_disabled = 1;
2541 }
2542 spin_unlock_irqrestore(&host->lock, flags);
2543
2544 pwr = msmsdcc_setup_pwr(host, ios);
2545
2546 spin_lock_irqsave(&host->lock, flags);
2547 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002548 if (!host->clks_on) {
2549 msmsdcc_setup_clocks(host, true);
2550 host->clks_on = 1;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302551 writel_relaxed(host->mci_irqenable,
2552 host->base + MMCIMASK0);
2553 mb();
2554 msmsdcc_cfg_sdio_wakeup(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002555 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002556
2557 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2558 /*
2559 * For DDR50 mode, controller needs clock rate to be
2560 * double than what is required on the SD card CLK pin.
2561 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302562 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002563 /*
2564 * Make sure that we don't double the clock if
2565 * doubled clock rate is already set
2566 */
2567 if (!host->ddr_doubled_clk_rate ||
2568 (host->ddr_doubled_clk_rate &&
2569 (host->ddr_doubled_clk_rate != ios->clock))) {
2570 host->ddr_doubled_clk_rate =
2571 msmsdcc_get_sup_clk_rate(
2572 host, (ios->clock * 2));
2573 clock = host->ddr_doubled_clk_rate;
2574 }
2575 } else {
2576 host->ddr_doubled_clk_rate = 0;
2577 }
2578
2579 if (clock != host->clk_rate) {
2580 rc = clk_set_rate(host->clk, clock);
2581 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302582 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002583 mmc_hostname(mmc), clock);
2584 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302585 host->reg_write_delay =
2586 (1 + ((3 * USEC_PER_SEC) /
2587 (host->clk_rate ? host->clk_rate :
2588 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002589 }
2590 /*
2591 * give atleast 2 MCLK cycles delay for clocks
2592 * and SDCC core to stabilize
2593 */
2594 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002595 clk |= MCI_CLK_ENABLE;
2596 }
2597
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002598 if (ios->bus_width == MMC_BUS_WIDTH_8)
2599 clk |= MCI_CLK_WIDEBUS_8;
2600 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2601 clk |= MCI_CLK_WIDEBUS_4;
2602 else
2603 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002604
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002605 if (msmsdcc_is_pwrsave(host))
2606 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002607
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002608 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002609
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002610 host->tuning_needed = 0;
2611 /*
2612 * Select the controller timing mode according
2613 * to current bus speed mode
2614 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302615 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2616 (ios->timing == MMC_TIMING_MMC_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002617 clk |= (4 << 14);
2618 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302619 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002620 clk |= (3 << 14);
2621 } else {
2622 clk |= (2 << 14); /* feedback clock */
2623 }
2624
2625 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2626 clk |= (2 << 23);
2627
Subhash Jadavani00083572012-02-15 16:18:01 +05302628 /* Clear IO_PAD_PWR_SWITCH while powering off the card */
2629 if (!ios->vdd)
2630 host->io_pad_pwr_switch = 0;
2631
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002632 if (host->io_pad_pwr_switch)
2633 clk |= IO_PAD_PWR_SWITCH;
2634
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302635 /* Don't write into registers if clocks are disabled */
2636 if (host->clks_on) {
2637 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
2638 writel_relaxed(clk, host->base + MMCICLOCK);
2639 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002640 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302641 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
2642 host->pwr = pwr;
2643 writel_relaxed(pwr, host->base + MMCIPOWER);
2644 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002645 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002646 }
2647
2648 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302649 msmsdcc_cfg_sdio_wakeup(host, true);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002650 msmsdcc_setup_clocks(host, false);
2651 host->clks_on = 0;
2652 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302653
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302654 if (host->tuning_in_progress)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302655 WARN(!host->clks_on,
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302656 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302657
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302658 /* Let interrupts be disabled if the host is powered off */
2659 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
2660 enable_irq(host->core_irqres->start);
2661 host->sdcc_irq_disabled = 0;
2662 }
2663
San Mehat4adbbcc2009-11-08 13:00:37 -08002664 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002665}
2666
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002667int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2668{
2669 struct msmsdcc_host *host = mmc_priv(mmc);
2670 u32 clk;
2671
2672 clk = readl_relaxed(host->base + MMCICLOCK);
2673 pr_debug("Changing to pwr_save=%d", pwrsave);
2674 if (pwrsave && msmsdcc_is_pwrsave(host))
2675 clk |= MCI_CLK_PWRSAVE;
2676 else
2677 clk &= ~MCI_CLK_PWRSAVE;
2678 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302679 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002680
2681 return 0;
2682}
2683
2684static int msmsdcc_get_ro(struct mmc_host *mmc)
2685{
2686 int status = -ENOSYS;
2687 struct msmsdcc_host *host = mmc_priv(mmc);
2688
2689 if (host->plat->wpswitch) {
2690 status = host->plat->wpswitch(mmc_dev(mmc));
2691 } else if (host->plat->wpswitch_gpio) {
2692 status = gpio_request(host->plat->wpswitch_gpio,
2693 "SD_WP_Switch");
2694 if (status) {
2695 pr_err("%s: %s: Failed to request GPIO %d\n",
2696 mmc_hostname(mmc), __func__,
2697 host->plat->wpswitch_gpio);
2698 } else {
2699 status = gpio_direction_input(
2700 host->plat->wpswitch_gpio);
2701 if (!status) {
2702 /*
2703 * Wait for atleast 300ms as debounce
2704 * time for GPIO input to stabilize.
2705 */
2706 msleep(300);
2707 status = gpio_get_value_cansleep(
2708 host->plat->wpswitch_gpio);
2709 status ^= !host->plat->wpswitch_polarity;
2710 }
2711 gpio_free(host->plat->wpswitch_gpio);
2712 }
2713 }
2714
2715 if (status < 0)
2716 status = -ENOSYS;
2717 pr_debug("%s: Card read-only status %d\n", __func__, status);
2718
2719 return status;
2720}
2721
2722#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002723static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2724{
2725 struct msmsdcc_host *host = mmc_priv(mmc);
2726 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002727
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302728 /*
2729 * We may come here with clocks turned off in that case don't
2730 * attempt to write into MASK0 register. While turning on the
2731 * clocks mci_irqenable will be written to MASK0 register.
2732 */
2733
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002734 if (enable) {
2735 spin_lock_irqsave(&host->lock, flags);
2736 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302737 if (host->clks_on) {
2738 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002739 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302740 mb();
2741 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002742 spin_unlock_irqrestore(&host->lock, flags);
2743 } else {
2744 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302745 if (host->clks_on) {
2746 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002747 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302748 mb();
2749 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002750 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002751}
2752#endif /* CONFIG_MMC_MSM_SDIO_SUPPORT */
2753
2754#ifdef CONFIG_PM_RUNTIME
2755static int msmsdcc_enable(struct mmc_host *mmc)
2756{
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302757 int rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002758 struct device *dev = mmc->parent;
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302759 struct msmsdcc_host *host = mmc_priv(mmc);
2760
2761 msmsdcc_pm_qos_update_latency(host, 1);
2762
2763 if (mmc->card && mmc_card_sdio(mmc->card) && host->is_resumed)
2764 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002765
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302766 if (dev->power.runtime_status == RPM_SUSPENDING) {
2767 if (mmc->suspend_task == current) {
2768 pm_runtime_get_noresume(dev);
2769 goto out;
2770 }
2771 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002772
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302773 rc = pm_runtime_get_sync(dev);
2774
2775 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002776 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2777 __func__, rc);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302778 return rc;
2779 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302780
2781 host->is_resumed = true;
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302782out:
2783 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002784}
2785
2786static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2787{
2788 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302789 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002790
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302791 msmsdcc_pm_qos_update_latency(host, 0);
2792
2793 if (mmc->card && mmc_card_sdio(mmc->card))
2794 return 0;
2795
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302796 if (host->plat->disable_runtime_pm)
2797 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002798
2799 rc = pm_runtime_put_sync(mmc->parent);
2800
2801 if (rc < 0)
2802 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2803 __func__, rc);
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302804 else
2805 host->is_resumed = false;
2806
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002807 return rc;
2808}
2809#else
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302810static int msmsdcc_enable(struct mmc_host *mmc)
2811{
2812 struct msmsdcc_host *host = mmc_priv(mmc);
2813 unsigned long flags;
2814
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302815 msmsdcc_pm_qos_update_latency(host, 1);
2816
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302817 spin_lock_irqsave(&host->lock, flags);
2818 if (!host->clks_on) {
2819 msmsdcc_setup_clocks(host, true);
2820 host->clks_on = 1;
2821 }
2822 spin_unlock_irqrestore(&host->lock, flags);
2823
2824 return 0;
2825}
2826
2827static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2828{
2829 struct msmsdcc_host *host = mmc_priv(mmc);
2830 unsigned long flags;
2831
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302832 msmsdcc_pm_qos_update_latency(host, 0);
2833
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302834 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302835 return 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302836
2837 spin_lock_irqsave(&host->lock, flags);
2838 if (host->clks_on) {
2839 msmsdcc_setup_clocks(host, false);
2840 host->clks_on = 0;
2841 }
2842 spin_unlock_irqrestore(&host->lock, flags);
2843
2844 return 0;
2845}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002846#endif
2847
2848static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2849 struct mmc_ios *ios)
2850{
2851 struct msmsdcc_host *host = mmc_priv(mmc);
2852 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302853 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002854
Subhash Jadavani00083572012-02-15 16:18:01 +05302855 spin_lock_irqsave(&host->lock, flags);
2856 host->io_pad_pwr_switch = 0;
2857 spin_unlock_irqrestore(&host->lock, flags);
2858
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302859 /*
2860 * For eMMC cards, VccQ voltage range must be changed
2861 * only if it operates in HS200 SDR 1.2V mode or in
2862 * DDR 1.2V mode.
2863 */
2864 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_120) {
2865 rc = msmsdcc_set_vccq_vol(host, 1200000);
2866 goto out;
2867 }
2868
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002869 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2870 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302871 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002872 goto out;
2873 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2874 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302875 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002876 goto out;
2877 }
San Mehat9d2bd732009-09-22 16:44:22 -07002878
2879 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002880 /*
2881 * If we are here means voltage switch from high voltage to
2882 * low voltage is required
2883 */
2884
2885 /*
2886 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2887 * register until they become all zeros.
2888 */
2889 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302890 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002891 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2892 mmc_hostname(mmc), __func__);
2893 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002894 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002895
2896 /* Stop SD CLK output. */
2897 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2898 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302899 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002900 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002901
2902 /*
2903 * Switch VDDPX from high voltage to low voltage
2904 * to change the VDD of the SD IO pads.
2905 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302906 rc = msmsdcc_set_vddp_low_vol(host);
2907 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002908 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002909
2910 spin_lock_irqsave(&host->lock, flags);
2911 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2912 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302913 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002914 host->io_pad_pwr_switch = 1;
2915 spin_unlock_irqrestore(&host->lock, flags);
2916
2917 /* Wait 5 ms for the voltage regulater in the card to become stable. */
2918 usleep_range(5000, 5500);
2919
2920 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302921 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002922 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2923 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302924 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002925 spin_unlock_irqrestore(&host->lock, flags);
2926
2927 /*
2928 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
2929 * don't become all ones within 1 ms then a Voltage Switch
2930 * sequence has failed and a power cycle to the card is required.
2931 * Otherwise Voltage Switch sequence is completed successfully.
2932 */
2933 usleep_range(1000, 1500);
2934
2935 spin_lock_irqsave(&host->lock, flags);
2936 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
2937 != (0xF << 1)) {
2938 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
2939 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302940 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002941 goto out_unlock;
2942 }
2943
2944out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302945 /* Enable PWRSAVE */
2946 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2947 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002948 spin_unlock_irqrestore(&host->lock, flags);
2949out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302950 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002951}
2952
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302953static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002954{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002955 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002956
2957 /* Program the MCLK value to MCLK_FREQ bit field */
2958 if (host->clk_rate <= 112000000)
2959 mclk_freq = 0;
2960 else if (host->clk_rate <= 125000000)
2961 mclk_freq = 1;
2962 else if (host->clk_rate <= 137000000)
2963 mclk_freq = 2;
2964 else if (host->clk_rate <= 150000000)
2965 mclk_freq = 3;
2966 else if (host->clk_rate <= 162000000)
2967 mclk_freq = 4;
2968 else if (host->clk_rate <= 175000000)
2969 mclk_freq = 5;
2970 else if (host->clk_rate <= 187000000)
2971 mclk_freq = 6;
2972 else if (host->clk_rate <= 200000000)
2973 mclk_freq = 7;
2974
2975 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2976 & ~(7 << 24)) | (mclk_freq << 24)),
2977 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002978}
2979
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302980/* Initialize the DLL (Programmable Delay Line ) */
2981static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002982{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002983 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302984 unsigned long flags;
2985 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002986
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302987 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002988 /*
2989 * Make sure that clock is always enabled when DLL
2990 * tuning is in progress. Keeping PWRSAVE ON may
2991 * turn off the clock. So let's disable the PWRSAVE
2992 * here and re-enable it once tuning is completed.
2993 */
2994 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2995 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302996
2997 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
2998 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2999 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3000
3001 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3002 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3003 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3004
3005 msmsdcc_cm_sdc4_dll_set_freq(host);
3006
3007 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3008 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3009 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3010
3011 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3012 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3013 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3014
3015 /* Set DLL_EN bit to 1. */
3016 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3017 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3018
3019 /* Set CK_OUT_EN bit to 1. */
3020 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3021 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3022
3023 wait_cnt = 50;
3024 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3025 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3026 /* max. wait for 50us sec for LOCK bit to be set */
3027 if (--wait_cnt == 0) {
3028 pr_err("%s: %s: DLL failed to LOCK\n",
3029 mmc_hostname(host->mmc), __func__);
3030 rc = -ETIMEDOUT;
3031 goto out;
3032 }
3033 /* wait for 1us before polling again */
3034 udelay(1);
3035 }
3036
3037out:
3038 /* re-enable PWRSAVE */
3039 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3040 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
3041 spin_unlock_irqrestore(&host->lock, flags);
3042
3043 return rc;
3044}
3045
3046static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3047 u8 poll)
3048{
3049 int rc = 0;
3050 u32 wait_cnt = 50;
3051 u8 ck_out_en = 0;
3052
3053 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3054 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3055 MCI_CK_OUT_EN);
3056
3057 while (ck_out_en != poll) {
3058 if (--wait_cnt == 0) {
3059 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3060 mmc_hostname(host->mmc), __func__, poll);
3061 rc = -ETIMEDOUT;
3062 goto out;
3063 }
3064 udelay(1);
3065
3066 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3067 MCI_CK_OUT_EN);
3068 }
3069out:
3070 return rc;
3071}
3072
3073/*
3074 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3075 * calibration sequence. This function should be called before
3076 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3077 * commands (CMD17/CMD18).
3078 *
3079 * This function gets called when host spinlock acquired.
3080 */
3081static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3082{
3083 int rc = 0;
3084 u32 config;
3085
3086 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3087 config |= MCI_CDR_EN;
3088 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3089 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3090
3091 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3092 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3093 if (rc)
3094 goto err_out;
3095
3096 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3097 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3098 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3099
3100 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3101 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3102 if (rc)
3103 goto err_out;
3104
3105 goto out;
3106
3107err_out:
3108 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3109out:
3110 return rc;
3111}
3112
3113static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3114 u8 phase)
3115{
3116 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303117 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3118 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3119 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303120 unsigned long flags;
3121 u32 config;
3122
3123 spin_lock_irqsave(&host->lock, flags);
3124
3125 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3126 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3127 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3128 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3129
3130 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3131 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3132 if (rc)
3133 goto err_out;
3134
3135 /*
3136 * Write the selected DLL clock output phase (0 ... 15)
3137 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
3138 */
3139 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3140 & ~(0xF << 20))
3141 | (grey_coded_phase_table[phase] << 20)),
3142 host->base + MCI_DLL_CONFIG);
3143
3144 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3145 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3146 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3147
3148 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3149 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3150 if (rc)
3151 goto err_out;
3152
3153 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3154 config |= MCI_CDR_EN;
3155 config &= ~MCI_CDR_EXT_EN;
3156 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3157 goto out;
3158
3159err_out:
3160 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3161 mmc_hostname(host->mmc), __func__, phase);
3162out:
3163 spin_unlock_irqrestore(&host->lock, flags);
3164 return rc;
3165}
3166
3167/*
3168 * Find out the greatest range of consecuitive selected
3169 * DLL clock output phases that can be used as sampling
3170 * setting for SD3.0 UHS-I card read operation (in SDR104
3171 * timing mode) or for eMMC4.5 card read operation (in HS200
3172 * timing mode).
3173 * Select the 3/4 of the range and configure the DLL with the
3174 * selected DLL clock output phase.
3175*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303176static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303177 u8 *phase_table, u8 total_phases)
3178{
Subhash Jadavani34187042012-03-02 10:59:49 +05303179 int ret;
3180 u8 ranges[16][16] = { {0}, {0} };
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303181 u8 phases_per_row[16] = {0};
3182 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303183 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3184 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303185
Subhash Jadavani34187042012-03-02 10:59:49 +05303186 if (total_phases > 16) {
3187 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3188 mmc_hostname(host->mmc), __func__, total_phases);
3189 return -EINVAL;
3190 }
3191
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303192 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303193 ranges[row_index][col_index] = phase_table[cnt];
3194 phases_per_row[row_index] += 1;
3195 col_index++;
3196
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303197 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303198 continue;
3199 /* check if next phase in phase_table is consecutive or not */
3200 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3201 row_index++;
3202 col_index = 0;
3203 }
3204 }
3205
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303206 /* Check if phase-0 is present in first valid window? */
3207 if (!ranges[0][0]) {
3208 phase_0_found = true;
3209 phase_0_raw_index = 0;
3210 /* Check if cycle exist between 2 valid windows */
3211 for (cnt = 1; cnt <= row_index; cnt++) {
3212 if (phases_per_row[cnt]) {
3213 for (i = 0; i <= phases_per_row[cnt]; i++) {
3214 if (ranges[cnt][i] == 15) {
3215 phase_15_found = true;
3216 phase_15_raw_index = cnt;
3217 break;
3218 }
3219 }
3220 }
3221 }
3222 }
3223
3224 /* If 2 valid windows form cycle then merge them as single window */
3225 if (phase_0_found && phase_15_found) {
3226 /* number of phases in raw where phase 0 is present */
3227 u8 phases_0 = phases_per_row[phase_0_raw_index];
3228 /* number of phases in raw where phase 15 is present */
3229 u8 phases_15 = phases_per_row[phase_15_raw_index];
3230
3231 cnt = 0;
3232 for (i = phases_15; i < (phases_15 + phases_0); i++) {
3233 ranges[phase_15_raw_index][i] =
3234 ranges[phase_0_raw_index][cnt];
3235 cnt++;
3236 }
3237 phases_per_row[phase_0_raw_index] = 0;
3238 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
3239 }
3240
3241 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303242 if (phases_per_row[cnt] > curr_max) {
3243 curr_max = phases_per_row[cnt];
3244 selected_row_index = cnt;
3245 }
3246 }
3247
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303248 i = ((curr_max * 3) / 4) - 1;
Subhash Jadavani34187042012-03-02 10:59:49 +05303249 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303250
3251 return ret;
3252}
3253
Girish K Sa3f41692012-02-29 12:00:09 +05303254static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303255{
3256 int rc = 0;
3257 struct msmsdcc_host *host = mmc_priv(mmc);
3258 unsigned long flags;
3259 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303260 const u32 *tuning_block_pattern = tuning_block_64;
3261 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303262
3263 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
3264
3265 /* Tuning is only required for SDR104 modes */
3266 if (!host->tuning_needed) {
3267 rc = 0;
3268 goto exit;
3269 }
3270
3271 spin_lock_irqsave(&host->lock, flags);
3272 WARN(!host->pwr, "SDCC power is turned off\n");
3273 WARN(!host->clks_on, "SDCC clocks are turned off\n");
3274 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
3275
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303276 host->tuning_in_progress = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05303277 msmsdcc_delay(host);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303278 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
3279 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
3280 tuning_block_pattern = tuning_block_128;
3281 size = sizeof(tuning_block_128);
3282 }
3283
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303284 spin_unlock_irqrestore(&host->lock, flags);
3285
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003286 /* first of all reset the tuning block */
3287 rc = msmsdcc_init_cm_sdc4_dll(host);
3288 if (rc)
3289 goto out;
3290
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303291 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003292 if (!data_buf) {
3293 rc = -ENOMEM;
3294 goto out;
3295 }
3296
3297 phase = 0;
3298 do {
3299 struct mmc_command cmd = {0};
3300 struct mmc_data data = {0};
3301 struct mmc_request mrq = {
3302 .cmd = &cmd,
3303 .data = &data
3304 };
3305 struct scatterlist sg;
3306
3307 /* set the phase in delay line hw block */
3308 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3309 if (rc)
3310 goto kfree;
3311
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303312 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003313 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
3314
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303315 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003316 data.blocks = 1;
3317 data.flags = MMC_DATA_READ;
3318 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
3319
3320 data.sg = &sg;
3321 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303322 sg_init_one(&sg, data_buf, size);
3323 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003324 mmc_wait_for_req(mmc, &mrq);
3325
3326 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303327 !memcmp(data_buf, tuning_block_pattern, size)) {
3328 /* tuning is successful at this tuning point */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003329 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303330 pr_debug("%s: %s: found good phase = %d\n",
3331 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003332 }
3333 } while (++phase < 16);
3334
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003335 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303336 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303337 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05303338 if (rc < 0)
3339 goto kfree;
3340 else
3341 phase = (u8)rc;
3342
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003343 /*
3344 * Finally set the selected phase in delay
3345 * line hw block.
3346 */
3347 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3348 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303349 goto kfree;
3350 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
3351 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003352 } else {
3353 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303354 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003355 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303356 msmsdcc_dump_sdcc_state(host);
3357 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003358 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003359
3360kfree:
3361 kfree(data_buf);
3362out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303363 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05303364 msmsdcc_delay(host);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303365 host->tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303366 spin_unlock_irqrestore(&host->lock, flags);
3367exit:
3368 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003369 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07003370}
3371
3372static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003373 .enable = msmsdcc_enable,
3374 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07003375 .request = msmsdcc_request,
3376 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003377 .get_ro = msmsdcc_get_ro,
3378#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07003379 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003380#endif
3381 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
3382 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07003383};
3384
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003385static unsigned int
3386msmsdcc_slot_status(struct msmsdcc_host *host)
3387{
3388 int status;
3389 unsigned int gpio_no = host->plat->status_gpio;
3390
3391 status = gpio_request(gpio_no, "SD_HW_Detect");
3392 if (status) {
3393 pr_err("%s: %s: Failed to request GPIO %d\n",
3394 mmc_hostname(host->mmc), __func__, gpio_no);
3395 } else {
3396 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003397 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08003398 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003399 if (host->plat->is_status_gpio_active_low)
3400 status = !status;
3401 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003402 gpio_free(gpio_no);
3403 }
3404 return status;
3405}
3406
San Mehat9d2bd732009-09-22 16:44:22 -07003407static void
3408msmsdcc_check_status(unsigned long data)
3409{
3410 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3411 unsigned int status;
3412
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003413 if (host->plat->status || host->plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08003414 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003415 status = host->plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08003416 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003417 status = msmsdcc_slot_status(host);
3418
Krishna Konda941604a2012-01-10 17:46:34 -08003419 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08003420
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003421 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08003422 if (host->plat->status)
3423 pr_info("%s: Slot status change detected "
3424 "(%d -> %d)\n",
3425 mmc_hostname(host->mmc),
3426 host->oldstat, status);
3427 else if (host->plat->is_status_gpio_active_low)
3428 pr_info("%s: Slot status change detected "
3429 "(%d -> %d) and the card detect GPIO"
3430 " is ACTIVE_LOW\n",
3431 mmc_hostname(host->mmc),
3432 host->oldstat, status);
3433 else
3434 pr_info("%s: Slot status change detected "
3435 "(%d -> %d) and the card detect GPIO"
3436 " is ACTIVE_HIGH\n",
3437 mmc_hostname(host->mmc),
3438 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07003439 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003440 }
3441 host->oldstat = status;
3442 } else {
3443 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07003444 }
San Mehat9d2bd732009-09-22 16:44:22 -07003445}
3446
3447static irqreturn_t
3448msmsdcc_platform_status_irq(int irq, void *dev_id)
3449{
3450 struct msmsdcc_host *host = dev_id;
3451
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003452 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07003453 msmsdcc_check_status((unsigned long) host);
3454 return IRQ_HANDLED;
3455}
3456
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003457static irqreturn_t
3458msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
3459{
3460 struct msmsdcc_host *host = dev_id;
3461
3462 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
3463 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303464 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003465 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303466 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003467 wake_lock(&host->sdio_wlock);
3468 msmsdcc_disable_irq_wake(host);
3469 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303470 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003471 }
3472 if (host->plat->is_sdio_al_client) {
3473 if (!host->clks_on) {
3474 msmsdcc_setup_clocks(host, true);
3475 host->clks_on = 1;
3476 }
3477 if (host->sdcc_irq_disabled) {
3478 writel_relaxed(host->mci_irqenable,
3479 host->base + MMCIMASK0);
3480 mb();
3481 enable_irq(host->core_irqres->start);
3482 host->sdcc_irq_disabled = 0;
3483 }
3484 wake_lock(&host->sdio_wlock);
3485 }
3486 spin_unlock(&host->lock);
3487
3488 return IRQ_HANDLED;
3489}
3490
San Mehat9d2bd732009-09-22 16:44:22 -07003491static void
3492msmsdcc_status_notify_cb(int card_present, void *dev_id)
3493{
3494 struct msmsdcc_host *host = dev_id;
3495
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003496 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07003497 card_present);
3498 msmsdcc_check_status((unsigned long) host);
3499}
3500
San Mehat9d2bd732009-09-22 16:44:22 -07003501static int
3502msmsdcc_init_dma(struct msmsdcc_host *host)
3503{
3504 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
3505 host->dma.host = host;
3506 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003507 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003508
3509 if (!host->dmares)
3510 return -ENODEV;
3511
3512 host->dma.nc = dma_alloc_coherent(NULL,
3513 sizeof(struct msmsdcc_nc_dmadata),
3514 &host->dma.nc_busaddr,
3515 GFP_KERNEL);
3516 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003517 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07003518 return -ENOMEM;
3519 }
3520 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
3521 host->dma.cmd_busaddr = host->dma.nc_busaddr;
3522 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
3523 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
3524 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07003525 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07003526
3527 return 0;
3528}
3529
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003530#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
3531/**
3532 * Allocate and Connect a SDCC peripheral's SPS endpoint
3533 *
3534 * This function allocates endpoint context and
3535 * connect it with memory endpoint by calling
3536 * appropriate SPS driver APIs.
3537 *
3538 * Also registers a SPS callback function with
3539 * SPS driver
3540 *
3541 * This function should only be called once typically
3542 * during driver probe.
3543 *
3544 * @host - Pointer to sdcc host structure
3545 * @ep - Pointer to sps endpoint data structure
3546 * @is_produce - 1 means Producer endpoint
3547 * 0 means Consumer endpoint
3548 *
3549 * @return - 0 if successful else negative value.
3550 *
3551 */
3552static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
3553 struct msmsdcc_sps_ep_conn_data *ep,
3554 bool is_producer)
3555{
3556 int rc = 0;
3557 struct sps_pipe *sps_pipe_handle;
3558 struct sps_connect *sps_config = &ep->config;
3559 struct sps_register_event *sps_event = &ep->event;
3560
3561 /* Allocate endpoint context */
3562 sps_pipe_handle = sps_alloc_endpoint();
3563 if (!sps_pipe_handle) {
3564 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
3565 mmc_hostname(host->mmc), is_producer);
3566 rc = -ENOMEM;
3567 goto out;
3568 }
3569
3570 /* Get default connection configuration for an endpoint */
3571 rc = sps_get_config(sps_pipe_handle, sps_config);
3572 if (rc) {
3573 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
3574 " rc=%d", mmc_hostname(host->mmc),
3575 (u32)sps_pipe_handle, rc);
3576 goto get_config_err;
3577 }
3578
3579 /* Modify the default connection configuration */
3580 if (is_producer) {
3581 /*
3582 * For SDCC producer transfer, source should be
3583 * SDCC peripheral where as destination should
3584 * be system memory.
3585 */
3586 sps_config->source = host->sps.bam_handle;
3587 sps_config->destination = SPS_DEV_HANDLE_MEM;
3588 /* Producer pipe will handle this connection */
3589 sps_config->mode = SPS_MODE_SRC;
3590 sps_config->options =
3591 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3592 } else {
3593 /*
3594 * For SDCC consumer transfer, source should be
3595 * system memory where as destination should
3596 * SDCC peripheral
3597 */
3598 sps_config->source = SPS_DEV_HANDLE_MEM;
3599 sps_config->destination = host->sps.bam_handle;
3600 sps_config->mode = SPS_MODE_DEST;
3601 sps_config->options =
3602 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3603 }
3604
3605 /* Producer pipe index */
3606 sps_config->src_pipe_index = host->sps.src_pipe_index;
3607 /* Consumer pipe index */
3608 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
3609 /*
3610 * This event thresold value is only significant for BAM-to-BAM
3611 * transfer. It's ignored for BAM-to-System mode transfer.
3612 */
3613 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05303614
3615 /* Allocate maximum descriptor fifo size */
3616 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
3617 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003618 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
3619 sps_config->desc.size,
3620 &sps_config->desc.phys_base,
3621 GFP_KERNEL);
3622
Pratibhasagar V00b94332011-10-18 14:57:27 +05303623 if (!sps_config->desc.base) {
3624 rc = -ENOMEM;
3625 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3626 , mmc_hostname(host->mmc));
3627 goto get_config_err;
3628 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003629 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3630
3631 /* Establish connection between peripheral and memory endpoint */
3632 rc = sps_connect(sps_pipe_handle, sps_config);
3633 if (rc) {
3634 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3635 " rc=%d", mmc_hostname(host->mmc),
3636 (u32)sps_pipe_handle, rc);
3637 goto sps_connect_err;
3638 }
3639
3640 sps_event->mode = SPS_TRIGGER_CALLBACK;
3641 sps_event->options = SPS_O_EOT;
3642 sps_event->callback = msmsdcc_sps_complete_cb;
3643 sps_event->xfer_done = NULL;
3644 sps_event->user = (void *)host;
3645
3646 /* Register callback event for EOT (End of transfer) event. */
3647 rc = sps_register_event(sps_pipe_handle, sps_event);
3648 if (rc) {
3649 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3650 " rc=%d", mmc_hostname(host->mmc),
3651 (u32)sps_pipe_handle, rc);
3652 goto reg_event_err;
3653 }
3654 /* Now save the sps pipe handle */
3655 ep->pipe_handle = sps_pipe_handle;
3656 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3657 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3658 __func__, is_producer ? "READ" : "WRITE",
3659 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3660 goto out;
3661
3662reg_event_err:
3663 sps_disconnect(sps_pipe_handle);
3664sps_connect_err:
3665 dma_free_coherent(mmc_dev(host->mmc),
3666 sps_config->desc.size,
3667 sps_config->desc.base,
3668 sps_config->desc.phys_base);
3669get_config_err:
3670 sps_free_endpoint(sps_pipe_handle);
3671out:
3672 return rc;
3673}
3674
3675/**
3676 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3677 *
3678 * This function disconnect endpoint and deallocates
3679 * endpoint context.
3680 *
3681 * This function should only be called once typically
3682 * during driver remove.
3683 *
3684 * @host - Pointer to sdcc host structure
3685 * @ep - Pointer to sps endpoint data structure
3686 *
3687 */
3688static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3689 struct msmsdcc_sps_ep_conn_data *ep)
3690{
3691 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3692 struct sps_connect *sps_config = &ep->config;
3693 struct sps_register_event *sps_event = &ep->event;
3694
3695 sps_event->xfer_done = NULL;
3696 sps_event->callback = NULL;
3697 sps_register_event(sps_pipe_handle, sps_event);
3698 sps_disconnect(sps_pipe_handle);
3699 dma_free_coherent(mmc_dev(host->mmc),
3700 sps_config->desc.size,
3701 sps_config->desc.base,
3702 sps_config->desc.phys_base);
3703 sps_free_endpoint(sps_pipe_handle);
3704}
3705
3706/**
3707 * Reset SDCC peripheral's SPS endpoint
3708 *
3709 * This function disconnects an endpoint.
3710 *
3711 * This function should be called for reseting
3712 * SPS endpoint when data transfer error is
3713 * encountered during data transfer. This
3714 * can be considered as soft reset to endpoint.
3715 *
3716 * This function should only be called if
3717 * msmsdcc_sps_init() is already called.
3718 *
3719 * @host - Pointer to sdcc host structure
3720 * @ep - Pointer to sps endpoint data structure
3721 *
3722 * @return - 0 if successful else negative value.
3723 */
3724static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3725 struct msmsdcc_sps_ep_conn_data *ep)
3726{
3727 int rc = 0;
3728 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3729
3730 rc = sps_disconnect(sps_pipe_handle);
3731 if (rc) {
3732 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3733 " rc=%d", mmc_hostname(host->mmc), __func__,
3734 (u32)sps_pipe_handle, rc);
3735 goto out;
3736 }
3737 out:
3738 return rc;
3739}
3740
3741/**
3742 * Restore SDCC peripheral's SPS endpoint
3743 *
3744 * This function connects an endpoint.
3745 *
3746 * This function should be called for restoring
3747 * SPS endpoint after data transfer error is
3748 * encountered during data transfer. This
3749 * can be considered as soft reset to endpoint.
3750 *
3751 * This function should only be called if
3752 * msmsdcc_sps_reset_ep() is called before.
3753 *
3754 * @host - Pointer to sdcc host structure
3755 * @ep - Pointer to sps endpoint data structure
3756 *
3757 * @return - 0 if successful else negative value.
3758 */
3759static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3760 struct msmsdcc_sps_ep_conn_data *ep)
3761{
3762 int rc = 0;
3763 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3764 struct sps_connect *sps_config = &ep->config;
3765 struct sps_register_event *sps_event = &ep->event;
3766
3767 /* Establish connection between peripheral and memory endpoint */
3768 rc = sps_connect(sps_pipe_handle, sps_config);
3769 if (rc) {
3770 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3771 " rc=%d", mmc_hostname(host->mmc), __func__,
3772 (u32)sps_pipe_handle, rc);
3773 goto out;
3774 }
3775
3776 /* Register callback event for EOT (End of transfer) event. */
3777 rc = sps_register_event(sps_pipe_handle, sps_event);
3778 if (rc) {
3779 pr_err("%s: %s: sps_register_event() failed!!!"
3780 " pipe_handle=0x%x, rc=%d",
3781 mmc_hostname(host->mmc), __func__,
3782 (u32)sps_pipe_handle, rc);
3783 goto reg_event_err;
3784 }
3785 goto out;
3786
3787reg_event_err:
3788 sps_disconnect(sps_pipe_handle);
3789out:
3790 return rc;
3791}
3792
3793/**
3794 * Initialize SPS HW connected with SDCC core
3795 *
3796 * This function register BAM HW resources with
3797 * SPS driver and then initialize 2 SPS endpoints
3798 *
3799 * This function should only be called once typically
3800 * during driver probe.
3801 *
3802 * @host - Pointer to sdcc host structure
3803 *
3804 * @return - 0 if successful else negative value.
3805 *
3806 */
3807static int msmsdcc_sps_init(struct msmsdcc_host *host)
3808{
3809 int rc = 0;
3810 struct sps_bam_props bam = {0};
3811
3812 host->bam_base = ioremap(host->bam_memres->start,
3813 resource_size(host->bam_memres));
3814 if (!host->bam_base) {
3815 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3816 " size=0x%x", mmc_hostname(host->mmc),
3817 host->bam_memres->start,
3818 (host->bam_memres->end -
3819 host->bam_memres->start));
3820 rc = -ENOMEM;
3821 goto out;
3822 }
3823
3824 bam.phys_addr = host->bam_memres->start;
3825 bam.virt_addr = host->bam_base;
3826 /*
3827 * This event thresold value is only significant for BAM-to-BAM
3828 * transfer. It's ignored for BAM-to-System mode transfer.
3829 */
3830 bam.event_threshold = 0x10; /* Pipe event threshold */
3831 /*
3832 * This threshold controls when the BAM publish
3833 * the descriptor size on the sideband interface.
3834 * SPS HW will only be used when
3835 * data transfer size > MCI_FIFOSIZE (64 bytes).
3836 * PIO mode will be used when
3837 * data transfer size < MCI_FIFOSIZE (64 bytes).
3838 * So set this thresold value to 64 bytes.
3839 */
3840 bam.summing_threshold = 64;
3841 /* SPS driver wll handle the SDCC BAM IRQ */
3842 bam.irq = (u32)host->bam_irqres->start;
3843 bam.manage = SPS_BAM_MGR_LOCAL;
3844
3845 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3846 (u32)bam.phys_addr);
3847 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3848 (u32)bam.virt_addr);
3849
3850 /* Register SDCC Peripheral BAM device to SPS driver */
3851 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3852 if (rc) {
3853 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3854 mmc_hostname(host->mmc), rc);
3855 goto reg_bam_err;
3856 }
3857 pr_info("%s: BAM device registered. bam_handle=0x%x",
3858 mmc_hostname(host->mmc), host->sps.bam_handle);
3859
3860 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3861 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3862
3863 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3864 SPS_PROD_PERIPHERAL);
3865 if (rc)
3866 goto sps_reset_err;
3867 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3868 SPS_CONS_PERIPHERAL);
3869 if (rc)
3870 goto cons_conn_err;
3871
3872 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3873 mmc_hostname(host->mmc),
3874 (unsigned long long)host->bam_memres->start,
3875 (unsigned int)host->bam_irqres->start);
3876 goto out;
3877
3878cons_conn_err:
3879 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3880sps_reset_err:
3881 sps_deregister_bam_device(host->sps.bam_handle);
3882reg_bam_err:
3883 iounmap(host->bam_base);
3884out:
3885 return rc;
3886}
3887
3888/**
3889 * De-initialize SPS HW connected with SDCC core
3890 *
3891 * This function deinitialize SPS endpoints and then
3892 * deregisters BAM resources from SPS driver.
3893 *
3894 * This function should only be called once typically
3895 * during driver remove.
3896 *
3897 * @host - Pointer to sdcc host structure
3898 *
3899 */
3900static void msmsdcc_sps_exit(struct msmsdcc_host *host)
3901{
3902 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
3903 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3904 sps_deregister_bam_device(host->sps.bam_handle);
3905 iounmap(host->bam_base);
3906}
3907#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
3908
3909static ssize_t
3910show_polling(struct device *dev, struct device_attribute *attr, char *buf)
3911{
3912 struct mmc_host *mmc = dev_get_drvdata(dev);
3913 struct msmsdcc_host *host = mmc_priv(mmc);
3914 int poll;
3915 unsigned long flags;
3916
3917 spin_lock_irqsave(&host->lock, flags);
3918 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
3919 spin_unlock_irqrestore(&host->lock, flags);
3920
3921 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
3922}
3923
3924static ssize_t
3925set_polling(struct device *dev, struct device_attribute *attr,
3926 const char *buf, size_t count)
3927{
3928 struct mmc_host *mmc = dev_get_drvdata(dev);
3929 struct msmsdcc_host *host = mmc_priv(mmc);
3930 int value;
3931 unsigned long flags;
3932
3933 sscanf(buf, "%d", &value);
3934
3935 spin_lock_irqsave(&host->lock, flags);
3936 if (value) {
3937 mmc->caps |= MMC_CAP_NEEDS_POLL;
3938 mmc_detect_change(host->mmc, 0);
3939 } else {
3940 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3941 }
3942#ifdef CONFIG_HAS_EARLYSUSPEND
3943 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
3944#endif
3945 spin_unlock_irqrestore(&host->lock, flags);
3946 return count;
3947}
3948
3949static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
3950 show_polling, set_polling);
3951static struct attribute *dev_attrs[] = {
3952 &dev_attr_polling.attr,
3953 NULL,
3954};
3955static struct attribute_group dev_attr_grp = {
3956 .attrs = dev_attrs,
3957};
3958
3959#ifdef CONFIG_HAS_EARLYSUSPEND
3960static void msmsdcc_early_suspend(struct early_suspend *h)
3961{
3962 struct msmsdcc_host *host =
3963 container_of(h, struct msmsdcc_host, early_suspend);
3964 unsigned long flags;
3965
3966 spin_lock_irqsave(&host->lock, flags);
3967 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
3968 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3969 spin_unlock_irqrestore(&host->lock, flags);
3970};
3971static void msmsdcc_late_resume(struct early_suspend *h)
3972{
3973 struct msmsdcc_host *host =
3974 container_of(h, struct msmsdcc_host, early_suspend);
3975 unsigned long flags;
3976
3977 if (host->polling_enabled) {
3978 spin_lock_irqsave(&host->lock, flags);
3979 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
3980 mmc_detect_change(host->mmc, 0);
3981 spin_unlock_irqrestore(&host->lock, flags);
3982 }
3983};
3984#endif
3985
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303986void msmsdcc_print_regs(const char *name, void __iomem *base,
3987 unsigned int no_of_regs)
3988{
3989 unsigned int i;
3990
3991 if (!base)
3992 return;
3993 pr_info("===== %s: Register Dumps @base=0x%x =====\n",
3994 name, (u32)base);
3995 for (i = 0; i < no_of_regs; i = i + 4) {
3996 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x.\n", i*4,
3997 (u32)readl_relaxed(base + i*4),
3998 (u32)readl_relaxed(base + ((i+1)*4)),
3999 (u32)readl_relaxed(base + ((i+2)*4)),
4000 (u32)readl_relaxed(base + ((i+3)*4)));
4001 }
4002}
4003
4004static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
4005{
4006 /* Dump current state of SDCC clocks, power and irq */
4007 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
4008 (host->pwr ? "ON" : "OFF"));
4009 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
4010 mmc_hostname(host->mmc),
4011 (host->clks_on ? "ON" : "OFF"),
4012 (u32)clk_get_rate(host->clk));
4013 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
4014 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
4015
4016 /* Now dump SDCC registers. Don't print FIFO registers */
4017 if (host->clks_on)
4018 msmsdcc_print_regs("SDCC-CORE", host->base, 28);
4019
4020 if (host->curr.data) {
4021 if (msmsdcc_check_dma_op_req(host->curr.data))
4022 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
4023 else if (host->is_dma_mode)
4024 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
4025 mmc_hostname(host->mmc), host->dma.busy,
4026 host->dma.channel, host->dma.crci);
4027 else if (host->is_sps_mode)
4028 pr_info("%s: SPS mode: busy=%d\n",
4029 mmc_hostname(host->mmc), host->sps.busy);
4030
4031 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
4032 mmc_hostname(host->mmc), host->curr.xfer_size,
4033 host->curr.data_xfered, host->curr.xfer_remain);
4034 pr_info("%s: got_dataend=%d, prog_enable=%d,"
4035 " wait_for_auto_prog_done=%d,"
4036 " got_auto_prog_done=%d\n",
4037 mmc_hostname(host->mmc), host->curr.got_dataend,
4038 host->prog_enable, host->curr.wait_for_auto_prog_done,
4039 host->curr.got_auto_prog_done);
4040 }
4041
4042}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004043static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
4044{
4045 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4046 struct mmc_request *mrq;
4047 unsigned long flags;
4048
4049 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004050 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004051 pr_info("%s: %s: dummy CMD52 timeout\n",
4052 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004053 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004054 }
4055
4056 mrq = host->curr.mrq;
4057
4058 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304059 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
4060 mrq->cmd->opcode);
4061 msmsdcc_dump_sdcc_state(host);
4062
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004063 if (!mrq->cmd->error)
4064 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304065 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004066 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004067 if (mrq->data && !mrq->data->error)
4068 mrq->data->error = -ETIMEDOUT;
4069 host->curr.data_xfered = 0;
4070 if (host->dma.sg && host->is_dma_mode) {
4071 msm_dmov_stop_cmd(host->dma.channel,
4072 &host->dma.hdr, 0);
4073 } else if (host->sps.sg && host->is_sps_mode) {
4074 /* Stop current SPS transfer */
4075 msmsdcc_sps_exit_curr_xfer(host);
4076 } else {
4077 msmsdcc_reset_and_restore(host);
4078 msmsdcc_stop_data(host);
4079 if (mrq->data && mrq->data->stop)
4080 msmsdcc_start_command(host,
4081 mrq->data->stop, 0);
4082 else
4083 msmsdcc_request_end(host, mrq);
4084 }
4085 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304086 host->prog_enable = 0;
Subhash Jadavanied6b0e42012-03-07 16:36:27 +05304087 host->curr.wait_for_auto_prog_done = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004088 msmsdcc_reset_and_restore(host);
4089 msmsdcc_request_end(host, mrq);
4090 }
4091 }
4092 spin_unlock_irqrestore(&host->lock, flags);
4093}
4094
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304095static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
4096{
4097 int i, ret;
4098 struct mmc_platform_data *pdata;
4099 struct device_node *np = dev->of_node;
4100 u32 bus_width = 0;
4101 u32 *clk_table;
4102 int clk_table_len;
4103 u32 *sup_voltages;
4104 int sup_volt_len;
4105
4106 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
4107 if (!pdata) {
4108 dev_err(dev, "could not allocate memory for platform data\n");
4109 goto err;
4110 }
4111
4112 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
4113 if (bus_width == 8) {
4114 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
4115 } else if (bus_width == 4) {
4116 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
4117 } else {
4118 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
4119 pdata->mmc_bus_width = 0;
4120 }
4121
4122 if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
4123 size_t sz;
4124 sz = sup_volt_len / sizeof(*sup_voltages);
4125 if (sz > 0) {
4126 sup_voltages = devm_kzalloc(dev,
4127 sz * sizeof(*sup_voltages), GFP_KERNEL);
4128 if (!sup_voltages) {
4129 dev_err(dev, "No memory for supported voltage\n");
4130 goto err;
4131 }
4132
4133 ret = of_property_read_u32_array(np,
4134 "qcom,sdcc-sup-voltages", sup_voltages, sz);
4135 if (ret < 0) {
4136 dev_err(dev, "error while reading voltage"
4137 "ranges %d\n", ret);
4138 goto err;
4139 }
4140 } else {
4141 dev_err(dev, "No supported voltages\n");
4142 goto err;
4143 }
4144 for (i = 0; i < sz; i += 2) {
4145 u32 mask;
4146
4147 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
4148 sup_voltages[i + 1]);
4149 if (!mask)
4150 dev_err(dev, "Invalide voltage range %d\n", i);
4151 pdata->ocr_mask |= mask;
4152 }
4153 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
4154 } else {
4155 dev_err(dev, "Supported voltage range not specified\n");
4156 }
4157
4158 if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
4159 size_t sz;
4160 sz = clk_table_len / sizeof(*clk_table);
4161
4162 if (sz > 0) {
4163 clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
4164 GFP_KERNEL);
4165 if (!clk_table) {
4166 dev_err(dev, "No memory for clock table\n");
4167 goto err;
4168 }
4169
4170 ret = of_property_read_u32_array(np,
4171 "qcom,sdcc-clk-rates", clk_table, sz);
4172 if (ret < 0) {
4173 dev_err(dev, "error while reading clk"
4174 "table %d\n", ret);
4175 goto err;
4176 }
4177 } else {
4178 dev_err(dev, "clk_table not specified\n");
4179 goto err;
4180 }
4181 pdata->sup_clk_table = clk_table;
4182 pdata->sup_clk_cnt = sz;
4183 } else {
4184 dev_err(dev, "Supported clock rates not specified\n");
4185 }
4186
4187 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
4188 pdata->nonremovable = true;
4189 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
4190 pdata->disable_cmd23 = true;
4191
4192 return pdata;
4193err:
4194 return NULL;
4195}
4196
San Mehat9d2bd732009-09-22 16:44:22 -07004197static int
4198msmsdcc_probe(struct platform_device *pdev)
4199{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304200 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07004201 struct msmsdcc_host *host;
4202 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004203 unsigned long flags;
4204 struct resource *core_irqres = NULL;
4205 struct resource *bam_irqres = NULL;
4206 struct resource *core_memres = NULL;
4207 struct resource *dml_memres = NULL;
4208 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07004209 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07004210 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05304211 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004212 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07004213
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304214 if (pdev->dev.of_node) {
4215 plat = msmsdcc_populate_pdata(&pdev->dev);
4216 of_property_read_u32((&pdev->dev)->of_node,
4217 "cell-index", &pdev->id);
4218 } else {
4219 plat = pdev->dev.platform_data;
4220 }
4221
San Mehat9d2bd732009-09-22 16:44:22 -07004222 /* must have platform data */
4223 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004224 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004225 ret = -EINVAL;
4226 goto out;
4227 }
4228
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004229 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07004230 return -EINVAL;
4231
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304232 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
4233 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
4234 return -EINVAL;
4235 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004236
San Mehat9d2bd732009-09-22 16:44:22 -07004237 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004238 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004239 return -ENXIO;
4240 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304241 if (pdev->dev.of_node) {
4242 /*
4243 * Device tree iomem resources are only accessible by index.
4244 * index = 0 -> SDCC register interface
4245 * index = 1 -> DML register interface
4246 * index = 2 -> BAM register interface
4247 * IRQ resources:
4248 * index = 0 -> SDCC IRQ
4249 * index = 1 -> BAM IRQ
4250 */
4251 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
4252 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
4253 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
4254 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
4255 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
4256 } else {
4257 for (i = 0; i < pdev->num_resources; i++) {
4258 if (pdev->resource[i].flags & IORESOURCE_MEM) {
4259 if (!strncmp(pdev->resource[i].name,
4260 "sdcc_dml_addr",
4261 sizeof("sdcc_dml_addr")))
4262 dml_memres = &pdev->resource[i];
4263 else if (!strncmp(pdev->resource[i].name,
4264 "sdcc_bam_addr",
4265 sizeof("sdcc_bam_addr")))
4266 bam_memres = &pdev->resource[i];
4267 else
4268 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07004269
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304270 }
4271 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
4272 if (!strncmp(pdev->resource[i].name,
4273 "sdcc_bam_irq",
4274 sizeof("sdcc_bam_irq")))
4275 bam_irqres = &pdev->resource[i];
4276 else
4277 core_irqres = &pdev->resource[i];
4278 }
4279 if (pdev->resource[i].flags & IORESOURCE_DMA) {
4280 if (!strncmp(pdev->resource[i].name,
4281 "sdcc_dma_chnl",
4282 sizeof("sdcc_dma_chnl")))
4283 dmares = &pdev->resource[i];
4284 else if (!strncmp(pdev->resource[i].name,
4285 "sdcc_dma_crci",
4286 sizeof("sdcc_dma_crci")))
4287 dma_crci_res = &pdev->resource[i];
4288 }
Krishna Konda25786ec2011-07-25 16:21:36 -07004289 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004290 }
4291
4292 if (!core_irqres || !core_memres) {
4293 pr_err("%s: Invalid sdcc core resource\n", __func__);
4294 return -ENXIO;
4295 }
4296
4297 /*
4298 * Both BAM and DML memory resource should be preset.
4299 * BAM IRQ resource should also be present.
4300 */
4301 if ((bam_memres && !dml_memres) ||
4302 (!bam_memres && dml_memres) ||
4303 ((bam_memres && dml_memres) && !bam_irqres)) {
4304 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004305 return -ENXIO;
4306 }
4307
4308 /*
4309 * Setup our host structure
4310 */
San Mehat9d2bd732009-09-22 16:44:22 -07004311 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
4312 if (!mmc) {
4313 ret = -ENOMEM;
4314 goto out;
4315 }
4316
4317 host = mmc_priv(mmc);
4318 host->pdev_id = pdev->id;
4319 host->plat = plat;
4320 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08004321 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05304322
4323 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004324 host->is_sps_mode = 1;
4325 else if (dmares)
4326 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07004327
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004328 host->base = ioremap(core_memres->start,
4329 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07004330 if (!host->base) {
4331 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004332 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004333 }
4334
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004335 host->core_irqres = core_irqres;
4336 host->bam_irqres = bam_irqres;
4337 host->core_memres = core_memres;
4338 host->dml_memres = dml_memres;
4339 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07004340 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07004341 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07004342 spin_lock_init(&host->lock);
4343
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004344#ifdef CONFIG_MMC_EMBEDDED_SDIO
4345 if (plat->embedded_sdio)
4346 mmc_set_embedded_sdio_data(mmc,
4347 &plat->embedded_sdio->cis,
4348 &plat->embedded_sdio->cccr,
4349 plat->embedded_sdio->funcs,
4350 plat->embedded_sdio->num_funcs);
4351#endif
4352
Sahitya Tummala62612cf2010-12-08 15:03:03 +05304353 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
4354 (unsigned long)host);
4355
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004356 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
4357 (unsigned long)host);
4358 if (host->is_dma_mode) {
4359 /* Setup DMA */
4360 ret = msmsdcc_init_dma(host);
4361 if (ret)
4362 goto ioremap_free;
4363 } else {
4364 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004365 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004366 }
4367
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004368 /*
4369 * Setup SDCC clock if derived from Dayatona
4370 * fabric core clock.
4371 */
4372 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07004373 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004374 if (!IS_ERR(host->dfab_pclk)) {
4375 /* Set the clock rate to 64MHz for max. performance */
4376 ret = clk_set_rate(host->dfab_pclk, 64000000);
4377 if (ret)
4378 goto dfab_pclk_put;
4379 ret = clk_enable(host->dfab_pclk);
4380 if (ret)
4381 goto dfab_pclk_put;
4382 } else
4383 goto dma_free;
4384 }
4385
4386 /*
4387 * Setup main peripheral bus clock
4388 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004389 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004390 if (!IS_ERR(host->pclk)) {
4391 ret = clk_enable(host->pclk);
4392 if (ret)
4393 goto pclk_put;
4394
4395 host->pclk_rate = clk_get_rate(host->pclk);
4396 }
4397
4398 /*
4399 * Setup SDC MMC clock
4400 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004401 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07004402 if (IS_ERR(host->clk)) {
4403 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004404 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07004405 }
4406
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004407 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
4408 if (ret) {
4409 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
4410 goto clk_put;
4411 }
4412
4413 ret = clk_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004414 if (ret)
4415 goto clk_put;
4416
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004417 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304418 if (!host->clk_rate)
4419 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304420
4421 /*
4422 * Lookup the Controller Version, to identify the supported features
4423 * Version number read as 0 would indicate SDCC3 or earlier versions
4424 */
4425 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
4426 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
4427 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304428 /*
4429 * Set the register write delay according to min. clock frequency
4430 * supported and update later when the host->clk_rate changes.
4431 */
4432 host->reg_write_delay =
4433 (1 + ((3 * USEC_PER_SEC) /
4434 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004435
4436 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05304437 /* Apply Hard reset to SDCC to put it in power on default state */
4438 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004439
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304440 /* pm qos request to prevent apps idle power collapse */
4441 if (host->plat->swfi_latency)
4442 pm_qos_add_request(&host->pm_qos_req_dma,
4443 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
4444
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004445 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07004446 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004447 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07004448 goto clk_disable;
4449 }
4450
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004451
4452 /* Clocks has to be running before accessing SPS/DML HW blocks */
4453 if (host->is_sps_mode) {
4454 /* Initialize SPS */
4455 ret = msmsdcc_sps_init(host);
4456 if (ret)
4457 goto vreg_deinit;
4458 /* Initialize DML */
4459 ret = msmsdcc_dml_init(host);
4460 if (ret)
4461 goto sps_exit;
4462 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05304463 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07004464
San Mehat9d2bd732009-09-22 16:44:22 -07004465 /*
4466 * Setup MMC host structure
4467 */
4468 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004469 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
4470 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004471 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004472 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
4473 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07004474
San Mehat9d2bd732009-09-22 16:44:22 -07004475 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304476 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304477
4478 /*
4479 * If we send the CMD23 before multi block write/read command
4480 * then we need not to send CMD12 at the end of the transfer.
4481 * If we don't send the CMD12 then only way to detect the PROG_DONE
4482 * status is to use the AUTO_PROG_DONE status provided by SDCC4
4483 * controller. So let's enable the CMD23 for SDCC4 only.
4484 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304485 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304486 mmc->caps |= MMC_CAP_CMD23;
4487
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004488 mmc->caps |= plat->uhs_caps;
4489 /*
4490 * XPC controls the maximum current in the default speed mode of SDXC
4491 * card. XPC=0 means 100mA (max.) but speed class is not supported.
4492 * XPC=1 means 150mA (max.) and speed class is supported.
4493 */
4494 if (plat->xpc_cap)
4495 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
4496 MMC_CAP_SET_XPC_180);
4497
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304498 if (pdev->dev.of_node) {
4499 if (of_get_property((&pdev->dev)->of_node,
4500 "qcom,sdcc-hs200", NULL))
4501 mmc->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
4502 }
4503
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004504 if (plat->nonremovable)
4505 mmc->caps |= MMC_CAP_NONREMOVABLE;
4506#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
4507 mmc->caps |= MMC_CAP_SDIO_IRQ;
4508#endif
4509
4510 if (plat->is_sdio_al_client)
4511 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07004512
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304513 mmc->max_segs = msmsdcc_get_nr_sg(host);
4514 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
4515 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07004516
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304517 mmc->max_req_size = MMC_MAX_REQ_SIZE;
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +05304518 mmc->max_seg_size = mmc->max_req_size;
San Mehat9d2bd732009-09-22 16:44:22 -07004519
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004520 writel_relaxed(0, host->base + MMCIMASK0);
4521 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -07004522
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004523 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
4524 mb();
4525 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07004526
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004527 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
4528 DRIVER_NAME " (cmd)", host);
4529 if (ret)
4530 goto dml_exit;
4531
4532 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
4533 DRIVER_NAME " (pio)", host);
4534 if (ret)
4535 goto irq_free;
4536
4537 /*
4538 * Enable SDCC IRQ only when host is powered on. Otherwise, this
4539 * IRQ is un-necessarily being monitored by MPM (Modem power
4540 * management block) during idle-power collapse. The MPM will be
4541 * configured to monitor the DATA1 GPIO line with level-low trigger
4542 * and thus depending on the GPIO status, it prevents TCXO shutdown
4543 * during idle-power collapse.
4544 */
4545 disable_irq(core_irqres->start);
4546 host->sdcc_irq_disabled = 1;
4547
4548 if (plat->sdiowakeup_irq) {
4549 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4550 mmc_hostname(mmc));
4551 ret = request_irq(plat->sdiowakeup_irq,
4552 msmsdcc_platform_sdiowakeup_irq,
4553 IRQF_SHARED | IRQF_TRIGGER_LOW,
4554 DRIVER_NAME "sdiowakeup", host);
4555 if (ret) {
4556 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
4557 plat->sdiowakeup_irq, ret);
4558 goto pio_irq_free;
4559 } else {
4560 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304561 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004562 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304563 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004564 }
4565 spin_unlock_irqrestore(&host->lock, flags);
4566 }
4567 }
4568
4569 if (plat->cfg_mpm_sdiowakeup) {
4570 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4571 mmc_hostname(mmc));
4572 }
4573
4574 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
4575 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004576 /*
4577 * Setup card detect change
4578 */
4579
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004580 if (plat->status || plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08004581 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004582 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08004583 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004584 host->oldstat = msmsdcc_slot_status(host);
Krishna Konda360aa422011-12-06 18:27:41 -08004585
Krishna Konda941604a2012-01-10 17:46:34 -08004586 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004587 }
San Mehat9d2bd732009-09-22 16:44:22 -07004588
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004589 if (plat->status_irq) {
4590 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07004591 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004592 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07004593 DRIVER_NAME " (slot)",
4594 host);
4595 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004596 pr_err("Unable to get slot IRQ %d (%d)\n",
4597 plat->status_irq, ret);
4598 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004599 }
4600 } else if (plat->register_status_notify) {
4601 plat->register_status_notify(msmsdcc_status_notify_cb, host);
4602 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004603 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07004604 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004605
4606 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004607
4608 ret = pm_runtime_set_active(&(pdev)->dev);
4609 if (ret < 0)
4610 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
4611 __func__, ret);
4612 /*
4613 * There is no notion of suspend/resume for SD/MMC/SDIO
4614 * cards. So host can be suspended/resumed with out
4615 * worrying about its children.
4616 */
4617 pm_suspend_ignore_children(&(pdev)->dev, true);
4618
4619 /*
4620 * MMC/SD/SDIO bus suspend/resume operations are defined
4621 * only for the slots that will be used for non-removable
4622 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
4623 * defined. Otherwise, they simply become card removal and
4624 * insertion events during suspend and resume respectively.
4625 * Hence, enable run-time PM only for slots for which bus
4626 * suspend/resume operations are defined.
4627 */
4628#ifdef CONFIG_MMC_UNSAFE_RESUME
4629 /*
4630 * If this capability is set, MMC core will enable/disable host
4631 * for every claim/release operation on a host. We use this
4632 * notification to increment/decrement runtime pm usage count.
4633 */
4634 mmc->caps |= MMC_CAP_DISABLE;
4635 pm_runtime_enable(&(pdev)->dev);
4636#else
4637 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
4638 mmc->caps |= MMC_CAP_DISABLE;
4639 pm_runtime_enable(&(pdev)->dev);
4640 }
4641#endif
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05304642#ifndef CONFIG_PM_RUNTIME
4643 mmc_set_disable_delay(mmc, MSM_MMC_DISABLE_TIMEOUT);
4644#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004645 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
4646 (unsigned long)host);
4647
San Mehat9d2bd732009-09-22 16:44:22 -07004648 mmc_add_host(mmc);
4649
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004650#ifdef CONFIG_HAS_EARLYSUSPEND
4651 host->early_suspend.suspend = msmsdcc_early_suspend;
4652 host->early_suspend.resume = msmsdcc_late_resume;
4653 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
4654 register_early_suspend(&host->early_suspend);
4655#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004656
Krishna Konda25786ec2011-07-25 16:21:36 -07004657 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
4658 " dmacrcri %d\n", mmc_hostname(mmc),
4659 (unsigned long long)core_memres->start,
4660 (unsigned int) core_irqres->start,
4661 (unsigned int) plat->status_irq, host->dma.channel,
4662 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004663
4664 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
4665 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
4666 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
4667 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
4668 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
4669 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
4670 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
4671 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
4672 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
4673 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
4674 host->eject);
4675 pr_info("%s: Power save feature enable = %d\n",
4676 mmc_hostname(mmc), msmsdcc_pwrsave);
4677
Krishna Konda25786ec2011-07-25 16:21:36 -07004678 if (host->is_dma_mode && host->dma.channel != -1
4679 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004680 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004681 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004682 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004683 mmc_hostname(mmc), host->dma.cmd_busaddr,
4684 host->dma.cmdptr_busaddr);
4685 } else if (host->is_sps_mode) {
4686 pr_info("%s: SPS-BAM data transfer mode available\n",
4687 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004688 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004689 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004690
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004691#if defined(CONFIG_DEBUG_FS)
4692 msmsdcc_dbg_createhost(host);
4693#endif
4694 if (!plat->status_irq) {
4695 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
4696 if (ret)
4697 goto platform_irq_free;
4698 }
San Mehat9d2bd732009-09-22 16:44:22 -07004699 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004700
4701 platform_irq_free:
4702 del_timer_sync(&host->req_tout_timer);
4703 pm_runtime_disable(&(pdev)->dev);
4704 pm_runtime_set_suspended(&(pdev)->dev);
4705
4706 if (plat->status_irq)
4707 free_irq(plat->status_irq, host);
4708 sdiowakeup_irq_free:
4709 wake_lock_destroy(&host->sdio_suspend_wlock);
4710 if (plat->sdiowakeup_irq)
4711 free_irq(plat->sdiowakeup_irq, host);
4712 pio_irq_free:
4713 if (plat->sdiowakeup_irq)
4714 wake_lock_destroy(&host->sdio_wlock);
4715 free_irq(core_irqres->start, host);
4716 irq_free:
4717 free_irq(core_irqres->start, host);
4718 dml_exit:
4719 if (host->is_sps_mode)
4720 msmsdcc_dml_exit(host);
4721 sps_exit:
4722 if (host->is_sps_mode)
4723 msmsdcc_sps_exit(host);
4724 vreg_deinit:
4725 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07004726 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004727 clk_disable(host->clk);
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304728 if (host->plat->swfi_latency)
4729 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07004730 clk_put:
4731 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004732 pclk_disable:
4733 if (!IS_ERR(host->pclk))
4734 clk_disable(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07004735 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004736 if (!IS_ERR(host->pclk))
4737 clk_put(host->pclk);
4738 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4739 clk_disable(host->dfab_pclk);
4740 dfab_pclk_put:
4741 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4742 clk_put(host->dfab_pclk);
4743 dma_free:
4744 if (host->is_dma_mode) {
4745 if (host->dmares)
4746 dma_free_coherent(NULL,
4747 sizeof(struct msmsdcc_nc_dmadata),
4748 host->dma.nc, host->dma.nc_busaddr);
4749 }
4750 ioremap_free:
4751 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07004752 host_free:
4753 mmc_free_host(mmc);
4754 out:
4755 return ret;
4756}
4757
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004758static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07004759{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004760 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4761 struct mmc_platform_data *plat;
4762 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004763
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004764 if (!mmc)
4765 return -ENXIO;
4766
4767 if (pm_runtime_suspended(&(pdev)->dev))
4768 pm_runtime_resume(&(pdev)->dev);
4769
4770 host = mmc_priv(mmc);
4771
4772 DBG(host, "Removing SDCC device = %d\n", pdev->id);
4773 plat = host->plat;
4774
4775 if (!plat->status_irq)
4776 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
4777
4778 del_timer_sync(&host->req_tout_timer);
4779 tasklet_kill(&host->dma_tlet);
4780 tasklet_kill(&host->sps.tlet);
4781 mmc_remove_host(mmc);
4782
4783 if (plat->status_irq)
4784 free_irq(plat->status_irq, host);
4785
4786 wake_lock_destroy(&host->sdio_suspend_wlock);
4787 if (plat->sdiowakeup_irq) {
4788 wake_lock_destroy(&host->sdio_wlock);
4789 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
4790 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07004791 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004792
4793 free_irq(host->core_irqres->start, host);
4794 free_irq(host->core_irqres->start, host);
4795
4796 clk_put(host->clk);
4797 if (!IS_ERR(host->pclk))
4798 clk_put(host->pclk);
4799 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4800 clk_put(host->dfab_pclk);
4801
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304802 if (host->plat->swfi_latency)
4803 pm_qos_remove_request(&host->pm_qos_req_dma);
4804
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004805 msmsdcc_vreg_init(host, false);
4806
4807 if (host->is_dma_mode) {
4808 if (host->dmares)
4809 dma_free_coherent(NULL,
4810 sizeof(struct msmsdcc_nc_dmadata),
4811 host->dma.nc, host->dma.nc_busaddr);
4812 }
4813
4814 if (host->is_sps_mode) {
4815 msmsdcc_dml_exit(host);
4816 msmsdcc_sps_exit(host);
4817 }
4818
4819 iounmap(host->base);
4820 mmc_free_host(mmc);
4821
4822#ifdef CONFIG_HAS_EARLYSUSPEND
4823 unregister_early_suspend(&host->early_suspend);
4824#endif
4825 pm_runtime_disable(&(pdev)->dev);
4826 pm_runtime_set_suspended(&(pdev)->dev);
4827
4828 return 0;
4829}
4830
Oluwafemi Adeyemif68d3e62012-03-13 11:46:49 -07004831static void msmsdcc_shutdown(struct platform_device *pdev)
4832{
4833 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4834
4835 mmc_remove_host(mmc);
4836 mmc_free_host(mmc);
4837}
4838
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004839#ifdef CONFIG_MSM_SDIO_AL
4840int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4841{
4842 struct msmsdcc_host *host = mmc_priv(mmc);
4843 unsigned long flags;
4844
4845 spin_lock_irqsave(&host->lock, flags);
4846 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
4847 enable ? "En" : "Dis");
4848
4849 if (enable) {
4850 if (!host->sdcc_irq_disabled) {
4851 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05304852 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004853 host->sdcc_irq_disabled = 1;
4854 }
4855
4856 if (host->clks_on) {
4857 msmsdcc_setup_clocks(host, false);
4858 host->clks_on = 0;
4859 }
4860
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304861 if (host->plat->sdio_lpm_gpio_setup &&
4862 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004863 spin_unlock_irqrestore(&host->lock, flags);
4864 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
4865 spin_lock_irqsave(&host->lock, flags);
4866 host->sdio_gpio_lpm = 1;
4867 }
4868
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304869 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004870 msmsdcc_enable_irq_wake(host);
4871 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304872 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004873 }
4874 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304875 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004876 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304877 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004878 msmsdcc_disable_irq_wake(host);
4879 }
4880
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304881 if (host->plat->sdio_lpm_gpio_setup &&
4882 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004883 spin_unlock_irqrestore(&host->lock, flags);
4884 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
4885 spin_lock_irqsave(&host->lock, flags);
4886 host->sdio_gpio_lpm = 0;
4887 }
4888
4889 if (!host->clks_on) {
4890 msmsdcc_setup_clocks(host, true);
4891 host->clks_on = 1;
4892 }
4893
4894 if (host->sdcc_irq_disabled) {
4895 writel_relaxed(host->mci_irqenable,
4896 host->base + MMCIMASK0);
4897 mb();
4898 enable_irq(host->core_irqres->start);
4899 host->sdcc_irq_disabled = 0;
4900 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004901 }
4902 spin_unlock_irqrestore(&host->lock, flags);
4903 return 0;
4904}
4905#else
4906int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4907{
4908 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004909}
4910#endif
4911
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004912#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07004913static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004914msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004915{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004916 struct mmc_host *mmc = dev_get_drvdata(dev);
4917 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07004918 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304919 unsigned long flags;
4920
San Mehat9d2bd732009-09-22 16:44:22 -07004921
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004922 if (host->plat->is_sdio_al_client)
4923 return 0;
Sahitya Tummala7661a452011-07-18 13:28:35 +05304924 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004925 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004926 host->sdcc_suspending = 1;
4927 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07004928
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004929 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004930 * MMC core thinks that host is disabled by now since
4931 * runtime suspend is scheduled after msmsdcc_disable()
4932 * is called. Thus, MMC core will try to enable the host
4933 * while suspending it. This results in a synchronous
4934 * runtime resume request while in runtime suspending
4935 * context and hence inorder to complete this resume
4936 * requet, it will wait for suspend to be complete,
4937 * but runtime suspend also can not proceed further
4938 * until the host is resumed. Thus, it leads to a hang.
4939 * Hence, increase the pm usage count before suspending
4940 * the host so that any resume requests after this will
4941 * simple become pm usage counter increment operations.
4942 */
4943 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05304944 /* If there is pending detect work abort runtime suspend */
4945 if (unlikely(work_busy(&mmc->detect.work)))
4946 rc = -EAGAIN;
4947 else
4948 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004949 pm_runtime_put_noidle(dev);
4950
4951 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304952 spin_lock_irqsave(&host->lock, flags);
4953 host->sdcc_suspended = true;
4954 spin_unlock_irqrestore(&host->lock, flags);
4955 if (mmc->card && mmc_card_sdio(mmc->card) &&
4956 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004957 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304958 * If SDIO function driver doesn't want
4959 * to power off the card, atleast turn off
4960 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004961 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304962 mmc_host_clk_hold(mmc);
4963 spin_lock_irqsave(&mmc->clk_lock, flags);
4964 mmc->clk_old = mmc->ios.clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004965 mmc->ios.clock = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304966 mmc->clk_gated = true;
4967 spin_unlock_irqrestore(&mmc->clk_lock, flags);
4968 mmc_set_ios(mmc);
4969 mmc_host_clk_release(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004970 }
4971 }
4972 host->sdcc_suspending = 0;
4973 mmc->suspend_task = NULL;
4974 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
4975 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004976 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05304977 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
San Mehat9d2bd732009-09-22 16:44:22 -07004978 return rc;
4979}
4980
4981static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004982msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004983{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004984 struct mmc_host *mmc = dev_get_drvdata(dev);
4985 struct msmsdcc_host *host = mmc_priv(mmc);
4986 unsigned long flags;
4987
4988 if (host->plat->is_sdio_al_client)
4989 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07004990
Sahitya Tummala7661a452011-07-18 13:28:35 +05304991 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004992 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304993 if (mmc->card && mmc_card_sdio(mmc->card) &&
4994 mmc_card_keep_power(mmc)) {
4995 mmc_host_clk_hold(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304996 mmc->ios.clock = host->clk_rate;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304997 mmc_set_ios(mmc);
4998 mmc_host_clk_release(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304999 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005000
5001 mmc_resume_host(mmc);
5002
5003 /*
5004 * FIXME: Clearing of flags must be handled in clients
5005 * resume handler.
5006 */
5007 spin_lock_irqsave(&host->lock, flags);
5008 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305009 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005010 spin_unlock_irqrestore(&host->lock, flags);
5011
5012 /*
5013 * After resuming the host wait for sometime so that
5014 * the SDIO work will be processed.
5015 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305016 if (mmc->card && mmc_card_sdio(mmc->card)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005017 if ((host->plat->cfg_mpm_sdiowakeup ||
5018 host->plat->sdiowakeup_irq) &&
5019 wake_lock_active(&host->sdio_wlock))
5020 wake_lock_timeout(&host->sdio_wlock, 1);
5021 }
5022
5023 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005024 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05305025 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005026 return 0;
5027}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005028
5029static int msmsdcc_runtime_idle(struct device *dev)
5030{
5031 struct mmc_host *mmc = dev_get_drvdata(dev);
5032 struct msmsdcc_host *host = mmc_priv(mmc);
5033
5034 if (host->plat->is_sdio_al_client)
5035 return 0;
5036
5037 /* Idle timeout is not configurable for now */
5038 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
5039
5040 return -EAGAIN;
5041}
5042
5043static int msmsdcc_pm_suspend(struct device *dev)
5044{
5045 struct mmc_host *mmc = dev_get_drvdata(dev);
5046 struct msmsdcc_host *host = mmc_priv(mmc);
5047 int rc = 0;
5048
5049 if (host->plat->is_sdio_al_client)
5050 return 0;
5051
5052
5053 if (host->plat->status_irq)
5054 disable_irq(host->plat->status_irq);
5055
5056 if (!pm_runtime_suspended(dev))
5057 rc = msmsdcc_runtime_suspend(dev);
5058
5059 return rc;
5060}
5061
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305062static int msmsdcc_suspend_noirq(struct device *dev)
5063{
5064 struct mmc_host *mmc = dev_get_drvdata(dev);
5065 struct msmsdcc_host *host = mmc_priv(mmc);
5066 int rc = 0;
5067
5068 /*
5069 * After platform suspend there may be active request
5070 * which might have enabled clocks. For example, in SDIO
5071 * case, ksdioirq thread might have scheduled after sdcc
5072 * suspend but before system freeze. In that case abort
5073 * suspend and retry instead of keeping the clocks on
5074 * during suspend and not allowing TCXO.
5075 */
5076
5077 if (host->clks_on) {
5078 pr_warn("%s: clocks are on after suspend, aborting system "
5079 "suspend\n", mmc_hostname(mmc));
5080 rc = -EAGAIN;
5081 }
5082
5083 return rc;
5084}
5085
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005086static int msmsdcc_pm_resume(struct device *dev)
5087{
5088 struct mmc_host *mmc = dev_get_drvdata(dev);
5089 struct msmsdcc_host *host = mmc_priv(mmc);
5090 int rc = 0;
5091
5092 if (host->plat->is_sdio_al_client)
5093 return 0;
5094
Sahitya Tummalafb486372011-09-02 19:01:49 +05305095 if (!pm_runtime_suspended(dev))
5096 rc = msmsdcc_runtime_resume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005097 if (host->plat->status_irq) {
5098 msmsdcc_check_status((unsigned long)host);
5099 enable_irq(host->plat->status_irq);
5100 }
5101
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005102 return rc;
5103}
5104
Daniel Walker08ecfde2010-06-23 12:32:20 -07005105#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005106#define msmsdcc_runtime_suspend NULL
5107#define msmsdcc_runtime_resume NULL
5108#define msmsdcc_runtime_idle NULL
5109#define msmsdcc_pm_suspend NULL
5110#define msmsdcc_pm_resume NULL
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305111#define msmsdcc_suspend_noirq NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07005112#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005113
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005114static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
5115 .runtime_suspend = msmsdcc_runtime_suspend,
5116 .runtime_resume = msmsdcc_runtime_resume,
5117 .runtime_idle = msmsdcc_runtime_idle,
5118 .suspend = msmsdcc_pm_suspend,
5119 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305120 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005121};
5122
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305123static const struct of_device_id msmsdcc_dt_match[] = {
5124 {.compatible = "qcom,msm-sdcc"},
5125
5126};
5127MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
5128
San Mehat9d2bd732009-09-22 16:44:22 -07005129static struct platform_driver msmsdcc_driver = {
5130 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005131 .remove = msmsdcc_remove,
Oluwafemi Adeyemif68d3e62012-03-13 11:46:49 -07005132 .shutdown = msmsdcc_shutdown,
San Mehat9d2bd732009-09-22 16:44:22 -07005133 .driver = {
5134 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005135 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305136 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07005137 },
5138};
5139
5140static int __init msmsdcc_init(void)
5141{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005142#if defined(CONFIG_DEBUG_FS)
5143 int ret = 0;
5144 ret = msmsdcc_dbg_init();
5145 if (ret) {
5146 pr_err("Failed to create debug fs dir \n");
5147 return ret;
5148 }
5149#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005150 return platform_driver_register(&msmsdcc_driver);
5151}
5152
5153static void __exit msmsdcc_exit(void)
5154{
5155 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005156
5157#if defined(CONFIG_DEBUG_FS)
5158 debugfs_remove(debugfs_file);
5159 debugfs_remove(debugfs_dir);
5160#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005161}
5162
5163module_init(msmsdcc_init);
5164module_exit(msmsdcc_exit);
5165
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005166MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07005167MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005168
5169#if defined(CONFIG_DEBUG_FS)
5170
5171static int
5172msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
5173{
5174 file->private_data = inode->i_private;
5175 return 0;
5176}
5177
5178static ssize_t
5179msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
5180 size_t count, loff_t *ppos)
5181{
5182 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08005183 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005184 int max, i;
5185
5186 i = 0;
5187 max = sizeof(buf) - 1;
5188
5189 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
5190 host->curr.cmd, host->curr.data);
5191 if (host->curr.cmd) {
5192 struct mmc_command *cmd = host->curr.cmd;
5193
5194 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
5195 cmd->opcode, cmd->arg, cmd->flags);
5196 }
5197 if (host->curr.data) {
5198 struct mmc_data *data = host->curr.data;
5199 i += scnprintf(buf + i, max - i,
5200 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
5201 data->timeout_ns, data->timeout_clks,
5202 data->blksz, data->blocks, data->error,
5203 data->flags);
5204 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
5205 host->curr.xfer_size, host->curr.xfer_remain,
5206 host->curr.data_xfered, host->dma.sg);
5207 }
5208
5209 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
5210}
5211
5212static const struct file_operations msmsdcc_dbg_state_ops = {
5213 .read = msmsdcc_dbg_state_read,
5214 .open = msmsdcc_dbg_state_open,
5215};
5216
5217static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
5218{
5219 if (debugfs_dir) {
5220 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
5221 0644, debugfs_dir, host,
5222 &msmsdcc_dbg_state_ops);
5223 }
5224}
5225
5226static int __init msmsdcc_dbg_init(void)
5227{
5228 int err;
5229
5230 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
5231 if (IS_ERR(debugfs_dir)) {
5232 err = PTR_ERR(debugfs_dir);
5233 debugfs_dir = NULL;
5234 return err;
5235 }
5236
5237 return 0;
5238}
5239#endif