blob: 0e096eb73c3627c53224f991bc42b23b81a99a70 [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>
Subhash Jadavanic9b85752012-04-13 11:16:49 +053057#include <mach/mpm.h>
San Mehat9d2bd732009-09-22 16:44:22 -070058
San Mehat9d2bd732009-09-22 16:44:22 -070059#include "msm_sdcc.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070060#include "msm_sdcc_dml.h"
San Mehat9d2bd732009-09-22 16:44:22 -070061
62#define DRIVER_NAME "msm-sdcc"
63
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070064#define DBG(host, fmt, args...) \
65 pr_debug("%s: %s: " fmt "\n", mmc_hostname(host->mmc), __func__ , args)
66
67#define IRQ_DEBUG 0
68#define SPS_SDCC_PRODUCER_PIPE_INDEX 1
69#define SPS_SDCC_CONSUMER_PIPE_INDEX 2
70#define SPS_CONS_PERIPHERAL 0
71#define SPS_PROD_PERIPHERAL 1
Subhash Jadavanie6e1b822012-03-12 18:17:58 +053072/* Use SPS only if transfer size is more than this macro */
73#define SPS_MIN_XFER_SIZE MCI_FIFOSIZE
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070074
75#if defined(CONFIG_DEBUG_FS)
76static void msmsdcc_dbg_createhost(struct msmsdcc_host *);
77static struct dentry *debugfs_dir;
78static struct dentry *debugfs_file;
79static int msmsdcc_dbg_init(void);
80#endif
81
Subhash Jadavani8766e352011-11-30 11:30:32 +053082static u64 dma_mask = DMA_BIT_MASK(32);
San Mehat9d2bd732009-09-22 16:44:22 -070083static unsigned int msmsdcc_pwrsave = 1;
San Mehat9d2bd732009-09-22 16:44:22 -070084
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070085static struct mmc_command dummy52cmd;
86static struct mmc_request dummy52mrq = {
87 .cmd = &dummy52cmd,
88 .data = NULL,
89 .stop = NULL,
90};
91static struct mmc_command dummy52cmd = {
92 .opcode = SD_IO_RW_DIRECT,
93 .flags = MMC_RSP_PRESENT,
94 .data = NULL,
95 .mrq = &dummy52mrq,
96};
97/*
98 * An array holding the Tuning pattern to compare with when
99 * executing a tuning cycle.
100 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +0530101static const u32 tuning_block_64[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700102 0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
103 0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
104 0xF0FFF0FF, 0x3CCCFC0F, 0xCFCC33CC, 0xEEFFEFFF,
105 0xFDFFFDFF, 0xFFBFFFDF, 0xFFF7FFBB, 0xDE7B7FF7
106};
San Mehat865c8062009-11-13 13:42:06 -0800107
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +0530108static const u32 tuning_block_128[] = {
109 0xFF00FFFF, 0x0000FFFF, 0xCCCCFFFF, 0xCCCC33CC,
110 0xCC3333CC, 0xFFFFCCCC, 0xFFFFEEFF, 0xFFEEEEFF,
111 0xFFDDFFFF, 0xDDDDFFFF, 0xBBFFFFFF, 0xBBFFFFFF,
112 0xFFFFFFBB, 0xFFFFFF77, 0x77FF7777, 0xFFEEDDBB,
113 0x00FFFFFF, 0x00FFFFFF, 0xCCFFFF00, 0xCC33CCCC,
114 0x3333CCCC, 0xFFCCCCCC, 0xFFEEFFFF, 0xEEEEFFFF,
115 0xDDFFFFFF, 0xDDFFFFFF, 0xFFFFFFDD, 0xFFFFFFBB,
116 0xFFFFBBBB, 0xFFFF77FF, 0xFF7777FF, 0xEEDDBB77
117};
118
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700119#if IRQ_DEBUG == 1
120static char *irq_status_bits[] = { "cmdcrcfail", "datcrcfail", "cmdtimeout",
121 "dattimeout", "txunderrun", "rxoverrun",
122 "cmdrespend", "cmdsent", "dataend", NULL,
123 "datablkend", "cmdactive", "txactive",
124 "rxactive", "txhalfempty", "rxhalffull",
125 "txfifofull", "rxfifofull", "txfifoempty",
126 "rxfifoempty", "txdataavlbl", "rxdataavlbl",
127 "sdiointr", "progdone", "atacmdcompl",
128 "sdiointrope", "ccstimeout", NULL, NULL,
129 NULL, NULL, NULL };
130
131static void
132msmsdcc_print_status(struct msmsdcc_host *host, char *hdr, uint32_t status)
San Mehat865c8062009-11-13 13:42:06 -0800133{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700134 int i;
San Mehat8b1c2ba2009-11-16 10:17:30 -0800135
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700136 pr_debug("%s-%s ", mmc_hostname(host->mmc), hdr);
137 for (i = 0; i < 32; i++) {
138 if (status & (1 << i))
139 pr_debug("%s ", irq_status_bits[i]);
San Mehat865c8062009-11-13 13:42:06 -0800140 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700141 pr_debug("\n");
San Mehatc7fc9372009-11-22 17:19:07 -0800142}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700143#endif
San Mehat865c8062009-11-13 13:42:06 -0800144
San Mehat9d2bd732009-09-22 16:44:22 -0700145static void
146msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
147 u32 c);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530148static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530149static inline void msmsdcc_delay(struct msmsdcc_host *host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530150static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -0800151static void msmsdcc_sg_start(struct msmsdcc_host *host);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -0800152static int msmsdcc_vreg_reset(struct msmsdcc_host *host);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530153
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530154static inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
155{
156 unsigned short ret = NR_SG;
157
158 if (host->is_sps_mode) {
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +0530159 ret = SPS_MAX_DESCS;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530160 } else { /* DMA or PIO mode */
161 if (NR_SG > MAX_NR_SG_DMA_PIO)
162 ret = MAX_NR_SG_DMA_PIO;
163 }
164
165 return ret;
166}
167
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530168/* Prevent idle power collapse(pc) while operating in peripheral mode */
169static void msmsdcc_pm_qos_update_latency(struct msmsdcc_host *host, int vote)
170{
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -0700171 if (!host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530172 return;
173
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530174 if (vote)
175 pm_qos_update_request(&host->pm_qos_req_dma,
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -0700176 host->cpu_dma_latency);
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530177 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 Jadavanidd432952012-03-28 11:25:56 +0530263 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700264 writel_relaxed(0, host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530265 msmsdcc_sync_reg_wr(host);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530266}
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
Subhash Jadavanidd432952012-03-28 11:25:56 +0530285 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530286 /* Give some delay for clock reset to propogate to controller */
287 msmsdcc_delay(host);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530288}
289
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700290static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
291{
Pratibhasagar V1c11da62011-11-14 12:36:35 +0530292 if (host->sdcc_version) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530293 if (host->is_sps_mode) {
294 /* Reset DML first */
295 msmsdcc_dml_reset(host);
296 /*
297 * delay the SPS pipe reset in thread context as
298 * sps_connect/sps_disconnect APIs can be called
299 * only from non-atomic context.
300 */
301 host->sps.pipe_reset_pending = true;
302 }
303 mb();
304 msmsdcc_soft_reset(host);
305
306 pr_debug("%s: Applied soft reset to Controller\n",
307 mmc_hostname(host->mmc));
308
309 if (host->is_sps_mode)
310 msmsdcc_dml_init(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700311 } else {
312 /* Give Clock reset (hard reset) to controller */
313 u32 mci_clk = 0;
314 u32 mci_mask0 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700315
316 /* Save the controller state */
317 mci_clk = readl_relaxed(host->base + MMCICLOCK);
318 mci_mask0 = readl_relaxed(host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +0530319 host->pwr = readl_relaxed(host->base + MMCIPOWER);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700320 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700321
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530322 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700323 pr_debug("%s: Controller has been reinitialized\n",
324 mmc_hostname(host->mmc));
325
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700326 /* Restore the contoller state */
327 writel_relaxed(host->pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530328 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700329 writel_relaxed(mci_clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530330 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700331 writel_relaxed(mci_mask0, host->base + MMCIMASK0);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530332 mb(); /* no delay required after writing to MASK0 register */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700333 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530334
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700335 if (host->dummy_52_needed)
336 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700337}
338
339static int
San Mehat9d2bd732009-09-22 16:44:22 -0700340msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
341{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700342 int retval = 0;
343
San Mehat9d2bd732009-09-22 16:44:22 -0700344 BUG_ON(host->curr.data);
345
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700346 del_timer(&host->req_tout_timer);
347
San Mehat9d2bd732009-09-22 16:44:22 -0700348 if (mrq->data)
349 mrq->data->bytes_xfered = host->curr.data_xfered;
350 if (mrq->cmd->error == -ETIMEDOUT)
351 mdelay(5);
352
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530353 /* Clear current request information as current request has ended */
354 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
355
San Mehat9d2bd732009-09-22 16:44:22 -0700356 /*
357 * Need to drop the host lock here; mmc_request_done may call
358 * back into the driver...
359 */
360 spin_unlock(&host->lock);
361 mmc_request_done(host->mmc, mrq);
362 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700363
364 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700365}
366
367static void
368msmsdcc_stop_data(struct msmsdcc_host *host)
369{
San Mehat9d2bd732009-09-22 16:44:22 -0700370 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530371 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530372 host->curr.wait_for_auto_prog_done = 0;
373 host->curr.got_auto_prog_done = 0;
Krishna Konda3f5d48f2011-07-27 10:47:31 -0700374 writel_relaxed(readl_relaxed(host->base + MMCIDATACTRL) &
375 (~(MCI_DPSM_ENABLE)), host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530376 msmsdcc_sync_reg_wr(host); /* Allow the DPSM to be reset */
San Mehat9d2bd732009-09-22 16:44:22 -0700377}
378
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700379static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700380{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700381 return host->core_memres->start + MMCIFIFO;
382}
383
384static inline unsigned int msmsdcc_get_min_sup_clk_rate(
385 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530386
Subhash Jadavanidd432952012-03-28 11:25:56 +0530387static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700388{
389 mb();
Subhash Jadavanidd432952012-03-28 11:25:56 +0530390 if (!host->sdcc_version)
391 udelay(host->reg_write_delay);
392 else if (readl_relaxed(host->base + MCI_STATUS2) &
393 MCI_MCLK_REG_WR_ACTIVE) {
394 ktime_t start, diff;
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530395
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530396 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
Subhash Jadavanidd432952012-03-28 11:25:56 +0530411static inline void msmsdcc_delay(struct msmsdcc_host *host)
412{
413 udelay(host->reg_write_delay);
414
415}
416
San Mehat56a8b5b2009-11-21 12:29:46 -0800417static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700418msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
419{
420 writel_relaxed(arg, host->base + MMCIARGUMENT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700421 writel_relaxed(c, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530422 /*
423 * As after sending the command, we don't write any of the
424 * controller registers and just wait for the
425 * CMD_RESPOND_END/CMD_SENT/Command failure notication
426 * from Controller.
427 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700428 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800429}
430
431static void
432msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
433{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700434 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800435
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700436 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
437 writel_relaxed((unsigned int)host->curr.xfer_size,
438 host->base + MMCIDATALENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700439 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530440 msmsdcc_sync_reg_wr(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800441
San Mehat6ac9ea62009-12-02 17:24:58 -0800442 if (host->cmd_cmd) {
443 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700444 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800445 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800446}
447
San Mehat9d2bd732009-09-22 16:44:22 -0700448static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530449msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700450{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530451 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700452 unsigned long flags;
453 struct mmc_request *mrq;
454
455 spin_lock_irqsave(&host->lock, flags);
456 mrq = host->curr.mrq;
457 BUG_ON(!mrq);
458
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530459 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700460 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700461 goto out;
462 }
463
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530464 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700465 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700466 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700467 } else {
468 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530469 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700470 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530471 mmc_hostname(host->mmc), host->dma.result);
472 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700473 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530474 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530475 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700476 host->dma.err.flush[0], host->dma.err.flush[1],
477 host->dma.err.flush[2], host->dma.err.flush[3],
478 host->dma.err.flush[4],
479 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530480 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700481 if (!mrq->data->error)
482 mrq->data->error = -EIO;
483 }
San Mehat9d2bd732009-09-22 16:44:22 -0700484 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents,
485 host->dma.dir);
486
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700487 if (host->curr.user_pages) {
488 struct scatterlist *sg = host->dma.sg;
489 int i;
490
491 for (i = 0; i < host->dma.num_ents; i++, sg++)
492 flush_dcache_page(sg_page(sg));
493 }
494
San Mehat9d2bd732009-09-22 16:44:22 -0700495 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800496 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700497
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530498 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
499 (host->curr.wait_for_auto_prog_done &&
500 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700501 /*
502 * If we've already gotten our DATAEND / DATABLKEND
503 * for this request, then complete it through here.
504 */
San Mehat9d2bd732009-09-22 16:44:22 -0700505
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700506 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700507 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700508 host->curr.xfer_remain -= host->curr.xfer_size;
509 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700510 if (host->dummy_52_needed) {
511 mrq->data->bytes_xfered = host->curr.data_xfered;
512 host->dummy_52_sent = 1;
513 msmsdcc_start_command(host, &dummy52cmd,
514 MCI_CPSM_PROGENA);
515 goto out;
516 }
517 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530518 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530519 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700520 mrq->data->bytes_xfered = host->curr.data_xfered;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700521 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530522 /*
523 * Clear current request information as current
524 * request has ended
525 */
526 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
San Mehat9d2bd732009-09-22 16:44:22 -0700527 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700528
San Mehat9d2bd732009-09-22 16:44:22 -0700529 mmc_request_done(host->mmc, mrq);
530 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530531 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
532 || !mrq->sbc)) {
533 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530534 }
San Mehat9d2bd732009-09-22 16:44:22 -0700535 }
536
537out:
538 spin_unlock_irqrestore(&host->lock, flags);
539 return;
540}
541
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700542#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
543/**
544 * Callback notification from SPS driver
545 *
546 * This callback function gets triggered called from
547 * SPS driver when requested SPS data transfer is
548 * completed.
549 *
550 * SPS driver invokes this callback in BAM irq context so
551 * SDCC driver schedule a tasklet for further processing
552 * this callback notification at later point of time in
553 * tasklet context and immediately returns control back
554 * to SPS driver.
555 *
556 * @nofity - Pointer to sps event notify sturcture
557 *
558 */
559static void
560msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
561{
562 struct msmsdcc_host *host =
563 (struct msmsdcc_host *)
564 ((struct sps_event_notify *)notify)->user;
565
566 host->sps.notify = *notify;
567 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
568 mmc_hostname(host->mmc), __func__, notify->event_id,
569 notify->data.transfer.iovec.addr,
570 notify->data.transfer.iovec.size,
571 notify->data.transfer.iovec.flags);
572 /* Schedule a tasklet for completing data transfer */
573 tasklet_schedule(&host->sps.tlet);
574}
575
576/**
577 * Tasklet handler for processing SPS callback event
578 *
579 * This function processing SPS event notification and
580 * checks if the SPS transfer is completed or not and
581 * then accordingly notifies status to MMC core layer.
582 *
583 * This function is called in tasklet context.
584 *
585 * @data - Pointer to sdcc driver data
586 *
587 */
588static void msmsdcc_sps_complete_tlet(unsigned long data)
589{
590 unsigned long flags;
591 int i, rc;
592 u32 data_xfered = 0;
593 struct mmc_request *mrq;
594 struct sps_iovec iovec;
595 struct sps_pipe *sps_pipe_handle;
596 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
597 struct sps_event_notify *notify = &host->sps.notify;
598
599 spin_lock_irqsave(&host->lock, flags);
600 if (host->sps.dir == DMA_FROM_DEVICE)
601 sps_pipe_handle = host->sps.prod.pipe_handle;
602 else
603 sps_pipe_handle = host->sps.cons.pipe_handle;
604 mrq = host->curr.mrq;
605
606 if (!mrq) {
607 spin_unlock_irqrestore(&host->lock, flags);
608 return;
609 }
610
611 pr_debug("%s: %s: sps event_id=%d\n",
612 mmc_hostname(host->mmc), __func__,
613 notify->event_id);
614
615 if (msmsdcc_is_dml_busy(host)) {
616 /* oops !!! this should never happen. */
617 pr_err("%s: %s: Received SPS EOT event"
618 " but DML HW is still busy !!!\n",
619 mmc_hostname(host->mmc), __func__);
620 }
621 /*
622 * Got End of transfer event!!! Check if all of the data
623 * has been transferred?
624 */
625 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
626 rc = sps_get_iovec(sps_pipe_handle, &iovec);
627 if (rc) {
628 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
629 mmc_hostname(host->mmc), __func__, rc, i);
630 break;
631 }
632 data_xfered += iovec.size;
633 }
634
635 if (data_xfered == host->curr.xfer_size) {
636 host->curr.data_xfered = host->curr.xfer_size;
637 host->curr.xfer_remain -= host->curr.xfer_size;
638 pr_debug("%s: Data xfer success. data_xfered=0x%x",
639 mmc_hostname(host->mmc),
640 host->curr.xfer_size);
641 } else {
642 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
643 " xfer_size=%d", mmc_hostname(host->mmc),
644 data_xfered, host->curr.xfer_size);
645 msmsdcc_reset_and_restore(host);
646 if (!mrq->data->error)
647 mrq->data->error = -EIO;
648 }
649
650 /* Unmap sg buffers */
651 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
652 host->sps.dir);
653
654 host->sps.sg = NULL;
655 host->sps.busy = 0;
656
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530657 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
658 (host->curr.wait_for_auto_prog_done &&
659 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700660 /*
661 * If we've already gotten our DATAEND / DATABLKEND
662 * for this request, then complete it through here.
663 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700664
665 if (!mrq->data->error) {
666 host->curr.data_xfered = host->curr.xfer_size;
667 host->curr.xfer_remain -= host->curr.xfer_size;
668 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700669 if (host->dummy_52_needed) {
670 mrq->data->bytes_xfered = host->curr.data_xfered;
671 host->dummy_52_sent = 1;
672 msmsdcc_start_command(host, &dummy52cmd,
673 MCI_CPSM_PROGENA);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700674 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700675 return;
676 }
677 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530678 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530679 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700680 mrq->data->bytes_xfered = host->curr.data_xfered;
681 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530682 /*
683 * Clear current request information as current
684 * request has ended
685 */
686 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700687 spin_unlock_irqrestore(&host->lock, flags);
688
689 mmc_request_done(host->mmc, mrq);
690 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530691 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
692 || !mrq->sbc)) {
693 msmsdcc_start_command(host, mrq->data->stop, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700694 }
695 }
696 spin_unlock_irqrestore(&host->lock, flags);
697}
698
699/**
700 * Exit from current SPS data transfer
701 *
702 * This function exits from current SPS data transfer.
703 *
704 * This function should be called when error condition
705 * is encountered during data transfer.
706 *
707 * @host - Pointer to sdcc host structure
708 *
709 */
710static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
711{
712 struct mmc_request *mrq;
713
714 mrq = host->curr.mrq;
715 BUG_ON(!mrq);
716
717 msmsdcc_reset_and_restore(host);
718 if (!mrq->data->error)
719 mrq->data->error = -EIO;
720
721 /* Unmap sg buffers */
722 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
723 host->sps.dir);
724
725 host->sps.sg = NULL;
726 host->sps.busy = 0;
727 if (host->curr.data)
728 msmsdcc_stop_data(host);
729
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530730 if (!mrq->data->stop || mrq->cmd->error ||
731 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700732 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530733 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
734 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700735 msmsdcc_start_command(host, mrq->data->stop, 0);
736
737}
738#else
739static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
740static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
741static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
742#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
743
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530744static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700745
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530746static void
747msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
748 unsigned int result,
749 struct msm_dmov_errdata *err)
750{
751 struct msmsdcc_dma_data *dma_data =
752 container_of(cmd, struct msmsdcc_dma_data, hdr);
753 struct msmsdcc_host *host = dma_data->host;
754
755 dma_data->result = result;
756 if (err)
757 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
758
759 tasklet_schedule(&host->dma_tlet);
760}
761
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530762static bool msmsdcc_is_dma_possible(struct msmsdcc_host *host,
763 struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700764{
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530765 bool ret = true;
766 u32 xfer_size = data->blksz * data->blocks;
767
768 if (host->is_sps_mode) {
769 /*
770 * BAM Mode: Fall back on PIO if size is less
771 * than or equal to SPS_MIN_XFER_SIZE bytes.
772 */
773 if (xfer_size <= SPS_MIN_XFER_SIZE)
774 ret = false;
775 } else if (host->is_dma_mode) {
776 /*
777 * ADM Mode: Fall back on PIO if size is less than FIFO size
778 * or not integer multiple of FIFO size
779 */
780 if (xfer_size % MCI_FIFOSIZE)
781 ret = false;
782 } else {
783 /* PIO Mode */
784 ret = false;
785 }
786
787 return ret;
San Mehat9d2bd732009-09-22 16:44:22 -0700788}
789
790static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
791{
792 struct msmsdcc_nc_dmadata *nc;
793 dmov_box *box;
794 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700795 unsigned int n;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530796 int i, err = 0, box_cmd_cnt = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700797 struct scatterlist *sg = data->sg;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530798 unsigned int len, offset;
San Mehat9d2bd732009-09-22 16:44:22 -0700799
Krishna Konda25786ec2011-07-25 16:21:36 -0700800 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700801 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700802
Krishna Konda25786ec2011-07-25 16:21:36 -0700803 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
804
San Mehat9d2bd732009-09-22 16:44:22 -0700805 host->dma.sg = data->sg;
806 host->dma.num_ents = data->sg_len;
807
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530808 /* Prevent memory corruption */
809 BUG_ON(host->dma.num_ents > msmsdcc_get_nr_sg(host));
San Mehat56a8b5b2009-11-21 12:29:46 -0800810
San Mehat9d2bd732009-09-22 16:44:22 -0700811 nc = host->dma.nc;
812
San Mehat9d2bd732009-09-22 16:44:22 -0700813 if (data->flags & MMC_DATA_READ)
814 host->dma.dir = DMA_FROM_DEVICE;
815 else
816 host->dma.dir = DMA_TO_DEVICE;
817
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700818 n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
819 host->dma.num_ents, host->dma.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700820
821 if (n != host->dma.num_ents) {
822 pr_err("%s: Unable to map in all sg elements\n",
823 mmc_hostname(host->mmc));
824 host->dma.sg = NULL;
825 host->dma.num_ents = 0;
826 return -ENOMEM;
San Mehat56a8b5b2009-11-21 12:29:46 -0800827 }
San Mehat9d2bd732009-09-22 16:44:22 -0700828
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530829 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
830 host->curr.user_pages = 0;
831 box = &nc->cmd[0];
832 for (i = 0; i < host->dma.num_ents; i++) {
833 len = sg_dma_len(sg);
834 offset = 0;
835
836 do {
837 /* Check if we can do DMA */
838 if (!len || (box_cmd_cnt >= MMC_MAX_DMA_CMDS)) {
839 err = -ENOTSUPP;
840 goto unmap;
841 }
842
843 box->cmd = CMD_MODE_BOX;
844
845 if (len >= MMC_MAX_DMA_BOX_LENGTH) {
846 len = MMC_MAX_DMA_BOX_LENGTH;
847 len -= len % data->blksz;
848 }
849 rows = (len % MCI_FIFOSIZE) ?
850 (len / MCI_FIFOSIZE) + 1 :
851 (len / MCI_FIFOSIZE);
852
853 if (data->flags & MMC_DATA_READ) {
854 box->src_row_addr = msmsdcc_fifo_addr(host);
855 box->dst_row_addr = sg_dma_address(sg) + offset;
856 box->src_dst_len = (MCI_FIFOSIZE << 16) |
857 (MCI_FIFOSIZE);
858 box->row_offset = MCI_FIFOSIZE;
859 box->num_rows = rows * ((1 << 16) + 1);
860 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
861 } else {
862 box->src_row_addr = sg_dma_address(sg) + offset;
863 box->dst_row_addr = msmsdcc_fifo_addr(host);
864 box->src_dst_len = (MCI_FIFOSIZE << 16) |
865 (MCI_FIFOSIZE);
866 box->row_offset = (MCI_FIFOSIZE << 16);
867 box->num_rows = rows * ((1 << 16) + 1);
868 box->cmd |= CMD_DST_CRCI(host->dma.crci);
869 }
870
871 offset += len;
872 len = sg_dma_len(sg) - offset;
873 box++;
874 box_cmd_cnt++;
875 } while (len);
876 sg++;
877 }
878 /* Mark last command */
879 box--;
880 box->cmd |= CMD_LC;
881
882 /* location of command block must be 64 bit aligned */
883 BUG_ON(host->dma.cmd_busaddr & 0x07);
884
885 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
886 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
887 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
888 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
889
890 /* Flush all data to memory before starting dma */
891 mb();
892
893unmap:
894 if (err) {
895 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
896 host->dma.num_ents, host->dma.dir);
897 pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
898 mmc_hostname(host->mmc), err);
899 }
900
901 return err;
San Mehat9d2bd732009-09-22 16:44:22 -0700902}
903
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700904#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
905/**
906 * Submits data transfer request to SPS driver
907 *
908 * This function make sg (scatter gather) data buffers
909 * DMA ready and then submits them to SPS driver for
910 * transfer.
911 *
912 * @host - Pointer to sdcc host structure
913 * @data - Pointer to mmc_data structure
914 *
915 * @return 0 if success else negative value
916 */
917static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
918 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -0800919{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700920 int rc = 0;
921 u32 flags;
922 int i;
923 u32 addr, len, data_cnt;
924 struct scatterlist *sg = data->sg;
925 struct sps_pipe *sps_pipe_handle;
926
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530927 /* Prevent memory corruption */
928 BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700929
930 host->sps.sg = data->sg;
931 host->sps.num_ents = data->sg_len;
932 host->sps.xfer_req_cnt = 0;
933 if (data->flags & MMC_DATA_READ) {
934 host->sps.dir = DMA_FROM_DEVICE;
935 sps_pipe_handle = host->sps.prod.pipe_handle;
936 } else {
937 host->sps.dir = DMA_TO_DEVICE;
938 sps_pipe_handle = host->sps.cons.pipe_handle;
939 }
940
941 /* Make sg buffers DMA ready */
942 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
943 host->sps.dir);
944
945 if (rc != data->sg_len) {
946 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
947 mmc_hostname(host->mmc), rc);
948 host->sps.sg = NULL;
949 host->sps.num_ents = 0;
950 rc = -ENOMEM;
951 goto dma_map_err;
952 }
953
954 pr_debug("%s: %s: %s: pipe=0x%x, total_xfer=0x%x, sg_len=%d\n",
955 mmc_hostname(host->mmc), __func__,
956 host->sps.dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
957 (u32)sps_pipe_handle, host->curr.xfer_size, data->sg_len);
958
959 for (i = 0; i < data->sg_len; i++) {
960 /*
961 * Check if this is the last buffer to transfer?
962 * If yes then set the INT and EOT flags.
963 */
964 len = sg_dma_len(sg);
965 addr = sg_dma_address(sg);
966 flags = 0;
967 while (len > 0) {
968 if (len > SPS_MAX_DESC_SIZE) {
969 data_cnt = SPS_MAX_DESC_SIZE;
970 } else {
971 data_cnt = len;
972 if (i == data->sg_len - 1)
973 flags = SPS_IOVEC_FLAG_INT |
974 SPS_IOVEC_FLAG_EOT;
975 }
976 rc = sps_transfer_one(sps_pipe_handle, addr,
977 data_cnt, host, flags);
978 if (rc) {
979 pr_err("%s: sps_transfer_one() error! rc=%d,"
980 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
981 mmc_hostname(host->mmc), rc,
982 (u32)sps_pipe_handle, (u32)sg, i);
983 goto dma_map_err;
984 }
985 addr += data_cnt;
986 len -= data_cnt;
987 host->sps.xfer_req_cnt++;
988 }
989 sg++;
990 }
991 goto out;
992
993dma_map_err:
994 /* unmap sg buffers */
995 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
996 host->sps.dir);
997out:
998 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -0700999}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001000#else
1001static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
1002 struct mmc_data *data) { return 0; }
1003#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -07001004
1005static void
San Mehat56a8b5b2009-11-21 12:29:46 -08001006msmsdcc_start_command_deferred(struct msmsdcc_host *host,
1007 struct mmc_command *cmd, u32 *c)
1008{
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301009 DBG(host, "op %02x arg %08x flags %08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001010 cmd->opcode, cmd->arg, cmd->flags);
1011
San Mehat56a8b5b2009-11-21 12:29:46 -08001012 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
1013
1014 if (cmd->flags & MMC_RSP_PRESENT) {
1015 if (cmd->flags & MMC_RSP_136)
1016 *c |= MCI_CPSM_LONGRSP;
1017 *c |= MCI_CPSM_RESPONSE;
1018 }
1019
1020 if (/*interrupt*/0)
1021 *c |= MCI_CPSM_INTERRUPT;
1022
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301023 if (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
1024 cmd->opcode == MMC_READ_MULTIPLE_BLOCK ||
1025 cmd->opcode == MMC_WRITE_BLOCK ||
1026 cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK ||
1027 cmd->opcode == SD_IO_RW_EXTENDED)
San Mehat56a8b5b2009-11-21 12:29:46 -08001028 *c |= MCI_CSPM_DATCMD;
1029
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001030 /* Check if AUTO CMD19 is required or not? */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301031 if (host->tuning_needed &&
1032 !(host->mmc->ios.timing == MMC_TIMING_MMC_HS200)) {
1033
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301034 /*
1035 * For open ended block read operation (without CMD23),
1036 * AUTO_CMD19 bit should be set while sending the READ command.
1037 * For close ended block read operation (with CMD23),
1038 * AUTO_CMD19 bit should be set while sending CMD23.
1039 */
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301040 if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
1041 host->curr.mrq->cmd->opcode ==
1042 MMC_READ_MULTIPLE_BLOCK) ||
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301043 (!host->curr.mrq->sbc &&
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301044 (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
1045 cmd->opcode == MMC_READ_MULTIPLE_BLOCK))) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301046 msmsdcc_enable_cdr_cm_sdc4_dll(host);
1047 *c |= MCI_CSPM_AUTO_CMD19;
1048 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001049 }
1050
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05301051 /* Clear CDR_EN bit for write operations */
1052 if (host->tuning_needed && cmd->mrq->data &&
1053 (cmd->mrq->data->flags & MMC_DATA_WRITE))
1054 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) &
1055 ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
1056
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301057 if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301058 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001059 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301060 }
1061
San Mehat56a8b5b2009-11-21 12:29:46 -08001062 if (cmd == cmd->mrq->stop)
1063 *c |= MCI_CSPM_MCIABORT;
1064
San Mehat56a8b5b2009-11-21 12:29:46 -08001065 if (host->curr.cmd != NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001066 pr_err("%s: Overlapping command requests\n",
1067 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -08001068 }
1069 host->curr.cmd = cmd;
1070}
1071
1072static void
1073msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1074 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001075{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301076 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001077 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001078 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001079 unsigned int pio_irqmask = 0;
1080
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301081 BUG_ON(!data->sg);
1082 BUG_ON(!data->sg_len);
1083
San Mehat9d2bd732009-09-22 16:44:22 -07001084 host->curr.data = data;
1085 host->curr.xfer_size = data->blksz * data->blocks;
1086 host->curr.xfer_remain = host->curr.xfer_size;
1087 host->curr.data_xfered = 0;
1088 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301089 host->curr.got_auto_prog_done = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001090
San Mehat9d2bd732009-09-22 16:44:22 -07001091 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1092
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301093 if (host->curr.wait_for_auto_prog_done)
1094 datactrl |= MCI_AUTO_PROG_DONE;
1095
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05301096 if (msmsdcc_is_dma_possible(host, data)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001097 if (host->is_dma_mode && !msmsdcc_config_dma(host, data)) {
1098 datactrl |= MCI_DPSM_DMAENABLE;
1099 } else if (host->is_sps_mode) {
1100 if (!msmsdcc_is_dml_busy(host)) {
1101 if (!msmsdcc_sps_start_xfer(host, data)) {
1102 /* Now kick start DML transfer */
1103 mb();
1104 msmsdcc_dml_start_xfer(host, data);
1105 datactrl |= MCI_DPSM_DMAENABLE;
1106 host->sps.busy = 1;
1107 }
1108 } else {
1109 /*
1110 * Can't proceed with new transfer as
1111 * previous trasnfer is already in progress.
1112 * There is no point of going into PIO mode
1113 * as well. Is this a time to do kernel panic?
1114 */
1115 pr_err("%s: %s: DML HW is busy!!!"
1116 " Can't perform new SPS transfers"
1117 " now\n", mmc_hostname(host->mmc),
1118 __func__);
1119 }
1120 }
1121 }
1122
1123 /* Is data transfer in PIO mode required? */
1124 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001125 if (data->flags & MMC_DATA_READ) {
1126 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1127 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1128 pio_irqmask |= MCI_RXDATAAVLBLMASK;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001129 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001130 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1131 MCI_TXFIFOEMPTYMASK;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001132
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001133 msmsdcc_sg_start(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001134 }
1135
1136 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301137 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
San Mehat9d2bd732009-09-22 16:44:22 -07001138
San Mehat56a8b5b2009-11-21 12:29:46 -08001139 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001140 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001141 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -07001142
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001143 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
1144 /* Use ADM (Application Data Mover) HW for Data transfer */
1145 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001146 host->cmd_timeout = timeout;
1147 host->cmd_pio_irqmask = pio_irqmask;
1148 host->cmd_datactrl = datactrl;
1149 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001150
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001151 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1152 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001153 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001154
1155 if (cmd) {
1156 msmsdcc_start_command_deferred(host, cmd, &c);
1157 host->cmd_c = c;
1158 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001159 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1160 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1161 host->base + MMCIMASK0);
1162 mb();
1163 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001164 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001165 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001166 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001167
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001168 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001169
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001170 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1171 (~(MCI_IRQ_PIO))) | pio_irqmask,
1172 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001173 writel_relaxed(datactrl, base + MMCIDATACTRL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001174
1175 if (cmd) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05301176 /* Delay between data/command */
1177 msmsdcc_sync_reg_wr(host);
San Mehat56a8b5b2009-11-21 12:29:46 -08001178 /* Daisy-chain the command if requested */
1179 msmsdcc_start_command(host, cmd, c);
Subhash Jadavanidd432952012-03-28 11:25:56 +05301180 } else {
1181 /*
1182 * We don't need delay after writing to DATA_CTRL
1183 * register if we are not writing to CMD register
1184 * immediately after this. As we already have delay
1185 * before sending the command, we just need mb() here.
1186 */
1187 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001188 }
San Mehat9d2bd732009-09-22 16:44:22 -07001189 }
1190}
1191
1192static void
1193msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1194{
San Mehat56a8b5b2009-11-21 12:29:46 -08001195 msmsdcc_start_command_deferred(host, cmd, &c);
1196 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001197}
1198
1199static void
1200msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1201 unsigned int status)
1202{
1203 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001204 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
Subhash Jadavanib30c9822012-03-27 18:03:16 +05301205 || data->mrq->cmd->opcode == MMC_BUS_TEST_R
1206 || data->mrq->cmd->opcode ==
1207 MMC_SEND_TUNING_BLOCK_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001208 pr_err("%s: Data CRC error\n",
1209 mmc_hostname(host->mmc));
1210 pr_err("%s: opcode 0x%.8x\n", __func__,
1211 data->mrq->cmd->opcode);
1212 pr_err("%s: blksz %d, blocks %d\n", __func__,
1213 data->blksz, data->blocks);
1214 data->error = -EILSEQ;
1215 }
San Mehat9d2bd732009-09-22 16:44:22 -07001216 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001217 /* CRC is optional for the bus test commands, not all
1218 * cards respond back with CRC. However controller
1219 * waits for the CRC and times out. Hence ignore the
1220 * data timeouts during the Bustest.
1221 */
1222 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1223 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301224 pr_err("%s: CMD%d: Data timeout\n",
1225 mmc_hostname(host->mmc),
1226 data->mrq->cmd->opcode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001227 data->error = -ETIMEDOUT;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301228 msmsdcc_dump_sdcc_state(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001229 }
San Mehat9d2bd732009-09-22 16:44:22 -07001230 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001231 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001232 data->error = -EIO;
1233 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001234 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001235 data->error = -EIO;
1236 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001237 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001238 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001239 data->error = -EIO;
1240 }
San Mehat9d2bd732009-09-22 16:44:22 -07001241
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001242 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001243 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001244 host->dummy_52_needed = 0;
1245}
San Mehat9d2bd732009-09-22 16:44:22 -07001246
1247static int
1248msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1249{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001250 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001251 uint32_t *ptr = (uint32_t *) buffer;
1252 int count = 0;
1253
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301254 if (remain % 4)
1255 remain = ((remain >> 2) + 1) << 2;
1256
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001257 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1258
1259 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001260 ptr++;
1261 count += sizeof(uint32_t);
1262
1263 remain -= sizeof(uint32_t);
1264 if (remain == 0)
1265 break;
1266 }
1267 return count;
1268}
1269
1270static int
1271msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001272 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001273{
1274 void __iomem *base = host->base;
1275 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001276 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001277
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001278 while (readl_relaxed(base + MMCISTATUS) &
1279 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1280 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001281
San Mehat9d2bd732009-09-22 16:44:22 -07001282 count = min(remain, maxcnt);
1283
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301284 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1285 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001286 ptr += count;
1287 remain -= count;
1288
1289 if (remain == 0)
1290 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001291 }
1292 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001293
1294 return ptr - buffer;
1295}
1296
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001297/*
1298 * Copy up to a word (4 bytes) between a scatterlist
1299 * and a temporary bounce buffer when the word lies across
1300 * two pages. The temporary buffer can then be read to/
1301 * written from the FIFO once.
1302 */
1303static void _msmsdcc_sg_consume_word(struct msmsdcc_host *host)
1304{
1305 struct msmsdcc_pio_data *pio = &host->pio;
1306 unsigned int bytes_avail;
1307
1308 if (host->curr.data->flags & MMC_DATA_READ)
1309 memcpy(pio->sg_miter.addr, pio->bounce_buf,
1310 pio->bounce_buf_len);
1311 else
1312 memcpy(pio->bounce_buf, pio->sg_miter.addr,
1313 pio->bounce_buf_len);
1314
1315 while (pio->bounce_buf_len != 4) {
1316 if (!sg_miter_next(&pio->sg_miter))
1317 break;
1318 bytes_avail = min_t(unsigned int, pio->sg_miter.length,
1319 4 - pio->bounce_buf_len);
1320 if (host->curr.data->flags & MMC_DATA_READ)
1321 memcpy(pio->sg_miter.addr,
1322 &pio->bounce_buf[pio->bounce_buf_len],
1323 bytes_avail);
1324 else
1325 memcpy(&pio->bounce_buf[pio->bounce_buf_len],
1326 pio->sg_miter.addr, bytes_avail);
1327
1328 pio->sg_miter.consumed = bytes_avail;
1329 pio->bounce_buf_len += bytes_avail;
1330 }
1331}
1332
1333/*
1334 * Use sg_miter_next to return as many 4-byte aligned
1335 * chunks as possible, using a temporary 4 byte buffer
1336 * for alignment if necessary
1337 */
1338static int msmsdcc_sg_next(struct msmsdcc_host *host, char **buf, int *len)
1339{
1340 struct msmsdcc_pio_data *pio = &host->pio;
1341 unsigned int length, rlength;
1342 char *buffer;
1343
1344 if (!sg_miter_next(&pio->sg_miter))
1345 return 0;
1346
1347 buffer = pio->sg_miter.addr;
1348 length = pio->sg_miter.length;
1349
1350 if (length < host->curr.xfer_remain) {
1351 rlength = round_down(length, 4);
1352 if (rlength) {
1353 /*
1354 * We have a 4-byte aligned chunk.
1355 * The rounding will be reflected by
1356 * a call to msmsdcc_sg_consumed
1357 */
1358 length = rlength;
1359 goto sg_next_end;
1360 }
1361 /*
1362 * We have a length less than 4 bytes. Check to
1363 * see if more buffer is available, and combine
1364 * to make 4 bytes if possible.
1365 */
1366 pio->bounce_buf_len = length;
1367 memset(pio->bounce_buf, 0, 4);
1368
1369 /*
1370 * On a read, get 4 bytes from FIFO, and distribute
1371 * (4-bouce_buf_len) bytes into consecutive
1372 * sgl buffers when msmsdcc_sg_consumed is called
1373 */
1374 if (host->curr.data->flags & MMC_DATA_READ) {
1375 buffer = pio->bounce_buf;
1376 length = 4;
1377 goto sg_next_end;
1378 } else {
1379 _msmsdcc_sg_consume_word(host);
1380 buffer = pio->bounce_buf;
1381 length = pio->bounce_buf_len;
1382 }
1383 }
1384
1385sg_next_end:
1386 *buf = buffer;
1387 *len = length;
1388 return 1;
1389}
1390
1391/*
1392 * Update sg_miter.consumed based on how many bytes were
1393 * consumed. If the bounce buffer was used to read from FIFO,
1394 * redistribute into sgls.
1395 */
1396static void msmsdcc_sg_consumed(struct msmsdcc_host *host,
1397 unsigned int length)
1398{
1399 struct msmsdcc_pio_data *pio = &host->pio;
1400
1401 if (host->curr.data->flags & MMC_DATA_READ) {
1402 if (length > pio->sg_miter.consumed)
1403 /*
1404 * consumed 4 bytes, but sgl
1405 * describes < 4 bytes
1406 */
1407 _msmsdcc_sg_consume_word(host);
1408 else
1409 pio->sg_miter.consumed = length;
1410 } else
1411 if (length < pio->sg_miter.consumed)
1412 pio->sg_miter.consumed = length;
1413}
1414
1415static void msmsdcc_sg_start(struct msmsdcc_host *host)
1416{
1417 unsigned int sg_miter_flags = SG_MITER_ATOMIC;
1418
1419 host->pio.bounce_buf_len = 0;
1420
1421 if (host->curr.data->flags & MMC_DATA_READ)
1422 sg_miter_flags |= SG_MITER_TO_SG;
1423 else
1424 sg_miter_flags |= SG_MITER_FROM_SG;
1425
1426 sg_miter_start(&host->pio.sg_miter, host->curr.data->sg,
1427 host->curr.data->sg_len, sg_miter_flags);
1428}
1429
1430static void msmsdcc_sg_stop(struct msmsdcc_host *host)
1431{
1432 sg_miter_stop(&host->pio.sg_miter);
1433}
1434
San Mehat1cd22962010-02-03 12:59:29 -08001435static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001436msmsdcc_pio_irq(int irq, void *dev_id)
1437{
1438 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001439 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001440 uint32_t status;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001441 unsigned long flags;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001442 unsigned int remain;
1443 char *buffer;
San Mehat9d2bd732009-09-22 16:44:22 -07001444
Murali Palnati36448a42011-09-02 15:06:18 +05301445 spin_lock(&host->lock);
1446
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001447 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001448
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001449 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301450 (MCI_IRQ_PIO)) == 0) {
1451 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001452 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301453 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001454#if IRQ_DEBUG
1455 msmsdcc_print_status(host, "irq1-r", status);
1456#endif
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001457 local_irq_save(flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001458
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001459 do {
1460 unsigned int len;
San Mehat9d2bd732009-09-22 16:44:22 -07001461
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001462 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1463 | MCI_RXDATAAVLBL)))
1464 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001465
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001466 if (!msmsdcc_sg_next(host, &buffer, &remain))
1467 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001468
San Mehat9d2bd732009-09-22 16:44:22 -07001469 len = 0;
1470 if (status & MCI_RXACTIVE)
1471 len = msmsdcc_pio_read(host, buffer, remain);
1472 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001473 len = msmsdcc_pio_write(host, buffer, remain);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001474
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301475 /* len might have aligned to 32bits above */
1476 if (len > remain)
1477 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001478
San Mehat9d2bd732009-09-22 16:44:22 -07001479 host->curr.xfer_remain -= len;
1480 host->curr.data_xfered += len;
1481 remain -= len;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001482 msmsdcc_sg_consumed(host, len);
San Mehat9d2bd732009-09-22 16:44:22 -07001483
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001484 if (remain) /* Done with this page? */
1485 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001486
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001487 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001488 } while (1);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001489
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001490 msmsdcc_sg_stop(host);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001491 local_irq_restore(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001492
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001493 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1494 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1495 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1496 host->base + MMCIMASK0);
1497 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301498 /*
1499 * back to back write to MASK0 register don't need
1500 * synchronization delay.
1501 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001502 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1503 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1504 }
1505 mb();
1506 } else if (!host->curr.xfer_remain) {
1507 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1508 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1509 mb();
1510 }
San Mehat9d2bd732009-09-22 16:44:22 -07001511
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001512 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001513
1514 return IRQ_HANDLED;
1515}
1516
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001517static void
1518msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1519
1520static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1521 struct mmc_data *data)
1522{
1523 u32 loop_cnt = 0;
1524
1525 /*
1526 * For read commands with data less than fifo size, it is possible to
1527 * get DATAEND first and RXDATA_AVAIL might be set later because of
1528 * synchronization delay through the asynchronous RX FIFO. Thus, for
1529 * such cases, even after DATAEND interrupt is received software
1530 * should poll for RXDATA_AVAIL until the requested data is read out
1531 * of FIFO. This change is needed to get around this abnormal but
1532 * sometimes expected behavior of SDCC3 controller.
1533 *
1534 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1535 * after the data is loaded into RX FIFO. This would amount to less
1536 * than a microsecond and thus looping for 1000 times is good enough
1537 * for that delay.
1538 */
1539 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1540 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1541 spin_unlock(&host->lock);
1542 msmsdcc_pio_irq(1, host);
1543 spin_lock(&host->lock);
1544 }
1545 }
1546 if (loop_cnt == 1000) {
1547 pr_info("%s: Timed out while polling for Rx Data\n",
1548 mmc_hostname(host->mmc));
1549 data->error = -ETIMEDOUT;
1550 msmsdcc_reset_and_restore(host);
1551 }
1552}
1553
San Mehat9d2bd732009-09-22 16:44:22 -07001554static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1555{
1556 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001557
1558 host->curr.cmd = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001559 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1560 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1561 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1562 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -07001563
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001564 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301565 pr_debug("%s: CMD%d: Command timeout\n",
1566 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001567 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001568 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301569 !host->tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301570 pr_err("%s: CMD%d: Command CRC error\n",
1571 mmc_hostname(host->mmc), cmd->opcode);
1572 msmsdcc_dump_sdcc_state(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001573 cmd->error = -EILSEQ;
1574 }
1575
1576 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001577 if (host->curr.data && host->dma.sg &&
1578 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001579 msm_dmov_stop_cmd(host->dma.channel,
1580 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001581 else if (host->curr.data && host->sps.sg &&
1582 host->is_sps_mode){
1583 /* Stop current SPS transfer */
1584 msmsdcc_sps_exit_curr_xfer(host);
1585 }
San Mehat9d2bd732009-09-22 16:44:22 -07001586 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301587 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001588 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301589 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301590 } else { /* host->data == NULL */
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301591 if (!cmd->error && host->prog_enable) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301592 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001593 host->prog_enable = 0;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301594 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001595 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301596 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301597 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301598 host->prog_enable = 0;
Subhash Jadavanied6b0e42012-03-07 16:36:27 +05301599 host->curr.wait_for_auto_prog_done = 0;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001600 if (host->dummy_52_needed)
1601 host->dummy_52_needed = 0;
1602 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001603 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301604 msmsdcc_request_end(host, cmd->mrq);
1605 }
1606 }
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301607 } else if ((cmd == host->curr.mrq->sbc) && cmd->data) {
1608 if (cmd->data->flags & MMC_DATA_READ)
1609 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1610 else
1611 msmsdcc_request_start(host, host->curr.mrq);
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301612 } else if (cmd->data) {
1613 if (!(cmd->data->flags & MMC_DATA_READ))
1614 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001615 }
1616}
1617
San Mehat9d2bd732009-09-22 16:44:22 -07001618static irqreturn_t
1619msmsdcc_irq(int irq, void *dev_id)
1620{
1621 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001622 u32 status;
1623 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001624 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001625
1626 spin_lock(&host->lock);
1627
1628 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001629 struct mmc_command *cmd;
1630 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001631
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001632 if (timer) {
1633 timer = 0;
1634 msmsdcc_delay(host);
1635 }
San Mehat865c8062009-11-13 13:42:06 -08001636
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001637 if (!host->clks_on) {
1638 pr_debug("%s: %s: SDIO async irq received\n",
1639 mmc_hostname(host->mmc), __func__);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301640
1641 /*
1642 * Only async interrupt can come when clocks are off,
1643 * disable further interrupts and enable them when
1644 * clocks are on.
1645 */
1646 if (!host->sdcc_irq_disabled) {
1647 disable_irq_nosync(irq);
1648 host->sdcc_irq_disabled = 1;
1649 }
1650
1651 /*
1652 * If mmc_card_wake_sdio_irq() is set, mmc core layer
1653 * will take care of signaling sdio irq during
1654 * mmc_sdio_resume().
1655 */
1656 if (host->sdcc_suspended)
1657 /*
1658 * This is a wakeup interrupt so hold wakelock
1659 * until SDCC resume is handled.
1660 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001661 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301662 else
1663 mmc_signal_sdio_irq(host->mmc);
1664 ret = 1;
1665 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001666 }
1667
1668 status = readl_relaxed(host->base + MMCISTATUS);
1669
1670 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1671 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001672 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001673
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001674#if IRQ_DEBUG
1675 msmsdcc_print_status(host, "irq0-r", status);
1676#endif
1677 status &= readl_relaxed(host->base + MMCIMASK0);
1678 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301679 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301680 if (host->clk_rate <=
1681 msmsdcc_get_min_sup_clk_rate(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +05301682 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001683#if IRQ_DEBUG
1684 msmsdcc_print_status(host, "irq0-p", status);
1685#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001686
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001687 if (status & MCI_SDIOINTROPE) {
1688 if (host->sdcc_suspending)
1689 wake_lock(&host->sdio_suspend_wlock);
1690 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001691 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001692 data = host->curr.data;
1693
1694 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001695 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1696 MCI_CMDTIMEOUT)) {
1697 if (status & MCI_CMDTIMEOUT)
1698 pr_debug("%s: dummy CMD52 timeout\n",
1699 mmc_hostname(host->mmc));
1700 if (status & MCI_CMDCRCFAIL)
1701 pr_debug("%s: dummy CMD52 CRC failed\n",
1702 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001703 host->dummy_52_sent = 0;
1704 host->dummy_52_needed = 0;
1705 if (data) {
1706 msmsdcc_stop_data(host);
1707 msmsdcc_request_end(host, data->mrq);
1708 }
1709 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001710 spin_unlock(&host->lock);
1711 return IRQ_HANDLED;
1712 }
1713 break;
1714 }
1715
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001716 /*
1717 * Check for proper command response
1718 */
1719 cmd = host->curr.cmd;
1720 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1721 MCI_CMDTIMEOUT | MCI_PROGDONE |
1722 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1723 msmsdcc_do_cmdirq(host, status);
1724 }
1725
Sathish Ambley081d7842011-11-29 11:19:41 -08001726 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001727 /* Check for data errors */
1728 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1729 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1730 msmsdcc_data_err(host, data, status);
1731 host->curr.data_xfered = 0;
1732 if (host->dma.sg && host->is_dma_mode)
1733 msm_dmov_stop_cmd(host->dma.channel,
1734 &host->dma.hdr, 0);
1735 else if (host->sps.sg && host->is_sps_mode) {
1736 /* Stop current SPS transfer */
1737 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301738 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001739 msmsdcc_reset_and_restore(host);
1740 if (host->curr.data)
1741 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301742 if (!data->stop || (host->curr.mrq->sbc
1743 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001744 timer |=
1745 msmsdcc_request_end(host,
1746 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301747 else if ((host->curr.mrq->sbc
1748 && data->error) ||
1749 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001750 msmsdcc_start_command(host,
1751 data->stop,
1752 0);
1753 timer = 1;
1754 }
1755 }
1756 }
1757
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301758 /* Check for prog done */
1759 if (host->curr.wait_for_auto_prog_done &&
1760 (status & MCI_PROGDONE))
1761 host->curr.got_auto_prog_done = 1;
1762
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001763 /* Check for data done */
1764 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1765 host->curr.got_dataend = 1;
1766
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301767 if (host->curr.got_dataend &&
1768 (!host->curr.wait_for_auto_prog_done ||
1769 (host->curr.wait_for_auto_prog_done &&
1770 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001771 /*
1772 * If DMA is still in progress, we complete
1773 * via the completion handler
1774 */
1775 if (!host->dma.busy && !host->sps.busy) {
1776 /*
1777 * There appears to be an issue in the
1778 * controller where if you request a
1779 * small block transfer (< fifo size),
1780 * you may get your DATAEND/DATABLKEND
1781 * irq without the PIO data irq.
1782 *
1783 * Check to see if theres still data
1784 * to be read, and simulate a PIO irq.
1785 */
1786 if (data->flags & MMC_DATA_READ)
1787 msmsdcc_wait_for_rxdata(host,
1788 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001789 if (!data->error) {
1790 host->curr.data_xfered =
1791 host->curr.xfer_size;
1792 host->curr.xfer_remain -=
1793 host->curr.xfer_size;
1794 }
1795
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001796 if (!host->dummy_52_needed) {
1797 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301798 if (!data->stop ||
1799 (host->curr.mrq->sbc
1800 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001801 msmsdcc_request_end(
1802 host,
1803 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301804 else if ((host->curr.mrq->sbc
1805 && data->error) ||
1806 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001807 msmsdcc_start_command(
1808 host,
1809 data->stop, 0);
1810 timer = 1;
1811 }
1812 } else {
1813 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001814 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001815 &dummy52cmd,
1816 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001817 }
1818 }
1819 }
1820 }
1821
San Mehat9d2bd732009-09-22 16:44:22 -07001822 ret = 1;
1823 } while (status);
1824
1825 spin_unlock(&host->lock);
1826
San Mehat9d2bd732009-09-22 16:44:22 -07001827 return IRQ_RETVAL(ret);
1828}
1829
1830static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001831msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1832{
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301833 if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001834 /* Queue/read data, daisy-chain command when data starts */
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301835 if (mrq->sbc)
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301836 msmsdcc_start_data(host, mrq->data, mrq->sbc, 0);
1837 else
1838 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001839 } else {
1840 msmsdcc_start_command(host, mrq->cmd, 0);
1841 }
1842}
1843
1844static void
San Mehat9d2bd732009-09-22 16:44:22 -07001845msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1846{
1847 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001848 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001849
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001850 /*
1851 * Get the SDIO AL client out of LPM.
1852 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001853 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001854 if (host->plat->is_sdio_al_client)
1855 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001856
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301857 /* check if sps pipe reset is pending? */
1858 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1859 msmsdcc_sps_pipes_reset_and_restore(host);
1860 host->sps.pipe_reset_pending = false;
1861 }
1862
San Mehat9d2bd732009-09-22 16:44:22 -07001863 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001864 WARN(host->curr.mrq, "Request in progress\n");
1865 WARN(!host->pwr, "SDCC power is turned off\n");
1866 WARN(!host->clks_on, "SDCC clocks are turned off\n");
1867 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
San Mehat9d2bd732009-09-22 16:44:22 -07001868
1869 if (host->eject) {
1870 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1871 mrq->cmd->error = 0;
1872 mrq->data->bytes_xfered = mrq->data->blksz *
1873 mrq->data->blocks;
1874 } else
1875 mrq->cmd->error = -ENOMEDIUM;
1876
1877 spin_unlock_irqrestore(&host->lock, flags);
1878 mmc_request_done(mmc, mrq);
1879 return;
1880 }
1881
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301882 /*
1883 * Kick the software command timeout timer here.
1884 * Timer expires in 10 secs.
1885 */
1886 mod_timer(&host->req_tout_timer,
1887 (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
San Mehat9d2bd732009-09-22 16:44:22 -07001888
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301889 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301890 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301891 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
1892 mrq->cmd->opcode == 54) {
Pratibhasagar V1c11da62011-11-14 12:36:35 +05301893 if (!host->sdcc_version)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001894 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301895 else
1896 /*
1897 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
1898 * write operations using CMD53 and CMD54.
1899 * Setting this bit with CMD53 would
1900 * automatically triggers PROG_DONE interrupt
1901 * without the need of sending dummy CMD52.
1902 */
1903 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani758cf8c2011-11-13 11:59:55 +05301904 } else if (mrq->cmd->opcode == MMC_WRITE_BLOCK &&
1905 host->sdcc_version) {
1906 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001907 }
San Mehat9d2bd732009-09-22 16:44:22 -07001908 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301909
Pratibhasagar V00b94332011-10-18 14:57:27 +05301910 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301911 mrq->sbc->mrq = mrq;
1912 mrq->sbc->data = mrq->data;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301913 if (mrq->data->flags & MMC_DATA_WRITE) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301914 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301915 msmsdcc_start_command(host, mrq->sbc, 0);
1916 } else {
1917 msmsdcc_request_start(host, mrq);
1918 }
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301919 } else {
1920 msmsdcc_request_start(host, mrq);
1921 }
1922
San Mehat9d2bd732009-09-22 16:44:22 -07001923 spin_unlock_irqrestore(&host->lock, flags);
1924}
1925
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001926static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1927 int min_uV, int max_uV)
1928{
1929 int rc = 0;
1930
1931 if (vreg->set_voltage_sup) {
1932 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1933 if (rc) {
1934 pr_err("%s: regulator_set_voltage(%s) failed."
1935 " min_uV=%d, max_uV=%d, rc=%d\n",
1936 __func__, vreg->name, min_uV, max_uV, rc);
1937 }
1938 }
1939
1940 return rc;
1941}
1942
1943static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1944 int uA_load)
1945{
1946 int rc = 0;
1947
Krishna Kondafea60182011-11-01 16:01:34 -07001948 /* regulators that do not support regulator_set_voltage also
1949 do not support regulator_set_optimum_mode */
1950 if (vreg->set_voltage_sup) {
1951 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1952 if (rc < 0)
1953 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
1954 "uA_load=%d) failed. rc=%d\n", __func__,
1955 vreg->name, uA_load, rc);
1956 else
1957 /* regulator_set_optimum_mode() can return non zero
1958 * value even for success case.
1959 */
1960 rc = 0;
1961 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001962
1963 return rc;
1964}
1965
1966static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1967 struct device *dev)
1968{
1969 int rc = 0;
1970
1971 /* check if regulator is already initialized? */
1972 if (vreg->reg)
1973 goto out;
1974
1975 /* Get the regulator handle */
1976 vreg->reg = regulator_get(dev, vreg->name);
1977 if (IS_ERR(vreg->reg)) {
1978 rc = PTR_ERR(vreg->reg);
1979 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
1980 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001981 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001982 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001983
1984 if (regulator_count_voltages(vreg->reg) > 0)
1985 vreg->set_voltage_sup = 1;
1986
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001987out:
1988 return rc;
1989}
1990
1991static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
1992{
1993 if (vreg->reg)
1994 regulator_put(vreg->reg);
1995}
1996
1997/* This init function should be called only once for each SDCC slot */
1998static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
1999{
2000 int rc = 0;
2001 struct msm_mmc_slot_reg_data *curr_slot;
2002 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
2003 struct device *dev = mmc_dev(host->mmc);
2004
2005 curr_slot = host->plat->vreg_data;
2006 if (!curr_slot)
2007 goto out;
2008
2009 curr_vdd_reg = curr_slot->vdd_data;
2010 curr_vccq_reg = curr_slot->vccq_data;
2011 curr_vddp_reg = curr_slot->vddp_data;
2012
2013 if (is_init) {
2014 /*
2015 * Get the regulator handle from voltage regulator framework
2016 * and then try to set the voltage level for the regulator
2017 */
2018 if (curr_vdd_reg) {
2019 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
2020 if (rc)
2021 goto out;
2022 }
2023 if (curr_vccq_reg) {
2024 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
2025 if (rc)
2026 goto vdd_reg_deinit;
2027 }
2028 if (curr_vddp_reg) {
2029 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
2030 if (rc)
2031 goto vccq_reg_deinit;
2032 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002033 rc = msmsdcc_vreg_reset(host);
2034 if (rc)
2035 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
2036 host->pdev_id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002037 goto out;
2038 } else {
2039 /* Deregister all regulators from regulator framework */
2040 goto vddp_reg_deinit;
2041 }
2042vddp_reg_deinit:
2043 if (curr_vddp_reg)
2044 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
2045vccq_reg_deinit:
2046 if (curr_vccq_reg)
2047 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
2048vdd_reg_deinit:
2049 if (curr_vdd_reg)
2050 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2051out:
2052 return rc;
2053}
2054
2055static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2056{
2057 int rc = 0;
2058
Subhash Jadavanicc922692011-08-01 23:05:01 +05302059 /* Put regulator in HPM (high power mode) */
2060 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2061 if (rc < 0)
2062 goto out;
2063
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002064 if (!vreg->is_enabled) {
2065 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302066 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2067 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002068 if (rc)
2069 goto out;
2070
2071 rc = regulator_enable(vreg->reg);
2072 if (rc) {
2073 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2074 __func__, vreg->name, rc);
2075 goto out;
2076 }
2077 vreg->is_enabled = true;
2078 }
2079
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002080out:
2081 return rc;
2082}
2083
2084static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
2085{
2086 int rc = 0;
2087
2088 /* Never disable regulator marked as always_on */
2089 if (vreg->is_enabled && !vreg->always_on) {
2090 rc = regulator_disable(vreg->reg);
2091 if (rc) {
2092 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2093 __func__, vreg->name, rc);
2094 goto out;
2095 }
2096 vreg->is_enabled = false;
2097
2098 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2099 if (rc < 0)
2100 goto out;
2101
2102 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302103 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002104 if (rc)
2105 goto out;
2106 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
2107 /* Put always_on regulator in LPM (low power mode) */
2108 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2109 if (rc < 0)
2110 goto out;
2111 }
2112out:
2113 return rc;
2114}
2115
2116static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
2117{
2118 int rc = 0, i;
2119 struct msm_mmc_slot_reg_data *curr_slot;
2120 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
2121 struct msm_mmc_reg_data *vreg_table[3];
2122
2123 curr_slot = host->plat->vreg_data;
2124 if (!curr_slot)
2125 goto out;
2126
2127 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
2128 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
2129 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
2130
2131 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2132 if (vreg_table[i]) {
2133 if (enable)
2134 rc = msmsdcc_vreg_enable(vreg_table[i]);
2135 else
2136 rc = msmsdcc_vreg_disable(vreg_table[i]);
2137 if (rc)
2138 goto out;
2139 }
2140 }
2141out:
2142 return rc;
2143}
2144
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002145/*
2146 * Reset vreg by ensuring it is off during probe. A call
2147 * to enable vreg is needed to balance disable vreg
2148 */
2149static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2150{
2151 int rc;
2152
2153 rc = msmsdcc_setup_vreg(host, 1);
2154 if (rc)
2155 return rc;
2156 rc = msmsdcc_setup_vreg(host, 0);
2157 return rc;
2158}
2159
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302160static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002161{
2162 int rc = 0;
2163
2164 if (host->plat->vreg_data) {
2165 struct msm_mmc_reg_data *vddp_reg =
2166 host->plat->vreg_data->vddp_data;
2167
2168 if (vddp_reg && vddp_reg->is_enabled)
2169 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
2170 }
2171
2172 return rc;
2173}
2174
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302175static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
2176{
2177 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2178 int rc = 0;
2179
2180 if (curr_slot && curr_slot->vddp_data) {
2181 rc = msmsdcc_set_vddp_level(host,
2182 curr_slot->vddp_data->low_vol_level);
2183
2184 if (rc)
2185 pr_err("%s: %s: failed to change vddp level to %d",
2186 mmc_hostname(host->mmc), __func__,
2187 curr_slot->vddp_data->low_vol_level);
2188 }
2189
2190 return rc;
2191}
2192
2193static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
2194{
2195 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2196 int rc = 0;
2197
2198 if (curr_slot && curr_slot->vddp_data) {
2199 rc = msmsdcc_set_vddp_level(host,
2200 curr_slot->vddp_data->high_vol_level);
2201
2202 if (rc)
2203 pr_err("%s: %s: failed to change vddp level to %d",
2204 mmc_hostname(host->mmc), __func__,
2205 curr_slot->vddp_data->high_vol_level);
2206 }
2207
2208 return rc;
2209}
2210
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302211static inline int msmsdcc_set_vccq_vol(struct msmsdcc_host *host, int level)
2212{
2213 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2214 int rc = 0;
2215
2216 if (curr_slot && curr_slot->vccq_data) {
2217 rc = msmsdcc_vreg_set_voltage(curr_slot->vccq_data,
2218 level, level);
2219 if (rc)
2220 pr_err("%s: %s: failed to change vccq level to %d",
2221 mmc_hostname(host->mmc), __func__, level);
2222 }
2223
2224 return rc;
2225}
2226
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002227static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2228{
2229 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2230 return 1;
2231 return 0;
2232}
2233
Asutosh Dasf5298c32012-04-03 14:51:47 +05302234/*
2235 * Any function calling msmsdcc_setup_clocks must
2236 * acquire clk_mutex. May sleep.
2237 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002238static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
2239{
2240 if (enable) {
2241 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302242 clk_prepare_enable(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002243 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302244 clk_prepare_enable(host->pclk);
2245 clk_prepare_enable(host->clk);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302246 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302247 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002248 } else {
Subhash Jadavanidd432952012-03-28 11:25:56 +05302249 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302250 msmsdcc_delay(host);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302251 clk_disable_unprepare(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002252 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302253 clk_disable_unprepare(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002254 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302255 clk_disable_unprepare(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002256 }
2257}
2258
2259static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2260 unsigned int req_clk)
2261{
2262 unsigned int sel_clk = -1;
2263
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302264 if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
2265 sel_clk = msmsdcc_get_min_sup_clk_rate(host);
2266 goto out;
2267 }
2268
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002269 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2270 unsigned char cnt;
2271
2272 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2273 if (host->plat->sup_clk_table[cnt] > req_clk)
2274 break;
2275 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2276 sel_clk = host->plat->sup_clk_table[cnt];
2277 break;
2278 } else
2279 sel_clk = host->plat->sup_clk_table[cnt];
2280 }
2281 } else {
2282 if ((req_clk < host->plat->msmsdcc_fmax) &&
2283 (req_clk > host->plat->msmsdcc_fmid))
2284 sel_clk = host->plat->msmsdcc_fmid;
2285 else
2286 sel_clk = req_clk;
2287 }
2288
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302289out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002290 return sel_clk;
2291}
2292
2293static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2294 struct msmsdcc_host *host)
2295{
2296 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2297 return host->plat->sup_clk_table[0];
2298 else
2299 return host->plat->msmsdcc_fmin;
2300}
2301
2302static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2303 struct msmsdcc_host *host)
2304{
2305 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2306 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2307 else
2308 return host->plat->msmsdcc_fmax;
2309}
2310
2311static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302312{
2313 struct msm_mmc_gpio_data *curr;
2314 int i, rc = 0;
2315
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002316 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302317 for (i = 0; i < curr->size; i++) {
2318 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002319 if (curr->gpio[i].is_always_on &&
2320 curr->gpio[i].is_enabled)
2321 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302322 rc = gpio_request(curr->gpio[i].no,
2323 curr->gpio[i].name);
2324 if (rc) {
2325 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2326 mmc_hostname(host->mmc),
2327 curr->gpio[i].no,
2328 curr->gpio[i].name, rc);
2329 goto free_gpios;
2330 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002331 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302332 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002333 if (curr->gpio[i].is_always_on)
2334 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302335 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002336 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302337 }
2338 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002339 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302340
2341free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002342 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302343 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002344 curr->gpio[i].is_enabled = false;
2345 }
2346out:
2347 return rc;
2348}
2349
2350static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2351{
2352 struct msm_mmc_pad_data *curr;
2353 int i;
2354
2355 curr = host->plat->pin_data->pad_data;
2356 for (i = 0; i < curr->drv->size; i++) {
2357 if (enable)
2358 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2359 curr->drv->on[i].val);
2360 else
2361 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2362 curr->drv->off[i].val);
2363 }
2364
2365 for (i = 0; i < curr->pull->size; i++) {
2366 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002367 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002368 curr->pull->on[i].val);
2369 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002370 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002371 curr->pull->off[i].val);
2372 }
2373
2374 return 0;
2375}
2376
2377static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2378{
2379 int rc = 0;
2380
2381 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2382 return 0;
2383
2384 if (host->plat->pin_data->is_gpio)
2385 rc = msmsdcc_setup_gpio(host, enable);
2386 else
2387 rc = msmsdcc_setup_pad(host, enable);
2388
2389 if (!rc)
2390 host->plat->pin_data->cfg_sts = enable;
2391
2392 return rc;
2393}
2394
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302395static int msmsdcc_cfg_mpm_sdiowakeup(struct msmsdcc_host *host,
2396 unsigned mode)
2397{
2398 int ret = 0;
2399 unsigned int pin = host->plat->mpm_sdiowakeup_int;
2400
2401 if (!pin)
2402 return 0;
2403
2404 switch (mode) {
2405 case SDC_DAT1_DISABLE:
2406 ret = msm_mpm_enable_pin(pin, 0);
2407 break;
2408 case SDC_DAT1_ENABLE:
2409 ret = msm_mpm_set_pin_type(pin, IRQ_TYPE_LEVEL_LOW);
2410 ret = msm_mpm_enable_pin(pin, 1);
2411 break;
2412 case SDC_DAT1_ENWAKE:
2413 ret = msm_mpm_set_pin_wake(pin, 1);
2414 break;
2415 case SDC_DAT1_DISWAKE:
2416 ret = msm_mpm_set_pin_wake(pin, 0);
2417 break;
2418 default:
2419 ret = -EINVAL;
2420 break;
2421 }
2422
2423 return ret;
2424}
2425
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302426static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2427{
2428 u32 pwr = 0;
2429 int ret = 0;
2430 struct mmc_host *mmc = host->mmc;
2431
2432 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2433 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2434 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2435 ret = msmsdcc_setup_vreg(host, !!ios->vdd);
2436
2437 if (ret) {
2438 pr_err("%s: Failed to setup voltage regulators\n",
2439 mmc_hostname(host->mmc));
2440 goto out;
2441 }
2442
2443 switch (ios->power_mode) {
2444 case MMC_POWER_OFF:
2445 pwr = MCI_PWR_OFF;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302446 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302447 /*
2448 * As VDD pad rail is always on, set low voltage for VDD
2449 * pad rail when slot is unused (when card is not present
2450 * or during system suspend).
2451 */
2452 msmsdcc_set_vddp_low_vol(host);
2453 msmsdcc_setup_pins(host, false);
2454 break;
2455 case MMC_POWER_UP:
2456 /* writing PWR_UP bit is redundant */
2457 pwr = MCI_PWR_UP;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302458 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302459
2460 msmsdcc_set_vddp_high_vol(host);
2461 msmsdcc_setup_pins(host, true);
2462 break;
2463 case MMC_POWER_ON:
2464 pwr = MCI_PWR_ON;
2465 break;
2466 }
2467
2468out:
2469 return pwr;
2470}
2471
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002472static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2473{
2474 unsigned int wakeup_irq;
2475
2476 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2477 host->plat->sdiowakeup_irq :
2478 host->core_irqres->start;
2479
2480 if (!host->irq_wake_enabled) {
2481 enable_irq_wake(wakeup_irq);
2482 host->irq_wake_enabled = true;
2483 }
2484}
2485
2486static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2487{
2488 unsigned int wakeup_irq;
2489
2490 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2491 host->plat->sdiowakeup_irq :
2492 host->core_irqres->start;
2493
2494 if (host->irq_wake_enabled) {
2495 disable_irq_wake(wakeup_irq);
2496 host->irq_wake_enabled = false;
2497 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302498}
2499
San Mehat9d2bd732009-09-22 16:44:22 -07002500static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302501msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
2502{
2503 struct mmc_host *mmc = host->mmc;
2504
2505 /*
2506 * SDIO_AL clients has different mechanism of handling LPM through
2507 * sdio_al driver itself. The sdio wakeup interrupt is configured as
2508 * part of that. Here, we are interested only in clients like WLAN.
2509 */
2510 if (!(mmc->card && mmc_card_sdio(mmc->card))
2511 || host->plat->is_sdio_al_client)
2512 goto out;
2513
2514 if (!host->sdcc_suspended) {
2515 /*
2516 * When MSM is not in power collapse and we
2517 * are disabling clocks, enable bit 22 in MASK0
2518 * to handle asynchronous SDIO interrupts.
2519 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302520 if (enable_wakeup_irq) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302521 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302522 mb();
2523 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302524 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302525 msmsdcc_sync_reg_wr(host);
2526 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302527 goto out;
2528 } else if (!mmc_card_wake_sdio_irq(mmc)) {
2529 /*
2530 * Wakeup MSM only if SDIO function drivers set
2531 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
2532 */
2533 goto out;
2534 }
2535
2536 if (enable_wakeup_irq) {
2537 if (!host->plat->sdiowakeup_irq) {
2538 /*
2539 * When there is no gpio line that can be configured
2540 * as wakeup interrupt handle it by configuring
2541 * asynchronous sdio interrupts and DAT1 line.
2542 */
2543 writel_relaxed(MCI_SDIOINTMASK,
2544 host->base + MMCIMASK0);
2545 mb();
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302546 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302547 /* configure sdcc core interrupt as wakeup interrupt */
2548 msmsdcc_enable_irq_wake(host);
2549 } else {
2550 /* Let gpio line handle wakeup interrupt */
2551 writel_relaxed(0, host->base + MMCIMASK0);
2552 mb();
2553 if (host->sdio_wakeupirq_disabled) {
2554 host->sdio_wakeupirq_disabled = 0;
2555 /* configure gpio line as wakeup interrupt */
2556 msmsdcc_enable_irq_wake(host);
2557 enable_irq(host->plat->sdiowakeup_irq);
2558 }
2559 }
2560 } else {
2561 if (!host->plat->sdiowakeup_irq) {
2562 /*
2563 * We may not have cleared bit 22 in the interrupt
2564 * handler as the clocks might be off at that time.
2565 */
2566 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302567 msmsdcc_sync_reg_wr(host);
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302568 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302569 msmsdcc_disable_irq_wake(host);
2570 } else if (!host->sdio_wakeupirq_disabled) {
2571 disable_irq_nosync(host->plat->sdiowakeup_irq);
2572 msmsdcc_disable_irq_wake(host);
2573 host->sdio_wakeupirq_disabled = 1;
2574 }
2575 }
2576out:
2577 return;
2578}
2579
2580static void
San Mehat9d2bd732009-09-22 16:44:22 -07002581msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2582{
2583 struct msmsdcc_host *host = mmc_priv(mmc);
2584 u32 clk = 0, pwr = 0;
2585 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002586 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002587 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002588
Sahitya Tummala7a892482011-01-18 11:22:49 +05302589
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302590 /*
2591 * Disable SDCC core interrupt until set_ios is completed.
2592 * This avoids any race conditions with interrupt raised
2593 * when turning on/off the clocks. One possible
2594 * scenario is SDIO operational interrupt while the clock
2595 * is turned off.
Asutosh Dasf5298c32012-04-03 14:51:47 +05302596 * host->lock is being released intermittently below.
2597 * Thus, prevent concurrent access to host.
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302598 */
2599
Asutosh Dasf5298c32012-04-03 14:51:47 +05302600 mutex_lock(&host->clk_mutex);
2601 DBG(host, "ios->clock = %u\n", ios->clock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302602 spin_lock_irqsave(&host->lock, flags);
2603 if (!host->sdcc_irq_disabled) {
2604 spin_unlock_irqrestore(&host->lock, flags);
2605 disable_irq(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002606 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302607 host->sdcc_irq_disabled = 1;
2608 }
2609 spin_unlock_irqrestore(&host->lock, flags);
2610
2611 pwr = msmsdcc_setup_pwr(host, ios);
2612
2613 spin_lock_irqsave(&host->lock, flags);
2614 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002615 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302616 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002617 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302618 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002619 host->clks_on = 1;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302620 writel_relaxed(host->mci_irqenable,
2621 host->base + MMCIMASK0);
2622 mb();
2623 msmsdcc_cfg_sdio_wakeup(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002624 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002625
2626 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2627 /*
2628 * For DDR50 mode, controller needs clock rate to be
2629 * double than what is required on the SD card CLK pin.
2630 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302631 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002632 /*
2633 * Make sure that we don't double the clock if
2634 * doubled clock rate is already set
2635 */
2636 if (!host->ddr_doubled_clk_rate ||
2637 (host->ddr_doubled_clk_rate &&
2638 (host->ddr_doubled_clk_rate != ios->clock))) {
2639 host->ddr_doubled_clk_rate =
2640 msmsdcc_get_sup_clk_rate(
2641 host, (ios->clock * 2));
2642 clock = host->ddr_doubled_clk_rate;
2643 }
2644 } else {
2645 host->ddr_doubled_clk_rate = 0;
2646 }
2647
2648 if (clock != host->clk_rate) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302649 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002650 rc = clk_set_rate(host->clk, clock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302651 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002652 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302653 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002654 mmc_hostname(mmc), clock);
2655 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302656 host->reg_write_delay =
2657 (1 + ((3 * USEC_PER_SEC) /
2658 (host->clk_rate ? host->clk_rate :
2659 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002660 }
2661 /*
2662 * give atleast 2 MCLK cycles delay for clocks
2663 * and SDCC core to stabilize
2664 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302665 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002666 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002667 clk |= MCI_CLK_ENABLE;
2668 }
2669
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002670 if (ios->bus_width == MMC_BUS_WIDTH_8)
2671 clk |= MCI_CLK_WIDEBUS_8;
2672 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2673 clk |= MCI_CLK_WIDEBUS_4;
2674 else
2675 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002676
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002677 if (msmsdcc_is_pwrsave(host))
2678 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002679
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002680 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002681
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002682 host->tuning_needed = 0;
2683 /*
2684 * Select the controller timing mode according
2685 * to current bus speed mode
2686 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302687 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2688 (ios->timing == MMC_TIMING_MMC_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002689 clk |= (4 << 14);
2690 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302691 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002692 clk |= (3 << 14);
2693 } else {
2694 clk |= (2 << 14); /* feedback clock */
2695 }
2696
2697 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2698 clk |= (2 << 23);
2699
Subhash Jadavani00083572012-02-15 16:18:01 +05302700 /* Clear IO_PAD_PWR_SWITCH while powering off the card */
2701 if (!ios->vdd)
2702 host->io_pad_pwr_switch = 0;
2703
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002704 if (host->io_pad_pwr_switch)
2705 clk |= IO_PAD_PWR_SWITCH;
2706
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302707 /* Don't write into registers if clocks are disabled */
2708 if (host->clks_on) {
2709 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
2710 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302711 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002712 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302713 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
2714 host->pwr = pwr;
2715 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302716 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002717 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002718 }
2719
2720 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302721 msmsdcc_cfg_sdio_wakeup(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302722 spin_unlock_irqrestore(&host->lock, flags);
2723 /*
2724 * May get a wake-up interrupt the instant we disable the
2725 * clocks. This would disable the wake-up interrupt.
2726 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002727 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302728 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002729 host->clks_on = 0;
2730 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302731
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302732 if (host->tuning_in_progress)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302733 WARN(!host->clks_on,
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302734 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302735
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302736 /* Let interrupts be disabled if the host is powered off */
2737 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
2738 enable_irq(host->core_irqres->start);
2739 host->sdcc_irq_disabled = 0;
2740 }
2741
San Mehat4adbbcc2009-11-08 13:00:37 -08002742 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302743 mutex_unlock(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07002744}
2745
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002746int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2747{
2748 struct msmsdcc_host *host = mmc_priv(mmc);
2749 u32 clk;
2750
2751 clk = readl_relaxed(host->base + MMCICLOCK);
2752 pr_debug("Changing to pwr_save=%d", pwrsave);
2753 if (pwrsave && msmsdcc_is_pwrsave(host))
2754 clk |= MCI_CLK_PWRSAVE;
2755 else
2756 clk &= ~MCI_CLK_PWRSAVE;
2757 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302758 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002759
2760 return 0;
2761}
2762
2763static int msmsdcc_get_ro(struct mmc_host *mmc)
2764{
2765 int status = -ENOSYS;
2766 struct msmsdcc_host *host = mmc_priv(mmc);
2767
2768 if (host->plat->wpswitch) {
2769 status = host->plat->wpswitch(mmc_dev(mmc));
2770 } else if (host->plat->wpswitch_gpio) {
2771 status = gpio_request(host->plat->wpswitch_gpio,
2772 "SD_WP_Switch");
2773 if (status) {
2774 pr_err("%s: %s: Failed to request GPIO %d\n",
2775 mmc_hostname(mmc), __func__,
2776 host->plat->wpswitch_gpio);
2777 } else {
2778 status = gpio_direction_input(
2779 host->plat->wpswitch_gpio);
2780 if (!status) {
2781 /*
2782 * Wait for atleast 300ms as debounce
2783 * time for GPIO input to stabilize.
2784 */
2785 msleep(300);
2786 status = gpio_get_value_cansleep(
2787 host->plat->wpswitch_gpio);
2788 status ^= !host->plat->wpswitch_polarity;
2789 }
2790 gpio_free(host->plat->wpswitch_gpio);
2791 }
2792 }
2793
2794 if (status < 0)
2795 status = -ENOSYS;
2796 pr_debug("%s: Card read-only status %d\n", __func__, status);
2797
2798 return status;
2799}
2800
San Mehat9d2bd732009-09-22 16:44:22 -07002801static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2802{
2803 struct msmsdcc_host *host = mmc_priv(mmc);
2804 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002805
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302806 /*
2807 * We may come here with clocks turned off in that case don't
2808 * attempt to write into MASK0 register. While turning on the
2809 * clocks mci_irqenable will be written to MASK0 register.
2810 */
2811
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002812 if (enable) {
2813 spin_lock_irqsave(&host->lock, flags);
2814 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302815 if (host->clks_on) {
2816 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002817 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302818 mb();
2819 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002820 spin_unlock_irqrestore(&host->lock, flags);
2821 } else {
2822 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302823 if (host->clks_on) {
2824 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002825 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302826 mb();
2827 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002828 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002829}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002830
2831#ifdef CONFIG_PM_RUNTIME
2832static int msmsdcc_enable(struct mmc_host *mmc)
2833{
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302834 int rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002835 struct device *dev = mmc->parent;
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302836 struct msmsdcc_host *host = mmc_priv(mmc);
2837
2838 msmsdcc_pm_qos_update_latency(host, 1);
2839
2840 if (mmc->card && mmc_card_sdio(mmc->card) && host->is_resumed)
2841 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002842
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302843 if (dev->power.runtime_status == RPM_SUSPENDING) {
2844 if (mmc->suspend_task == current) {
2845 pm_runtime_get_noresume(dev);
2846 goto out;
2847 }
2848 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002849
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302850 rc = pm_runtime_get_sync(dev);
2851
2852 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002853 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2854 __func__, rc);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302855 return rc;
2856 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302857
2858 host->is_resumed = true;
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302859out:
2860 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002861}
2862
2863static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2864{
2865 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302866 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002867
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302868 msmsdcc_pm_qos_update_latency(host, 0);
2869
2870 if (mmc->card && mmc_card_sdio(mmc->card))
2871 return 0;
2872
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302873 if (host->plat->disable_runtime_pm)
2874 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002875
2876 rc = pm_runtime_put_sync(mmc->parent);
2877
2878 if (rc < 0)
2879 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2880 __func__, rc);
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302881 else
2882 host->is_resumed = false;
2883
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002884 return rc;
2885}
2886#else
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302887static int msmsdcc_enable(struct mmc_host *mmc)
2888{
2889 struct msmsdcc_host *host = mmc_priv(mmc);
2890 unsigned long flags;
2891
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302892 msmsdcc_pm_qos_update_latency(host, 1);
2893
Asutosh Dasf5298c32012-04-03 14:51:47 +05302894 mutex_lock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302895 spin_lock_irqsave(&host->lock, flags);
2896 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302897 spin_unlock_irqrestore(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302898 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302899 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302900 host->clks_on = 1;
2901 }
2902 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302903 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302904
2905 return 0;
2906}
2907
2908static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2909{
2910 struct msmsdcc_host *host = mmc_priv(mmc);
2911 unsigned long flags;
2912
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302913 msmsdcc_pm_qos_update_latency(host, 0);
2914
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302915 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302916 return 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302917
Asutosh Dasf5298c32012-04-03 14:51:47 +05302918 mutex_lock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302919 spin_lock_irqsave(&host->lock, flags);
2920 if (host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302921 spin_unlock_irqrestore(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302922 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302923 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302924 host->clks_on = 0;
2925 }
2926 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302927 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302928
2929 return 0;
2930}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002931#endif
2932
2933static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2934 struct mmc_ios *ios)
2935{
2936 struct msmsdcc_host *host = mmc_priv(mmc);
2937 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302938 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002939
Subhash Jadavani00083572012-02-15 16:18:01 +05302940 spin_lock_irqsave(&host->lock, flags);
2941 host->io_pad_pwr_switch = 0;
2942 spin_unlock_irqrestore(&host->lock, flags);
2943
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302944 /*
2945 * For eMMC cards, VccQ voltage range must be changed
2946 * only if it operates in HS200 SDR 1.2V mode or in
2947 * DDR 1.2V mode.
2948 */
2949 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_120) {
2950 rc = msmsdcc_set_vccq_vol(host, 1200000);
2951 goto out;
2952 }
2953
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002954 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2955 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302956 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002957 goto out;
2958 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2959 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302960 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002961 goto out;
2962 }
San Mehat9d2bd732009-09-22 16:44:22 -07002963
2964 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002965 /*
2966 * If we are here means voltage switch from high voltage to
2967 * low voltage is required
2968 */
2969
2970 /*
2971 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2972 * register until they become all zeros.
2973 */
2974 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302975 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002976 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2977 mmc_hostname(mmc), __func__);
2978 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002979 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002980
2981 /* Stop SD CLK output. */
2982 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2983 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302984 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002985 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002986
2987 /*
2988 * Switch VDDPX from high voltage to low voltage
2989 * to change the VDD of the SD IO pads.
2990 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302991 rc = msmsdcc_set_vddp_low_vol(host);
2992 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002993 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002994
2995 spin_lock_irqsave(&host->lock, flags);
2996 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2997 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302998 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002999 host->io_pad_pwr_switch = 1;
3000 spin_unlock_irqrestore(&host->lock, flags);
3001
3002 /* Wait 5 ms for the voltage regulater in the card to become stable. */
3003 usleep_range(5000, 5500);
3004
3005 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303006 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003007 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3008 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303009 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003010 spin_unlock_irqrestore(&host->lock, flags);
3011
3012 /*
3013 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
3014 * don't become all ones within 1 ms then a Voltage Switch
3015 * sequence has failed and a power cycle to the card is required.
3016 * Otherwise Voltage Switch sequence is completed successfully.
3017 */
3018 usleep_range(1000, 1500);
3019
3020 spin_lock_irqsave(&host->lock, flags);
3021 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
3022 != (0xF << 1)) {
3023 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
3024 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303025 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003026 goto out_unlock;
3027 }
3028
3029out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303030 /* Enable PWRSAVE */
3031 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3032 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303033 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003034 spin_unlock_irqrestore(&host->lock, flags);
3035out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303036 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003037}
3038
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303039static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003040{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003041 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003042
3043 /* Program the MCLK value to MCLK_FREQ bit field */
3044 if (host->clk_rate <= 112000000)
3045 mclk_freq = 0;
3046 else if (host->clk_rate <= 125000000)
3047 mclk_freq = 1;
3048 else if (host->clk_rate <= 137000000)
3049 mclk_freq = 2;
3050 else if (host->clk_rate <= 150000000)
3051 mclk_freq = 3;
3052 else if (host->clk_rate <= 162000000)
3053 mclk_freq = 4;
3054 else if (host->clk_rate <= 175000000)
3055 mclk_freq = 5;
3056 else if (host->clk_rate <= 187000000)
3057 mclk_freq = 6;
3058 else if (host->clk_rate <= 200000000)
3059 mclk_freq = 7;
3060
3061 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3062 & ~(7 << 24)) | (mclk_freq << 24)),
3063 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003064}
3065
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303066/* Initialize the DLL (Programmable Delay Line ) */
3067static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003068{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003069 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303070 unsigned long flags;
3071 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003072
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303073 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003074 /*
3075 * Make sure that clock is always enabled when DLL
3076 * tuning is in progress. Keeping PWRSAVE ON may
3077 * turn off the clock. So let's disable the PWRSAVE
3078 * here and re-enable it once tuning is completed.
3079 */
3080 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3081 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303082 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303083
3084 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3085 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3086 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3087
3088 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3089 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3090 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3091
3092 msmsdcc_cm_sdc4_dll_set_freq(host);
3093
3094 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3095 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3096 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3097
3098 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3099 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3100 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3101
3102 /* Set DLL_EN bit to 1. */
3103 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3104 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3105
3106 /* Set CK_OUT_EN bit to 1. */
3107 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3108 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3109
3110 wait_cnt = 50;
3111 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3112 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3113 /* max. wait for 50us sec for LOCK bit to be set */
3114 if (--wait_cnt == 0) {
3115 pr_err("%s: %s: DLL failed to LOCK\n",
3116 mmc_hostname(host->mmc), __func__);
3117 rc = -ETIMEDOUT;
3118 goto out;
3119 }
3120 /* wait for 1us before polling again */
3121 udelay(1);
3122 }
3123
3124out:
3125 /* re-enable PWRSAVE */
3126 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3127 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303128 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303129 spin_unlock_irqrestore(&host->lock, flags);
3130
3131 return rc;
3132}
3133
3134static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3135 u8 poll)
3136{
3137 int rc = 0;
3138 u32 wait_cnt = 50;
3139 u8 ck_out_en = 0;
3140
3141 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3142 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3143 MCI_CK_OUT_EN);
3144
3145 while (ck_out_en != poll) {
3146 if (--wait_cnt == 0) {
3147 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3148 mmc_hostname(host->mmc), __func__, poll);
3149 rc = -ETIMEDOUT;
3150 goto out;
3151 }
3152 udelay(1);
3153
3154 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3155 MCI_CK_OUT_EN);
3156 }
3157out:
3158 return rc;
3159}
3160
3161/*
3162 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3163 * calibration sequence. This function should be called before
3164 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3165 * commands (CMD17/CMD18).
3166 *
3167 * This function gets called when host spinlock acquired.
3168 */
3169static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3170{
3171 int rc = 0;
3172 u32 config;
3173
3174 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3175 config |= MCI_CDR_EN;
3176 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3177 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3178
3179 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3180 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3181 if (rc)
3182 goto err_out;
3183
3184 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3185 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3186 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3187
3188 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3189 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3190 if (rc)
3191 goto err_out;
3192
3193 goto out;
3194
3195err_out:
3196 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3197out:
3198 return rc;
3199}
3200
3201static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3202 u8 phase)
3203{
3204 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303205 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3206 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3207 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303208 unsigned long flags;
3209 u32 config;
3210
3211 spin_lock_irqsave(&host->lock, flags);
3212
3213 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3214 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3215 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3216 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3217
3218 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3219 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3220 if (rc)
3221 goto err_out;
3222
3223 /*
3224 * Write the selected DLL clock output phase (0 ... 15)
3225 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
3226 */
3227 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3228 & ~(0xF << 20))
3229 | (grey_coded_phase_table[phase] << 20)),
3230 host->base + MCI_DLL_CONFIG);
3231
3232 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3233 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3234 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3235
3236 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3237 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3238 if (rc)
3239 goto err_out;
3240
3241 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3242 config |= MCI_CDR_EN;
3243 config &= ~MCI_CDR_EXT_EN;
3244 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3245 goto out;
3246
3247err_out:
3248 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3249 mmc_hostname(host->mmc), __func__, phase);
3250out:
3251 spin_unlock_irqrestore(&host->lock, flags);
3252 return rc;
3253}
3254
3255/*
3256 * Find out the greatest range of consecuitive selected
3257 * DLL clock output phases that can be used as sampling
3258 * setting for SD3.0 UHS-I card read operation (in SDR104
3259 * timing mode) or for eMMC4.5 card read operation (in HS200
3260 * timing mode).
3261 * Select the 3/4 of the range and configure the DLL with the
3262 * selected DLL clock output phase.
3263*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303264static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303265 u8 *phase_table, u8 total_phases)
3266{
Subhash Jadavani6159c622012-03-15 19:05:55 +05303267 #define MAX_PHASES 16
Subhash Jadavani34187042012-03-02 10:59:49 +05303268 int ret;
Subhash Jadavani6159c622012-03-15 19:05:55 +05303269 u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
3270 u8 phases_per_row[MAX_PHASES] = {0};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303271 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303272 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3273 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303274
Subhash Jadavani6159c622012-03-15 19:05:55 +05303275 if (!total_phases || (total_phases > MAX_PHASES)) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303276 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3277 mmc_hostname(host->mmc), __func__, total_phases);
3278 return -EINVAL;
3279 }
3280
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303281 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303282 ranges[row_index][col_index] = phase_table[cnt];
3283 phases_per_row[row_index] += 1;
3284 col_index++;
3285
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303286 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303287 continue;
3288 /* check if next phase in phase_table is consecutive or not */
3289 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3290 row_index++;
3291 col_index = 0;
3292 }
3293 }
3294
Subhash Jadavani6159c622012-03-15 19:05:55 +05303295 if (row_index >= MAX_PHASES)
3296 return -EINVAL;
3297
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303298 /* Check if phase-0 is present in first valid window? */
3299 if (!ranges[0][0]) {
3300 phase_0_found = true;
3301 phase_0_raw_index = 0;
3302 /* Check if cycle exist between 2 valid windows */
3303 for (cnt = 1; cnt <= row_index; cnt++) {
3304 if (phases_per_row[cnt]) {
Subhash Jadavani6159c622012-03-15 19:05:55 +05303305 for (i = 0; i < phases_per_row[cnt]; i++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303306 if (ranges[cnt][i] == 15) {
3307 phase_15_found = true;
3308 phase_15_raw_index = cnt;
3309 break;
3310 }
3311 }
3312 }
3313 }
3314 }
3315
3316 /* If 2 valid windows form cycle then merge them as single window */
3317 if (phase_0_found && phase_15_found) {
3318 /* number of phases in raw where phase 0 is present */
3319 u8 phases_0 = phases_per_row[phase_0_raw_index];
3320 /* number of phases in raw where phase 15 is present */
3321 u8 phases_15 = phases_per_row[phase_15_raw_index];
3322
Subhash Jadavani6159c622012-03-15 19:05:55 +05303323 if (phases_0 + phases_15 >= MAX_PHASES)
3324 /*
3325 * If there are more than 1 phase windows then total
3326 * number of phases in both the windows should not be
3327 * more than or equal to MAX_PHASES.
3328 */
3329 return -EINVAL;
3330
3331 /* Merge 2 cyclic windows */
3332 i = phases_15;
3333 for (cnt = 0; cnt < phases_0; cnt++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303334 ranges[phase_15_raw_index][i] =
3335 ranges[phase_0_raw_index][cnt];
Subhash Jadavani6159c622012-03-15 19:05:55 +05303336 if (++i >= MAX_PHASES)
3337 break;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303338 }
Subhash Jadavani6159c622012-03-15 19:05:55 +05303339
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303340 phases_per_row[phase_0_raw_index] = 0;
3341 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
3342 }
3343
3344 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303345 if (phases_per_row[cnt] > curr_max) {
3346 curr_max = phases_per_row[cnt];
3347 selected_row_index = cnt;
3348 }
3349 }
3350
Subhash Jadavani6159c622012-03-15 19:05:55 +05303351 i = ((curr_max * 3) / 4);
3352 if (i)
3353 i--;
3354
Subhash Jadavani34187042012-03-02 10:59:49 +05303355 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303356
Subhash Jadavani6159c622012-03-15 19:05:55 +05303357 if (ret >= MAX_PHASES) {
3358 ret = -EINVAL;
3359 pr_err("%s: %s: invalid phase selected=%d\n",
3360 mmc_hostname(host->mmc), __func__, ret);
3361 }
3362
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303363 return ret;
3364}
3365
Girish K Sa3f41692012-02-29 12:00:09 +05303366static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303367{
3368 int rc = 0;
3369 struct msmsdcc_host *host = mmc_priv(mmc);
3370 unsigned long flags;
3371 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303372 const u32 *tuning_block_pattern = tuning_block_64;
3373 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303374
3375 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
3376
3377 /* Tuning is only required for SDR104 modes */
3378 if (!host->tuning_needed) {
3379 rc = 0;
3380 goto exit;
3381 }
3382
3383 spin_lock_irqsave(&host->lock, flags);
3384 WARN(!host->pwr, "SDCC power is turned off\n");
3385 WARN(!host->clks_on, "SDCC clocks are turned off\n");
3386 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
3387
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303388 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303389 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
3390 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
3391 tuning_block_pattern = tuning_block_128;
3392 size = sizeof(tuning_block_128);
3393 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303394 spin_unlock_irqrestore(&host->lock, flags);
3395
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003396 /* first of all reset the tuning block */
3397 rc = msmsdcc_init_cm_sdc4_dll(host);
3398 if (rc)
3399 goto out;
3400
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303401 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003402 if (!data_buf) {
3403 rc = -ENOMEM;
3404 goto out;
3405 }
3406
3407 phase = 0;
3408 do {
3409 struct mmc_command cmd = {0};
3410 struct mmc_data data = {0};
3411 struct mmc_request mrq = {
3412 .cmd = &cmd,
3413 .data = &data
3414 };
3415 struct scatterlist sg;
3416
3417 /* set the phase in delay line hw block */
3418 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3419 if (rc)
3420 goto kfree;
3421
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303422 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003423 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
3424
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303425 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003426 data.blocks = 1;
3427 data.flags = MMC_DATA_READ;
3428 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
3429
3430 data.sg = &sg;
3431 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303432 sg_init_one(&sg, data_buf, size);
3433 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003434 mmc_wait_for_req(mmc, &mrq);
3435
3436 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303437 !memcmp(data_buf, tuning_block_pattern, size)) {
3438 /* tuning is successful at this tuning point */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003439 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303440 pr_debug("%s: %s: found good phase = %d\n",
3441 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003442 }
3443 } while (++phase < 16);
3444
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003445 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303446 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303447 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05303448 if (rc < 0)
3449 goto kfree;
3450 else
3451 phase = (u8)rc;
3452
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003453 /*
3454 * Finally set the selected phase in delay
3455 * line hw block.
3456 */
3457 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3458 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303459 goto kfree;
3460 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
3461 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003462 } else {
3463 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303464 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003465 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303466 msmsdcc_dump_sdcc_state(host);
3467 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003468 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003469
3470kfree:
3471 kfree(data_buf);
3472out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303473 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303474 host->tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303475 spin_unlock_irqrestore(&host->lock, flags);
3476exit:
3477 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003478 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07003479}
3480
3481static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003482 .enable = msmsdcc_enable,
3483 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07003484 .request = msmsdcc_request,
3485 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003486 .get_ro = msmsdcc_get_ro,
San Mehat9d2bd732009-09-22 16:44:22 -07003487 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003488 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
3489 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07003490};
3491
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003492static unsigned int
3493msmsdcc_slot_status(struct msmsdcc_host *host)
3494{
3495 int status;
3496 unsigned int gpio_no = host->plat->status_gpio;
3497
3498 status = gpio_request(gpio_no, "SD_HW_Detect");
3499 if (status) {
3500 pr_err("%s: %s: Failed to request GPIO %d\n",
3501 mmc_hostname(host->mmc), __func__, gpio_no);
3502 } else {
3503 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003504 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08003505 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003506 if (host->plat->is_status_gpio_active_low)
3507 status = !status;
3508 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003509 gpio_free(gpio_no);
3510 }
3511 return status;
3512}
3513
San Mehat9d2bd732009-09-22 16:44:22 -07003514static void
3515msmsdcc_check_status(unsigned long data)
3516{
3517 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3518 unsigned int status;
3519
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003520 if (host->plat->status || host->plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08003521 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003522 status = host->plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08003523 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003524 status = msmsdcc_slot_status(host);
3525
Krishna Konda941604a2012-01-10 17:46:34 -08003526 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08003527
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003528 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08003529 if (host->plat->status)
3530 pr_info("%s: Slot status change detected "
3531 "(%d -> %d)\n",
3532 mmc_hostname(host->mmc),
3533 host->oldstat, status);
3534 else if (host->plat->is_status_gpio_active_low)
3535 pr_info("%s: Slot status change detected "
3536 "(%d -> %d) and the card detect GPIO"
3537 " is ACTIVE_LOW\n",
3538 mmc_hostname(host->mmc),
3539 host->oldstat, status);
3540 else
3541 pr_info("%s: Slot status change detected "
3542 "(%d -> %d) and the card detect GPIO"
3543 " is ACTIVE_HIGH\n",
3544 mmc_hostname(host->mmc),
3545 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07003546 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003547 }
3548 host->oldstat = status;
3549 } else {
3550 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07003551 }
San Mehat9d2bd732009-09-22 16:44:22 -07003552}
3553
3554static irqreturn_t
3555msmsdcc_platform_status_irq(int irq, void *dev_id)
3556{
3557 struct msmsdcc_host *host = dev_id;
3558
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003559 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07003560 msmsdcc_check_status((unsigned long) host);
3561 return IRQ_HANDLED;
3562}
3563
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003564static irqreturn_t
3565msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
3566{
3567 struct msmsdcc_host *host = dev_id;
3568
3569 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
3570 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303571 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003572 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303573 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003574 wake_lock(&host->sdio_wlock);
3575 msmsdcc_disable_irq_wake(host);
3576 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303577 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003578 }
3579 if (host->plat->is_sdio_al_client) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003580 wake_lock(&host->sdio_wlock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303581 mmc_signal_sdio_irq(host->mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003582 }
3583 spin_unlock(&host->lock);
3584
3585 return IRQ_HANDLED;
3586}
3587
San Mehat9d2bd732009-09-22 16:44:22 -07003588static void
3589msmsdcc_status_notify_cb(int card_present, void *dev_id)
3590{
3591 struct msmsdcc_host *host = dev_id;
3592
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003593 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07003594 card_present);
3595 msmsdcc_check_status((unsigned long) host);
3596}
3597
San Mehat9d2bd732009-09-22 16:44:22 -07003598static int
3599msmsdcc_init_dma(struct msmsdcc_host *host)
3600{
3601 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
3602 host->dma.host = host;
3603 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003604 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003605
3606 if (!host->dmares)
3607 return -ENODEV;
3608
3609 host->dma.nc = dma_alloc_coherent(NULL,
3610 sizeof(struct msmsdcc_nc_dmadata),
3611 &host->dma.nc_busaddr,
3612 GFP_KERNEL);
3613 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003614 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07003615 return -ENOMEM;
3616 }
3617 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
3618 host->dma.cmd_busaddr = host->dma.nc_busaddr;
3619 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
3620 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
3621 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07003622 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07003623
3624 return 0;
3625}
3626
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003627#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
3628/**
3629 * Allocate and Connect a SDCC peripheral's SPS endpoint
3630 *
3631 * This function allocates endpoint context and
3632 * connect it with memory endpoint by calling
3633 * appropriate SPS driver APIs.
3634 *
3635 * Also registers a SPS callback function with
3636 * SPS driver
3637 *
3638 * This function should only be called once typically
3639 * during driver probe.
3640 *
3641 * @host - Pointer to sdcc host structure
3642 * @ep - Pointer to sps endpoint data structure
3643 * @is_produce - 1 means Producer endpoint
3644 * 0 means Consumer endpoint
3645 *
3646 * @return - 0 if successful else negative value.
3647 *
3648 */
3649static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
3650 struct msmsdcc_sps_ep_conn_data *ep,
3651 bool is_producer)
3652{
3653 int rc = 0;
3654 struct sps_pipe *sps_pipe_handle;
3655 struct sps_connect *sps_config = &ep->config;
3656 struct sps_register_event *sps_event = &ep->event;
3657
3658 /* Allocate endpoint context */
3659 sps_pipe_handle = sps_alloc_endpoint();
3660 if (!sps_pipe_handle) {
3661 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
3662 mmc_hostname(host->mmc), is_producer);
3663 rc = -ENOMEM;
3664 goto out;
3665 }
3666
3667 /* Get default connection configuration for an endpoint */
3668 rc = sps_get_config(sps_pipe_handle, sps_config);
3669 if (rc) {
3670 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
3671 " rc=%d", mmc_hostname(host->mmc),
3672 (u32)sps_pipe_handle, rc);
3673 goto get_config_err;
3674 }
3675
3676 /* Modify the default connection configuration */
3677 if (is_producer) {
3678 /*
3679 * For SDCC producer transfer, source should be
3680 * SDCC peripheral where as destination should
3681 * be system memory.
3682 */
3683 sps_config->source = host->sps.bam_handle;
3684 sps_config->destination = SPS_DEV_HANDLE_MEM;
3685 /* Producer pipe will handle this connection */
3686 sps_config->mode = SPS_MODE_SRC;
3687 sps_config->options =
3688 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3689 } else {
3690 /*
3691 * For SDCC consumer transfer, source should be
3692 * system memory where as destination should
3693 * SDCC peripheral
3694 */
3695 sps_config->source = SPS_DEV_HANDLE_MEM;
3696 sps_config->destination = host->sps.bam_handle;
3697 sps_config->mode = SPS_MODE_DEST;
3698 sps_config->options =
3699 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3700 }
3701
3702 /* Producer pipe index */
3703 sps_config->src_pipe_index = host->sps.src_pipe_index;
3704 /* Consumer pipe index */
3705 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
3706 /*
3707 * This event thresold value is only significant for BAM-to-BAM
3708 * transfer. It's ignored for BAM-to-System mode transfer.
3709 */
3710 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05303711
3712 /* Allocate maximum descriptor fifo size */
3713 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
3714 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003715 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
3716 sps_config->desc.size,
3717 &sps_config->desc.phys_base,
3718 GFP_KERNEL);
3719
Pratibhasagar V00b94332011-10-18 14:57:27 +05303720 if (!sps_config->desc.base) {
3721 rc = -ENOMEM;
3722 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3723 , mmc_hostname(host->mmc));
3724 goto get_config_err;
3725 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003726 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3727
3728 /* Establish connection between peripheral and memory endpoint */
3729 rc = sps_connect(sps_pipe_handle, sps_config);
3730 if (rc) {
3731 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3732 " rc=%d", mmc_hostname(host->mmc),
3733 (u32)sps_pipe_handle, rc);
3734 goto sps_connect_err;
3735 }
3736
3737 sps_event->mode = SPS_TRIGGER_CALLBACK;
3738 sps_event->options = SPS_O_EOT;
3739 sps_event->callback = msmsdcc_sps_complete_cb;
3740 sps_event->xfer_done = NULL;
3741 sps_event->user = (void *)host;
3742
3743 /* Register callback event for EOT (End of transfer) event. */
3744 rc = sps_register_event(sps_pipe_handle, sps_event);
3745 if (rc) {
3746 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3747 " rc=%d", mmc_hostname(host->mmc),
3748 (u32)sps_pipe_handle, rc);
3749 goto reg_event_err;
3750 }
3751 /* Now save the sps pipe handle */
3752 ep->pipe_handle = sps_pipe_handle;
3753 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3754 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3755 __func__, is_producer ? "READ" : "WRITE",
3756 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3757 goto out;
3758
3759reg_event_err:
3760 sps_disconnect(sps_pipe_handle);
3761sps_connect_err:
3762 dma_free_coherent(mmc_dev(host->mmc),
3763 sps_config->desc.size,
3764 sps_config->desc.base,
3765 sps_config->desc.phys_base);
3766get_config_err:
3767 sps_free_endpoint(sps_pipe_handle);
3768out:
3769 return rc;
3770}
3771
3772/**
3773 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3774 *
3775 * This function disconnect endpoint and deallocates
3776 * endpoint context.
3777 *
3778 * This function should only be called once typically
3779 * during driver remove.
3780 *
3781 * @host - Pointer to sdcc host structure
3782 * @ep - Pointer to sps endpoint data structure
3783 *
3784 */
3785static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3786 struct msmsdcc_sps_ep_conn_data *ep)
3787{
3788 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3789 struct sps_connect *sps_config = &ep->config;
3790 struct sps_register_event *sps_event = &ep->event;
3791
3792 sps_event->xfer_done = NULL;
3793 sps_event->callback = NULL;
3794 sps_register_event(sps_pipe_handle, sps_event);
3795 sps_disconnect(sps_pipe_handle);
3796 dma_free_coherent(mmc_dev(host->mmc),
3797 sps_config->desc.size,
3798 sps_config->desc.base,
3799 sps_config->desc.phys_base);
3800 sps_free_endpoint(sps_pipe_handle);
3801}
3802
3803/**
3804 * Reset SDCC peripheral's SPS endpoint
3805 *
3806 * This function disconnects an endpoint.
3807 *
3808 * This function should be called for reseting
3809 * SPS endpoint when data transfer error is
3810 * encountered during data transfer. This
3811 * can be considered as soft reset to endpoint.
3812 *
3813 * This function should only be called if
3814 * msmsdcc_sps_init() is already called.
3815 *
3816 * @host - Pointer to sdcc host structure
3817 * @ep - Pointer to sps endpoint data structure
3818 *
3819 * @return - 0 if successful else negative value.
3820 */
3821static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3822 struct msmsdcc_sps_ep_conn_data *ep)
3823{
3824 int rc = 0;
3825 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3826
3827 rc = sps_disconnect(sps_pipe_handle);
3828 if (rc) {
3829 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3830 " rc=%d", mmc_hostname(host->mmc), __func__,
3831 (u32)sps_pipe_handle, rc);
3832 goto out;
3833 }
3834 out:
3835 return rc;
3836}
3837
3838/**
3839 * Restore SDCC peripheral's SPS endpoint
3840 *
3841 * This function connects an endpoint.
3842 *
3843 * This function should be called for restoring
3844 * SPS endpoint after data transfer error is
3845 * encountered during data transfer. This
3846 * can be considered as soft reset to endpoint.
3847 *
3848 * This function should only be called if
3849 * msmsdcc_sps_reset_ep() is called before.
3850 *
3851 * @host - Pointer to sdcc host structure
3852 * @ep - Pointer to sps endpoint data structure
3853 *
3854 * @return - 0 if successful else negative value.
3855 */
3856static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3857 struct msmsdcc_sps_ep_conn_data *ep)
3858{
3859 int rc = 0;
3860 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3861 struct sps_connect *sps_config = &ep->config;
3862 struct sps_register_event *sps_event = &ep->event;
3863
3864 /* Establish connection between peripheral and memory endpoint */
3865 rc = sps_connect(sps_pipe_handle, sps_config);
3866 if (rc) {
3867 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3868 " rc=%d", mmc_hostname(host->mmc), __func__,
3869 (u32)sps_pipe_handle, rc);
3870 goto out;
3871 }
3872
3873 /* Register callback event for EOT (End of transfer) event. */
3874 rc = sps_register_event(sps_pipe_handle, sps_event);
3875 if (rc) {
3876 pr_err("%s: %s: sps_register_event() failed!!!"
3877 " pipe_handle=0x%x, rc=%d",
3878 mmc_hostname(host->mmc), __func__,
3879 (u32)sps_pipe_handle, rc);
3880 goto reg_event_err;
3881 }
3882 goto out;
3883
3884reg_event_err:
3885 sps_disconnect(sps_pipe_handle);
3886out:
3887 return rc;
3888}
3889
3890/**
3891 * Initialize SPS HW connected with SDCC core
3892 *
3893 * This function register BAM HW resources with
3894 * SPS driver and then initialize 2 SPS endpoints
3895 *
3896 * This function should only be called once typically
3897 * during driver probe.
3898 *
3899 * @host - Pointer to sdcc host structure
3900 *
3901 * @return - 0 if successful else negative value.
3902 *
3903 */
3904static int msmsdcc_sps_init(struct msmsdcc_host *host)
3905{
3906 int rc = 0;
3907 struct sps_bam_props bam = {0};
3908
3909 host->bam_base = ioremap(host->bam_memres->start,
3910 resource_size(host->bam_memres));
3911 if (!host->bam_base) {
3912 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3913 " size=0x%x", mmc_hostname(host->mmc),
3914 host->bam_memres->start,
3915 (host->bam_memres->end -
3916 host->bam_memres->start));
3917 rc = -ENOMEM;
3918 goto out;
3919 }
3920
3921 bam.phys_addr = host->bam_memres->start;
3922 bam.virt_addr = host->bam_base;
3923 /*
3924 * This event thresold value is only significant for BAM-to-BAM
3925 * transfer. It's ignored for BAM-to-System mode transfer.
3926 */
3927 bam.event_threshold = 0x10; /* Pipe event threshold */
3928 /*
3929 * This threshold controls when the BAM publish
3930 * the descriptor size on the sideband interface.
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05303931 * SPS HW will be used for data transfer size even
3932 * less than SDCC FIFO size. So let's set BAM summing
3933 * thresold to SPS_MIN_XFER_SIZE bytes.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003934 */
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05303935 bam.summing_threshold = SPS_MIN_XFER_SIZE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003936 /* SPS driver wll handle the SDCC BAM IRQ */
3937 bam.irq = (u32)host->bam_irqres->start;
3938 bam.manage = SPS_BAM_MGR_LOCAL;
3939
3940 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3941 (u32)bam.phys_addr);
3942 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3943 (u32)bam.virt_addr);
3944
3945 /* Register SDCC Peripheral BAM device to SPS driver */
3946 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3947 if (rc) {
3948 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3949 mmc_hostname(host->mmc), rc);
3950 goto reg_bam_err;
3951 }
3952 pr_info("%s: BAM device registered. bam_handle=0x%x",
3953 mmc_hostname(host->mmc), host->sps.bam_handle);
3954
3955 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3956 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3957
3958 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3959 SPS_PROD_PERIPHERAL);
3960 if (rc)
3961 goto sps_reset_err;
3962 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3963 SPS_CONS_PERIPHERAL);
3964 if (rc)
3965 goto cons_conn_err;
3966
3967 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3968 mmc_hostname(host->mmc),
3969 (unsigned long long)host->bam_memres->start,
3970 (unsigned int)host->bam_irqres->start);
3971 goto out;
3972
3973cons_conn_err:
3974 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3975sps_reset_err:
3976 sps_deregister_bam_device(host->sps.bam_handle);
3977reg_bam_err:
3978 iounmap(host->bam_base);
3979out:
3980 return rc;
3981}
3982
3983/**
3984 * De-initialize SPS HW connected with SDCC core
3985 *
3986 * This function deinitialize SPS endpoints and then
3987 * deregisters BAM resources from SPS driver.
3988 *
3989 * This function should only be called once typically
3990 * during driver remove.
3991 *
3992 * @host - Pointer to sdcc host structure
3993 *
3994 */
3995static void msmsdcc_sps_exit(struct msmsdcc_host *host)
3996{
3997 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
3998 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3999 sps_deregister_bam_device(host->sps.bam_handle);
4000 iounmap(host->bam_base);
4001}
4002#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
4003
4004static ssize_t
4005show_polling(struct device *dev, struct device_attribute *attr, char *buf)
4006{
4007 struct mmc_host *mmc = dev_get_drvdata(dev);
4008 struct msmsdcc_host *host = mmc_priv(mmc);
4009 int poll;
4010 unsigned long flags;
4011
4012 spin_lock_irqsave(&host->lock, flags);
4013 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
4014 spin_unlock_irqrestore(&host->lock, flags);
4015
4016 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
4017}
4018
4019static ssize_t
4020set_polling(struct device *dev, struct device_attribute *attr,
4021 const char *buf, size_t count)
4022{
4023 struct mmc_host *mmc = dev_get_drvdata(dev);
4024 struct msmsdcc_host *host = mmc_priv(mmc);
4025 int value;
4026 unsigned long flags;
4027
4028 sscanf(buf, "%d", &value);
4029
4030 spin_lock_irqsave(&host->lock, flags);
4031 if (value) {
4032 mmc->caps |= MMC_CAP_NEEDS_POLL;
4033 mmc_detect_change(host->mmc, 0);
4034 } else {
4035 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4036 }
4037#ifdef CONFIG_HAS_EARLYSUSPEND
4038 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
4039#endif
4040 spin_unlock_irqrestore(&host->lock, flags);
4041 return count;
4042}
4043
4044static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
4045 show_polling, set_polling);
4046static struct attribute *dev_attrs[] = {
4047 &dev_attr_polling.attr,
4048 NULL,
4049};
4050static struct attribute_group dev_attr_grp = {
4051 .attrs = dev_attrs,
4052};
4053
4054#ifdef CONFIG_HAS_EARLYSUSPEND
4055static void msmsdcc_early_suspend(struct early_suspend *h)
4056{
4057 struct msmsdcc_host *host =
4058 container_of(h, struct msmsdcc_host, early_suspend);
4059 unsigned long flags;
4060
4061 spin_lock_irqsave(&host->lock, flags);
4062 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
4063 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4064 spin_unlock_irqrestore(&host->lock, flags);
4065};
4066static void msmsdcc_late_resume(struct early_suspend *h)
4067{
4068 struct msmsdcc_host *host =
4069 container_of(h, struct msmsdcc_host, early_suspend);
4070 unsigned long flags;
4071
4072 if (host->polling_enabled) {
4073 spin_lock_irqsave(&host->lock, flags);
4074 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
4075 mmc_detect_change(host->mmc, 0);
4076 spin_unlock_irqrestore(&host->lock, flags);
4077 }
4078};
4079#endif
4080
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304081static void msmsdcc_print_regs(const char *name, void __iomem *base,
4082 u32 phys_base, unsigned int no_of_regs)
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304083{
4084 unsigned int i;
4085
4086 if (!base)
4087 return;
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304088
4089 pr_info("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
4090 " =====\n", name, phys_base, (u32)base);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304091 for (i = 0; i < no_of_regs; i = i + 4) {
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304092 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
4093 (u32)readl_relaxed(base + i*4),
4094 (u32)readl_relaxed(base + ((i+1)*4)),
4095 (u32)readl_relaxed(base + ((i+2)*4)),
4096 (u32)readl_relaxed(base + ((i+3)*4)));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304097 }
4098}
4099
4100static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
4101{
4102 /* Dump current state of SDCC clocks, power and irq */
4103 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304104 (host->pwr ? "ON" : "OFF"));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304105 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304106 mmc_hostname(host->mmc), (host->clks_on ? "ON" : "OFF"),
4107 (u32)clk_get_rate(host->clk));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304108 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
4109 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
4110
4111 /* Now dump SDCC registers. Don't print FIFO registers */
4112 if (host->clks_on)
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304113 msmsdcc_print_regs("SDCC-CORE", host->base,
4114 host->core_memres->start, 28);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304115
4116 if (host->curr.data) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304117 if (!msmsdcc_is_dma_possible(host, host->curr.data))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304118 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
4119 else if (host->is_dma_mode)
4120 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
4121 mmc_hostname(host->mmc), host->dma.busy,
4122 host->dma.channel, host->dma.crci);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304123 else if (host->is_sps_mode) {
4124 if (host->sps.busy)
4125 msmsdcc_print_regs("SDCC-DML", host->dml_base,
4126 host->dml_memres->start,
4127 16);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304128 pr_info("%s: SPS mode: busy=%d\n",
4129 mmc_hostname(host->mmc), host->sps.busy);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304130 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304131
4132 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
4133 mmc_hostname(host->mmc), host->curr.xfer_size,
4134 host->curr.data_xfered, host->curr.xfer_remain);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304135 }
4136
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304137 pr_info("%s: got_dataend=%d, prog_enable=%d,"
4138 " wait_for_auto_prog_done=%d, got_auto_prog_done=%d\n",
4139 mmc_hostname(host->mmc), host->curr.got_dataend,
4140 host->prog_enable, host->curr.wait_for_auto_prog_done,
4141 host->curr.got_auto_prog_done);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304142}
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304143
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004144static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
4145{
4146 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4147 struct mmc_request *mrq;
4148 unsigned long flags;
4149
4150 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004151 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004152 pr_info("%s: %s: dummy CMD52 timeout\n",
4153 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004154 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004155 }
4156
4157 mrq = host->curr.mrq;
4158
4159 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304160 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
4161 mrq->cmd->opcode);
4162 msmsdcc_dump_sdcc_state(host);
4163
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004164 if (!mrq->cmd->error)
4165 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304166 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004167 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004168 if (mrq->data && !mrq->data->error)
4169 mrq->data->error = -ETIMEDOUT;
4170 host->curr.data_xfered = 0;
4171 if (host->dma.sg && host->is_dma_mode) {
4172 msm_dmov_stop_cmd(host->dma.channel,
4173 &host->dma.hdr, 0);
4174 } else if (host->sps.sg && host->is_sps_mode) {
4175 /* Stop current SPS transfer */
4176 msmsdcc_sps_exit_curr_xfer(host);
4177 } else {
4178 msmsdcc_reset_and_restore(host);
4179 msmsdcc_stop_data(host);
4180 if (mrq->data && mrq->data->stop)
4181 msmsdcc_start_command(host,
4182 mrq->data->stop, 0);
4183 else
4184 msmsdcc_request_end(host, mrq);
4185 }
4186 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304187 host->prog_enable = 0;
Subhash Jadavanied6b0e42012-03-07 16:36:27 +05304188 host->curr.wait_for_auto_prog_done = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004189 msmsdcc_reset_and_restore(host);
4190 msmsdcc_request_end(host, mrq);
4191 }
4192 }
4193 spin_unlock_irqrestore(&host->lock, flags);
4194}
4195
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304196static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
4197{
4198 int i, ret;
4199 struct mmc_platform_data *pdata;
4200 struct device_node *np = dev->of_node;
4201 u32 bus_width = 0;
4202 u32 *clk_table;
4203 int clk_table_len;
4204 u32 *sup_voltages;
4205 int sup_volt_len;
4206
4207 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
4208 if (!pdata) {
4209 dev_err(dev, "could not allocate memory for platform data\n");
4210 goto err;
4211 }
4212
4213 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
4214 if (bus_width == 8) {
4215 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
4216 } else if (bus_width == 4) {
4217 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
4218 } else {
4219 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
4220 pdata->mmc_bus_width = 0;
4221 }
4222
4223 if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
4224 size_t sz;
4225 sz = sup_volt_len / sizeof(*sup_voltages);
4226 if (sz > 0) {
4227 sup_voltages = devm_kzalloc(dev,
4228 sz * sizeof(*sup_voltages), GFP_KERNEL);
4229 if (!sup_voltages) {
4230 dev_err(dev, "No memory for supported voltage\n");
4231 goto err;
4232 }
4233
4234 ret = of_property_read_u32_array(np,
4235 "qcom,sdcc-sup-voltages", sup_voltages, sz);
4236 if (ret < 0) {
4237 dev_err(dev, "error while reading voltage"
4238 "ranges %d\n", ret);
4239 goto err;
4240 }
4241 } else {
4242 dev_err(dev, "No supported voltages\n");
4243 goto err;
4244 }
4245 for (i = 0; i < sz; i += 2) {
4246 u32 mask;
4247
4248 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
4249 sup_voltages[i + 1]);
4250 if (!mask)
4251 dev_err(dev, "Invalide voltage range %d\n", i);
4252 pdata->ocr_mask |= mask;
4253 }
4254 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
4255 } else {
4256 dev_err(dev, "Supported voltage range not specified\n");
4257 }
4258
4259 if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
4260 size_t sz;
4261 sz = clk_table_len / sizeof(*clk_table);
4262
4263 if (sz > 0) {
4264 clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
4265 GFP_KERNEL);
4266 if (!clk_table) {
4267 dev_err(dev, "No memory for clock table\n");
4268 goto err;
4269 }
4270
4271 ret = of_property_read_u32_array(np,
4272 "qcom,sdcc-clk-rates", clk_table, sz);
4273 if (ret < 0) {
4274 dev_err(dev, "error while reading clk"
4275 "table %d\n", ret);
4276 goto err;
4277 }
4278 } else {
4279 dev_err(dev, "clk_table not specified\n");
4280 goto err;
4281 }
4282 pdata->sup_clk_table = clk_table;
4283 pdata->sup_clk_cnt = sz;
4284 } else {
4285 dev_err(dev, "Supported clock rates not specified\n");
4286 }
4287
4288 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
4289 pdata->nonremovable = true;
4290 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
4291 pdata->disable_cmd23 = true;
4292
4293 return pdata;
4294err:
4295 return NULL;
4296}
4297
San Mehat9d2bd732009-09-22 16:44:22 -07004298static int
4299msmsdcc_probe(struct platform_device *pdev)
4300{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304301 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07004302 struct msmsdcc_host *host;
4303 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004304 unsigned long flags;
4305 struct resource *core_irqres = NULL;
4306 struct resource *bam_irqres = NULL;
4307 struct resource *core_memres = NULL;
4308 struct resource *dml_memres = NULL;
4309 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07004310 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07004311 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05304312 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004313 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07004314
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304315 if (pdev->dev.of_node) {
4316 plat = msmsdcc_populate_pdata(&pdev->dev);
4317 of_property_read_u32((&pdev->dev)->of_node,
4318 "cell-index", &pdev->id);
4319 } else {
4320 plat = pdev->dev.platform_data;
4321 }
4322
San Mehat9d2bd732009-09-22 16:44:22 -07004323 /* must have platform data */
4324 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004325 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004326 ret = -EINVAL;
4327 goto out;
4328 }
4329
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004330 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07004331 return -EINVAL;
4332
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304333 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
4334 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
4335 return -EINVAL;
4336 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004337
San Mehat9d2bd732009-09-22 16:44:22 -07004338 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004339 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004340 return -ENXIO;
4341 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304342 if (pdev->dev.of_node) {
4343 /*
4344 * Device tree iomem resources are only accessible by index.
4345 * index = 0 -> SDCC register interface
4346 * index = 1 -> DML register interface
4347 * index = 2 -> BAM register interface
4348 * IRQ resources:
4349 * index = 0 -> SDCC IRQ
4350 * index = 1 -> BAM IRQ
4351 */
4352 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
4353 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
4354 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
4355 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
4356 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
4357 } else {
4358 for (i = 0; i < pdev->num_resources; i++) {
4359 if (pdev->resource[i].flags & IORESOURCE_MEM) {
4360 if (!strncmp(pdev->resource[i].name,
4361 "sdcc_dml_addr",
4362 sizeof("sdcc_dml_addr")))
4363 dml_memres = &pdev->resource[i];
4364 else if (!strncmp(pdev->resource[i].name,
4365 "sdcc_bam_addr",
4366 sizeof("sdcc_bam_addr")))
4367 bam_memres = &pdev->resource[i];
4368 else
4369 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07004370
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304371 }
4372 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
4373 if (!strncmp(pdev->resource[i].name,
4374 "sdcc_bam_irq",
4375 sizeof("sdcc_bam_irq")))
4376 bam_irqres = &pdev->resource[i];
4377 else
4378 core_irqres = &pdev->resource[i];
4379 }
4380 if (pdev->resource[i].flags & IORESOURCE_DMA) {
4381 if (!strncmp(pdev->resource[i].name,
4382 "sdcc_dma_chnl",
4383 sizeof("sdcc_dma_chnl")))
4384 dmares = &pdev->resource[i];
4385 else if (!strncmp(pdev->resource[i].name,
4386 "sdcc_dma_crci",
4387 sizeof("sdcc_dma_crci")))
4388 dma_crci_res = &pdev->resource[i];
4389 }
Krishna Konda25786ec2011-07-25 16:21:36 -07004390 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004391 }
4392
4393 if (!core_irqres || !core_memres) {
4394 pr_err("%s: Invalid sdcc core resource\n", __func__);
4395 return -ENXIO;
4396 }
4397
4398 /*
4399 * Both BAM and DML memory resource should be preset.
4400 * BAM IRQ resource should also be present.
4401 */
4402 if ((bam_memres && !dml_memres) ||
4403 (!bam_memres && dml_memres) ||
4404 ((bam_memres && dml_memres) && !bam_irqres)) {
4405 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004406 return -ENXIO;
4407 }
4408
4409 /*
4410 * Setup our host structure
4411 */
San Mehat9d2bd732009-09-22 16:44:22 -07004412 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
4413 if (!mmc) {
4414 ret = -ENOMEM;
4415 goto out;
4416 }
4417
4418 host = mmc_priv(mmc);
4419 host->pdev_id = pdev->id;
4420 host->plat = plat;
4421 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08004422 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05304423
4424 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004425 host->is_sps_mode = 1;
4426 else if (dmares)
4427 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07004428
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004429 host->base = ioremap(core_memres->start,
4430 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07004431 if (!host->base) {
4432 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004433 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004434 }
4435
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004436 host->core_irqres = core_irqres;
4437 host->bam_irqres = bam_irqres;
4438 host->core_memres = core_memres;
4439 host->dml_memres = dml_memres;
4440 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07004441 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07004442 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07004443 spin_lock_init(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304444 mutex_init(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07004445
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004446#ifdef CONFIG_MMC_EMBEDDED_SDIO
4447 if (plat->embedded_sdio)
4448 mmc_set_embedded_sdio_data(mmc,
4449 &plat->embedded_sdio->cis,
4450 &plat->embedded_sdio->cccr,
4451 plat->embedded_sdio->funcs,
4452 plat->embedded_sdio->num_funcs);
4453#endif
4454
Sahitya Tummala62612cf2010-12-08 15:03:03 +05304455 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
4456 (unsigned long)host);
4457
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004458 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
4459 (unsigned long)host);
4460 if (host->is_dma_mode) {
4461 /* Setup DMA */
4462 ret = msmsdcc_init_dma(host);
4463 if (ret)
4464 goto ioremap_free;
4465 } else {
4466 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004467 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004468 }
4469
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004470 /*
4471 * Setup SDCC clock if derived from Dayatona
4472 * fabric core clock.
4473 */
4474 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07004475 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004476 if (!IS_ERR(host->dfab_pclk)) {
4477 /* Set the clock rate to 64MHz for max. performance */
4478 ret = clk_set_rate(host->dfab_pclk, 64000000);
4479 if (ret)
4480 goto dfab_pclk_put;
Asutosh Dasf5298c32012-04-03 14:51:47 +05304481 ret = clk_prepare_enable(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004482 if (ret)
4483 goto dfab_pclk_put;
4484 } else
4485 goto dma_free;
4486 }
4487
4488 /*
4489 * Setup main peripheral bus clock
4490 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004491 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004492 if (!IS_ERR(host->pclk)) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05304493 ret = clk_prepare_enable(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004494 if (ret)
4495 goto pclk_put;
4496
4497 host->pclk_rate = clk_get_rate(host->pclk);
4498 }
4499
4500 /*
4501 * Setup SDC MMC clock
4502 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004503 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07004504 if (IS_ERR(host->clk)) {
4505 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004506 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07004507 }
4508
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004509 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
4510 if (ret) {
4511 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
4512 goto clk_put;
4513 }
4514
Asutosh Dasf5298c32012-04-03 14:51:47 +05304515 ret = clk_prepare_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004516 if (ret)
4517 goto clk_put;
4518
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004519 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304520 if (!host->clk_rate)
4521 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304522
4523 /*
4524 * Lookup the Controller Version, to identify the supported features
4525 * Version number read as 0 would indicate SDCC3 or earlier versions
4526 */
4527 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
4528 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
4529 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304530 /*
4531 * Set the register write delay according to min. clock frequency
4532 * supported and update later when the host->clk_rate changes.
4533 */
4534 host->reg_write_delay =
4535 (1 + ((3 * USEC_PER_SEC) /
4536 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004537
4538 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05304539 /* Apply Hard reset to SDCC to put it in power on default state */
4540 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004541
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004542#define MSM_MMC_DEFAULT_CPUDMA_LATENCY 200 /* usecs */
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304543 /* pm qos request to prevent apps idle power collapse */
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004544 if (host->plat->cpu_dma_latency)
4545 host->cpu_dma_latency = host->plat->cpu_dma_latency;
4546 else
4547 host->cpu_dma_latency = MSM_MMC_DEFAULT_CPUDMA_LATENCY;
4548 pm_qos_add_request(&host->pm_qos_req_dma,
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304549 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
4550
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004551 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07004552 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004553 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07004554 goto clk_disable;
4555 }
4556
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004557
4558 /* Clocks has to be running before accessing SPS/DML HW blocks */
4559 if (host->is_sps_mode) {
4560 /* Initialize SPS */
4561 ret = msmsdcc_sps_init(host);
4562 if (ret)
4563 goto vreg_deinit;
4564 /* Initialize DML */
4565 ret = msmsdcc_dml_init(host);
4566 if (ret)
4567 goto sps_exit;
4568 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05304569 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07004570
San Mehat9d2bd732009-09-22 16:44:22 -07004571 /*
4572 * Setup MMC host structure
4573 */
4574 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004575 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
4576 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004577 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004578 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
4579 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07004580
San Mehat9d2bd732009-09-22 16:44:22 -07004581 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05304582 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304583
4584 /*
4585 * If we send the CMD23 before multi block write/read command
4586 * then we need not to send CMD12 at the end of the transfer.
4587 * If we don't send the CMD12 then only way to detect the PROG_DONE
4588 * status is to use the AUTO_PROG_DONE status provided by SDCC4
4589 * controller. So let's enable the CMD23 for SDCC4 only.
4590 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304591 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304592 mmc->caps |= MMC_CAP_CMD23;
4593
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004594 mmc->caps |= plat->uhs_caps;
4595 /*
4596 * XPC controls the maximum current in the default speed mode of SDXC
4597 * card. XPC=0 means 100mA (max.) but speed class is not supported.
4598 * XPC=1 means 150mA (max.) and speed class is supported.
4599 */
4600 if (plat->xpc_cap)
4601 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
4602 MMC_CAP_SET_XPC_180);
4603
Subhash Jadavani6bb34a82012-04-18 13:18:40 +05304604 mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304605 if (pdev->dev.of_node) {
4606 if (of_get_property((&pdev->dev)->of_node,
4607 "qcom,sdcc-hs200", NULL))
4608 mmc->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
4609 }
4610
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004611 if (plat->nonremovable)
4612 mmc->caps |= MMC_CAP_NONREMOVABLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004613 mmc->caps |= MMC_CAP_SDIO_IRQ;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004614
4615 if (plat->is_sdio_al_client)
4616 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07004617
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304618 mmc->max_segs = msmsdcc_get_nr_sg(host);
4619 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
4620 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07004621
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304622 mmc->max_req_size = MMC_MAX_REQ_SIZE;
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +05304623 mmc->max_seg_size = mmc->max_req_size;
San Mehat9d2bd732009-09-22 16:44:22 -07004624
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004625 writel_relaxed(0, host->base + MMCIMASK0);
4626 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05304627 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004628
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004629 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
4630 mb();
4631 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07004632
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004633 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
4634 DRIVER_NAME " (cmd)", host);
4635 if (ret)
4636 goto dml_exit;
4637
4638 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
4639 DRIVER_NAME " (pio)", host);
4640 if (ret)
4641 goto irq_free;
4642
4643 /*
4644 * Enable SDCC IRQ only when host is powered on. Otherwise, this
4645 * IRQ is un-necessarily being monitored by MPM (Modem power
4646 * management block) during idle-power collapse. The MPM will be
4647 * configured to monitor the DATA1 GPIO line with level-low trigger
4648 * and thus depending on the GPIO status, it prevents TCXO shutdown
4649 * during idle-power collapse.
4650 */
4651 disable_irq(core_irqres->start);
4652 host->sdcc_irq_disabled = 1;
4653
4654 if (plat->sdiowakeup_irq) {
4655 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4656 mmc_hostname(mmc));
4657 ret = request_irq(plat->sdiowakeup_irq,
4658 msmsdcc_platform_sdiowakeup_irq,
4659 IRQF_SHARED | IRQF_TRIGGER_LOW,
4660 DRIVER_NAME "sdiowakeup", host);
4661 if (ret) {
4662 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
4663 plat->sdiowakeup_irq, ret);
4664 goto pio_irq_free;
4665 } else {
4666 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304667 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004668 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304669 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004670 }
4671 spin_unlock_irqrestore(&host->lock, flags);
4672 }
4673 }
4674
Subhash Jadavanic9b85752012-04-13 11:16:49 +05304675 if (host->plat->mpm_sdiowakeup_int) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004676 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4677 mmc_hostname(mmc));
4678 }
4679
4680 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
4681 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004682 /*
4683 * Setup card detect change
4684 */
4685
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004686 if (plat->status || plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08004687 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004688 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08004689 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004690 host->oldstat = msmsdcc_slot_status(host);
Krishna Konda360aa422011-12-06 18:27:41 -08004691
Krishna Konda941604a2012-01-10 17:46:34 -08004692 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004693 }
San Mehat9d2bd732009-09-22 16:44:22 -07004694
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004695 if (plat->status_irq) {
4696 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07004697 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004698 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07004699 DRIVER_NAME " (slot)",
4700 host);
4701 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004702 pr_err("Unable to get slot IRQ %d (%d)\n",
4703 plat->status_irq, ret);
4704 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004705 }
4706 } else if (plat->register_status_notify) {
4707 plat->register_status_notify(msmsdcc_status_notify_cb, host);
4708 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004709 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07004710 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004711
4712 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004713
4714 ret = pm_runtime_set_active(&(pdev)->dev);
4715 if (ret < 0)
4716 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
4717 __func__, ret);
4718 /*
4719 * There is no notion of suspend/resume for SD/MMC/SDIO
4720 * cards. So host can be suspended/resumed with out
4721 * worrying about its children.
4722 */
4723 pm_suspend_ignore_children(&(pdev)->dev, true);
4724
4725 /*
4726 * MMC/SD/SDIO bus suspend/resume operations are defined
4727 * only for the slots that will be used for non-removable
4728 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
4729 * defined. Otherwise, they simply become card removal and
4730 * insertion events during suspend and resume respectively.
4731 * Hence, enable run-time PM only for slots for which bus
4732 * suspend/resume operations are defined.
4733 */
4734#ifdef CONFIG_MMC_UNSAFE_RESUME
4735 /*
4736 * If this capability is set, MMC core will enable/disable host
4737 * for every claim/release operation on a host. We use this
4738 * notification to increment/decrement runtime pm usage count.
4739 */
4740 mmc->caps |= MMC_CAP_DISABLE;
4741 pm_runtime_enable(&(pdev)->dev);
4742#else
4743 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
4744 mmc->caps |= MMC_CAP_DISABLE;
4745 pm_runtime_enable(&(pdev)->dev);
4746 }
4747#endif
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05304748#ifndef CONFIG_PM_RUNTIME
4749 mmc_set_disable_delay(mmc, MSM_MMC_DISABLE_TIMEOUT);
4750#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004751 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
4752 (unsigned long)host);
4753
San Mehat9d2bd732009-09-22 16:44:22 -07004754 mmc_add_host(mmc);
4755
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004756#ifdef CONFIG_HAS_EARLYSUSPEND
4757 host->early_suspend.suspend = msmsdcc_early_suspend;
4758 host->early_suspend.resume = msmsdcc_late_resume;
4759 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
4760 register_early_suspend(&host->early_suspend);
4761#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004762
Krishna Konda25786ec2011-07-25 16:21:36 -07004763 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
4764 " dmacrcri %d\n", mmc_hostname(mmc),
4765 (unsigned long long)core_memres->start,
4766 (unsigned int) core_irqres->start,
4767 (unsigned int) plat->status_irq, host->dma.channel,
4768 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004769
4770 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
4771 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
4772 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
4773 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
4774 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
4775 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
4776 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
4777 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
4778 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
4779 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
4780 host->eject);
4781 pr_info("%s: Power save feature enable = %d\n",
4782 mmc_hostname(mmc), msmsdcc_pwrsave);
4783
Krishna Konda25786ec2011-07-25 16:21:36 -07004784 if (host->is_dma_mode && host->dma.channel != -1
4785 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004786 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004787 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004788 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004789 mmc_hostname(mmc), host->dma.cmd_busaddr,
4790 host->dma.cmdptr_busaddr);
4791 } else if (host->is_sps_mode) {
4792 pr_info("%s: SPS-BAM data transfer mode available\n",
4793 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004794 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004795 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004796
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004797#if defined(CONFIG_DEBUG_FS)
4798 msmsdcc_dbg_createhost(host);
4799#endif
4800 if (!plat->status_irq) {
4801 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
4802 if (ret)
4803 goto platform_irq_free;
4804 }
San Mehat9d2bd732009-09-22 16:44:22 -07004805 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004806
4807 platform_irq_free:
4808 del_timer_sync(&host->req_tout_timer);
4809 pm_runtime_disable(&(pdev)->dev);
4810 pm_runtime_set_suspended(&(pdev)->dev);
4811
4812 if (plat->status_irq)
4813 free_irq(plat->status_irq, host);
4814 sdiowakeup_irq_free:
4815 wake_lock_destroy(&host->sdio_suspend_wlock);
4816 if (plat->sdiowakeup_irq)
4817 free_irq(plat->sdiowakeup_irq, host);
4818 pio_irq_free:
4819 if (plat->sdiowakeup_irq)
4820 wake_lock_destroy(&host->sdio_wlock);
4821 free_irq(core_irqres->start, host);
4822 irq_free:
4823 free_irq(core_irqres->start, host);
4824 dml_exit:
4825 if (host->is_sps_mode)
4826 msmsdcc_dml_exit(host);
4827 sps_exit:
4828 if (host->is_sps_mode)
4829 msmsdcc_sps_exit(host);
4830 vreg_deinit:
4831 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07004832 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004833 clk_disable(host->clk);
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004834 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304835 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07004836 clk_put:
4837 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004838 pclk_disable:
4839 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05304840 clk_disable_unprepare(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07004841 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004842 if (!IS_ERR(host->pclk))
4843 clk_put(host->pclk);
4844 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05304845 clk_disable_unprepare(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004846 dfab_pclk_put:
4847 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4848 clk_put(host->dfab_pclk);
4849 dma_free:
4850 if (host->is_dma_mode) {
4851 if (host->dmares)
4852 dma_free_coherent(NULL,
4853 sizeof(struct msmsdcc_nc_dmadata),
4854 host->dma.nc, host->dma.nc_busaddr);
4855 }
4856 ioremap_free:
4857 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07004858 host_free:
4859 mmc_free_host(mmc);
4860 out:
4861 return ret;
4862}
4863
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004864static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07004865{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004866 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4867 struct mmc_platform_data *plat;
4868 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004869
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004870 if (!mmc)
4871 return -ENXIO;
4872
4873 if (pm_runtime_suspended(&(pdev)->dev))
4874 pm_runtime_resume(&(pdev)->dev);
4875
4876 host = mmc_priv(mmc);
4877
4878 DBG(host, "Removing SDCC device = %d\n", pdev->id);
4879 plat = host->plat;
4880
4881 if (!plat->status_irq)
4882 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
4883
4884 del_timer_sync(&host->req_tout_timer);
4885 tasklet_kill(&host->dma_tlet);
4886 tasklet_kill(&host->sps.tlet);
4887 mmc_remove_host(mmc);
4888
4889 if (plat->status_irq)
4890 free_irq(plat->status_irq, host);
4891
4892 wake_lock_destroy(&host->sdio_suspend_wlock);
4893 if (plat->sdiowakeup_irq) {
4894 wake_lock_destroy(&host->sdio_wlock);
4895 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
4896 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07004897 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004898
4899 free_irq(host->core_irqres->start, host);
4900 free_irq(host->core_irqres->start, host);
4901
4902 clk_put(host->clk);
4903 if (!IS_ERR(host->pclk))
4904 clk_put(host->pclk);
4905 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4906 clk_put(host->dfab_pclk);
4907
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004908 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304909 pm_qos_remove_request(&host->pm_qos_req_dma);
4910
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004911 msmsdcc_vreg_init(host, false);
4912
4913 if (host->is_dma_mode) {
4914 if (host->dmares)
4915 dma_free_coherent(NULL,
4916 sizeof(struct msmsdcc_nc_dmadata),
4917 host->dma.nc, host->dma.nc_busaddr);
4918 }
4919
4920 if (host->is_sps_mode) {
4921 msmsdcc_dml_exit(host);
4922 msmsdcc_sps_exit(host);
4923 }
4924
4925 iounmap(host->base);
4926 mmc_free_host(mmc);
4927
4928#ifdef CONFIG_HAS_EARLYSUSPEND
4929 unregister_early_suspend(&host->early_suspend);
4930#endif
4931 pm_runtime_disable(&(pdev)->dev);
4932 pm_runtime_set_suspended(&(pdev)->dev);
4933
4934 return 0;
4935}
4936
4937#ifdef CONFIG_MSM_SDIO_AL
4938int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4939{
4940 struct msmsdcc_host *host = mmc_priv(mmc);
4941 unsigned long flags;
4942
Asutosh Dasf5298c32012-04-03 14:51:47 +05304943 mutex_lock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004944 spin_lock_irqsave(&host->lock, flags);
4945 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
4946 enable ? "En" : "Dis");
4947
4948 if (enable) {
4949 if (!host->sdcc_irq_disabled) {
4950 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05304951 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004952 host->sdcc_irq_disabled = 1;
4953 }
4954
4955 if (host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05304956 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004957 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304958 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004959 host->clks_on = 0;
4960 }
4961
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304962 if (host->plat->sdio_lpm_gpio_setup &&
4963 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004964 spin_unlock_irqrestore(&host->lock, flags);
4965 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
4966 spin_lock_irqsave(&host->lock, flags);
4967 host->sdio_gpio_lpm = 1;
4968 }
4969
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304970 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004971 msmsdcc_enable_irq_wake(host);
4972 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304973 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004974 }
4975 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304976 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004977 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304978 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004979 msmsdcc_disable_irq_wake(host);
4980 }
4981
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304982 if (host->plat->sdio_lpm_gpio_setup &&
4983 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004984 spin_unlock_irqrestore(&host->lock, flags);
4985 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
4986 spin_lock_irqsave(&host->lock, flags);
4987 host->sdio_gpio_lpm = 0;
4988 }
4989
4990 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05304991 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004992 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304993 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004994 host->clks_on = 1;
4995 }
4996
4997 if (host->sdcc_irq_disabled) {
4998 writel_relaxed(host->mci_irqenable,
4999 host->base + MMCIMASK0);
5000 mb();
5001 enable_irq(host->core_irqres->start);
5002 host->sdcc_irq_disabled = 0;
5003 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005004 }
5005 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305006 mutex_unlock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005007 return 0;
5008}
5009#else
5010int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
5011{
5012 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07005013}
5014#endif
5015
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005016#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07005017static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005018msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07005019{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005020 struct mmc_host *mmc = dev_get_drvdata(dev);
5021 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07005022 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305023 unsigned long flags;
5024
San Mehat9d2bd732009-09-22 16:44:22 -07005025
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005026 if (host->plat->is_sdio_al_client)
5027 return 0;
Sahitya Tummala7661a452011-07-18 13:28:35 +05305028 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005029 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005030 host->sdcc_suspending = 1;
5031 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07005032
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005033 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005034 * MMC core thinks that host is disabled by now since
5035 * runtime suspend is scheduled after msmsdcc_disable()
5036 * is called. Thus, MMC core will try to enable the host
5037 * while suspending it. This results in a synchronous
5038 * runtime resume request while in runtime suspending
5039 * context and hence inorder to complete this resume
5040 * requet, it will wait for suspend to be complete,
5041 * but runtime suspend also can not proceed further
5042 * until the host is resumed. Thus, it leads to a hang.
5043 * Hence, increase the pm usage count before suspending
5044 * the host so that any resume requests after this will
5045 * simple become pm usage counter increment operations.
5046 */
5047 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05305048 /* If there is pending detect work abort runtime suspend */
5049 if (unlikely(work_busy(&mmc->detect.work)))
5050 rc = -EAGAIN;
5051 else
5052 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005053 pm_runtime_put_noidle(dev);
5054
5055 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305056 spin_lock_irqsave(&host->lock, flags);
5057 host->sdcc_suspended = true;
5058 spin_unlock_irqrestore(&host->lock, flags);
5059 if (mmc->card && mmc_card_sdio(mmc->card) &&
5060 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005061 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305062 * If SDIO function driver doesn't want
5063 * to power off the card, atleast turn off
5064 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005065 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305066 mmc_host_clk_hold(mmc);
5067 spin_lock_irqsave(&mmc->clk_lock, flags);
5068 mmc->clk_old = mmc->ios.clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005069 mmc->ios.clock = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305070 mmc->clk_gated = true;
5071 spin_unlock_irqrestore(&mmc->clk_lock, flags);
5072 mmc_set_ios(mmc);
5073 mmc_host_clk_release(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005074 }
5075 }
5076 host->sdcc_suspending = 0;
5077 mmc->suspend_task = NULL;
5078 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
5079 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005080 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05305081 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
San Mehat9d2bd732009-09-22 16:44:22 -07005082 return rc;
5083}
5084
5085static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005086msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07005087{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005088 struct mmc_host *mmc = dev_get_drvdata(dev);
5089 struct msmsdcc_host *host = mmc_priv(mmc);
5090 unsigned long flags;
5091
5092 if (host->plat->is_sdio_al_client)
5093 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07005094
Sahitya Tummala7661a452011-07-18 13:28:35 +05305095 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005096 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305097 if (mmc->card && mmc_card_sdio(mmc->card) &&
5098 mmc_card_keep_power(mmc)) {
5099 mmc_host_clk_hold(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305100 mmc->ios.clock = host->clk_rate;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305101 mmc_set_ios(mmc);
5102 mmc_host_clk_release(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305103 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005104
5105 mmc_resume_host(mmc);
5106
5107 /*
5108 * FIXME: Clearing of flags must be handled in clients
5109 * resume handler.
5110 */
5111 spin_lock_irqsave(&host->lock, flags);
5112 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305113 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005114 spin_unlock_irqrestore(&host->lock, flags);
5115
5116 /*
5117 * After resuming the host wait for sometime so that
5118 * the SDIO work will be processed.
5119 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305120 if (mmc->card && mmc_card_sdio(mmc->card)) {
Subhash Jadavanic9b85752012-04-13 11:16:49 +05305121 if ((host->plat->mpm_sdiowakeup_int ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005122 host->plat->sdiowakeup_irq) &&
5123 wake_lock_active(&host->sdio_wlock))
5124 wake_lock_timeout(&host->sdio_wlock, 1);
5125 }
5126
5127 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005128 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05305129 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005130 return 0;
5131}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005132
5133static int msmsdcc_runtime_idle(struct device *dev)
5134{
5135 struct mmc_host *mmc = dev_get_drvdata(dev);
5136 struct msmsdcc_host *host = mmc_priv(mmc);
5137
5138 if (host->plat->is_sdio_al_client)
5139 return 0;
5140
5141 /* Idle timeout is not configurable for now */
5142 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
5143
5144 return -EAGAIN;
5145}
5146
5147static int msmsdcc_pm_suspend(struct device *dev)
5148{
5149 struct mmc_host *mmc = dev_get_drvdata(dev);
5150 struct msmsdcc_host *host = mmc_priv(mmc);
5151 int rc = 0;
5152
5153 if (host->plat->is_sdio_al_client)
5154 return 0;
5155
5156
5157 if (host->plat->status_irq)
5158 disable_irq(host->plat->status_irq);
5159
Subhash Jadavani18702212012-03-19 18:50:18 +05305160 if (!pm_runtime_suspended(dev)) {
5161 if (!(mmc->card && mmc_card_sdio(mmc->card))) {
5162 /*
5163 * decrement power.usage_counter if it's
5164 * not zero earlier
5165 */
5166 pm_runtime_put_noidle(dev);
5167 rc = pm_runtime_suspend(dev);
5168 }
5169
5170 /*
5171 * if device runtime PM status is still not suspended
5172 * then perform suspend here.
5173 */
5174 if (!pm_runtime_suspended(dev))
5175 rc = msmsdcc_runtime_suspend(dev);
5176 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005177
5178 return rc;
5179}
5180
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305181static int msmsdcc_suspend_noirq(struct device *dev)
5182{
5183 struct mmc_host *mmc = dev_get_drvdata(dev);
5184 struct msmsdcc_host *host = mmc_priv(mmc);
5185 int rc = 0;
5186
5187 /*
5188 * After platform suspend there may be active request
5189 * which might have enabled clocks. For example, in SDIO
5190 * case, ksdioirq thread might have scheduled after sdcc
5191 * suspend but before system freeze. In that case abort
5192 * suspend and retry instead of keeping the clocks on
5193 * during suspend and not allowing TCXO.
5194 */
5195
Asutosh Dasf5298c32012-04-03 14:51:47 +05305196 if (host->clks_on && !host->plat->is_sdio_al_client) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305197 pr_warn("%s: clocks are on after suspend, aborting system "
5198 "suspend\n", mmc_hostname(mmc));
5199 rc = -EAGAIN;
5200 }
5201
5202 return rc;
5203}
5204
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005205static int msmsdcc_pm_resume(struct device *dev)
5206{
5207 struct mmc_host *mmc = dev_get_drvdata(dev);
5208 struct msmsdcc_host *host = mmc_priv(mmc);
5209 int rc = 0;
5210
5211 if (host->plat->is_sdio_al_client)
5212 return 0;
5213
Sahitya Tummalafb486372011-09-02 19:01:49 +05305214 if (!pm_runtime_suspended(dev))
5215 rc = msmsdcc_runtime_resume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005216 if (host->plat->status_irq) {
5217 msmsdcc_check_status((unsigned long)host);
5218 enable_irq(host->plat->status_irq);
5219 }
5220
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005221 return rc;
5222}
5223
Daniel Walker08ecfde2010-06-23 12:32:20 -07005224#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005225#define msmsdcc_runtime_suspend NULL
5226#define msmsdcc_runtime_resume NULL
5227#define msmsdcc_runtime_idle NULL
5228#define msmsdcc_pm_suspend NULL
5229#define msmsdcc_pm_resume NULL
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305230#define msmsdcc_suspend_noirq NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07005231#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005232
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005233static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
5234 .runtime_suspend = msmsdcc_runtime_suspend,
5235 .runtime_resume = msmsdcc_runtime_resume,
5236 .runtime_idle = msmsdcc_runtime_idle,
5237 .suspend = msmsdcc_pm_suspend,
5238 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305239 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005240};
5241
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305242static const struct of_device_id msmsdcc_dt_match[] = {
5243 {.compatible = "qcom,msm-sdcc"},
5244
5245};
5246MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
5247
San Mehat9d2bd732009-09-22 16:44:22 -07005248static struct platform_driver msmsdcc_driver = {
5249 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005250 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07005251 .driver = {
5252 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005253 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305254 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07005255 },
5256};
5257
5258static int __init msmsdcc_init(void)
5259{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005260#if defined(CONFIG_DEBUG_FS)
5261 int ret = 0;
5262 ret = msmsdcc_dbg_init();
5263 if (ret) {
5264 pr_err("Failed to create debug fs dir \n");
5265 return ret;
5266 }
5267#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005268 return platform_driver_register(&msmsdcc_driver);
5269}
5270
5271static void __exit msmsdcc_exit(void)
5272{
5273 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005274
5275#if defined(CONFIG_DEBUG_FS)
5276 debugfs_remove(debugfs_file);
5277 debugfs_remove(debugfs_dir);
5278#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005279}
5280
5281module_init(msmsdcc_init);
5282module_exit(msmsdcc_exit);
5283
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005284MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07005285MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005286
5287#if defined(CONFIG_DEBUG_FS)
5288
5289static int
5290msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
5291{
5292 file->private_data = inode->i_private;
5293 return 0;
5294}
5295
5296static ssize_t
5297msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
5298 size_t count, loff_t *ppos)
5299{
5300 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08005301 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005302 int max, i;
5303
5304 i = 0;
5305 max = sizeof(buf) - 1;
5306
5307 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
5308 host->curr.cmd, host->curr.data);
5309 if (host->curr.cmd) {
5310 struct mmc_command *cmd = host->curr.cmd;
5311
5312 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
5313 cmd->opcode, cmd->arg, cmd->flags);
5314 }
5315 if (host->curr.data) {
5316 struct mmc_data *data = host->curr.data;
5317 i += scnprintf(buf + i, max - i,
5318 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
5319 data->timeout_ns, data->timeout_clks,
5320 data->blksz, data->blocks, data->error,
5321 data->flags);
5322 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
5323 host->curr.xfer_size, host->curr.xfer_remain,
5324 host->curr.data_xfered, host->dma.sg);
5325 }
5326
5327 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
5328}
5329
5330static const struct file_operations msmsdcc_dbg_state_ops = {
5331 .read = msmsdcc_dbg_state_read,
5332 .open = msmsdcc_dbg_state_open,
5333};
5334
5335static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
5336{
5337 if (debugfs_dir) {
5338 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
5339 0644, debugfs_dir, host,
5340 &msmsdcc_dbg_state_ops);
5341 }
5342}
5343
5344static int __init msmsdcc_dbg_init(void)
5345{
5346 int err;
5347
5348 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
5349 if (IS_ERR(debugfs_dir)) {
5350 err = PTR_ERR(debugfs_dir);
5351 debugfs_dir = NULL;
5352 return err;
5353 }
5354
5355 return 0;
5356}
5357#endif