blob: 2a2290ba7e64888897bac7acba66c0a614d0b976 [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
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302231 if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
2232 sel_clk = msmsdcc_get_min_sup_clk_rate(host);
2233 goto out;
2234 }
2235
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002236 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2237 unsigned char cnt;
2238
2239 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2240 if (host->plat->sup_clk_table[cnt] > req_clk)
2241 break;
2242 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2243 sel_clk = host->plat->sup_clk_table[cnt];
2244 break;
2245 } else
2246 sel_clk = host->plat->sup_clk_table[cnt];
2247 }
2248 } else {
2249 if ((req_clk < host->plat->msmsdcc_fmax) &&
2250 (req_clk > host->plat->msmsdcc_fmid))
2251 sel_clk = host->plat->msmsdcc_fmid;
2252 else
2253 sel_clk = req_clk;
2254 }
2255
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302256out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002257 return sel_clk;
2258}
2259
2260static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2261 struct msmsdcc_host *host)
2262{
2263 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2264 return host->plat->sup_clk_table[0];
2265 else
2266 return host->plat->msmsdcc_fmin;
2267}
2268
2269static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2270 struct msmsdcc_host *host)
2271{
2272 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2273 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2274 else
2275 return host->plat->msmsdcc_fmax;
2276}
2277
2278static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302279{
2280 struct msm_mmc_gpio_data *curr;
2281 int i, rc = 0;
2282
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002283 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302284 for (i = 0; i < curr->size; i++) {
2285 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002286 if (curr->gpio[i].is_always_on &&
2287 curr->gpio[i].is_enabled)
2288 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302289 rc = gpio_request(curr->gpio[i].no,
2290 curr->gpio[i].name);
2291 if (rc) {
2292 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2293 mmc_hostname(host->mmc),
2294 curr->gpio[i].no,
2295 curr->gpio[i].name, rc);
2296 goto free_gpios;
2297 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002298 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302299 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002300 if (curr->gpio[i].is_always_on)
2301 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302302 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002303 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302304 }
2305 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002306 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302307
2308free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002309 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302310 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002311 curr->gpio[i].is_enabled = false;
2312 }
2313out:
2314 return rc;
2315}
2316
2317static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2318{
2319 struct msm_mmc_pad_data *curr;
2320 int i;
2321
2322 curr = host->plat->pin_data->pad_data;
2323 for (i = 0; i < curr->drv->size; i++) {
2324 if (enable)
2325 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2326 curr->drv->on[i].val);
2327 else
2328 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2329 curr->drv->off[i].val);
2330 }
2331
2332 for (i = 0; i < curr->pull->size; i++) {
2333 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002334 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002335 curr->pull->on[i].val);
2336 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002337 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002338 curr->pull->off[i].val);
2339 }
2340
2341 return 0;
2342}
2343
2344static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2345{
2346 int rc = 0;
2347
2348 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2349 return 0;
2350
2351 if (host->plat->pin_data->is_gpio)
2352 rc = msmsdcc_setup_gpio(host, enable);
2353 else
2354 rc = msmsdcc_setup_pad(host, enable);
2355
2356 if (!rc)
2357 host->plat->pin_data->cfg_sts = enable;
2358
2359 return rc;
2360}
2361
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302362static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2363{
2364 u32 pwr = 0;
2365 int ret = 0;
2366 struct mmc_host *mmc = host->mmc;
2367
2368 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2369 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2370 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2371 ret = msmsdcc_setup_vreg(host, !!ios->vdd);
2372
2373 if (ret) {
2374 pr_err("%s: Failed to setup voltage regulators\n",
2375 mmc_hostname(host->mmc));
2376 goto out;
2377 }
2378
2379 switch (ios->power_mode) {
2380 case MMC_POWER_OFF:
2381 pwr = MCI_PWR_OFF;
2382 if (host->plat->cfg_mpm_sdiowakeup)
2383 host->plat->cfg_mpm_sdiowakeup(
2384 mmc_dev(mmc), SDC_DAT1_DISABLE);
2385 /*
2386 * As VDD pad rail is always on, set low voltage for VDD
2387 * pad rail when slot is unused (when card is not present
2388 * or during system suspend).
2389 */
2390 msmsdcc_set_vddp_low_vol(host);
2391 msmsdcc_setup_pins(host, false);
2392 break;
2393 case MMC_POWER_UP:
2394 /* writing PWR_UP bit is redundant */
2395 pwr = MCI_PWR_UP;
2396 if (host->plat->cfg_mpm_sdiowakeup)
2397 host->plat->cfg_mpm_sdiowakeup(
2398 mmc_dev(mmc), SDC_DAT1_ENABLE);
2399
2400 msmsdcc_set_vddp_high_vol(host);
2401 msmsdcc_setup_pins(host, true);
2402 break;
2403 case MMC_POWER_ON:
2404 pwr = MCI_PWR_ON;
2405 break;
2406 }
2407
2408out:
2409 return pwr;
2410}
2411
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002412static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2413{
2414 unsigned int wakeup_irq;
2415
2416 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2417 host->plat->sdiowakeup_irq :
2418 host->core_irqres->start;
2419
2420 if (!host->irq_wake_enabled) {
2421 enable_irq_wake(wakeup_irq);
2422 host->irq_wake_enabled = true;
2423 }
2424}
2425
2426static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2427{
2428 unsigned int wakeup_irq;
2429
2430 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2431 host->plat->sdiowakeup_irq :
2432 host->core_irqres->start;
2433
2434 if (host->irq_wake_enabled) {
2435 disable_irq_wake(wakeup_irq);
2436 host->irq_wake_enabled = false;
2437 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302438}
2439
San Mehat9d2bd732009-09-22 16:44:22 -07002440static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302441msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
2442{
2443 struct mmc_host *mmc = host->mmc;
2444
2445 /*
2446 * SDIO_AL clients has different mechanism of handling LPM through
2447 * sdio_al driver itself. The sdio wakeup interrupt is configured as
2448 * part of that. Here, we are interested only in clients like WLAN.
2449 */
2450 if (!(mmc->card && mmc_card_sdio(mmc->card))
2451 || host->plat->is_sdio_al_client)
2452 goto out;
2453
2454 if (!host->sdcc_suspended) {
2455 /*
2456 * When MSM is not in power collapse and we
2457 * are disabling clocks, enable bit 22 in MASK0
2458 * to handle asynchronous SDIO interrupts.
2459 */
2460 if (enable_wakeup_irq)
2461 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
2462 else
2463 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
2464 mb();
2465 goto out;
2466 } else if (!mmc_card_wake_sdio_irq(mmc)) {
2467 /*
2468 * Wakeup MSM only if SDIO function drivers set
2469 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
2470 */
2471 goto out;
2472 }
2473
2474 if (enable_wakeup_irq) {
2475 if (!host->plat->sdiowakeup_irq) {
2476 /*
2477 * When there is no gpio line that can be configured
2478 * as wakeup interrupt handle it by configuring
2479 * asynchronous sdio interrupts and DAT1 line.
2480 */
2481 writel_relaxed(MCI_SDIOINTMASK,
2482 host->base + MMCIMASK0);
2483 mb();
2484 if (host->plat->cfg_mpm_sdiowakeup)
2485 host->plat->cfg_mpm_sdiowakeup(
2486 mmc_dev(mmc), SDC_DAT1_ENWAKE);
2487 /* configure sdcc core interrupt as wakeup interrupt */
2488 msmsdcc_enable_irq_wake(host);
2489 } else {
2490 /* Let gpio line handle wakeup interrupt */
2491 writel_relaxed(0, host->base + MMCIMASK0);
2492 mb();
2493 if (host->sdio_wakeupirq_disabled) {
2494 host->sdio_wakeupirq_disabled = 0;
2495 /* configure gpio line as wakeup interrupt */
2496 msmsdcc_enable_irq_wake(host);
2497 enable_irq(host->plat->sdiowakeup_irq);
2498 }
2499 }
2500 } else {
2501 if (!host->plat->sdiowakeup_irq) {
2502 /*
2503 * We may not have cleared bit 22 in the interrupt
2504 * handler as the clocks might be off at that time.
2505 */
2506 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
2507 mb();
2508 if (host->plat->cfg_mpm_sdiowakeup)
2509 host->plat->cfg_mpm_sdiowakeup(
2510 mmc_dev(mmc), SDC_DAT1_DISWAKE);
2511 msmsdcc_disable_irq_wake(host);
2512 } else if (!host->sdio_wakeupirq_disabled) {
2513 disable_irq_nosync(host->plat->sdiowakeup_irq);
2514 msmsdcc_disable_irq_wake(host);
2515 host->sdio_wakeupirq_disabled = 1;
2516 }
2517 }
2518out:
2519 return;
2520}
2521
2522static void
San Mehat9d2bd732009-09-22 16:44:22 -07002523msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2524{
2525 struct msmsdcc_host *host = mmc_priv(mmc);
2526 u32 clk = 0, pwr = 0;
2527 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002528 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002529 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002530
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002531 DBG(host, "ios->clock = %u\n", ios->clock);
Sahitya Tummala7a892482011-01-18 11:22:49 +05302532
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302533 /*
2534 * Disable SDCC core interrupt until set_ios is completed.
2535 * This avoids any race conditions with interrupt raised
2536 * when turning on/off the clocks. One possible
2537 * scenario is SDIO operational interrupt while the clock
2538 * is turned off.
2539 */
2540
2541 spin_lock_irqsave(&host->lock, flags);
2542 if (!host->sdcc_irq_disabled) {
2543 spin_unlock_irqrestore(&host->lock, flags);
2544 disable_irq(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002545 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302546 host->sdcc_irq_disabled = 1;
2547 }
2548 spin_unlock_irqrestore(&host->lock, flags);
2549
2550 pwr = msmsdcc_setup_pwr(host, ios);
2551
2552 spin_lock_irqsave(&host->lock, flags);
2553 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002554 if (!host->clks_on) {
2555 msmsdcc_setup_clocks(host, true);
2556 host->clks_on = 1;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302557 writel_relaxed(host->mci_irqenable,
2558 host->base + MMCIMASK0);
2559 mb();
2560 msmsdcc_cfg_sdio_wakeup(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002561 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002562
2563 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2564 /*
2565 * For DDR50 mode, controller needs clock rate to be
2566 * double than what is required on the SD card CLK pin.
2567 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302568 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002569 /*
2570 * Make sure that we don't double the clock if
2571 * doubled clock rate is already set
2572 */
2573 if (!host->ddr_doubled_clk_rate ||
2574 (host->ddr_doubled_clk_rate &&
2575 (host->ddr_doubled_clk_rate != ios->clock))) {
2576 host->ddr_doubled_clk_rate =
2577 msmsdcc_get_sup_clk_rate(
2578 host, (ios->clock * 2));
2579 clock = host->ddr_doubled_clk_rate;
2580 }
2581 } else {
2582 host->ddr_doubled_clk_rate = 0;
2583 }
2584
2585 if (clock != host->clk_rate) {
2586 rc = clk_set_rate(host->clk, clock);
2587 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302588 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002589 mmc_hostname(mmc), clock);
2590 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302591 host->reg_write_delay =
2592 (1 + ((3 * USEC_PER_SEC) /
2593 (host->clk_rate ? host->clk_rate :
2594 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002595 }
2596 /*
2597 * give atleast 2 MCLK cycles delay for clocks
2598 * and SDCC core to stabilize
2599 */
2600 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002601 clk |= MCI_CLK_ENABLE;
2602 }
2603
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002604 if (ios->bus_width == MMC_BUS_WIDTH_8)
2605 clk |= MCI_CLK_WIDEBUS_8;
2606 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2607 clk |= MCI_CLK_WIDEBUS_4;
2608 else
2609 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002610
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002611 if (msmsdcc_is_pwrsave(host))
2612 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002613
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002614 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002615
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002616 host->tuning_needed = 0;
2617 /*
2618 * Select the controller timing mode according
2619 * to current bus speed mode
2620 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302621 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2622 (ios->timing == MMC_TIMING_MMC_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002623 clk |= (4 << 14);
2624 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302625 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002626 clk |= (3 << 14);
2627 } else {
2628 clk |= (2 << 14); /* feedback clock */
2629 }
2630
2631 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2632 clk |= (2 << 23);
2633
Subhash Jadavani00083572012-02-15 16:18:01 +05302634 /* Clear IO_PAD_PWR_SWITCH while powering off the card */
2635 if (!ios->vdd)
2636 host->io_pad_pwr_switch = 0;
2637
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002638 if (host->io_pad_pwr_switch)
2639 clk |= IO_PAD_PWR_SWITCH;
2640
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302641 /* Don't write into registers if clocks are disabled */
2642 if (host->clks_on) {
2643 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
2644 writel_relaxed(clk, host->base + MMCICLOCK);
2645 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002646 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302647 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
2648 host->pwr = pwr;
2649 writel_relaxed(pwr, host->base + MMCIPOWER);
2650 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002651 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002652 }
2653
2654 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302655 msmsdcc_cfg_sdio_wakeup(host, true);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002656 msmsdcc_setup_clocks(host, false);
2657 host->clks_on = 0;
2658 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302659
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302660 if (host->tuning_in_progress)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302661 WARN(!host->clks_on,
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302662 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302663
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302664 /* Let interrupts be disabled if the host is powered off */
2665 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
2666 enable_irq(host->core_irqres->start);
2667 host->sdcc_irq_disabled = 0;
2668 }
2669
San Mehat4adbbcc2009-11-08 13:00:37 -08002670 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002671}
2672
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002673int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2674{
2675 struct msmsdcc_host *host = mmc_priv(mmc);
2676 u32 clk;
2677
2678 clk = readl_relaxed(host->base + MMCICLOCK);
2679 pr_debug("Changing to pwr_save=%d", pwrsave);
2680 if (pwrsave && msmsdcc_is_pwrsave(host))
2681 clk |= MCI_CLK_PWRSAVE;
2682 else
2683 clk &= ~MCI_CLK_PWRSAVE;
2684 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302685 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002686
2687 return 0;
2688}
2689
2690static int msmsdcc_get_ro(struct mmc_host *mmc)
2691{
2692 int status = -ENOSYS;
2693 struct msmsdcc_host *host = mmc_priv(mmc);
2694
2695 if (host->plat->wpswitch) {
2696 status = host->plat->wpswitch(mmc_dev(mmc));
2697 } else if (host->plat->wpswitch_gpio) {
2698 status = gpio_request(host->plat->wpswitch_gpio,
2699 "SD_WP_Switch");
2700 if (status) {
2701 pr_err("%s: %s: Failed to request GPIO %d\n",
2702 mmc_hostname(mmc), __func__,
2703 host->plat->wpswitch_gpio);
2704 } else {
2705 status = gpio_direction_input(
2706 host->plat->wpswitch_gpio);
2707 if (!status) {
2708 /*
2709 * Wait for atleast 300ms as debounce
2710 * time for GPIO input to stabilize.
2711 */
2712 msleep(300);
2713 status = gpio_get_value_cansleep(
2714 host->plat->wpswitch_gpio);
2715 status ^= !host->plat->wpswitch_polarity;
2716 }
2717 gpio_free(host->plat->wpswitch_gpio);
2718 }
2719 }
2720
2721 if (status < 0)
2722 status = -ENOSYS;
2723 pr_debug("%s: Card read-only status %d\n", __func__, status);
2724
2725 return status;
2726}
2727
2728#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002729static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2730{
2731 struct msmsdcc_host *host = mmc_priv(mmc);
2732 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002733
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302734 /*
2735 * We may come here with clocks turned off in that case don't
2736 * attempt to write into MASK0 register. While turning on the
2737 * clocks mci_irqenable will be written to MASK0 register.
2738 */
2739
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002740 if (enable) {
2741 spin_lock_irqsave(&host->lock, flags);
2742 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302743 if (host->clks_on) {
2744 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002745 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302746 mb();
2747 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002748 spin_unlock_irqrestore(&host->lock, flags);
2749 } else {
2750 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302751 if (host->clks_on) {
2752 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002753 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302754 mb();
2755 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002756 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002757}
2758#endif /* CONFIG_MMC_MSM_SDIO_SUPPORT */
2759
2760#ifdef CONFIG_PM_RUNTIME
2761static int msmsdcc_enable(struct mmc_host *mmc)
2762{
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302763 int rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002764 struct device *dev = mmc->parent;
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302765 struct msmsdcc_host *host = mmc_priv(mmc);
2766
2767 msmsdcc_pm_qos_update_latency(host, 1);
2768
2769 if (mmc->card && mmc_card_sdio(mmc->card) && host->is_resumed)
2770 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002771
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302772 if (dev->power.runtime_status == RPM_SUSPENDING) {
2773 if (mmc->suspend_task == current) {
2774 pm_runtime_get_noresume(dev);
2775 goto out;
2776 }
2777 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002778
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302779 rc = pm_runtime_get_sync(dev);
2780
2781 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002782 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2783 __func__, rc);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302784 return rc;
2785 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302786
2787 host->is_resumed = true;
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302788out:
2789 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002790}
2791
2792static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2793{
2794 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302795 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002796
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302797 msmsdcc_pm_qos_update_latency(host, 0);
2798
2799 if (mmc->card && mmc_card_sdio(mmc->card))
2800 return 0;
2801
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302802 if (host->plat->disable_runtime_pm)
2803 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002804
2805 rc = pm_runtime_put_sync(mmc->parent);
2806
2807 if (rc < 0)
2808 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2809 __func__, rc);
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302810 else
2811 host->is_resumed = false;
2812
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002813 return rc;
2814}
2815#else
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302816static int msmsdcc_enable(struct mmc_host *mmc)
2817{
2818 struct msmsdcc_host *host = mmc_priv(mmc);
2819 unsigned long flags;
2820
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302821 msmsdcc_pm_qos_update_latency(host, 1);
2822
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302823 spin_lock_irqsave(&host->lock, flags);
2824 if (!host->clks_on) {
2825 msmsdcc_setup_clocks(host, true);
2826 host->clks_on = 1;
2827 }
2828 spin_unlock_irqrestore(&host->lock, flags);
2829
2830 return 0;
2831}
2832
2833static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2834{
2835 struct msmsdcc_host *host = mmc_priv(mmc);
2836 unsigned long flags;
2837
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302838 msmsdcc_pm_qos_update_latency(host, 0);
2839
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302840 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302841 return 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302842
2843 spin_lock_irqsave(&host->lock, flags);
2844 if (host->clks_on) {
2845 msmsdcc_setup_clocks(host, false);
2846 host->clks_on = 0;
2847 }
2848 spin_unlock_irqrestore(&host->lock, flags);
2849
2850 return 0;
2851}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002852#endif
2853
2854static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2855 struct mmc_ios *ios)
2856{
2857 struct msmsdcc_host *host = mmc_priv(mmc);
2858 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302859 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002860
Subhash Jadavani00083572012-02-15 16:18:01 +05302861 spin_lock_irqsave(&host->lock, flags);
2862 host->io_pad_pwr_switch = 0;
2863 spin_unlock_irqrestore(&host->lock, flags);
2864
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302865 /*
2866 * For eMMC cards, VccQ voltage range must be changed
2867 * only if it operates in HS200 SDR 1.2V mode or in
2868 * DDR 1.2V mode.
2869 */
2870 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_120) {
2871 rc = msmsdcc_set_vccq_vol(host, 1200000);
2872 goto out;
2873 }
2874
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002875 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2876 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302877 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002878 goto out;
2879 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2880 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302881 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002882 goto out;
2883 }
San Mehat9d2bd732009-09-22 16:44:22 -07002884
2885 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002886 /*
2887 * If we are here means voltage switch from high voltage to
2888 * low voltage is required
2889 */
2890
2891 /*
2892 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2893 * register until they become all zeros.
2894 */
2895 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302896 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002897 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2898 mmc_hostname(mmc), __func__);
2899 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002900 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002901
2902 /* Stop SD CLK output. */
2903 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2904 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302905 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002906 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002907
2908 /*
2909 * Switch VDDPX from high voltage to low voltage
2910 * to change the VDD of the SD IO pads.
2911 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302912 rc = msmsdcc_set_vddp_low_vol(host);
2913 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002914 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002915
2916 spin_lock_irqsave(&host->lock, flags);
2917 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2918 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302919 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002920 host->io_pad_pwr_switch = 1;
2921 spin_unlock_irqrestore(&host->lock, flags);
2922
2923 /* Wait 5 ms for the voltage regulater in the card to become stable. */
2924 usleep_range(5000, 5500);
2925
2926 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302927 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002928 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2929 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302930 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002931 spin_unlock_irqrestore(&host->lock, flags);
2932
2933 /*
2934 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
2935 * don't become all ones within 1 ms then a Voltage Switch
2936 * sequence has failed and a power cycle to the card is required.
2937 * Otherwise Voltage Switch sequence is completed successfully.
2938 */
2939 usleep_range(1000, 1500);
2940
2941 spin_lock_irqsave(&host->lock, flags);
2942 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
2943 != (0xF << 1)) {
2944 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
2945 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302946 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002947 goto out_unlock;
2948 }
2949
2950out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302951 /* Enable PWRSAVE */
2952 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2953 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002954 spin_unlock_irqrestore(&host->lock, flags);
2955out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302956 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002957}
2958
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302959static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002960{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002961 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002962
2963 /* Program the MCLK value to MCLK_FREQ bit field */
2964 if (host->clk_rate <= 112000000)
2965 mclk_freq = 0;
2966 else if (host->clk_rate <= 125000000)
2967 mclk_freq = 1;
2968 else if (host->clk_rate <= 137000000)
2969 mclk_freq = 2;
2970 else if (host->clk_rate <= 150000000)
2971 mclk_freq = 3;
2972 else if (host->clk_rate <= 162000000)
2973 mclk_freq = 4;
2974 else if (host->clk_rate <= 175000000)
2975 mclk_freq = 5;
2976 else if (host->clk_rate <= 187000000)
2977 mclk_freq = 6;
2978 else if (host->clk_rate <= 200000000)
2979 mclk_freq = 7;
2980
2981 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2982 & ~(7 << 24)) | (mclk_freq << 24)),
2983 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002984}
2985
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302986/* Initialize the DLL (Programmable Delay Line ) */
2987static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002988{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002989 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302990 unsigned long flags;
2991 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002992
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302993 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002994 /*
2995 * Make sure that clock is always enabled when DLL
2996 * tuning is in progress. Keeping PWRSAVE ON may
2997 * turn off the clock. So let's disable the PWRSAVE
2998 * here and re-enable it once tuning is completed.
2999 */
3000 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3001 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303002
3003 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3004 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3005 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3006
3007 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3008 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3009 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3010
3011 msmsdcc_cm_sdc4_dll_set_freq(host);
3012
3013 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3014 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3015 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3016
3017 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3018 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3019 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3020
3021 /* Set DLL_EN bit to 1. */
3022 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3023 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3024
3025 /* Set CK_OUT_EN bit to 1. */
3026 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3027 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3028
3029 wait_cnt = 50;
3030 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3031 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3032 /* max. wait for 50us sec for LOCK bit to be set */
3033 if (--wait_cnt == 0) {
3034 pr_err("%s: %s: DLL failed to LOCK\n",
3035 mmc_hostname(host->mmc), __func__);
3036 rc = -ETIMEDOUT;
3037 goto out;
3038 }
3039 /* wait for 1us before polling again */
3040 udelay(1);
3041 }
3042
3043out:
3044 /* re-enable PWRSAVE */
3045 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3046 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
3047 spin_unlock_irqrestore(&host->lock, flags);
3048
3049 return rc;
3050}
3051
3052static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3053 u8 poll)
3054{
3055 int rc = 0;
3056 u32 wait_cnt = 50;
3057 u8 ck_out_en = 0;
3058
3059 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3060 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3061 MCI_CK_OUT_EN);
3062
3063 while (ck_out_en != poll) {
3064 if (--wait_cnt == 0) {
3065 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3066 mmc_hostname(host->mmc), __func__, poll);
3067 rc = -ETIMEDOUT;
3068 goto out;
3069 }
3070 udelay(1);
3071
3072 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3073 MCI_CK_OUT_EN);
3074 }
3075out:
3076 return rc;
3077}
3078
3079/*
3080 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3081 * calibration sequence. This function should be called before
3082 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3083 * commands (CMD17/CMD18).
3084 *
3085 * This function gets called when host spinlock acquired.
3086 */
3087static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3088{
3089 int rc = 0;
3090 u32 config;
3091
3092 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3093 config |= MCI_CDR_EN;
3094 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3095 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3096
3097 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3098 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3099 if (rc)
3100 goto err_out;
3101
3102 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3103 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3104 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3105
3106 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3107 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3108 if (rc)
3109 goto err_out;
3110
3111 goto out;
3112
3113err_out:
3114 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3115out:
3116 return rc;
3117}
3118
3119static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3120 u8 phase)
3121{
3122 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303123 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3124 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3125 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303126 unsigned long flags;
3127 u32 config;
3128
3129 spin_lock_irqsave(&host->lock, flags);
3130
3131 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3132 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3133 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3134 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3135
3136 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3137 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3138 if (rc)
3139 goto err_out;
3140
3141 /*
3142 * Write the selected DLL clock output phase (0 ... 15)
3143 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
3144 */
3145 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3146 & ~(0xF << 20))
3147 | (grey_coded_phase_table[phase] << 20)),
3148 host->base + MCI_DLL_CONFIG);
3149
3150 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3151 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3152 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3153
3154 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3155 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3156 if (rc)
3157 goto err_out;
3158
3159 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3160 config |= MCI_CDR_EN;
3161 config &= ~MCI_CDR_EXT_EN;
3162 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3163 goto out;
3164
3165err_out:
3166 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3167 mmc_hostname(host->mmc), __func__, phase);
3168out:
3169 spin_unlock_irqrestore(&host->lock, flags);
3170 return rc;
3171}
3172
3173/*
3174 * Find out the greatest range of consecuitive selected
3175 * DLL clock output phases that can be used as sampling
3176 * setting for SD3.0 UHS-I card read operation (in SDR104
3177 * timing mode) or for eMMC4.5 card read operation (in HS200
3178 * timing mode).
3179 * Select the 3/4 of the range and configure the DLL with the
3180 * selected DLL clock output phase.
3181*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303182static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303183 u8 *phase_table, u8 total_phases)
3184{
Subhash Jadavani34187042012-03-02 10:59:49 +05303185 int ret;
3186 u8 ranges[16][16] = { {0}, {0} };
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303187 u8 phases_per_row[16] = {0};
3188 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303189 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3190 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303191
Subhash Jadavani34187042012-03-02 10:59:49 +05303192 if (total_phases > 16) {
3193 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3194 mmc_hostname(host->mmc), __func__, total_phases);
3195 return -EINVAL;
3196 }
3197
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303198 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303199 ranges[row_index][col_index] = phase_table[cnt];
3200 phases_per_row[row_index] += 1;
3201 col_index++;
3202
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303203 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303204 continue;
3205 /* check if next phase in phase_table is consecutive or not */
3206 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3207 row_index++;
3208 col_index = 0;
3209 }
3210 }
3211
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303212 /* Check if phase-0 is present in first valid window? */
3213 if (!ranges[0][0]) {
3214 phase_0_found = true;
3215 phase_0_raw_index = 0;
3216 /* Check if cycle exist between 2 valid windows */
3217 for (cnt = 1; cnt <= row_index; cnt++) {
3218 if (phases_per_row[cnt]) {
3219 for (i = 0; i <= phases_per_row[cnt]; i++) {
3220 if (ranges[cnt][i] == 15) {
3221 phase_15_found = true;
3222 phase_15_raw_index = cnt;
3223 break;
3224 }
3225 }
3226 }
3227 }
3228 }
3229
3230 /* If 2 valid windows form cycle then merge them as single window */
3231 if (phase_0_found && phase_15_found) {
3232 /* number of phases in raw where phase 0 is present */
3233 u8 phases_0 = phases_per_row[phase_0_raw_index];
3234 /* number of phases in raw where phase 15 is present */
3235 u8 phases_15 = phases_per_row[phase_15_raw_index];
3236
3237 cnt = 0;
3238 for (i = phases_15; i < (phases_15 + phases_0); i++) {
3239 ranges[phase_15_raw_index][i] =
3240 ranges[phase_0_raw_index][cnt];
3241 cnt++;
3242 }
3243 phases_per_row[phase_0_raw_index] = 0;
3244 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
3245 }
3246
3247 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303248 if (phases_per_row[cnt] > curr_max) {
3249 curr_max = phases_per_row[cnt];
3250 selected_row_index = cnt;
3251 }
3252 }
3253
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303254 i = ((curr_max * 3) / 4) - 1;
Subhash Jadavani34187042012-03-02 10:59:49 +05303255 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303256
3257 return ret;
3258}
3259
Girish K Sa3f41692012-02-29 12:00:09 +05303260static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303261{
3262 int rc = 0;
3263 struct msmsdcc_host *host = mmc_priv(mmc);
3264 unsigned long flags;
3265 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303266 const u32 *tuning_block_pattern = tuning_block_64;
3267 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303268
3269 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
3270
3271 /* Tuning is only required for SDR104 modes */
3272 if (!host->tuning_needed) {
3273 rc = 0;
3274 goto exit;
3275 }
3276
3277 spin_lock_irqsave(&host->lock, flags);
3278 WARN(!host->pwr, "SDCC power is turned off\n");
3279 WARN(!host->clks_on, "SDCC clocks are turned off\n");
3280 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
3281
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303282 host->tuning_in_progress = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05303283 msmsdcc_delay(host);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303284 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
3285 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
3286 tuning_block_pattern = tuning_block_128;
3287 size = sizeof(tuning_block_128);
3288 }
3289
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303290 spin_unlock_irqrestore(&host->lock, flags);
3291
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003292 /* first of all reset the tuning block */
3293 rc = msmsdcc_init_cm_sdc4_dll(host);
3294 if (rc)
3295 goto out;
3296
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303297 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003298 if (!data_buf) {
3299 rc = -ENOMEM;
3300 goto out;
3301 }
3302
3303 phase = 0;
3304 do {
3305 struct mmc_command cmd = {0};
3306 struct mmc_data data = {0};
3307 struct mmc_request mrq = {
3308 .cmd = &cmd,
3309 .data = &data
3310 };
3311 struct scatterlist sg;
3312
3313 /* set the phase in delay line hw block */
3314 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3315 if (rc)
3316 goto kfree;
3317
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303318 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003319 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
3320
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303321 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003322 data.blocks = 1;
3323 data.flags = MMC_DATA_READ;
3324 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
3325
3326 data.sg = &sg;
3327 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303328 sg_init_one(&sg, data_buf, size);
3329 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003330 mmc_wait_for_req(mmc, &mrq);
3331
3332 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303333 !memcmp(data_buf, tuning_block_pattern, size)) {
3334 /* tuning is successful at this tuning point */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003335 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303336 pr_debug("%s: %s: found good phase = %d\n",
3337 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003338 }
3339 } while (++phase < 16);
3340
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003341 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303342 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303343 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05303344 if (rc < 0)
3345 goto kfree;
3346 else
3347 phase = (u8)rc;
3348
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003349 /*
3350 * Finally set the selected phase in delay
3351 * line hw block.
3352 */
3353 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3354 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303355 goto kfree;
3356 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
3357 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003358 } else {
3359 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303360 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003361 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303362 msmsdcc_dump_sdcc_state(host);
3363 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003364 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003365
3366kfree:
3367 kfree(data_buf);
3368out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303369 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05303370 msmsdcc_delay(host);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303371 host->tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303372 spin_unlock_irqrestore(&host->lock, flags);
3373exit:
3374 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003375 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07003376}
3377
3378static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003379 .enable = msmsdcc_enable,
3380 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07003381 .request = msmsdcc_request,
3382 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003383 .get_ro = msmsdcc_get_ro,
3384#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07003385 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003386#endif
3387 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
3388 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07003389};
3390
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003391static unsigned int
3392msmsdcc_slot_status(struct msmsdcc_host *host)
3393{
3394 int status;
3395 unsigned int gpio_no = host->plat->status_gpio;
3396
3397 status = gpio_request(gpio_no, "SD_HW_Detect");
3398 if (status) {
3399 pr_err("%s: %s: Failed to request GPIO %d\n",
3400 mmc_hostname(host->mmc), __func__, gpio_no);
3401 } else {
3402 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003403 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08003404 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003405 if (host->plat->is_status_gpio_active_low)
3406 status = !status;
3407 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003408 gpio_free(gpio_no);
3409 }
3410 return status;
3411}
3412
San Mehat9d2bd732009-09-22 16:44:22 -07003413static void
3414msmsdcc_check_status(unsigned long data)
3415{
3416 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3417 unsigned int status;
3418
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003419 if (host->plat->status || host->plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08003420 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003421 status = host->plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08003422 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003423 status = msmsdcc_slot_status(host);
3424
Krishna Konda941604a2012-01-10 17:46:34 -08003425 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08003426
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003427 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08003428 if (host->plat->status)
3429 pr_info("%s: Slot status change detected "
3430 "(%d -> %d)\n",
3431 mmc_hostname(host->mmc),
3432 host->oldstat, status);
3433 else if (host->plat->is_status_gpio_active_low)
3434 pr_info("%s: Slot status change detected "
3435 "(%d -> %d) and the card detect GPIO"
3436 " is ACTIVE_LOW\n",
3437 mmc_hostname(host->mmc),
3438 host->oldstat, status);
3439 else
3440 pr_info("%s: Slot status change detected "
3441 "(%d -> %d) and the card detect GPIO"
3442 " is ACTIVE_HIGH\n",
3443 mmc_hostname(host->mmc),
3444 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07003445 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003446 }
3447 host->oldstat = status;
3448 } else {
3449 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07003450 }
San Mehat9d2bd732009-09-22 16:44:22 -07003451}
3452
3453static irqreturn_t
3454msmsdcc_platform_status_irq(int irq, void *dev_id)
3455{
3456 struct msmsdcc_host *host = dev_id;
3457
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003458 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07003459 msmsdcc_check_status((unsigned long) host);
3460 return IRQ_HANDLED;
3461}
3462
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003463static irqreturn_t
3464msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
3465{
3466 struct msmsdcc_host *host = dev_id;
3467
3468 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
3469 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303470 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003471 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303472 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003473 wake_lock(&host->sdio_wlock);
3474 msmsdcc_disable_irq_wake(host);
3475 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303476 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003477 }
3478 if (host->plat->is_sdio_al_client) {
3479 if (!host->clks_on) {
3480 msmsdcc_setup_clocks(host, true);
3481 host->clks_on = 1;
3482 }
3483 if (host->sdcc_irq_disabled) {
3484 writel_relaxed(host->mci_irqenable,
3485 host->base + MMCIMASK0);
3486 mb();
3487 enable_irq(host->core_irqres->start);
3488 host->sdcc_irq_disabled = 0;
3489 }
3490 wake_lock(&host->sdio_wlock);
3491 }
3492 spin_unlock(&host->lock);
3493
3494 return IRQ_HANDLED;
3495}
3496
San Mehat9d2bd732009-09-22 16:44:22 -07003497static void
3498msmsdcc_status_notify_cb(int card_present, void *dev_id)
3499{
3500 struct msmsdcc_host *host = dev_id;
3501
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003502 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07003503 card_present);
3504 msmsdcc_check_status((unsigned long) host);
3505}
3506
San Mehat9d2bd732009-09-22 16:44:22 -07003507static int
3508msmsdcc_init_dma(struct msmsdcc_host *host)
3509{
3510 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
3511 host->dma.host = host;
3512 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003513 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003514
3515 if (!host->dmares)
3516 return -ENODEV;
3517
3518 host->dma.nc = dma_alloc_coherent(NULL,
3519 sizeof(struct msmsdcc_nc_dmadata),
3520 &host->dma.nc_busaddr,
3521 GFP_KERNEL);
3522 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003523 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07003524 return -ENOMEM;
3525 }
3526 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
3527 host->dma.cmd_busaddr = host->dma.nc_busaddr;
3528 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
3529 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
3530 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07003531 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07003532
3533 return 0;
3534}
3535
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003536#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
3537/**
3538 * Allocate and Connect a SDCC peripheral's SPS endpoint
3539 *
3540 * This function allocates endpoint context and
3541 * connect it with memory endpoint by calling
3542 * appropriate SPS driver APIs.
3543 *
3544 * Also registers a SPS callback function with
3545 * SPS driver
3546 *
3547 * This function should only be called once typically
3548 * during driver probe.
3549 *
3550 * @host - Pointer to sdcc host structure
3551 * @ep - Pointer to sps endpoint data structure
3552 * @is_produce - 1 means Producer endpoint
3553 * 0 means Consumer endpoint
3554 *
3555 * @return - 0 if successful else negative value.
3556 *
3557 */
3558static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
3559 struct msmsdcc_sps_ep_conn_data *ep,
3560 bool is_producer)
3561{
3562 int rc = 0;
3563 struct sps_pipe *sps_pipe_handle;
3564 struct sps_connect *sps_config = &ep->config;
3565 struct sps_register_event *sps_event = &ep->event;
3566
3567 /* Allocate endpoint context */
3568 sps_pipe_handle = sps_alloc_endpoint();
3569 if (!sps_pipe_handle) {
3570 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
3571 mmc_hostname(host->mmc), is_producer);
3572 rc = -ENOMEM;
3573 goto out;
3574 }
3575
3576 /* Get default connection configuration for an endpoint */
3577 rc = sps_get_config(sps_pipe_handle, sps_config);
3578 if (rc) {
3579 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
3580 " rc=%d", mmc_hostname(host->mmc),
3581 (u32)sps_pipe_handle, rc);
3582 goto get_config_err;
3583 }
3584
3585 /* Modify the default connection configuration */
3586 if (is_producer) {
3587 /*
3588 * For SDCC producer transfer, source should be
3589 * SDCC peripheral where as destination should
3590 * be system memory.
3591 */
3592 sps_config->source = host->sps.bam_handle;
3593 sps_config->destination = SPS_DEV_HANDLE_MEM;
3594 /* Producer pipe will handle this connection */
3595 sps_config->mode = SPS_MODE_SRC;
3596 sps_config->options =
3597 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3598 } else {
3599 /*
3600 * For SDCC consumer transfer, source should be
3601 * system memory where as destination should
3602 * SDCC peripheral
3603 */
3604 sps_config->source = SPS_DEV_HANDLE_MEM;
3605 sps_config->destination = host->sps.bam_handle;
3606 sps_config->mode = SPS_MODE_DEST;
3607 sps_config->options =
3608 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3609 }
3610
3611 /* Producer pipe index */
3612 sps_config->src_pipe_index = host->sps.src_pipe_index;
3613 /* Consumer pipe index */
3614 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
3615 /*
3616 * This event thresold value is only significant for BAM-to-BAM
3617 * transfer. It's ignored for BAM-to-System mode transfer.
3618 */
3619 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05303620
3621 /* Allocate maximum descriptor fifo size */
3622 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
3623 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003624 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
3625 sps_config->desc.size,
3626 &sps_config->desc.phys_base,
3627 GFP_KERNEL);
3628
Pratibhasagar V00b94332011-10-18 14:57:27 +05303629 if (!sps_config->desc.base) {
3630 rc = -ENOMEM;
3631 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3632 , mmc_hostname(host->mmc));
3633 goto get_config_err;
3634 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003635 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3636
3637 /* Establish connection between peripheral and memory endpoint */
3638 rc = sps_connect(sps_pipe_handle, sps_config);
3639 if (rc) {
3640 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3641 " rc=%d", mmc_hostname(host->mmc),
3642 (u32)sps_pipe_handle, rc);
3643 goto sps_connect_err;
3644 }
3645
3646 sps_event->mode = SPS_TRIGGER_CALLBACK;
3647 sps_event->options = SPS_O_EOT;
3648 sps_event->callback = msmsdcc_sps_complete_cb;
3649 sps_event->xfer_done = NULL;
3650 sps_event->user = (void *)host;
3651
3652 /* Register callback event for EOT (End of transfer) event. */
3653 rc = sps_register_event(sps_pipe_handle, sps_event);
3654 if (rc) {
3655 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3656 " rc=%d", mmc_hostname(host->mmc),
3657 (u32)sps_pipe_handle, rc);
3658 goto reg_event_err;
3659 }
3660 /* Now save the sps pipe handle */
3661 ep->pipe_handle = sps_pipe_handle;
3662 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3663 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3664 __func__, is_producer ? "READ" : "WRITE",
3665 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3666 goto out;
3667
3668reg_event_err:
3669 sps_disconnect(sps_pipe_handle);
3670sps_connect_err:
3671 dma_free_coherent(mmc_dev(host->mmc),
3672 sps_config->desc.size,
3673 sps_config->desc.base,
3674 sps_config->desc.phys_base);
3675get_config_err:
3676 sps_free_endpoint(sps_pipe_handle);
3677out:
3678 return rc;
3679}
3680
3681/**
3682 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3683 *
3684 * This function disconnect endpoint and deallocates
3685 * endpoint context.
3686 *
3687 * This function should only be called once typically
3688 * during driver remove.
3689 *
3690 * @host - Pointer to sdcc host structure
3691 * @ep - Pointer to sps endpoint data structure
3692 *
3693 */
3694static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3695 struct msmsdcc_sps_ep_conn_data *ep)
3696{
3697 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3698 struct sps_connect *sps_config = &ep->config;
3699 struct sps_register_event *sps_event = &ep->event;
3700
3701 sps_event->xfer_done = NULL;
3702 sps_event->callback = NULL;
3703 sps_register_event(sps_pipe_handle, sps_event);
3704 sps_disconnect(sps_pipe_handle);
3705 dma_free_coherent(mmc_dev(host->mmc),
3706 sps_config->desc.size,
3707 sps_config->desc.base,
3708 sps_config->desc.phys_base);
3709 sps_free_endpoint(sps_pipe_handle);
3710}
3711
3712/**
3713 * Reset SDCC peripheral's SPS endpoint
3714 *
3715 * This function disconnects an endpoint.
3716 *
3717 * This function should be called for reseting
3718 * SPS endpoint when data transfer error is
3719 * encountered during data transfer. This
3720 * can be considered as soft reset to endpoint.
3721 *
3722 * This function should only be called if
3723 * msmsdcc_sps_init() is already called.
3724 *
3725 * @host - Pointer to sdcc host structure
3726 * @ep - Pointer to sps endpoint data structure
3727 *
3728 * @return - 0 if successful else negative value.
3729 */
3730static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3731 struct msmsdcc_sps_ep_conn_data *ep)
3732{
3733 int rc = 0;
3734 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3735
3736 rc = sps_disconnect(sps_pipe_handle);
3737 if (rc) {
3738 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3739 " rc=%d", mmc_hostname(host->mmc), __func__,
3740 (u32)sps_pipe_handle, rc);
3741 goto out;
3742 }
3743 out:
3744 return rc;
3745}
3746
3747/**
3748 * Restore SDCC peripheral's SPS endpoint
3749 *
3750 * This function connects an endpoint.
3751 *
3752 * This function should be called for restoring
3753 * SPS endpoint after data transfer error is
3754 * encountered during data transfer. This
3755 * can be considered as soft reset to endpoint.
3756 *
3757 * This function should only be called if
3758 * msmsdcc_sps_reset_ep() is called before.
3759 *
3760 * @host - Pointer to sdcc host structure
3761 * @ep - Pointer to sps endpoint data structure
3762 *
3763 * @return - 0 if successful else negative value.
3764 */
3765static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3766 struct msmsdcc_sps_ep_conn_data *ep)
3767{
3768 int rc = 0;
3769 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3770 struct sps_connect *sps_config = &ep->config;
3771 struct sps_register_event *sps_event = &ep->event;
3772
3773 /* Establish connection between peripheral and memory endpoint */
3774 rc = sps_connect(sps_pipe_handle, sps_config);
3775 if (rc) {
3776 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3777 " rc=%d", mmc_hostname(host->mmc), __func__,
3778 (u32)sps_pipe_handle, rc);
3779 goto out;
3780 }
3781
3782 /* Register callback event for EOT (End of transfer) event. */
3783 rc = sps_register_event(sps_pipe_handle, sps_event);
3784 if (rc) {
3785 pr_err("%s: %s: sps_register_event() failed!!!"
3786 " pipe_handle=0x%x, rc=%d",
3787 mmc_hostname(host->mmc), __func__,
3788 (u32)sps_pipe_handle, rc);
3789 goto reg_event_err;
3790 }
3791 goto out;
3792
3793reg_event_err:
3794 sps_disconnect(sps_pipe_handle);
3795out:
3796 return rc;
3797}
3798
3799/**
3800 * Initialize SPS HW connected with SDCC core
3801 *
3802 * This function register BAM HW resources with
3803 * SPS driver and then initialize 2 SPS endpoints
3804 *
3805 * This function should only be called once typically
3806 * during driver probe.
3807 *
3808 * @host - Pointer to sdcc host structure
3809 *
3810 * @return - 0 if successful else negative value.
3811 *
3812 */
3813static int msmsdcc_sps_init(struct msmsdcc_host *host)
3814{
3815 int rc = 0;
3816 struct sps_bam_props bam = {0};
3817
3818 host->bam_base = ioremap(host->bam_memres->start,
3819 resource_size(host->bam_memres));
3820 if (!host->bam_base) {
3821 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3822 " size=0x%x", mmc_hostname(host->mmc),
3823 host->bam_memres->start,
3824 (host->bam_memres->end -
3825 host->bam_memres->start));
3826 rc = -ENOMEM;
3827 goto out;
3828 }
3829
3830 bam.phys_addr = host->bam_memres->start;
3831 bam.virt_addr = host->bam_base;
3832 /*
3833 * This event thresold value is only significant for BAM-to-BAM
3834 * transfer. It's ignored for BAM-to-System mode transfer.
3835 */
3836 bam.event_threshold = 0x10; /* Pipe event threshold */
3837 /*
3838 * This threshold controls when the BAM publish
3839 * the descriptor size on the sideband interface.
3840 * SPS HW will only be used when
3841 * data transfer size > MCI_FIFOSIZE (64 bytes).
3842 * PIO mode will be used when
3843 * data transfer size < MCI_FIFOSIZE (64 bytes).
3844 * So set this thresold value to 64 bytes.
3845 */
3846 bam.summing_threshold = 64;
3847 /* SPS driver wll handle the SDCC BAM IRQ */
3848 bam.irq = (u32)host->bam_irqres->start;
3849 bam.manage = SPS_BAM_MGR_LOCAL;
3850
3851 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3852 (u32)bam.phys_addr);
3853 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3854 (u32)bam.virt_addr);
3855
3856 /* Register SDCC Peripheral BAM device to SPS driver */
3857 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3858 if (rc) {
3859 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3860 mmc_hostname(host->mmc), rc);
3861 goto reg_bam_err;
3862 }
3863 pr_info("%s: BAM device registered. bam_handle=0x%x",
3864 mmc_hostname(host->mmc), host->sps.bam_handle);
3865
3866 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3867 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3868
3869 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3870 SPS_PROD_PERIPHERAL);
3871 if (rc)
3872 goto sps_reset_err;
3873 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3874 SPS_CONS_PERIPHERAL);
3875 if (rc)
3876 goto cons_conn_err;
3877
3878 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3879 mmc_hostname(host->mmc),
3880 (unsigned long long)host->bam_memres->start,
3881 (unsigned int)host->bam_irqres->start);
3882 goto out;
3883
3884cons_conn_err:
3885 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3886sps_reset_err:
3887 sps_deregister_bam_device(host->sps.bam_handle);
3888reg_bam_err:
3889 iounmap(host->bam_base);
3890out:
3891 return rc;
3892}
3893
3894/**
3895 * De-initialize SPS HW connected with SDCC core
3896 *
3897 * This function deinitialize SPS endpoints and then
3898 * deregisters BAM resources from SPS driver.
3899 *
3900 * This function should only be called once typically
3901 * during driver remove.
3902 *
3903 * @host - Pointer to sdcc host structure
3904 *
3905 */
3906static void msmsdcc_sps_exit(struct msmsdcc_host *host)
3907{
3908 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
3909 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3910 sps_deregister_bam_device(host->sps.bam_handle);
3911 iounmap(host->bam_base);
3912}
3913#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
3914
3915static ssize_t
3916show_polling(struct device *dev, struct device_attribute *attr, char *buf)
3917{
3918 struct mmc_host *mmc = dev_get_drvdata(dev);
3919 struct msmsdcc_host *host = mmc_priv(mmc);
3920 int poll;
3921 unsigned long flags;
3922
3923 spin_lock_irqsave(&host->lock, flags);
3924 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
3925 spin_unlock_irqrestore(&host->lock, flags);
3926
3927 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
3928}
3929
3930static ssize_t
3931set_polling(struct device *dev, struct device_attribute *attr,
3932 const char *buf, size_t count)
3933{
3934 struct mmc_host *mmc = dev_get_drvdata(dev);
3935 struct msmsdcc_host *host = mmc_priv(mmc);
3936 int value;
3937 unsigned long flags;
3938
3939 sscanf(buf, "%d", &value);
3940
3941 spin_lock_irqsave(&host->lock, flags);
3942 if (value) {
3943 mmc->caps |= MMC_CAP_NEEDS_POLL;
3944 mmc_detect_change(host->mmc, 0);
3945 } else {
3946 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3947 }
3948#ifdef CONFIG_HAS_EARLYSUSPEND
3949 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
3950#endif
3951 spin_unlock_irqrestore(&host->lock, flags);
3952 return count;
3953}
3954
3955static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
3956 show_polling, set_polling);
3957static struct attribute *dev_attrs[] = {
3958 &dev_attr_polling.attr,
3959 NULL,
3960};
3961static struct attribute_group dev_attr_grp = {
3962 .attrs = dev_attrs,
3963};
3964
3965#ifdef CONFIG_HAS_EARLYSUSPEND
3966static void msmsdcc_early_suspend(struct early_suspend *h)
3967{
3968 struct msmsdcc_host *host =
3969 container_of(h, struct msmsdcc_host, early_suspend);
3970 unsigned long flags;
3971
3972 spin_lock_irqsave(&host->lock, flags);
3973 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
3974 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3975 spin_unlock_irqrestore(&host->lock, flags);
3976};
3977static void msmsdcc_late_resume(struct early_suspend *h)
3978{
3979 struct msmsdcc_host *host =
3980 container_of(h, struct msmsdcc_host, early_suspend);
3981 unsigned long flags;
3982
3983 if (host->polling_enabled) {
3984 spin_lock_irqsave(&host->lock, flags);
3985 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
3986 mmc_detect_change(host->mmc, 0);
3987 spin_unlock_irqrestore(&host->lock, flags);
3988 }
3989};
3990#endif
3991
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303992void msmsdcc_print_regs(const char *name, void __iomem *base,
3993 unsigned int no_of_regs)
3994{
3995 unsigned int i;
3996
3997 if (!base)
3998 return;
3999 pr_info("===== %s: Register Dumps @base=0x%x =====\n",
4000 name, (u32)base);
4001 for (i = 0; i < no_of_regs; i = i + 4) {
4002 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x.\n", i*4,
4003 (u32)readl_relaxed(base + i*4),
4004 (u32)readl_relaxed(base + ((i+1)*4)),
4005 (u32)readl_relaxed(base + ((i+2)*4)),
4006 (u32)readl_relaxed(base + ((i+3)*4)));
4007 }
4008}
4009
4010static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
4011{
4012 /* Dump current state of SDCC clocks, power and irq */
4013 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
4014 (host->pwr ? "ON" : "OFF"));
4015 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
4016 mmc_hostname(host->mmc),
4017 (host->clks_on ? "ON" : "OFF"),
4018 (u32)clk_get_rate(host->clk));
4019 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
4020 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
4021
4022 /* Now dump SDCC registers. Don't print FIFO registers */
4023 if (host->clks_on)
4024 msmsdcc_print_regs("SDCC-CORE", host->base, 28);
4025
4026 if (host->curr.data) {
4027 if (msmsdcc_check_dma_op_req(host->curr.data))
4028 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
4029 else if (host->is_dma_mode)
4030 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
4031 mmc_hostname(host->mmc), host->dma.busy,
4032 host->dma.channel, host->dma.crci);
4033 else if (host->is_sps_mode)
4034 pr_info("%s: SPS mode: busy=%d\n",
4035 mmc_hostname(host->mmc), host->sps.busy);
4036
4037 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
4038 mmc_hostname(host->mmc), host->curr.xfer_size,
4039 host->curr.data_xfered, host->curr.xfer_remain);
4040 pr_info("%s: got_dataend=%d, prog_enable=%d,"
4041 " wait_for_auto_prog_done=%d,"
4042 " got_auto_prog_done=%d\n",
4043 mmc_hostname(host->mmc), host->curr.got_dataend,
4044 host->prog_enable, host->curr.wait_for_auto_prog_done,
4045 host->curr.got_auto_prog_done);
4046 }
4047
4048}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004049static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
4050{
4051 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4052 struct mmc_request *mrq;
4053 unsigned long flags;
4054
4055 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004056 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004057 pr_info("%s: %s: dummy CMD52 timeout\n",
4058 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004059 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004060 }
4061
4062 mrq = host->curr.mrq;
4063
4064 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304065 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
4066 mrq->cmd->opcode);
4067 msmsdcc_dump_sdcc_state(host);
4068
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004069 if (!mrq->cmd->error)
4070 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304071 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004072 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004073 if (mrq->data && !mrq->data->error)
4074 mrq->data->error = -ETIMEDOUT;
4075 host->curr.data_xfered = 0;
4076 if (host->dma.sg && host->is_dma_mode) {
4077 msm_dmov_stop_cmd(host->dma.channel,
4078 &host->dma.hdr, 0);
4079 } else if (host->sps.sg && host->is_sps_mode) {
4080 /* Stop current SPS transfer */
4081 msmsdcc_sps_exit_curr_xfer(host);
4082 } else {
4083 msmsdcc_reset_and_restore(host);
4084 msmsdcc_stop_data(host);
4085 if (mrq->data && mrq->data->stop)
4086 msmsdcc_start_command(host,
4087 mrq->data->stop, 0);
4088 else
4089 msmsdcc_request_end(host, mrq);
4090 }
4091 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304092 host->prog_enable = 0;
Subhash Jadavanied6b0e42012-03-07 16:36:27 +05304093 host->curr.wait_for_auto_prog_done = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004094 msmsdcc_reset_and_restore(host);
4095 msmsdcc_request_end(host, mrq);
4096 }
4097 }
4098 spin_unlock_irqrestore(&host->lock, flags);
4099}
4100
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304101static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
4102{
4103 int i, ret;
4104 struct mmc_platform_data *pdata;
4105 struct device_node *np = dev->of_node;
4106 u32 bus_width = 0;
4107 u32 *clk_table;
4108 int clk_table_len;
4109 u32 *sup_voltages;
4110 int sup_volt_len;
4111
4112 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
4113 if (!pdata) {
4114 dev_err(dev, "could not allocate memory for platform data\n");
4115 goto err;
4116 }
4117
4118 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
4119 if (bus_width == 8) {
4120 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
4121 } else if (bus_width == 4) {
4122 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
4123 } else {
4124 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
4125 pdata->mmc_bus_width = 0;
4126 }
4127
4128 if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
4129 size_t sz;
4130 sz = sup_volt_len / sizeof(*sup_voltages);
4131 if (sz > 0) {
4132 sup_voltages = devm_kzalloc(dev,
4133 sz * sizeof(*sup_voltages), GFP_KERNEL);
4134 if (!sup_voltages) {
4135 dev_err(dev, "No memory for supported voltage\n");
4136 goto err;
4137 }
4138
4139 ret = of_property_read_u32_array(np,
4140 "qcom,sdcc-sup-voltages", sup_voltages, sz);
4141 if (ret < 0) {
4142 dev_err(dev, "error while reading voltage"
4143 "ranges %d\n", ret);
4144 goto err;
4145 }
4146 } else {
4147 dev_err(dev, "No supported voltages\n");
4148 goto err;
4149 }
4150 for (i = 0; i < sz; i += 2) {
4151 u32 mask;
4152
4153 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
4154 sup_voltages[i + 1]);
4155 if (!mask)
4156 dev_err(dev, "Invalide voltage range %d\n", i);
4157 pdata->ocr_mask |= mask;
4158 }
4159 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
4160 } else {
4161 dev_err(dev, "Supported voltage range not specified\n");
4162 }
4163
4164 if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
4165 size_t sz;
4166 sz = clk_table_len / sizeof(*clk_table);
4167
4168 if (sz > 0) {
4169 clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
4170 GFP_KERNEL);
4171 if (!clk_table) {
4172 dev_err(dev, "No memory for clock table\n");
4173 goto err;
4174 }
4175
4176 ret = of_property_read_u32_array(np,
4177 "qcom,sdcc-clk-rates", clk_table, sz);
4178 if (ret < 0) {
4179 dev_err(dev, "error while reading clk"
4180 "table %d\n", ret);
4181 goto err;
4182 }
4183 } else {
4184 dev_err(dev, "clk_table not specified\n");
4185 goto err;
4186 }
4187 pdata->sup_clk_table = clk_table;
4188 pdata->sup_clk_cnt = sz;
4189 } else {
4190 dev_err(dev, "Supported clock rates not specified\n");
4191 }
4192
4193 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
4194 pdata->nonremovable = true;
4195 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
4196 pdata->disable_cmd23 = true;
4197
4198 return pdata;
4199err:
4200 return NULL;
4201}
4202
San Mehat9d2bd732009-09-22 16:44:22 -07004203static int
4204msmsdcc_probe(struct platform_device *pdev)
4205{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304206 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07004207 struct msmsdcc_host *host;
4208 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004209 unsigned long flags;
4210 struct resource *core_irqres = NULL;
4211 struct resource *bam_irqres = NULL;
4212 struct resource *core_memres = NULL;
4213 struct resource *dml_memres = NULL;
4214 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07004215 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07004216 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05304217 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004218 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07004219
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304220 if (pdev->dev.of_node) {
4221 plat = msmsdcc_populate_pdata(&pdev->dev);
4222 of_property_read_u32((&pdev->dev)->of_node,
4223 "cell-index", &pdev->id);
4224 } else {
4225 plat = pdev->dev.platform_data;
4226 }
4227
San Mehat9d2bd732009-09-22 16:44:22 -07004228 /* must have platform data */
4229 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004230 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004231 ret = -EINVAL;
4232 goto out;
4233 }
4234
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004235 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07004236 return -EINVAL;
4237
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304238 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
4239 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
4240 return -EINVAL;
4241 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004242
San Mehat9d2bd732009-09-22 16:44:22 -07004243 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004244 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004245 return -ENXIO;
4246 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304247 if (pdev->dev.of_node) {
4248 /*
4249 * Device tree iomem resources are only accessible by index.
4250 * index = 0 -> SDCC register interface
4251 * index = 1 -> DML register interface
4252 * index = 2 -> BAM register interface
4253 * IRQ resources:
4254 * index = 0 -> SDCC IRQ
4255 * index = 1 -> BAM IRQ
4256 */
4257 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
4258 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
4259 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
4260 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
4261 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
4262 } else {
4263 for (i = 0; i < pdev->num_resources; i++) {
4264 if (pdev->resource[i].flags & IORESOURCE_MEM) {
4265 if (!strncmp(pdev->resource[i].name,
4266 "sdcc_dml_addr",
4267 sizeof("sdcc_dml_addr")))
4268 dml_memres = &pdev->resource[i];
4269 else if (!strncmp(pdev->resource[i].name,
4270 "sdcc_bam_addr",
4271 sizeof("sdcc_bam_addr")))
4272 bam_memres = &pdev->resource[i];
4273 else
4274 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07004275
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304276 }
4277 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
4278 if (!strncmp(pdev->resource[i].name,
4279 "sdcc_bam_irq",
4280 sizeof("sdcc_bam_irq")))
4281 bam_irqres = &pdev->resource[i];
4282 else
4283 core_irqres = &pdev->resource[i];
4284 }
4285 if (pdev->resource[i].flags & IORESOURCE_DMA) {
4286 if (!strncmp(pdev->resource[i].name,
4287 "sdcc_dma_chnl",
4288 sizeof("sdcc_dma_chnl")))
4289 dmares = &pdev->resource[i];
4290 else if (!strncmp(pdev->resource[i].name,
4291 "sdcc_dma_crci",
4292 sizeof("sdcc_dma_crci")))
4293 dma_crci_res = &pdev->resource[i];
4294 }
Krishna Konda25786ec2011-07-25 16:21:36 -07004295 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004296 }
4297
4298 if (!core_irqres || !core_memres) {
4299 pr_err("%s: Invalid sdcc core resource\n", __func__);
4300 return -ENXIO;
4301 }
4302
4303 /*
4304 * Both BAM and DML memory resource should be preset.
4305 * BAM IRQ resource should also be present.
4306 */
4307 if ((bam_memres && !dml_memres) ||
4308 (!bam_memres && dml_memres) ||
4309 ((bam_memres && dml_memres) && !bam_irqres)) {
4310 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004311 return -ENXIO;
4312 }
4313
4314 /*
4315 * Setup our host structure
4316 */
San Mehat9d2bd732009-09-22 16:44:22 -07004317 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
4318 if (!mmc) {
4319 ret = -ENOMEM;
4320 goto out;
4321 }
4322
4323 host = mmc_priv(mmc);
4324 host->pdev_id = pdev->id;
4325 host->plat = plat;
4326 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08004327 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05304328
4329 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004330 host->is_sps_mode = 1;
4331 else if (dmares)
4332 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07004333
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004334 host->base = ioremap(core_memres->start,
4335 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07004336 if (!host->base) {
4337 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004338 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004339 }
4340
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004341 host->core_irqres = core_irqres;
4342 host->bam_irqres = bam_irqres;
4343 host->core_memres = core_memres;
4344 host->dml_memres = dml_memres;
4345 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07004346 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07004347 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07004348 spin_lock_init(&host->lock);
4349
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004350#ifdef CONFIG_MMC_EMBEDDED_SDIO
4351 if (plat->embedded_sdio)
4352 mmc_set_embedded_sdio_data(mmc,
4353 &plat->embedded_sdio->cis,
4354 &plat->embedded_sdio->cccr,
4355 plat->embedded_sdio->funcs,
4356 plat->embedded_sdio->num_funcs);
4357#endif
4358
Sahitya Tummala62612cf2010-12-08 15:03:03 +05304359 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
4360 (unsigned long)host);
4361
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004362 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
4363 (unsigned long)host);
4364 if (host->is_dma_mode) {
4365 /* Setup DMA */
4366 ret = msmsdcc_init_dma(host);
4367 if (ret)
4368 goto ioremap_free;
4369 } else {
4370 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004371 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004372 }
4373
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004374 /*
4375 * Setup SDCC clock if derived from Dayatona
4376 * fabric core clock.
4377 */
4378 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07004379 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004380 if (!IS_ERR(host->dfab_pclk)) {
4381 /* Set the clock rate to 64MHz for max. performance */
4382 ret = clk_set_rate(host->dfab_pclk, 64000000);
4383 if (ret)
4384 goto dfab_pclk_put;
4385 ret = clk_enable(host->dfab_pclk);
4386 if (ret)
4387 goto dfab_pclk_put;
4388 } else
4389 goto dma_free;
4390 }
4391
4392 /*
4393 * Setup main peripheral bus clock
4394 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004395 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004396 if (!IS_ERR(host->pclk)) {
4397 ret = clk_enable(host->pclk);
4398 if (ret)
4399 goto pclk_put;
4400
4401 host->pclk_rate = clk_get_rate(host->pclk);
4402 }
4403
4404 /*
4405 * Setup SDC MMC clock
4406 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004407 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07004408 if (IS_ERR(host->clk)) {
4409 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004410 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07004411 }
4412
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004413 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
4414 if (ret) {
4415 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
4416 goto clk_put;
4417 }
4418
4419 ret = clk_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004420 if (ret)
4421 goto clk_put;
4422
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004423 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304424 if (!host->clk_rate)
4425 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304426
4427 /*
4428 * Lookup the Controller Version, to identify the supported features
4429 * Version number read as 0 would indicate SDCC3 or earlier versions
4430 */
4431 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
4432 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
4433 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304434 /*
4435 * Set the register write delay according to min. clock frequency
4436 * supported and update later when the host->clk_rate changes.
4437 */
4438 host->reg_write_delay =
4439 (1 + ((3 * USEC_PER_SEC) /
4440 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004441
4442 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05304443 /* Apply Hard reset to SDCC to put it in power on default state */
4444 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004445
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304446 /* pm qos request to prevent apps idle power collapse */
4447 if (host->plat->swfi_latency)
4448 pm_qos_add_request(&host->pm_qos_req_dma,
4449 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
4450
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004451 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07004452 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004453 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07004454 goto clk_disable;
4455 }
4456
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004457
4458 /* Clocks has to be running before accessing SPS/DML HW blocks */
4459 if (host->is_sps_mode) {
4460 /* Initialize SPS */
4461 ret = msmsdcc_sps_init(host);
4462 if (ret)
4463 goto vreg_deinit;
4464 /* Initialize DML */
4465 ret = msmsdcc_dml_init(host);
4466 if (ret)
4467 goto sps_exit;
4468 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05304469 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07004470
San Mehat9d2bd732009-09-22 16:44:22 -07004471 /*
4472 * Setup MMC host structure
4473 */
4474 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004475 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
4476 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004477 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004478 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
4479 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07004480
San Mehat9d2bd732009-09-22 16:44:22 -07004481 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05304482 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304483
4484 /*
4485 * If we send the CMD23 before multi block write/read command
4486 * then we need not to send CMD12 at the end of the transfer.
4487 * If we don't send the CMD12 then only way to detect the PROG_DONE
4488 * status is to use the AUTO_PROG_DONE status provided by SDCC4
4489 * controller. So let's enable the CMD23 for SDCC4 only.
4490 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304491 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304492 mmc->caps |= MMC_CAP_CMD23;
4493
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004494 mmc->caps |= plat->uhs_caps;
4495 /*
4496 * XPC controls the maximum current in the default speed mode of SDXC
4497 * card. XPC=0 means 100mA (max.) but speed class is not supported.
4498 * XPC=1 means 150mA (max.) and speed class is supported.
4499 */
4500 if (plat->xpc_cap)
4501 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
4502 MMC_CAP_SET_XPC_180);
4503
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304504 if (pdev->dev.of_node) {
4505 if (of_get_property((&pdev->dev)->of_node,
4506 "qcom,sdcc-hs200", NULL))
4507 mmc->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
4508 }
4509
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004510 if (plat->nonremovable)
4511 mmc->caps |= MMC_CAP_NONREMOVABLE;
4512#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
4513 mmc->caps |= MMC_CAP_SDIO_IRQ;
4514#endif
4515
4516 if (plat->is_sdio_al_client)
4517 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07004518
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304519 mmc->max_segs = msmsdcc_get_nr_sg(host);
4520 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
4521 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07004522
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304523 mmc->max_req_size = MMC_MAX_REQ_SIZE;
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +05304524 mmc->max_seg_size = mmc->max_req_size;
San Mehat9d2bd732009-09-22 16:44:22 -07004525
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004526 writel_relaxed(0, host->base + MMCIMASK0);
4527 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -07004528
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004529 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
4530 mb();
4531 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07004532
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004533 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
4534 DRIVER_NAME " (cmd)", host);
4535 if (ret)
4536 goto dml_exit;
4537
4538 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
4539 DRIVER_NAME " (pio)", host);
4540 if (ret)
4541 goto irq_free;
4542
4543 /*
4544 * Enable SDCC IRQ only when host is powered on. Otherwise, this
4545 * IRQ is un-necessarily being monitored by MPM (Modem power
4546 * management block) during idle-power collapse. The MPM will be
4547 * configured to monitor the DATA1 GPIO line with level-low trigger
4548 * and thus depending on the GPIO status, it prevents TCXO shutdown
4549 * during idle-power collapse.
4550 */
4551 disable_irq(core_irqres->start);
4552 host->sdcc_irq_disabled = 1;
4553
4554 if (plat->sdiowakeup_irq) {
4555 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4556 mmc_hostname(mmc));
4557 ret = request_irq(plat->sdiowakeup_irq,
4558 msmsdcc_platform_sdiowakeup_irq,
4559 IRQF_SHARED | IRQF_TRIGGER_LOW,
4560 DRIVER_NAME "sdiowakeup", host);
4561 if (ret) {
4562 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
4563 plat->sdiowakeup_irq, ret);
4564 goto pio_irq_free;
4565 } else {
4566 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304567 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004568 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304569 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004570 }
4571 spin_unlock_irqrestore(&host->lock, flags);
4572 }
4573 }
4574
4575 if (plat->cfg_mpm_sdiowakeup) {
4576 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4577 mmc_hostname(mmc));
4578 }
4579
4580 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
4581 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004582 /*
4583 * Setup card detect change
4584 */
4585
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004586 if (plat->status || plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08004587 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004588 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08004589 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004590 host->oldstat = msmsdcc_slot_status(host);
Krishna Konda360aa422011-12-06 18:27:41 -08004591
Krishna Konda941604a2012-01-10 17:46:34 -08004592 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004593 }
San Mehat9d2bd732009-09-22 16:44:22 -07004594
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004595 if (plat->status_irq) {
4596 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07004597 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004598 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07004599 DRIVER_NAME " (slot)",
4600 host);
4601 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004602 pr_err("Unable to get slot IRQ %d (%d)\n",
4603 plat->status_irq, ret);
4604 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004605 }
4606 } else if (plat->register_status_notify) {
4607 plat->register_status_notify(msmsdcc_status_notify_cb, host);
4608 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004609 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07004610 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004611
4612 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004613
4614 ret = pm_runtime_set_active(&(pdev)->dev);
4615 if (ret < 0)
4616 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
4617 __func__, ret);
4618 /*
4619 * There is no notion of suspend/resume for SD/MMC/SDIO
4620 * cards. So host can be suspended/resumed with out
4621 * worrying about its children.
4622 */
4623 pm_suspend_ignore_children(&(pdev)->dev, true);
4624
4625 /*
4626 * MMC/SD/SDIO bus suspend/resume operations are defined
4627 * only for the slots that will be used for non-removable
4628 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
4629 * defined. Otherwise, they simply become card removal and
4630 * insertion events during suspend and resume respectively.
4631 * Hence, enable run-time PM only for slots for which bus
4632 * suspend/resume operations are defined.
4633 */
4634#ifdef CONFIG_MMC_UNSAFE_RESUME
4635 /*
4636 * If this capability is set, MMC core will enable/disable host
4637 * for every claim/release operation on a host. We use this
4638 * notification to increment/decrement runtime pm usage count.
4639 */
4640 mmc->caps |= MMC_CAP_DISABLE;
4641 pm_runtime_enable(&(pdev)->dev);
4642#else
4643 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
4644 mmc->caps |= MMC_CAP_DISABLE;
4645 pm_runtime_enable(&(pdev)->dev);
4646 }
4647#endif
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05304648#ifndef CONFIG_PM_RUNTIME
4649 mmc_set_disable_delay(mmc, MSM_MMC_DISABLE_TIMEOUT);
4650#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004651 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
4652 (unsigned long)host);
4653
San Mehat9d2bd732009-09-22 16:44:22 -07004654 mmc_add_host(mmc);
4655
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004656#ifdef CONFIG_HAS_EARLYSUSPEND
4657 host->early_suspend.suspend = msmsdcc_early_suspend;
4658 host->early_suspend.resume = msmsdcc_late_resume;
4659 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
4660 register_early_suspend(&host->early_suspend);
4661#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004662
Krishna Konda25786ec2011-07-25 16:21:36 -07004663 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
4664 " dmacrcri %d\n", mmc_hostname(mmc),
4665 (unsigned long long)core_memres->start,
4666 (unsigned int) core_irqres->start,
4667 (unsigned int) plat->status_irq, host->dma.channel,
4668 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004669
4670 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
4671 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
4672 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
4673 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
4674 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
4675 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
4676 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
4677 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
4678 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
4679 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
4680 host->eject);
4681 pr_info("%s: Power save feature enable = %d\n",
4682 mmc_hostname(mmc), msmsdcc_pwrsave);
4683
Krishna Konda25786ec2011-07-25 16:21:36 -07004684 if (host->is_dma_mode && host->dma.channel != -1
4685 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004686 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004687 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004688 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004689 mmc_hostname(mmc), host->dma.cmd_busaddr,
4690 host->dma.cmdptr_busaddr);
4691 } else if (host->is_sps_mode) {
4692 pr_info("%s: SPS-BAM data transfer mode available\n",
4693 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004694 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004695 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004696
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004697#if defined(CONFIG_DEBUG_FS)
4698 msmsdcc_dbg_createhost(host);
4699#endif
4700 if (!plat->status_irq) {
4701 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
4702 if (ret)
4703 goto platform_irq_free;
4704 }
San Mehat9d2bd732009-09-22 16:44:22 -07004705 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004706
4707 platform_irq_free:
4708 del_timer_sync(&host->req_tout_timer);
4709 pm_runtime_disable(&(pdev)->dev);
4710 pm_runtime_set_suspended(&(pdev)->dev);
4711
4712 if (plat->status_irq)
4713 free_irq(plat->status_irq, host);
4714 sdiowakeup_irq_free:
4715 wake_lock_destroy(&host->sdio_suspend_wlock);
4716 if (plat->sdiowakeup_irq)
4717 free_irq(plat->sdiowakeup_irq, host);
4718 pio_irq_free:
4719 if (plat->sdiowakeup_irq)
4720 wake_lock_destroy(&host->sdio_wlock);
4721 free_irq(core_irqres->start, host);
4722 irq_free:
4723 free_irq(core_irqres->start, host);
4724 dml_exit:
4725 if (host->is_sps_mode)
4726 msmsdcc_dml_exit(host);
4727 sps_exit:
4728 if (host->is_sps_mode)
4729 msmsdcc_sps_exit(host);
4730 vreg_deinit:
4731 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07004732 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004733 clk_disable(host->clk);
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304734 if (host->plat->swfi_latency)
4735 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07004736 clk_put:
4737 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004738 pclk_disable:
4739 if (!IS_ERR(host->pclk))
4740 clk_disable(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07004741 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004742 if (!IS_ERR(host->pclk))
4743 clk_put(host->pclk);
4744 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4745 clk_disable(host->dfab_pclk);
4746 dfab_pclk_put:
4747 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4748 clk_put(host->dfab_pclk);
4749 dma_free:
4750 if (host->is_dma_mode) {
4751 if (host->dmares)
4752 dma_free_coherent(NULL,
4753 sizeof(struct msmsdcc_nc_dmadata),
4754 host->dma.nc, host->dma.nc_busaddr);
4755 }
4756 ioremap_free:
4757 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07004758 host_free:
4759 mmc_free_host(mmc);
4760 out:
4761 return ret;
4762}
4763
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004764static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07004765{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004766 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4767 struct mmc_platform_data *plat;
4768 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004769
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004770 if (!mmc)
4771 return -ENXIO;
4772
4773 if (pm_runtime_suspended(&(pdev)->dev))
4774 pm_runtime_resume(&(pdev)->dev);
4775
4776 host = mmc_priv(mmc);
4777
4778 DBG(host, "Removing SDCC device = %d\n", pdev->id);
4779 plat = host->plat;
4780
4781 if (!plat->status_irq)
4782 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
4783
4784 del_timer_sync(&host->req_tout_timer);
4785 tasklet_kill(&host->dma_tlet);
4786 tasklet_kill(&host->sps.tlet);
4787 mmc_remove_host(mmc);
4788
4789 if (plat->status_irq)
4790 free_irq(plat->status_irq, host);
4791
4792 wake_lock_destroy(&host->sdio_suspend_wlock);
4793 if (plat->sdiowakeup_irq) {
4794 wake_lock_destroy(&host->sdio_wlock);
4795 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
4796 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07004797 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004798
4799 free_irq(host->core_irqres->start, host);
4800 free_irq(host->core_irqres->start, host);
4801
4802 clk_put(host->clk);
4803 if (!IS_ERR(host->pclk))
4804 clk_put(host->pclk);
4805 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4806 clk_put(host->dfab_pclk);
4807
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304808 if (host->plat->swfi_latency)
4809 pm_qos_remove_request(&host->pm_qos_req_dma);
4810
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004811 msmsdcc_vreg_init(host, false);
4812
4813 if (host->is_dma_mode) {
4814 if (host->dmares)
4815 dma_free_coherent(NULL,
4816 sizeof(struct msmsdcc_nc_dmadata),
4817 host->dma.nc, host->dma.nc_busaddr);
4818 }
4819
4820 if (host->is_sps_mode) {
4821 msmsdcc_dml_exit(host);
4822 msmsdcc_sps_exit(host);
4823 }
4824
4825 iounmap(host->base);
4826 mmc_free_host(mmc);
4827
4828#ifdef CONFIG_HAS_EARLYSUSPEND
4829 unregister_early_suspend(&host->early_suspend);
4830#endif
4831 pm_runtime_disable(&(pdev)->dev);
4832 pm_runtime_set_suspended(&(pdev)->dev);
4833
4834 return 0;
4835}
4836
Oluwafemi Adeyemif68d3e62012-03-13 11:46:49 -07004837static void msmsdcc_shutdown(struct platform_device *pdev)
4838{
4839 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4840
4841 mmc_remove_host(mmc);
4842 mmc_free_host(mmc);
4843}
4844
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004845#ifdef CONFIG_MSM_SDIO_AL
4846int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4847{
4848 struct msmsdcc_host *host = mmc_priv(mmc);
4849 unsigned long flags;
4850
4851 spin_lock_irqsave(&host->lock, flags);
4852 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
4853 enable ? "En" : "Dis");
4854
4855 if (enable) {
4856 if (!host->sdcc_irq_disabled) {
4857 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05304858 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004859 host->sdcc_irq_disabled = 1;
4860 }
4861
4862 if (host->clks_on) {
4863 msmsdcc_setup_clocks(host, false);
4864 host->clks_on = 0;
4865 }
4866
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304867 if (host->plat->sdio_lpm_gpio_setup &&
4868 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004869 spin_unlock_irqrestore(&host->lock, flags);
4870 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
4871 spin_lock_irqsave(&host->lock, flags);
4872 host->sdio_gpio_lpm = 1;
4873 }
4874
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304875 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004876 msmsdcc_enable_irq_wake(host);
4877 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304878 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004879 }
4880 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304881 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004882 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304883 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004884 msmsdcc_disable_irq_wake(host);
4885 }
4886
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304887 if (host->plat->sdio_lpm_gpio_setup &&
4888 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004889 spin_unlock_irqrestore(&host->lock, flags);
4890 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
4891 spin_lock_irqsave(&host->lock, flags);
4892 host->sdio_gpio_lpm = 0;
4893 }
4894
4895 if (!host->clks_on) {
4896 msmsdcc_setup_clocks(host, true);
4897 host->clks_on = 1;
4898 }
4899
4900 if (host->sdcc_irq_disabled) {
4901 writel_relaxed(host->mci_irqenable,
4902 host->base + MMCIMASK0);
4903 mb();
4904 enable_irq(host->core_irqres->start);
4905 host->sdcc_irq_disabled = 0;
4906 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004907 }
4908 spin_unlock_irqrestore(&host->lock, flags);
4909 return 0;
4910}
4911#else
4912int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4913{
4914 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004915}
4916#endif
4917
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004918#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07004919static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004920msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004921{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004922 struct mmc_host *mmc = dev_get_drvdata(dev);
4923 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07004924 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304925 unsigned long flags;
4926
San Mehat9d2bd732009-09-22 16:44:22 -07004927
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004928 if (host->plat->is_sdio_al_client)
4929 return 0;
Sahitya Tummala7661a452011-07-18 13:28:35 +05304930 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004931 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004932 host->sdcc_suspending = 1;
4933 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07004934
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004935 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004936 * MMC core thinks that host is disabled by now since
4937 * runtime suspend is scheduled after msmsdcc_disable()
4938 * is called. Thus, MMC core will try to enable the host
4939 * while suspending it. This results in a synchronous
4940 * runtime resume request while in runtime suspending
4941 * context and hence inorder to complete this resume
4942 * requet, it will wait for suspend to be complete,
4943 * but runtime suspend also can not proceed further
4944 * until the host is resumed. Thus, it leads to a hang.
4945 * Hence, increase the pm usage count before suspending
4946 * the host so that any resume requests after this will
4947 * simple become pm usage counter increment operations.
4948 */
4949 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05304950 /* If there is pending detect work abort runtime suspend */
4951 if (unlikely(work_busy(&mmc->detect.work)))
4952 rc = -EAGAIN;
4953 else
4954 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004955 pm_runtime_put_noidle(dev);
4956
4957 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304958 spin_lock_irqsave(&host->lock, flags);
4959 host->sdcc_suspended = true;
4960 spin_unlock_irqrestore(&host->lock, flags);
4961 if (mmc->card && mmc_card_sdio(mmc->card) &&
4962 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004963 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304964 * If SDIO function driver doesn't want
4965 * to power off the card, atleast turn off
4966 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004967 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304968 mmc_host_clk_hold(mmc);
4969 spin_lock_irqsave(&mmc->clk_lock, flags);
4970 mmc->clk_old = mmc->ios.clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004971 mmc->ios.clock = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304972 mmc->clk_gated = true;
4973 spin_unlock_irqrestore(&mmc->clk_lock, flags);
4974 mmc_set_ios(mmc);
4975 mmc_host_clk_release(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004976 }
4977 }
4978 host->sdcc_suspending = 0;
4979 mmc->suspend_task = NULL;
4980 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
4981 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004982 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05304983 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
San Mehat9d2bd732009-09-22 16:44:22 -07004984 return rc;
4985}
4986
4987static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004988msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004989{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004990 struct mmc_host *mmc = dev_get_drvdata(dev);
4991 struct msmsdcc_host *host = mmc_priv(mmc);
4992 unsigned long flags;
4993
4994 if (host->plat->is_sdio_al_client)
4995 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07004996
Sahitya Tummala7661a452011-07-18 13:28:35 +05304997 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004998 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304999 if (mmc->card && mmc_card_sdio(mmc->card) &&
5000 mmc_card_keep_power(mmc)) {
5001 mmc_host_clk_hold(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305002 mmc->ios.clock = host->clk_rate;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305003 mmc_set_ios(mmc);
5004 mmc_host_clk_release(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305005 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005006
5007 mmc_resume_host(mmc);
5008
5009 /*
5010 * FIXME: Clearing of flags must be handled in clients
5011 * resume handler.
5012 */
5013 spin_lock_irqsave(&host->lock, flags);
5014 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305015 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005016 spin_unlock_irqrestore(&host->lock, flags);
5017
5018 /*
5019 * After resuming the host wait for sometime so that
5020 * the SDIO work will be processed.
5021 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305022 if (mmc->card && mmc_card_sdio(mmc->card)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005023 if ((host->plat->cfg_mpm_sdiowakeup ||
5024 host->plat->sdiowakeup_irq) &&
5025 wake_lock_active(&host->sdio_wlock))
5026 wake_lock_timeout(&host->sdio_wlock, 1);
5027 }
5028
5029 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005030 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05305031 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005032 return 0;
5033}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005034
5035static int msmsdcc_runtime_idle(struct device *dev)
5036{
5037 struct mmc_host *mmc = dev_get_drvdata(dev);
5038 struct msmsdcc_host *host = mmc_priv(mmc);
5039
5040 if (host->plat->is_sdio_al_client)
5041 return 0;
5042
5043 /* Idle timeout is not configurable for now */
5044 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
5045
5046 return -EAGAIN;
5047}
5048
5049static int msmsdcc_pm_suspend(struct device *dev)
5050{
5051 struct mmc_host *mmc = dev_get_drvdata(dev);
5052 struct msmsdcc_host *host = mmc_priv(mmc);
5053 int rc = 0;
5054
5055 if (host->plat->is_sdio_al_client)
5056 return 0;
5057
5058
5059 if (host->plat->status_irq)
5060 disable_irq(host->plat->status_irq);
5061
5062 if (!pm_runtime_suspended(dev))
5063 rc = msmsdcc_runtime_suspend(dev);
5064
5065 return rc;
5066}
5067
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305068static int msmsdcc_suspend_noirq(struct device *dev)
5069{
5070 struct mmc_host *mmc = dev_get_drvdata(dev);
5071 struct msmsdcc_host *host = mmc_priv(mmc);
5072 int rc = 0;
5073
5074 /*
5075 * After platform suspend there may be active request
5076 * which might have enabled clocks. For example, in SDIO
5077 * case, ksdioirq thread might have scheduled after sdcc
5078 * suspend but before system freeze. In that case abort
5079 * suspend and retry instead of keeping the clocks on
5080 * during suspend and not allowing TCXO.
5081 */
5082
5083 if (host->clks_on) {
5084 pr_warn("%s: clocks are on after suspend, aborting system "
5085 "suspend\n", mmc_hostname(mmc));
5086 rc = -EAGAIN;
5087 }
5088
5089 return rc;
5090}
5091
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005092static int msmsdcc_pm_resume(struct device *dev)
5093{
5094 struct mmc_host *mmc = dev_get_drvdata(dev);
5095 struct msmsdcc_host *host = mmc_priv(mmc);
5096 int rc = 0;
5097
5098 if (host->plat->is_sdio_al_client)
5099 return 0;
5100
Sahitya Tummalafb486372011-09-02 19:01:49 +05305101 if (!pm_runtime_suspended(dev))
5102 rc = msmsdcc_runtime_resume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005103 if (host->plat->status_irq) {
5104 msmsdcc_check_status((unsigned long)host);
5105 enable_irq(host->plat->status_irq);
5106 }
5107
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005108 return rc;
5109}
5110
Daniel Walker08ecfde2010-06-23 12:32:20 -07005111#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005112#define msmsdcc_runtime_suspend NULL
5113#define msmsdcc_runtime_resume NULL
5114#define msmsdcc_runtime_idle NULL
5115#define msmsdcc_pm_suspend NULL
5116#define msmsdcc_pm_resume NULL
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305117#define msmsdcc_suspend_noirq NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07005118#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005119
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005120static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
5121 .runtime_suspend = msmsdcc_runtime_suspend,
5122 .runtime_resume = msmsdcc_runtime_resume,
5123 .runtime_idle = msmsdcc_runtime_idle,
5124 .suspend = msmsdcc_pm_suspend,
5125 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305126 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005127};
5128
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305129static const struct of_device_id msmsdcc_dt_match[] = {
5130 {.compatible = "qcom,msm-sdcc"},
5131
5132};
5133MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
5134
San Mehat9d2bd732009-09-22 16:44:22 -07005135static struct platform_driver msmsdcc_driver = {
5136 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005137 .remove = msmsdcc_remove,
Oluwafemi Adeyemif68d3e62012-03-13 11:46:49 -07005138 .shutdown = msmsdcc_shutdown,
San Mehat9d2bd732009-09-22 16:44:22 -07005139 .driver = {
5140 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005141 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305142 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07005143 },
5144};
5145
5146static int __init msmsdcc_init(void)
5147{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005148#if defined(CONFIG_DEBUG_FS)
5149 int ret = 0;
5150 ret = msmsdcc_dbg_init();
5151 if (ret) {
5152 pr_err("Failed to create debug fs dir \n");
5153 return ret;
5154 }
5155#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005156 return platform_driver_register(&msmsdcc_driver);
5157}
5158
5159static void __exit msmsdcc_exit(void)
5160{
5161 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005162
5163#if defined(CONFIG_DEBUG_FS)
5164 debugfs_remove(debugfs_file);
5165 debugfs_remove(debugfs_dir);
5166#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005167}
5168
5169module_init(msmsdcc_init);
5170module_exit(msmsdcc_exit);
5171
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005172MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07005173MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005174
5175#if defined(CONFIG_DEBUG_FS)
5176
5177static int
5178msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
5179{
5180 file->private_data = inode->i_private;
5181 return 0;
5182}
5183
5184static ssize_t
5185msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
5186 size_t count, loff_t *ppos)
5187{
5188 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08005189 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005190 int max, i;
5191
5192 i = 0;
5193 max = sizeof(buf) - 1;
5194
5195 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
5196 host->curr.cmd, host->curr.data);
5197 if (host->curr.cmd) {
5198 struct mmc_command *cmd = host->curr.cmd;
5199
5200 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
5201 cmd->opcode, cmd->arg, cmd->flags);
5202 }
5203 if (host->curr.data) {
5204 struct mmc_data *data = host->curr.data;
5205 i += scnprintf(buf + i, max - i,
5206 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
5207 data->timeout_ns, data->timeout_clks,
5208 data->blksz, data->blocks, data->error,
5209 data->flags);
5210 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
5211 host->curr.xfer_size, host->curr.xfer_remain,
5212 host->curr.data_xfered, host->dma.sg);
5213 }
5214
5215 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
5216}
5217
5218static const struct file_operations msmsdcc_dbg_state_ops = {
5219 .read = msmsdcc_dbg_state_read,
5220 .open = msmsdcc_dbg_state_open,
5221};
5222
5223static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
5224{
5225 if (debugfs_dir) {
5226 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
5227 0644, debugfs_dir, host,
5228 &msmsdcc_dbg_state_ops);
5229 }
5230}
5231
5232static int __init msmsdcc_dbg_init(void)
5233{
5234 int err;
5235
5236 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
5237 if (IS_ERR(debugfs_dir)) {
5238 err = PTR_ERR(debugfs_dir);
5239 debugfs_dir = NULL;
5240 return err;
5241 }
5242
5243 return 0;
5244}
5245#endif