blob: e364eac03c292156f5ce2fd8bd99dec2cf4f2c54 [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>
56#include <mach/htc_pwrsink.h>
57#include <mach/sdio_al.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
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070072
73#if defined(CONFIG_DEBUG_FS)
74static void msmsdcc_dbg_createhost(struct msmsdcc_host *);
75static struct dentry *debugfs_dir;
76static struct dentry *debugfs_file;
77static int msmsdcc_dbg_init(void);
78#endif
79
Subhash Jadavani8766e352011-11-30 11:30:32 +053080static u64 dma_mask = DMA_BIT_MASK(32);
San Mehat9d2bd732009-09-22 16:44:22 -070081static unsigned int msmsdcc_pwrsave = 1;
San Mehat9d2bd732009-09-22 16:44:22 -070082
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070083static struct mmc_command dummy52cmd;
84static struct mmc_request dummy52mrq = {
85 .cmd = &dummy52cmd,
86 .data = NULL,
87 .stop = NULL,
88};
89static struct mmc_command dummy52cmd = {
90 .opcode = SD_IO_RW_DIRECT,
91 .flags = MMC_RSP_PRESENT,
92 .data = NULL,
93 .mrq = &dummy52mrq,
94};
95/*
96 * An array holding the Tuning pattern to compare with when
97 * executing a tuning cycle.
98 */
99static const u32 cmd19_tuning_block[16] = {
100 0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
101 0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
102 0xF0FFF0FF, 0x3CCCFC0F, 0xCFCC33CC, 0xEEFFEFFF,
103 0xFDFFFDFF, 0xFFBFFFDF, 0xFFF7FFBB, 0xDE7B7FF7
104};
San Mehat865c8062009-11-13 13:42:06 -0800105
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700106#if IRQ_DEBUG == 1
107static char *irq_status_bits[] = { "cmdcrcfail", "datcrcfail", "cmdtimeout",
108 "dattimeout", "txunderrun", "rxoverrun",
109 "cmdrespend", "cmdsent", "dataend", NULL,
110 "datablkend", "cmdactive", "txactive",
111 "rxactive", "txhalfempty", "rxhalffull",
112 "txfifofull", "rxfifofull", "txfifoempty",
113 "rxfifoempty", "txdataavlbl", "rxdataavlbl",
114 "sdiointr", "progdone", "atacmdcompl",
115 "sdiointrope", "ccstimeout", NULL, NULL,
116 NULL, NULL, NULL };
117
118static void
119msmsdcc_print_status(struct msmsdcc_host *host, char *hdr, uint32_t status)
San Mehat865c8062009-11-13 13:42:06 -0800120{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700121 int i;
San Mehat8b1c2ba2009-11-16 10:17:30 -0800122
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700123 pr_debug("%s-%s ", mmc_hostname(host->mmc), hdr);
124 for (i = 0; i < 32; i++) {
125 if (status & (1 << i))
126 pr_debug("%s ", irq_status_bits[i]);
San Mehat865c8062009-11-13 13:42:06 -0800127 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700128 pr_debug("\n");
San Mehatc7fc9372009-11-22 17:19:07 -0800129}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700130#endif
San Mehat865c8062009-11-13 13:42:06 -0800131
San Mehat9d2bd732009-09-22 16:44:22 -0700132static void
133msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
134 u32 c);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530135static inline void msmsdcc_delay(struct msmsdcc_host *host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530136static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530137
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530138static inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
139{
140 unsigned short ret = NR_SG;
141
142 if (host->is_sps_mode) {
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +0530143 ret = SPS_MAX_DESCS;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530144 } else { /* DMA or PIO mode */
145 if (NR_SG > MAX_NR_SG_DMA_PIO)
146 ret = MAX_NR_SG_DMA_PIO;
147 }
148
149 return ret;
150}
151
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530152/* Prevent idle power collapse(pc) while operating in peripheral mode */
153static void msmsdcc_pm_qos_update_latency(struct msmsdcc_host *host, int vote)
154{
155 u32 swfi_latency = 0;
156
157 if (!host->plat->swfi_latency)
158 return;
159
160 swfi_latency = host->plat->swfi_latency + 1;
161
162 if (vote)
163 pm_qos_update_request(&host->pm_qos_req_dma,
164 swfi_latency);
165 else
166 pm_qos_update_request(&host->pm_qos_req_dma,
167 PM_QOS_DEFAULT_VALUE);
168}
169
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700170#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
171static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
172 struct msmsdcc_sps_ep_conn_data *ep);
173static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
174 struct msmsdcc_sps_ep_conn_data *ep);
175#else
176static inline int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
177 struct msmsdcc_sps_ep_conn_data *ep,
178 bool is_producer) { return 0; }
179static inline void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
180 struct msmsdcc_sps_ep_conn_data *ep) { }
181static inline int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
182 struct msmsdcc_sps_ep_conn_data *ep)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530183{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700184 return 0;
185}
186static inline int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
187 struct msmsdcc_sps_ep_conn_data *ep)
188{
189 return 0;
190}
191static inline int msmsdcc_sps_init(struct msmsdcc_host *host) { return 0; }
192static inline void msmsdcc_sps_exit(struct msmsdcc_host *host) {}
193#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530194
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700195/**
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530196 * Apply soft reset to all SDCC BAM pipes
197 *
198 * This function applies soft reset to SDCC BAM pipe.
199 *
200 * This function should be called to recover from error
201 * conditions encountered during CMD/DATA tranfsers with card.
202 *
203 * @host - Pointer to driver's host structure
204 *
205 */
206static void msmsdcc_sps_pipes_reset_and_restore(struct msmsdcc_host *host)
207{
208 int rc;
209
210 /* Reset all SDCC BAM pipes */
211 rc = msmsdcc_sps_reset_ep(host, &host->sps.prod);
212 if (rc)
213 pr_err("%s:msmsdcc_sps_reset_ep(prod) error=%d\n",
214 mmc_hostname(host->mmc), rc);
215 rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
216 if (rc)
217 pr_err("%s:msmsdcc_sps_reset_ep(cons) error=%d\n",
218 mmc_hostname(host->mmc), rc);
219
220 /* Restore all BAM pipes connections */
221 rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
222 if (rc)
223 pr_err("%s:msmsdcc_sps_restore_ep(prod) error=%d\n",
224 mmc_hostname(host->mmc), rc);
225 rc = msmsdcc_sps_restore_ep(host, &host->sps.cons);
226 if (rc)
227 pr_err("%s:msmsdcc_sps_restore_ep(cons) error=%d\n",
228 mmc_hostname(host->mmc), rc);
229}
230
231/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700232 * Apply soft reset
233 *
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530234 * This function applies soft reset to SDCC core and DML core.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700235 *
236 * This function should be called to recover from error
237 * conditions encountered with CMD/DATA tranfsers with card.
238 *
239 * Soft reset should only be used with SDCC controller v4.
240 *
241 * @host - Pointer to driver's host structure
242 *
243 */
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530244static void msmsdcc_soft_reset(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700245{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700246 /*
247 * Reset SDCC controller's DPSM (data path state machine
248 * and CPSM (command path state machine).
249 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700250 writel_relaxed(0, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530251 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700252 writel_relaxed(0, host->base + MMCIDATACTRL);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530253 msmsdcc_delay(host);
254}
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530255
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530256static void msmsdcc_hard_reset(struct msmsdcc_host *host)
257{
258 int ret;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530259
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530260 /* Reset the controller */
261 ret = clk_reset(host->clk, CLK_RESET_ASSERT);
262 if (ret)
263 pr_err("%s: Clock assert failed at %u Hz"
264 " with err %d\n", mmc_hostname(host->mmc),
265 host->clk_rate, ret);
266
267 ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
268 if (ret)
269 pr_err("%s: Clock deassert failed at %u Hz"
270 " with err %d\n", mmc_hostname(host->mmc),
271 host->clk_rate, ret);
272
273 /* Give some delay for clock reset to propogate to controller */
274 msmsdcc_delay(host);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530275}
276
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700277static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
278{
Pratibhasagar V1c11da62011-11-14 12:36:35 +0530279 if (host->sdcc_version) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530280 if (host->is_sps_mode) {
281 /* Reset DML first */
282 msmsdcc_dml_reset(host);
283 /*
284 * delay the SPS pipe reset in thread context as
285 * sps_connect/sps_disconnect APIs can be called
286 * only from non-atomic context.
287 */
288 host->sps.pipe_reset_pending = true;
289 }
290 mb();
291 msmsdcc_soft_reset(host);
292
293 pr_debug("%s: Applied soft reset to Controller\n",
294 mmc_hostname(host->mmc));
295
296 if (host->is_sps_mode)
297 msmsdcc_dml_init(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700298 } else {
299 /* Give Clock reset (hard reset) to controller */
300 u32 mci_clk = 0;
301 u32 mci_mask0 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700302
303 /* Save the controller state */
304 mci_clk = readl_relaxed(host->base + MMCICLOCK);
305 mci_mask0 = readl_relaxed(host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700306 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700307
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530308 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700309 pr_debug("%s: Controller has been reinitialized\n",
310 mmc_hostname(host->mmc));
311
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700312 /* Restore the contoller state */
313 writel_relaxed(host->pwr, host->base + MMCIPOWER);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530314 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700315 writel_relaxed(mci_clk, host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530316 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700317 writel_relaxed(mci_mask0, host->base + MMCIMASK0);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530318 mb(); /* no delay required after writing to MASK0 register */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700319 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530320
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700321 if (host->dummy_52_needed)
322 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700323}
324
325static int
San Mehat9d2bd732009-09-22 16:44:22 -0700326msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
327{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700328 int retval = 0;
329
San Mehat9d2bd732009-09-22 16:44:22 -0700330 BUG_ON(host->curr.data);
331
332 host->curr.mrq = NULL;
333 host->curr.cmd = NULL;
334
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700335 del_timer(&host->req_tout_timer);
336
San Mehat9d2bd732009-09-22 16:44:22 -0700337 if (mrq->data)
338 mrq->data->bytes_xfered = host->curr.data_xfered;
339 if (mrq->cmd->error == -ETIMEDOUT)
340 mdelay(5);
341
342 /*
343 * Need to drop the host lock here; mmc_request_done may call
344 * back into the driver...
345 */
346 spin_unlock(&host->lock);
347 mmc_request_done(host->mmc, mrq);
348 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700349
350 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700351}
352
353static void
354msmsdcc_stop_data(struct msmsdcc_host *host)
355{
San Mehat9d2bd732009-09-22 16:44:22 -0700356 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530357 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530358 host->curr.wait_for_auto_prog_done = 0;
359 host->curr.got_auto_prog_done = 0;
Krishna Konda3f5d48f2011-07-27 10:47:31 -0700360 writel_relaxed(readl_relaxed(host->base + MMCIDATACTRL) &
361 (~(MCI_DPSM_ENABLE)), host->base + MMCIDATACTRL);
Krishna Konda3e5c4d02011-07-11 16:31:45 -0700362 msmsdcc_delay(host); /* Allow the DPSM to be reset */
San Mehat9d2bd732009-09-22 16:44:22 -0700363}
364
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700365static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700366{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700367 return host->core_memres->start + MMCIFIFO;
368}
369
370static inline unsigned int msmsdcc_get_min_sup_clk_rate(
371 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530372
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700373static inline void msmsdcc_delay(struct msmsdcc_host *host)
374{
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530375 ktime_t start, diff;
376
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700377 mb();
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +0530378 udelay(host->reg_write_delay);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530379
Pratibhasagar V1c11da62011-11-14 12:36:35 +0530380 if (host->sdcc_version &&
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530381 (readl_relaxed(host->base + MCI_STATUS2) &
382 MCI_MCLK_REG_WR_ACTIVE)) {
383 start = ktime_get();
384 while (readl_relaxed(host->base + MCI_STATUS2) &
385 MCI_MCLK_REG_WR_ACTIVE) {
386 diff = ktime_sub(ktime_get(), start);
387 /* poll for max. 1 ms */
388 if (ktime_to_us(diff) > 1000) {
389 pr_warning("%s: previous reg. write is"
390 " still active\n",
391 mmc_hostname(host->mmc));
392 break;
393 }
394 }
395 }
San Mehat9d2bd732009-09-22 16:44:22 -0700396}
397
San Mehat56a8b5b2009-11-21 12:29:46 -0800398static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700399msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
400{
401 writel_relaxed(arg, host->base + MMCIARGUMENT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700402 writel_relaxed(c, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530403 /*
404 * As after sending the command, we don't write any of the
405 * controller registers and just wait for the
406 * CMD_RESPOND_END/CMD_SENT/Command failure notication
407 * from Controller.
408 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700409 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800410}
411
412static void
413msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
414{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700415 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800416
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700417 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
418 writel_relaxed((unsigned int)host->curr.xfer_size,
419 host->base + MMCIDATALENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700420 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
421 msmsdcc_delay(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800422
San Mehat6ac9ea62009-12-02 17:24:58 -0800423 if (host->cmd_cmd) {
424 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700425 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800426 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800427}
428
San Mehat9d2bd732009-09-22 16:44:22 -0700429static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530430msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700431{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530432 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700433 unsigned long flags;
434 struct mmc_request *mrq;
435
436 spin_lock_irqsave(&host->lock, flags);
437 mrq = host->curr.mrq;
438 BUG_ON(!mrq);
439
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530440 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700441 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700442 goto out;
443 }
444
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530445 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700446 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700447 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700448 } else {
449 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530450 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700451 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530452 mmc_hostname(host->mmc), host->dma.result);
453 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700454 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530455 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530456 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700457 host->dma.err.flush[0], host->dma.err.flush[1],
458 host->dma.err.flush[2], host->dma.err.flush[3],
459 host->dma.err.flush[4],
460 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530461 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700462 if (!mrq->data->error)
463 mrq->data->error = -EIO;
464 }
San Mehat9d2bd732009-09-22 16:44:22 -0700465 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents,
466 host->dma.dir);
467
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700468 if (host->curr.user_pages) {
469 struct scatterlist *sg = host->dma.sg;
470 int i;
471
472 for (i = 0; i < host->dma.num_ents; i++, sg++)
473 flush_dcache_page(sg_page(sg));
474 }
475
San Mehat9d2bd732009-09-22 16:44:22 -0700476 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800477 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700478
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530479 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
480 (host->curr.wait_for_auto_prog_done &&
481 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700482 /*
483 * If we've already gotten our DATAEND / DATABLKEND
484 * for this request, then complete it through here.
485 */
San Mehat9d2bd732009-09-22 16:44:22 -0700486
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700487 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700488 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700489 host->curr.xfer_remain -= host->curr.xfer_size;
490 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700491 if (host->dummy_52_needed) {
492 mrq->data->bytes_xfered = host->curr.data_xfered;
493 host->dummy_52_sent = 1;
494 msmsdcc_start_command(host, &dummy52cmd,
495 MCI_CPSM_PROGENA);
496 goto out;
497 }
498 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530499 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530500 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700501 host->curr.mrq = NULL;
502 host->curr.cmd = NULL;
503 mrq->data->bytes_xfered = host->curr.data_xfered;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700504 del_timer(&host->req_tout_timer);
San Mehat9d2bd732009-09-22 16:44:22 -0700505 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700506
San Mehat9d2bd732009-09-22 16:44:22 -0700507 mmc_request_done(host->mmc, mrq);
508 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530509 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
510 || !mrq->sbc)) {
511 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530512 }
San Mehat9d2bd732009-09-22 16:44:22 -0700513 }
514
515out:
516 spin_unlock_irqrestore(&host->lock, flags);
517 return;
518}
519
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700520#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
521/**
522 * Callback notification from SPS driver
523 *
524 * This callback function gets triggered called from
525 * SPS driver when requested SPS data transfer is
526 * completed.
527 *
528 * SPS driver invokes this callback in BAM irq context so
529 * SDCC driver schedule a tasklet for further processing
530 * this callback notification at later point of time in
531 * tasklet context and immediately returns control back
532 * to SPS driver.
533 *
534 * @nofity - Pointer to sps event notify sturcture
535 *
536 */
537static void
538msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
539{
540 struct msmsdcc_host *host =
541 (struct msmsdcc_host *)
542 ((struct sps_event_notify *)notify)->user;
543
544 host->sps.notify = *notify;
545 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
546 mmc_hostname(host->mmc), __func__, notify->event_id,
547 notify->data.transfer.iovec.addr,
548 notify->data.transfer.iovec.size,
549 notify->data.transfer.iovec.flags);
550 /* Schedule a tasklet for completing data transfer */
551 tasklet_schedule(&host->sps.tlet);
552}
553
554/**
555 * Tasklet handler for processing SPS callback event
556 *
557 * This function processing SPS event notification and
558 * checks if the SPS transfer is completed or not and
559 * then accordingly notifies status to MMC core layer.
560 *
561 * This function is called in tasklet context.
562 *
563 * @data - Pointer to sdcc driver data
564 *
565 */
566static void msmsdcc_sps_complete_tlet(unsigned long data)
567{
568 unsigned long flags;
569 int i, rc;
570 u32 data_xfered = 0;
571 struct mmc_request *mrq;
572 struct sps_iovec iovec;
573 struct sps_pipe *sps_pipe_handle;
574 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
575 struct sps_event_notify *notify = &host->sps.notify;
576
577 spin_lock_irqsave(&host->lock, flags);
578 if (host->sps.dir == DMA_FROM_DEVICE)
579 sps_pipe_handle = host->sps.prod.pipe_handle;
580 else
581 sps_pipe_handle = host->sps.cons.pipe_handle;
582 mrq = host->curr.mrq;
583
584 if (!mrq) {
585 spin_unlock_irqrestore(&host->lock, flags);
586 return;
587 }
588
589 pr_debug("%s: %s: sps event_id=%d\n",
590 mmc_hostname(host->mmc), __func__,
591 notify->event_id);
592
593 if (msmsdcc_is_dml_busy(host)) {
594 /* oops !!! this should never happen. */
595 pr_err("%s: %s: Received SPS EOT event"
596 " but DML HW is still busy !!!\n",
597 mmc_hostname(host->mmc), __func__);
598 }
599 /*
600 * Got End of transfer event!!! Check if all of the data
601 * has been transferred?
602 */
603 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
604 rc = sps_get_iovec(sps_pipe_handle, &iovec);
605 if (rc) {
606 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
607 mmc_hostname(host->mmc), __func__, rc, i);
608 break;
609 }
610 data_xfered += iovec.size;
611 }
612
613 if (data_xfered == host->curr.xfer_size) {
614 host->curr.data_xfered = host->curr.xfer_size;
615 host->curr.xfer_remain -= host->curr.xfer_size;
616 pr_debug("%s: Data xfer success. data_xfered=0x%x",
617 mmc_hostname(host->mmc),
618 host->curr.xfer_size);
619 } else {
620 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
621 " xfer_size=%d", mmc_hostname(host->mmc),
622 data_xfered, host->curr.xfer_size);
623 msmsdcc_reset_and_restore(host);
624 if (!mrq->data->error)
625 mrq->data->error = -EIO;
626 }
627
628 /* Unmap sg buffers */
629 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
630 host->sps.dir);
631
632 host->sps.sg = NULL;
633 host->sps.busy = 0;
634
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530635 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
636 (host->curr.wait_for_auto_prog_done &&
637 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700638 /*
639 * If we've already gotten our DATAEND / DATABLKEND
640 * for this request, then complete it through here.
641 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700642
643 if (!mrq->data->error) {
644 host->curr.data_xfered = host->curr.xfer_size;
645 host->curr.xfer_remain -= host->curr.xfer_size;
646 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700647 if (host->dummy_52_needed) {
648 mrq->data->bytes_xfered = host->curr.data_xfered;
649 host->dummy_52_sent = 1;
650 msmsdcc_start_command(host, &dummy52cmd,
651 MCI_CPSM_PROGENA);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700652 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700653 return;
654 }
655 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530656 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530657 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700658 host->curr.mrq = NULL;
659 host->curr.cmd = NULL;
660 mrq->data->bytes_xfered = host->curr.data_xfered;
661 del_timer(&host->req_tout_timer);
662 spin_unlock_irqrestore(&host->lock, flags);
663
664 mmc_request_done(host->mmc, mrq);
665 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530666 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
667 || !mrq->sbc)) {
668 msmsdcc_start_command(host, mrq->data->stop, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700669 }
670 }
671 spin_unlock_irqrestore(&host->lock, flags);
672}
673
674/**
675 * Exit from current SPS data transfer
676 *
677 * This function exits from current SPS data transfer.
678 *
679 * This function should be called when error condition
680 * is encountered during data transfer.
681 *
682 * @host - Pointer to sdcc host structure
683 *
684 */
685static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
686{
687 struct mmc_request *mrq;
688
689 mrq = host->curr.mrq;
690 BUG_ON(!mrq);
691
692 msmsdcc_reset_and_restore(host);
693 if (!mrq->data->error)
694 mrq->data->error = -EIO;
695
696 /* Unmap sg buffers */
697 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
698 host->sps.dir);
699
700 host->sps.sg = NULL;
701 host->sps.busy = 0;
702 if (host->curr.data)
703 msmsdcc_stop_data(host);
704
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530705 if (!mrq->data->stop || mrq->cmd->error ||
706 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700707 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530708 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
709 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700710 msmsdcc_start_command(host, mrq->data->stop, 0);
711
712}
713#else
714static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
715static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
716static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
717#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
718
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530719static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700720
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530721static void
722msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
723 unsigned int result,
724 struct msm_dmov_errdata *err)
725{
726 struct msmsdcc_dma_data *dma_data =
727 container_of(cmd, struct msmsdcc_dma_data, hdr);
728 struct msmsdcc_host *host = dma_data->host;
729
730 dma_data->result = result;
731 if (err)
732 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
733
734 tasklet_schedule(&host->dma_tlet);
735}
736
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700737static int msmsdcc_check_dma_op_req(struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700738{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700739 if (((data->blksz * data->blocks) < MCI_FIFOSIZE) ||
740 ((data->blksz * data->blocks) % MCI_FIFOSIZE))
San Mehat9d2bd732009-09-22 16:44:22 -0700741 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700742 else
743 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700744}
745
746static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
747{
748 struct msmsdcc_nc_dmadata *nc;
749 dmov_box *box;
750 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700751 unsigned int n;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530752 int i, err = 0, box_cmd_cnt = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700753 struct scatterlist *sg = data->sg;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530754 unsigned int len, offset;
San Mehat9d2bd732009-09-22 16:44:22 -0700755
Krishna Konda25786ec2011-07-25 16:21:36 -0700756 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700757 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700758
Krishna Konda25786ec2011-07-25 16:21:36 -0700759 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
760
San Mehat9d2bd732009-09-22 16:44:22 -0700761 host->dma.sg = data->sg;
762 host->dma.num_ents = data->sg_len;
763
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530764 /* Prevent memory corruption */
765 BUG_ON(host->dma.num_ents > msmsdcc_get_nr_sg(host));
San Mehat56a8b5b2009-11-21 12:29:46 -0800766
San Mehat9d2bd732009-09-22 16:44:22 -0700767 nc = host->dma.nc;
768
San Mehat9d2bd732009-09-22 16:44:22 -0700769 if (data->flags & MMC_DATA_READ)
770 host->dma.dir = DMA_FROM_DEVICE;
771 else
772 host->dma.dir = DMA_TO_DEVICE;
773
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700774 n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
775 host->dma.num_ents, host->dma.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700776
777 if (n != host->dma.num_ents) {
778 pr_err("%s: Unable to map in all sg elements\n",
779 mmc_hostname(host->mmc));
780 host->dma.sg = NULL;
781 host->dma.num_ents = 0;
782 return -ENOMEM;
San Mehat56a8b5b2009-11-21 12:29:46 -0800783 }
San Mehat9d2bd732009-09-22 16:44:22 -0700784
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530785 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
786 host->curr.user_pages = 0;
787 box = &nc->cmd[0];
788 for (i = 0; i < host->dma.num_ents; i++) {
789 len = sg_dma_len(sg);
790 offset = 0;
791
792 do {
793 /* Check if we can do DMA */
794 if (!len || (box_cmd_cnt >= MMC_MAX_DMA_CMDS)) {
795 err = -ENOTSUPP;
796 goto unmap;
797 }
798
799 box->cmd = CMD_MODE_BOX;
800
801 if (len >= MMC_MAX_DMA_BOX_LENGTH) {
802 len = MMC_MAX_DMA_BOX_LENGTH;
803 len -= len % data->blksz;
804 }
805 rows = (len % MCI_FIFOSIZE) ?
806 (len / MCI_FIFOSIZE) + 1 :
807 (len / MCI_FIFOSIZE);
808
809 if (data->flags & MMC_DATA_READ) {
810 box->src_row_addr = msmsdcc_fifo_addr(host);
811 box->dst_row_addr = sg_dma_address(sg) + offset;
812 box->src_dst_len = (MCI_FIFOSIZE << 16) |
813 (MCI_FIFOSIZE);
814 box->row_offset = MCI_FIFOSIZE;
815 box->num_rows = rows * ((1 << 16) + 1);
816 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
817 } else {
818 box->src_row_addr = sg_dma_address(sg) + offset;
819 box->dst_row_addr = msmsdcc_fifo_addr(host);
820 box->src_dst_len = (MCI_FIFOSIZE << 16) |
821 (MCI_FIFOSIZE);
822 box->row_offset = (MCI_FIFOSIZE << 16);
823 box->num_rows = rows * ((1 << 16) + 1);
824 box->cmd |= CMD_DST_CRCI(host->dma.crci);
825 }
826
827 offset += len;
828 len = sg_dma_len(sg) - offset;
829 box++;
830 box_cmd_cnt++;
831 } while (len);
832 sg++;
833 }
834 /* Mark last command */
835 box--;
836 box->cmd |= CMD_LC;
837
838 /* location of command block must be 64 bit aligned */
839 BUG_ON(host->dma.cmd_busaddr & 0x07);
840
841 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
842 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
843 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
844 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
845
846 /* Flush all data to memory before starting dma */
847 mb();
848
849unmap:
850 if (err) {
851 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
852 host->dma.num_ents, host->dma.dir);
853 pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
854 mmc_hostname(host->mmc), err);
855 }
856
857 return err;
San Mehat9d2bd732009-09-22 16:44:22 -0700858}
859
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700860#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
861/**
862 * Submits data transfer request to SPS driver
863 *
864 * This function make sg (scatter gather) data buffers
865 * DMA ready and then submits them to SPS driver for
866 * transfer.
867 *
868 * @host - Pointer to sdcc host structure
869 * @data - Pointer to mmc_data structure
870 *
871 * @return 0 if success else negative value
872 */
873static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
874 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -0800875{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700876 int rc = 0;
877 u32 flags;
878 int i;
879 u32 addr, len, data_cnt;
880 struct scatterlist *sg = data->sg;
881 struct sps_pipe *sps_pipe_handle;
882
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530883 /* Prevent memory corruption */
884 BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700885
886 host->sps.sg = data->sg;
887 host->sps.num_ents = data->sg_len;
888 host->sps.xfer_req_cnt = 0;
889 if (data->flags & MMC_DATA_READ) {
890 host->sps.dir = DMA_FROM_DEVICE;
891 sps_pipe_handle = host->sps.prod.pipe_handle;
892 } else {
893 host->sps.dir = DMA_TO_DEVICE;
894 sps_pipe_handle = host->sps.cons.pipe_handle;
895 }
896
897 /* Make sg buffers DMA ready */
898 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
899 host->sps.dir);
900
901 if (rc != data->sg_len) {
902 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
903 mmc_hostname(host->mmc), rc);
904 host->sps.sg = NULL;
905 host->sps.num_ents = 0;
906 rc = -ENOMEM;
907 goto dma_map_err;
908 }
909
910 pr_debug("%s: %s: %s: pipe=0x%x, total_xfer=0x%x, sg_len=%d\n",
911 mmc_hostname(host->mmc), __func__,
912 host->sps.dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
913 (u32)sps_pipe_handle, host->curr.xfer_size, data->sg_len);
914
915 for (i = 0; i < data->sg_len; i++) {
916 /*
917 * Check if this is the last buffer to transfer?
918 * If yes then set the INT and EOT flags.
919 */
920 len = sg_dma_len(sg);
921 addr = sg_dma_address(sg);
922 flags = 0;
923 while (len > 0) {
924 if (len > SPS_MAX_DESC_SIZE) {
925 data_cnt = SPS_MAX_DESC_SIZE;
926 } else {
927 data_cnt = len;
928 if (i == data->sg_len - 1)
929 flags = SPS_IOVEC_FLAG_INT |
930 SPS_IOVEC_FLAG_EOT;
931 }
932 rc = sps_transfer_one(sps_pipe_handle, addr,
933 data_cnt, host, flags);
934 if (rc) {
935 pr_err("%s: sps_transfer_one() error! rc=%d,"
936 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
937 mmc_hostname(host->mmc), rc,
938 (u32)sps_pipe_handle, (u32)sg, i);
939 goto dma_map_err;
940 }
941 addr += data_cnt;
942 len -= data_cnt;
943 host->sps.xfer_req_cnt++;
944 }
945 sg++;
946 }
947 goto out;
948
949dma_map_err:
950 /* unmap sg buffers */
951 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
952 host->sps.dir);
953out:
954 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -0700955}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700956#else
957static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
958 struct mmc_data *data) { return 0; }
959#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -0700960
961static void
San Mehat56a8b5b2009-11-21 12:29:46 -0800962msmsdcc_start_command_deferred(struct msmsdcc_host *host,
963 struct mmc_command *cmd, u32 *c)
964{
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530965 DBG(host, "op %02x arg %08x flags %08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700966 cmd->opcode, cmd->arg, cmd->flags);
967
San Mehat56a8b5b2009-11-21 12:29:46 -0800968 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
969
970 if (cmd->flags & MMC_RSP_PRESENT) {
971 if (cmd->flags & MMC_RSP_136)
972 *c |= MCI_CPSM_LONGRSP;
973 *c |= MCI_CPSM_RESPONSE;
974 }
975
976 if (/*interrupt*/0)
977 *c |= MCI_CPSM_INTERRUPT;
978
Subhash Jadavanide0fc772011-11-13 12:27:52 +0530979 if (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
980 cmd->opcode == MMC_READ_MULTIPLE_BLOCK ||
981 cmd->opcode == MMC_WRITE_BLOCK ||
982 cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK ||
983 cmd->opcode == SD_IO_RW_EXTENDED)
San Mehat56a8b5b2009-11-21 12:29:46 -0800984 *c |= MCI_CSPM_DATCMD;
985
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700986 /* Check if AUTO CMD19 is required or not? */
Subhash Jadavani1d6ba602011-09-21 18:10:54 +0530987 if (host->tuning_needed) {
988 /*
989 * For open ended block read operation (without CMD23),
990 * AUTO_CMD19 bit should be set while sending the READ command.
991 * For close ended block read operation (with CMD23),
992 * AUTO_CMD19 bit should be set while sending CMD23.
993 */
Subhash Jadavanide0fc772011-11-13 12:27:52 +0530994 if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
995 host->curr.mrq->cmd->opcode ==
996 MMC_READ_MULTIPLE_BLOCK) ||
Subhash Jadavani1d6ba602011-09-21 18:10:54 +0530997 (!host->curr.mrq->sbc &&
Subhash Jadavanide0fc772011-11-13 12:27:52 +0530998 (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
999 cmd->opcode == MMC_READ_MULTIPLE_BLOCK))) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301000 msmsdcc_enable_cdr_cm_sdc4_dll(host);
1001 *c |= MCI_CSPM_AUTO_CMD19;
1002 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001003 }
1004
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05301005 /* Clear CDR_EN bit for write operations */
1006 if (host->tuning_needed && cmd->mrq->data &&
1007 (cmd->mrq->data->flags & MMC_DATA_WRITE))
1008 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) &
1009 ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
1010
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301011 if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301012 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001013 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301014 }
1015
San Mehat56a8b5b2009-11-21 12:29:46 -08001016 if (cmd == cmd->mrq->stop)
1017 *c |= MCI_CSPM_MCIABORT;
1018
San Mehat56a8b5b2009-11-21 12:29:46 -08001019 if (host->curr.cmd != NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001020 pr_err("%s: Overlapping command requests\n",
1021 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -08001022 }
1023 host->curr.cmd = cmd;
1024}
1025
1026static void
1027msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1028 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001029{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301030 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001031 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001032 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001033 unsigned int pio_irqmask = 0;
1034
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301035 BUG_ON(!data->sg);
1036 BUG_ON(!data->sg_len);
1037
San Mehat9d2bd732009-09-22 16:44:22 -07001038 host->curr.data = data;
1039 host->curr.xfer_size = data->blksz * data->blocks;
1040 host->curr.xfer_remain = host->curr.xfer_size;
1041 host->curr.data_xfered = 0;
1042 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301043 host->curr.got_auto_prog_done = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001044
San Mehat9d2bd732009-09-22 16:44:22 -07001045 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1046
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301047 if (host->curr.wait_for_auto_prog_done)
1048 datactrl |= MCI_AUTO_PROG_DONE;
1049
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001050 if (!msmsdcc_check_dma_op_req(data)) {
1051 if (host->is_dma_mode && !msmsdcc_config_dma(host, data)) {
1052 datactrl |= MCI_DPSM_DMAENABLE;
1053 } else if (host->is_sps_mode) {
1054 if (!msmsdcc_is_dml_busy(host)) {
1055 if (!msmsdcc_sps_start_xfer(host, data)) {
1056 /* Now kick start DML transfer */
1057 mb();
1058 msmsdcc_dml_start_xfer(host, data);
1059 datactrl |= MCI_DPSM_DMAENABLE;
1060 host->sps.busy = 1;
1061 }
1062 } else {
1063 /*
1064 * Can't proceed with new transfer as
1065 * previous trasnfer is already in progress.
1066 * There is no point of going into PIO mode
1067 * as well. Is this a time to do kernel panic?
1068 */
1069 pr_err("%s: %s: DML HW is busy!!!"
1070 " Can't perform new SPS transfers"
1071 " now\n", mmc_hostname(host->mmc),
1072 __func__);
1073 }
1074 }
1075 }
1076
1077 /* Is data transfer in PIO mode required? */
1078 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001079 unsigned int sg_miter_flags = SG_MITER_ATOMIC;
San Mehat9d2bd732009-09-22 16:44:22 -07001080
1081 if (data->flags & MMC_DATA_READ) {
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001082 sg_miter_flags |= SG_MITER_TO_SG;
San Mehat9d2bd732009-09-22 16:44:22 -07001083 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1084 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1085 pio_irqmask |= MCI_RXDATAAVLBLMASK;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001086 } else {
1087 sg_miter_flags |= SG_MITER_FROM_SG;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001088 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1089 MCI_TXFIFOEMPTYMASK;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001090 }
1091
1092 sg_miter_start(&host->sg_miter, data->sg, data->sg_len,
1093 sg_miter_flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001094 }
1095
1096 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301097 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
San Mehat9d2bd732009-09-22 16:44:22 -07001098
San Mehat56a8b5b2009-11-21 12:29:46 -08001099 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001100 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001101 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -07001102
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001103 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
1104 /* Use ADM (Application Data Mover) HW for Data transfer */
1105 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001106 host->cmd_timeout = timeout;
1107 host->cmd_pio_irqmask = pio_irqmask;
1108 host->cmd_datactrl = datactrl;
1109 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001110
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001111 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1112 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001113 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001114
1115 if (cmd) {
1116 msmsdcc_start_command_deferred(host, cmd, &c);
1117 host->cmd_c = c;
1118 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001119 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1120 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1121 host->base + MMCIMASK0);
1122 mb();
1123 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001124 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001125 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001126 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001127
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001128 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001129
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001130 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1131 (~(MCI_IRQ_PIO))) | pio_irqmask,
1132 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001133 writel_relaxed(datactrl, base + MMCIDATACTRL);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301134 /*
1135 * We don't need delay after writing to DATA_CTRL register
1136 * if we are not writing to CMD register immediately after
1137 * this. As we already have delay before sending the
1138 * command, we just need mb() here.
1139 */
1140 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001141
1142 if (cmd) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001143 msmsdcc_delay(host); /* Delay between data/command */
San Mehat56a8b5b2009-11-21 12:29:46 -08001144 /* Daisy-chain the command if requested */
1145 msmsdcc_start_command(host, cmd, c);
1146 }
San Mehat9d2bd732009-09-22 16:44:22 -07001147 }
1148}
1149
1150static void
1151msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1152{
San Mehat56a8b5b2009-11-21 12:29:46 -08001153 msmsdcc_start_command_deferred(host, cmd, &c);
1154 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001155}
1156
1157static void
1158msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1159 unsigned int status)
1160{
1161 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001162 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1163 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1164 pr_err("%s: Data CRC error\n",
1165 mmc_hostname(host->mmc));
1166 pr_err("%s: opcode 0x%.8x\n", __func__,
1167 data->mrq->cmd->opcode);
1168 pr_err("%s: blksz %d, blocks %d\n", __func__,
1169 data->blksz, data->blocks);
1170 data->error = -EILSEQ;
1171 }
San Mehat9d2bd732009-09-22 16:44:22 -07001172 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001173 /* CRC is optional for the bus test commands, not all
1174 * cards respond back with CRC. However controller
1175 * waits for the CRC and times out. Hence ignore the
1176 * data timeouts during the Bustest.
1177 */
1178 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1179 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301180 pr_err("%s: CMD%d: Data timeout\n",
1181 mmc_hostname(host->mmc),
1182 data->mrq->cmd->opcode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001183 data->error = -ETIMEDOUT;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301184 msmsdcc_dump_sdcc_state(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001185 }
San Mehat9d2bd732009-09-22 16:44:22 -07001186 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001187 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001188 data->error = -EIO;
1189 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001190 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001191 data->error = -EIO;
1192 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001193 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001194 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001195 data->error = -EIO;
1196 }
San Mehat9d2bd732009-09-22 16:44:22 -07001197
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001198 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001199 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001200 host->dummy_52_needed = 0;
1201}
San Mehat9d2bd732009-09-22 16:44:22 -07001202
1203static int
1204msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1205{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001206 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001207 uint32_t *ptr = (uint32_t *) buffer;
1208 int count = 0;
1209
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301210 if (remain % 4)
1211 remain = ((remain >> 2) + 1) << 2;
1212
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001213 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1214
1215 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001216 ptr++;
1217 count += sizeof(uint32_t);
1218
1219 remain -= sizeof(uint32_t);
1220 if (remain == 0)
1221 break;
1222 }
1223 return count;
1224}
1225
1226static int
1227msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001228 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001229{
1230 void __iomem *base = host->base;
1231 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001232 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001233
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001234 while (readl_relaxed(base + MMCISTATUS) &
1235 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1236 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001237
San Mehat9d2bd732009-09-22 16:44:22 -07001238 count = min(remain, maxcnt);
1239
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301240 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1241 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001242 ptr += count;
1243 remain -= count;
1244
1245 if (remain == 0)
1246 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001247 }
1248 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001249
1250 return ptr - buffer;
1251}
1252
San Mehat1cd22962010-02-03 12:59:29 -08001253static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001254msmsdcc_pio_irq(int irq, void *dev_id)
1255{
1256 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001257 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001258 uint32_t status;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001259 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001260
Murali Palnati36448a42011-09-02 15:06:18 +05301261 spin_lock(&host->lock);
1262
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001263 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001264
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001265 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301266 (MCI_IRQ_PIO)) == 0) {
1267 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001268 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301269 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001270
1271#if IRQ_DEBUG
1272 msmsdcc_print_status(host, "irq1-r", status);
1273#endif
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001274 local_irq_save(flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001275
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001276 while (sg_miter_next(&host->sg_miter)) {
1277
San Mehat9d2bd732009-09-22 16:44:22 -07001278 unsigned int remain, len;
1279 char *buffer;
1280
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001281 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1282 | MCI_RXDATAAVLBL)))
1283 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001284
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001285 buffer = host->sg_miter.addr;
1286 remain = host->sg_miter.length;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001287
San Mehat9d2bd732009-09-22 16:44:22 -07001288 len = 0;
1289 if (status & MCI_RXACTIVE)
1290 len = msmsdcc_pio_read(host, buffer, remain);
1291 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001292 len = msmsdcc_pio_write(host, buffer, remain);
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301293 /* len might have aligned to 32bits above */
1294 if (len > remain)
1295 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001296
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001297 host->sg_miter.consumed = len;
San Mehat9d2bd732009-09-22 16:44:22 -07001298 host->curr.xfer_remain -= len;
1299 host->curr.data_xfered += len;
1300 remain -= len;
1301
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001302 if (remain) /* Done with this page? */
1303 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001304
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001305 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001306 }
1307
1308 sg_miter_stop(&host->sg_miter);
1309 local_irq_restore(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001310
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001311 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1312 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1313 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1314 host->base + MMCIMASK0);
1315 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301316 /*
1317 * back to back write to MASK0 register don't need
1318 * synchronization delay.
1319 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001320 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1321 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1322 }
1323 mb();
1324 } else if (!host->curr.xfer_remain) {
1325 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1326 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1327 mb();
1328 }
San Mehat9d2bd732009-09-22 16:44:22 -07001329
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001330 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001331
1332 return IRQ_HANDLED;
1333}
1334
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001335static void
1336msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1337
1338static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1339 struct mmc_data *data)
1340{
1341 u32 loop_cnt = 0;
1342
1343 /*
1344 * For read commands with data less than fifo size, it is possible to
1345 * get DATAEND first and RXDATA_AVAIL might be set later because of
1346 * synchronization delay through the asynchronous RX FIFO. Thus, for
1347 * such cases, even after DATAEND interrupt is received software
1348 * should poll for RXDATA_AVAIL until the requested data is read out
1349 * of FIFO. This change is needed to get around this abnormal but
1350 * sometimes expected behavior of SDCC3 controller.
1351 *
1352 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1353 * after the data is loaded into RX FIFO. This would amount to less
1354 * than a microsecond and thus looping for 1000 times is good enough
1355 * for that delay.
1356 */
1357 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1358 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1359 spin_unlock(&host->lock);
1360 msmsdcc_pio_irq(1, host);
1361 spin_lock(&host->lock);
1362 }
1363 }
1364 if (loop_cnt == 1000) {
1365 pr_info("%s: Timed out while polling for Rx Data\n",
1366 mmc_hostname(host->mmc));
1367 data->error = -ETIMEDOUT;
1368 msmsdcc_reset_and_restore(host);
1369 }
1370}
1371
San Mehat9d2bd732009-09-22 16:44:22 -07001372static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1373{
1374 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001375
1376 host->curr.cmd = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001377 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1378 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1379 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1380 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -07001381
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001382 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301383 pr_debug("%s: CMD%d: Command timeout\n",
1384 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001385 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001386 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
1387 !host->cmd19_tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301388 pr_err("%s: CMD%d: Command CRC error\n",
1389 mmc_hostname(host->mmc), cmd->opcode);
1390 msmsdcc_dump_sdcc_state(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001391 cmd->error = -EILSEQ;
1392 }
1393
1394 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001395 if (host->curr.data && host->dma.sg &&
1396 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001397 msm_dmov_stop_cmd(host->dma.channel,
1398 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001399 else if (host->curr.data && host->sps.sg &&
1400 host->is_sps_mode){
1401 /* Stop current SPS transfer */
1402 msmsdcc_sps_exit_curr_xfer(host);
1403 }
San Mehat9d2bd732009-09-22 16:44:22 -07001404 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301405 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001406 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301407 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301408 } else { /* host->data == NULL */
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301409 if (!cmd->error && host->prog_enable) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301410 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001411 host->prog_enable = 0;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301412 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001413 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301414 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301415 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301416 host->prog_enable = 0;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001417 if (host->dummy_52_needed)
1418 host->dummy_52_needed = 0;
1419 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001420 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301421 msmsdcc_request_end(host, cmd->mrq);
1422 }
1423 }
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301424 } else if ((cmd == host->curr.mrq->sbc) && cmd->data) {
1425 if (cmd->data->flags & MMC_DATA_READ)
1426 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1427 else
1428 msmsdcc_request_start(host, host->curr.mrq);
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301429 } else if (cmd->data) {
1430 if (!(cmd->data->flags & MMC_DATA_READ))
1431 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001432 }
1433}
1434
San Mehat9d2bd732009-09-22 16:44:22 -07001435static irqreturn_t
1436msmsdcc_irq(int irq, void *dev_id)
1437{
1438 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001439 u32 status;
1440 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001441 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001442
1443 spin_lock(&host->lock);
1444
1445 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001446 struct mmc_command *cmd;
1447 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001448
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001449 if (timer) {
1450 timer = 0;
1451 msmsdcc_delay(host);
1452 }
San Mehat865c8062009-11-13 13:42:06 -08001453
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001454 if (!host->clks_on) {
1455 pr_debug("%s: %s: SDIO async irq received\n",
1456 mmc_hostname(host->mmc), __func__);
1457 host->mmc->ios.clock = host->clk_rate;
1458 spin_unlock(&host->lock);
1459 host->mmc->ops->set_ios(host->mmc, &host->mmc->ios);
1460 spin_lock(&host->lock);
1461 if (host->plat->cfg_mpm_sdiowakeup &&
1462 (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
1463 wake_lock(&host->sdio_wlock);
1464 /* only ansyc interrupt can come when clocks are off */
1465 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301466 if (host->clk_rate <=
1467 msmsdcc_get_min_sup_clk_rate(host))
1468 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001469 }
1470
1471 status = readl_relaxed(host->base + MMCISTATUS);
1472
1473 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1474 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001475 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001476
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001477#if IRQ_DEBUG
1478 msmsdcc_print_status(host, "irq0-r", status);
1479#endif
1480 status &= readl_relaxed(host->base + MMCIMASK0);
1481 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301482 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301483 if (host->clk_rate <=
1484 msmsdcc_get_min_sup_clk_rate(host))
1485 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001486#if IRQ_DEBUG
1487 msmsdcc_print_status(host, "irq0-p", status);
1488#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001489
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001490#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
1491 if (status & MCI_SDIOINTROPE) {
1492 if (host->sdcc_suspending)
1493 wake_lock(&host->sdio_suspend_wlock);
1494 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001495 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001496#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001497 data = host->curr.data;
1498
1499 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001500 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1501 MCI_CMDTIMEOUT)) {
1502 if (status & MCI_CMDTIMEOUT)
1503 pr_debug("%s: dummy CMD52 timeout\n",
1504 mmc_hostname(host->mmc));
1505 if (status & MCI_CMDCRCFAIL)
1506 pr_debug("%s: dummy CMD52 CRC failed\n",
1507 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001508 host->dummy_52_sent = 0;
1509 host->dummy_52_needed = 0;
1510 if (data) {
1511 msmsdcc_stop_data(host);
1512 msmsdcc_request_end(host, data->mrq);
1513 }
1514 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001515 spin_unlock(&host->lock);
1516 return IRQ_HANDLED;
1517 }
1518 break;
1519 }
1520
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001521 /*
1522 * Check for proper command response
1523 */
1524 cmd = host->curr.cmd;
1525 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1526 MCI_CMDTIMEOUT | MCI_PROGDONE |
1527 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1528 msmsdcc_do_cmdirq(host, status);
1529 }
1530
Sathish Ambley081d7842011-11-29 11:19:41 -08001531 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001532 /* Check for data errors */
1533 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1534 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1535 msmsdcc_data_err(host, data, status);
1536 host->curr.data_xfered = 0;
1537 if (host->dma.sg && host->is_dma_mode)
1538 msm_dmov_stop_cmd(host->dma.channel,
1539 &host->dma.hdr, 0);
1540 else if (host->sps.sg && host->is_sps_mode) {
1541 /* Stop current SPS transfer */
1542 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301543 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001544 msmsdcc_reset_and_restore(host);
1545 if (host->curr.data)
1546 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301547 if (!data->stop || (host->curr.mrq->sbc
1548 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001549 timer |=
1550 msmsdcc_request_end(host,
1551 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301552 else if ((host->curr.mrq->sbc
1553 && data->error) ||
1554 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001555 msmsdcc_start_command(host,
1556 data->stop,
1557 0);
1558 timer = 1;
1559 }
1560 }
1561 }
1562
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301563 /* Check for prog done */
1564 if (host->curr.wait_for_auto_prog_done &&
1565 (status & MCI_PROGDONE))
1566 host->curr.got_auto_prog_done = 1;
1567
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001568 /* Check for data done */
1569 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1570 host->curr.got_dataend = 1;
1571
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301572 if (host->curr.got_dataend &&
1573 (!host->curr.wait_for_auto_prog_done ||
1574 (host->curr.wait_for_auto_prog_done &&
1575 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001576 /*
1577 * If DMA is still in progress, we complete
1578 * via the completion handler
1579 */
1580 if (!host->dma.busy && !host->sps.busy) {
1581 /*
1582 * There appears to be an issue in the
1583 * controller where if you request a
1584 * small block transfer (< fifo size),
1585 * you may get your DATAEND/DATABLKEND
1586 * irq without the PIO data irq.
1587 *
1588 * Check to see if theres still data
1589 * to be read, and simulate a PIO irq.
1590 */
1591 if (data->flags & MMC_DATA_READ)
1592 msmsdcc_wait_for_rxdata(host,
1593 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001594 if (!data->error) {
1595 host->curr.data_xfered =
1596 host->curr.xfer_size;
1597 host->curr.xfer_remain -=
1598 host->curr.xfer_size;
1599 }
1600
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001601 if (!host->dummy_52_needed) {
1602 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301603 if (!data->stop ||
1604 (host->curr.mrq->sbc
1605 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001606 msmsdcc_request_end(
1607 host,
1608 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301609 else if ((host->curr.mrq->sbc
1610 && data->error) ||
1611 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001612 msmsdcc_start_command(
1613 host,
1614 data->stop, 0);
1615 timer = 1;
1616 }
1617 } else {
1618 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001619 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001620 &dummy52cmd,
1621 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001622 }
1623 }
1624 }
1625 }
1626
San Mehat9d2bd732009-09-22 16:44:22 -07001627 ret = 1;
1628 } while (status);
1629
1630 spin_unlock(&host->lock);
1631
San Mehat9d2bd732009-09-22 16:44:22 -07001632 return IRQ_RETVAL(ret);
1633}
1634
1635static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001636msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1637{
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301638 if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001639 /* Queue/read data, daisy-chain command when data starts */
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301640 if (mrq->sbc)
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301641 msmsdcc_start_data(host, mrq->data, mrq->sbc, 0);
1642 else
1643 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001644 } else {
1645 msmsdcc_start_command(host, mrq->cmd, 0);
1646 }
1647}
1648
1649static void
San Mehat9d2bd732009-09-22 16:44:22 -07001650msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1651{
1652 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001653 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001654
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001655 /*
1656 * Get the SDIO AL client out of LPM.
1657 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001658 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001659 if (host->plat->is_sdio_al_client)
1660 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001661
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301662 /* check if sps pipe reset is pending? */
1663 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1664 msmsdcc_sps_pipes_reset_and_restore(host);
1665 host->sps.pipe_reset_pending = false;
1666 }
1667
San Mehat9d2bd732009-09-22 16:44:22 -07001668 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001669 WARN(host->curr.mrq, "Request in progress\n");
1670 WARN(!host->pwr, "SDCC power is turned off\n");
1671 WARN(!host->clks_on, "SDCC clocks are turned off\n");
1672 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
San Mehat9d2bd732009-09-22 16:44:22 -07001673
1674 if (host->eject) {
1675 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1676 mrq->cmd->error = 0;
1677 mrq->data->bytes_xfered = mrq->data->blksz *
1678 mrq->data->blocks;
1679 } else
1680 mrq->cmd->error = -ENOMEDIUM;
1681
1682 spin_unlock_irqrestore(&host->lock, flags);
1683 mmc_request_done(mmc, mrq);
1684 return;
1685 }
1686
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301687 /*
1688 * Kick the software command timeout timer here.
1689 * Timer expires in 10 secs.
1690 */
1691 mod_timer(&host->req_tout_timer,
1692 (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
San Mehat9d2bd732009-09-22 16:44:22 -07001693
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301694 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301695 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301696 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
1697 mrq->cmd->opcode == 54) {
Pratibhasagar V1c11da62011-11-14 12:36:35 +05301698 if (!host->sdcc_version)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001699 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301700 else
1701 /*
1702 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
1703 * write operations using CMD53 and CMD54.
1704 * Setting this bit with CMD53 would
1705 * automatically triggers PROG_DONE interrupt
1706 * without the need of sending dummy CMD52.
1707 */
1708 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani758cf8c2011-11-13 11:59:55 +05301709 } else if (mrq->cmd->opcode == MMC_WRITE_BLOCK &&
1710 host->sdcc_version) {
1711 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001712 }
San Mehat9d2bd732009-09-22 16:44:22 -07001713 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301714
Pratibhasagar V00b94332011-10-18 14:57:27 +05301715 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301716 mrq->sbc->mrq = mrq;
1717 mrq->sbc->data = mrq->data;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301718 if (mrq->data->flags & MMC_DATA_WRITE) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301719 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301720 msmsdcc_start_command(host, mrq->sbc, 0);
1721 } else {
1722 msmsdcc_request_start(host, mrq);
1723 }
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301724 } else {
1725 msmsdcc_request_start(host, mrq);
1726 }
1727
San Mehat9d2bd732009-09-22 16:44:22 -07001728 spin_unlock_irqrestore(&host->lock, flags);
1729}
1730
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001731static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1732 int min_uV, int max_uV)
1733{
1734 int rc = 0;
1735
1736 if (vreg->set_voltage_sup) {
1737 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1738 if (rc) {
1739 pr_err("%s: regulator_set_voltage(%s) failed."
1740 " min_uV=%d, max_uV=%d, rc=%d\n",
1741 __func__, vreg->name, min_uV, max_uV, rc);
1742 }
1743 }
1744
1745 return rc;
1746}
1747
1748static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1749 int uA_load)
1750{
1751 int rc = 0;
1752
Krishna Kondafea60182011-11-01 16:01:34 -07001753 /* regulators that do not support regulator_set_voltage also
1754 do not support regulator_set_optimum_mode */
1755 if (vreg->set_voltage_sup) {
1756 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1757 if (rc < 0)
1758 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
1759 "uA_load=%d) failed. rc=%d\n", __func__,
1760 vreg->name, uA_load, rc);
1761 else
1762 /* regulator_set_optimum_mode() can return non zero
1763 * value even for success case.
1764 */
1765 rc = 0;
1766 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001767
1768 return rc;
1769}
1770
1771static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1772 struct device *dev)
1773{
1774 int rc = 0;
1775
1776 /* check if regulator is already initialized? */
1777 if (vreg->reg)
1778 goto out;
1779
1780 /* Get the regulator handle */
1781 vreg->reg = regulator_get(dev, vreg->name);
1782 if (IS_ERR(vreg->reg)) {
1783 rc = PTR_ERR(vreg->reg);
1784 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
1785 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001786 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001787 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001788
1789 if (regulator_count_voltages(vreg->reg) > 0)
1790 vreg->set_voltage_sup = 1;
1791
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001792out:
1793 return rc;
1794}
1795
1796static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
1797{
1798 if (vreg->reg)
1799 regulator_put(vreg->reg);
1800}
1801
1802/* This init function should be called only once for each SDCC slot */
1803static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
1804{
1805 int rc = 0;
1806 struct msm_mmc_slot_reg_data *curr_slot;
1807 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1808 struct device *dev = mmc_dev(host->mmc);
1809
1810 curr_slot = host->plat->vreg_data;
1811 if (!curr_slot)
1812 goto out;
1813
1814 curr_vdd_reg = curr_slot->vdd_data;
1815 curr_vccq_reg = curr_slot->vccq_data;
1816 curr_vddp_reg = curr_slot->vddp_data;
1817
1818 if (is_init) {
1819 /*
1820 * Get the regulator handle from voltage regulator framework
1821 * and then try to set the voltage level for the regulator
1822 */
1823 if (curr_vdd_reg) {
1824 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
1825 if (rc)
1826 goto out;
1827 }
1828 if (curr_vccq_reg) {
1829 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
1830 if (rc)
1831 goto vdd_reg_deinit;
1832 }
1833 if (curr_vddp_reg) {
1834 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
1835 if (rc)
1836 goto vccq_reg_deinit;
1837 }
1838 goto out;
1839 } else {
1840 /* Deregister all regulators from regulator framework */
1841 goto vddp_reg_deinit;
1842 }
1843vddp_reg_deinit:
1844 if (curr_vddp_reg)
1845 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
1846vccq_reg_deinit:
1847 if (curr_vccq_reg)
1848 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
1849vdd_reg_deinit:
1850 if (curr_vdd_reg)
1851 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
1852out:
1853 return rc;
1854}
1855
1856static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
1857{
1858 int rc = 0;
1859
Subhash Jadavanicc922692011-08-01 23:05:01 +05301860 /* Put regulator in HPM (high power mode) */
1861 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
1862 if (rc < 0)
1863 goto out;
1864
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001865 if (!vreg->is_enabled) {
1866 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301867 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
1868 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001869 if (rc)
1870 goto out;
1871
1872 rc = regulator_enable(vreg->reg);
1873 if (rc) {
1874 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
1875 __func__, vreg->name, rc);
1876 goto out;
1877 }
1878 vreg->is_enabled = true;
1879 }
1880
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001881out:
1882 return rc;
1883}
1884
1885static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
1886{
1887 int rc = 0;
1888
1889 /* Never disable regulator marked as always_on */
1890 if (vreg->is_enabled && !vreg->always_on) {
1891 rc = regulator_disable(vreg->reg);
1892 if (rc) {
1893 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
1894 __func__, vreg->name, rc);
1895 goto out;
1896 }
1897 vreg->is_enabled = false;
1898
1899 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
1900 if (rc < 0)
1901 goto out;
1902
1903 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301904 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001905 if (rc)
1906 goto out;
1907 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
1908 /* Put always_on regulator in LPM (low power mode) */
1909 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
1910 if (rc < 0)
1911 goto out;
1912 }
1913out:
1914 return rc;
1915}
1916
1917static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
1918{
1919 int rc = 0, i;
1920 struct msm_mmc_slot_reg_data *curr_slot;
1921 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1922 struct msm_mmc_reg_data *vreg_table[3];
1923
1924 curr_slot = host->plat->vreg_data;
1925 if (!curr_slot)
1926 goto out;
1927
1928 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
1929 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
1930 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
1931
1932 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
1933 if (vreg_table[i]) {
1934 if (enable)
1935 rc = msmsdcc_vreg_enable(vreg_table[i]);
1936 else
1937 rc = msmsdcc_vreg_disable(vreg_table[i]);
1938 if (rc)
1939 goto out;
1940 }
1941 }
1942out:
1943 return rc;
1944}
1945
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301946static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001947{
1948 int rc = 0;
1949
1950 if (host->plat->vreg_data) {
1951 struct msm_mmc_reg_data *vddp_reg =
1952 host->plat->vreg_data->vddp_data;
1953
1954 if (vddp_reg && vddp_reg->is_enabled)
1955 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
1956 }
1957
1958 return rc;
1959}
1960
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301961static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
1962{
1963 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1964 int rc = 0;
1965
1966 if (curr_slot && curr_slot->vddp_data) {
1967 rc = msmsdcc_set_vddp_level(host,
1968 curr_slot->vddp_data->low_vol_level);
1969
1970 if (rc)
1971 pr_err("%s: %s: failed to change vddp level to %d",
1972 mmc_hostname(host->mmc), __func__,
1973 curr_slot->vddp_data->low_vol_level);
1974 }
1975
1976 return rc;
1977}
1978
1979static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
1980{
1981 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1982 int rc = 0;
1983
1984 if (curr_slot && curr_slot->vddp_data) {
1985 rc = msmsdcc_set_vddp_level(host,
1986 curr_slot->vddp_data->high_vol_level);
1987
1988 if (rc)
1989 pr_err("%s: %s: failed to change vddp level to %d",
1990 mmc_hostname(host->mmc), __func__,
1991 curr_slot->vddp_data->high_vol_level);
1992 }
1993
1994 return rc;
1995}
1996
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001997static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
1998{
1999 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2000 return 1;
2001 return 0;
2002}
2003
2004static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
2005{
2006 if (enable) {
2007 if (!IS_ERR_OR_NULL(host->dfab_pclk))
2008 clk_enable(host->dfab_pclk);
2009 if (!IS_ERR(host->pclk))
2010 clk_enable(host->pclk);
2011 clk_enable(host->clk);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302012 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002013 } else {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302014 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002015 clk_disable(host->clk);
2016 if (!IS_ERR(host->pclk))
2017 clk_disable(host->pclk);
2018 if (!IS_ERR_OR_NULL(host->dfab_pclk))
2019 clk_disable(host->dfab_pclk);
2020 }
2021}
2022
2023static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2024 unsigned int req_clk)
2025{
2026 unsigned int sel_clk = -1;
2027
2028 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2029 unsigned char cnt;
2030
2031 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2032 if (host->plat->sup_clk_table[cnt] > req_clk)
2033 break;
2034 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2035 sel_clk = host->plat->sup_clk_table[cnt];
2036 break;
2037 } else
2038 sel_clk = host->plat->sup_clk_table[cnt];
2039 }
2040 } else {
2041 if ((req_clk < host->plat->msmsdcc_fmax) &&
2042 (req_clk > host->plat->msmsdcc_fmid))
2043 sel_clk = host->plat->msmsdcc_fmid;
2044 else
2045 sel_clk = req_clk;
2046 }
2047
2048 return sel_clk;
2049}
2050
2051static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2052 struct msmsdcc_host *host)
2053{
2054 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2055 return host->plat->sup_clk_table[0];
2056 else
2057 return host->plat->msmsdcc_fmin;
2058}
2059
2060static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2061 struct msmsdcc_host *host)
2062{
2063 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2064 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2065 else
2066 return host->plat->msmsdcc_fmax;
2067}
2068
2069static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302070{
2071 struct msm_mmc_gpio_data *curr;
2072 int i, rc = 0;
2073
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002074 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302075 for (i = 0; i < curr->size; i++) {
2076 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002077 if (curr->gpio[i].is_always_on &&
2078 curr->gpio[i].is_enabled)
2079 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302080 rc = gpio_request(curr->gpio[i].no,
2081 curr->gpio[i].name);
2082 if (rc) {
2083 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2084 mmc_hostname(host->mmc),
2085 curr->gpio[i].no,
2086 curr->gpio[i].name, rc);
2087 goto free_gpios;
2088 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002089 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302090 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002091 if (curr->gpio[i].is_always_on)
2092 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302093 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002094 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302095 }
2096 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002097 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302098
2099free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002100 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302101 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002102 curr->gpio[i].is_enabled = false;
2103 }
2104out:
2105 return rc;
2106}
2107
2108static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2109{
2110 struct msm_mmc_pad_data *curr;
2111 int i;
2112
2113 curr = host->plat->pin_data->pad_data;
2114 for (i = 0; i < curr->drv->size; i++) {
2115 if (enable)
2116 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2117 curr->drv->on[i].val);
2118 else
2119 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2120 curr->drv->off[i].val);
2121 }
2122
2123 for (i = 0; i < curr->pull->size; i++) {
2124 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002125 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002126 curr->pull->on[i].val);
2127 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002128 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002129 curr->pull->off[i].val);
2130 }
2131
2132 return 0;
2133}
2134
2135static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2136{
2137 int rc = 0;
2138
2139 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2140 return 0;
2141
2142 if (host->plat->pin_data->is_gpio)
2143 rc = msmsdcc_setup_gpio(host, enable);
2144 else
2145 rc = msmsdcc_setup_pad(host, enable);
2146
2147 if (!rc)
2148 host->plat->pin_data->cfg_sts = enable;
2149
2150 return rc;
2151}
2152
2153static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2154{
2155 unsigned int wakeup_irq;
2156
2157 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2158 host->plat->sdiowakeup_irq :
2159 host->core_irqres->start;
2160
2161 if (!host->irq_wake_enabled) {
2162 enable_irq_wake(wakeup_irq);
2163 host->irq_wake_enabled = true;
2164 }
2165}
2166
2167static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2168{
2169 unsigned int wakeup_irq;
2170
2171 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2172 host->plat->sdiowakeup_irq :
2173 host->core_irqres->start;
2174
2175 if (host->irq_wake_enabled) {
2176 disable_irq_wake(wakeup_irq);
2177 host->irq_wake_enabled = false;
2178 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302179}
2180
San Mehat9d2bd732009-09-22 16:44:22 -07002181static void
2182msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2183{
2184 struct msmsdcc_host *host = mmc_priv(mmc);
2185 u32 clk = 0, pwr = 0;
2186 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002187 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002188 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002189
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002190 DBG(host, "ios->clock = %u\n", ios->clock);
Sahitya Tummala7a892482011-01-18 11:22:49 +05302191
San Mehat9d2bd732009-09-22 16:44:22 -07002192 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002193 spin_lock_irqsave(&host->lock, flags);
2194 if (!host->clks_on) {
2195 msmsdcc_setup_clocks(host, true);
2196 host->clks_on = 1;
2197 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2198 if (!host->plat->sdiowakeup_irq) {
2199 writel_relaxed(host->mci_irqenable,
2200 host->base + MMCIMASK0);
2201 mb();
2202 if (host->plat->cfg_mpm_sdiowakeup &&
2203 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2204 host->plat->cfg_mpm_sdiowakeup(
2205 mmc_dev(mmc), SDC_DAT1_DISWAKE);
2206 msmsdcc_disable_irq_wake(host);
2207 } else if (!(mmc->pm_flags &
2208 MMC_PM_WAKE_SDIO_IRQ)) {
2209 writel_relaxed(host->mci_irqenable,
2210 host->base + MMCIMASK0);
2211 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05302212 } else {
2213 writel_relaxed(host->mci_irqenable,
2214 host->base + MMCIMASK0);
2215 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002216 }
San Mehat9d2bd732009-09-22 16:44:22 -07002217 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002218 spin_unlock_irqrestore(&host->lock, flags);
2219
2220 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2221 /*
2222 * For DDR50 mode, controller needs clock rate to be
2223 * double than what is required on the SD card CLK pin.
2224 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302225 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002226 /*
2227 * Make sure that we don't double the clock if
2228 * doubled clock rate is already set
2229 */
2230 if (!host->ddr_doubled_clk_rate ||
2231 (host->ddr_doubled_clk_rate &&
2232 (host->ddr_doubled_clk_rate != ios->clock))) {
2233 host->ddr_doubled_clk_rate =
2234 msmsdcc_get_sup_clk_rate(
2235 host, (ios->clock * 2));
2236 clock = host->ddr_doubled_clk_rate;
2237 }
2238 } else {
2239 host->ddr_doubled_clk_rate = 0;
2240 }
2241
2242 if (clock != host->clk_rate) {
2243 rc = clk_set_rate(host->clk, clock);
2244 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302245 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002246 mmc_hostname(mmc), clock);
2247 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302248 host->reg_write_delay =
2249 (1 + ((3 * USEC_PER_SEC) /
2250 (host->clk_rate ? host->clk_rate :
2251 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002252 }
2253 /*
2254 * give atleast 2 MCLK cycles delay for clocks
2255 * and SDCC core to stabilize
2256 */
2257 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002258 clk |= MCI_CLK_ENABLE;
2259 }
2260
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002261 if (ios->bus_width == MMC_BUS_WIDTH_8)
2262 clk |= MCI_CLK_WIDEBUS_8;
2263 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2264 clk |= MCI_CLK_WIDEBUS_4;
2265 else
2266 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002267
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002268 if (msmsdcc_is_pwrsave(host))
2269 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002270
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002271 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002272
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002273 host->tuning_needed = 0;
2274 /*
2275 * Select the controller timing mode according
2276 * to current bus speed mode
2277 */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302278 if (ios->timing == MMC_TIMING_UHS_SDR104) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002279 clk |= (4 << 14);
2280 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302281 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002282 clk |= (3 << 14);
2283 } else {
2284 clk |= (2 << 14); /* feedback clock */
2285 }
2286
2287 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2288 clk |= (2 << 23);
2289
Subhash Jadavani00083572012-02-15 16:18:01 +05302290 /* Clear IO_PAD_PWR_SWITCH while powering off the card */
2291 if (!ios->vdd)
2292 host->io_pad_pwr_switch = 0;
2293
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002294 if (host->io_pad_pwr_switch)
2295 clk |= IO_PAD_PWR_SWITCH;
2296
2297 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
San Mehat9d2bd732009-09-22 16:44:22 -07002298 pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002299 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2300 pwr |= msmsdcc_setup_vreg(host, !!ios->vdd);
San Mehat9d2bd732009-09-22 16:44:22 -07002301
2302 switch (ios->power_mode) {
2303 case MMC_POWER_OFF:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002304 htc_pwrsink_set(PWRSINK_SDCARD, 0);
2305 if (!host->sdcc_irq_disabled) {
2306 if (host->plat->cfg_mpm_sdiowakeup)
2307 host->plat->cfg_mpm_sdiowakeup(
2308 mmc_dev(mmc), SDC_DAT1_DISABLE);
2309 disable_irq(host->core_irqres->start);
2310 host->sdcc_irq_disabled = 1;
2311 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302312 /*
2313 * As VDD pad rail is always on, set low voltage for VDD
2314 * pad rail when slot is unused (when card is not present
2315 * or during system suspend).
2316 */
2317 msmsdcc_set_vddp_low_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002318 msmsdcc_setup_pins(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002319 break;
2320 case MMC_POWER_UP:
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302321 /* writing PWR_UP bit is redundant */
San Mehat9d2bd732009-09-22 16:44:22 -07002322 pwr |= MCI_PWR_UP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002323 if (host->sdcc_irq_disabled) {
2324 if (host->plat->cfg_mpm_sdiowakeup)
2325 host->plat->cfg_mpm_sdiowakeup(
2326 mmc_dev(mmc), SDC_DAT1_ENABLE);
2327 enable_irq(host->core_irqres->start);
2328 host->sdcc_irq_disabled = 0;
2329 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302330 msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002331 msmsdcc_setup_pins(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07002332 break;
2333 case MMC_POWER_ON:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002334 htc_pwrsink_set(PWRSINK_SDCARD, 100);
San Mehat9d2bd732009-09-22 16:44:22 -07002335 pwr |= MCI_PWR_ON;
2336 break;
2337 }
2338
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002339 spin_lock_irqsave(&host->lock, flags);
2340 if (!host->clks_on) {
2341 /* force the clocks to be on */
2342 msmsdcc_setup_clocks(host, true);
2343 /*
2344 * give atleast 2 MCLK cycles delay for clocks
2345 * and SDCC core to stabilize
2346 */
2347 msmsdcc_delay(host);
2348 }
2349 writel_relaxed(clk, host->base + MMCICLOCK);
2350 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002351
2352 if (host->pwr != pwr) {
2353 host->pwr = pwr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002354 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302355 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002356 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002357 if (!host->clks_on) {
2358 /* force the clocks to be off */
2359 msmsdcc_setup_clocks(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002360 }
2361
2362 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
2363 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2364 if (!host->plat->sdiowakeup_irq) {
2365 writel_relaxed(MCI_SDIOINTMASK,
2366 host->base + MMCIMASK0);
2367 mb();
2368 if (host->plat->cfg_mpm_sdiowakeup &&
2369 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2370 host->plat->cfg_mpm_sdiowakeup(
2371 mmc_dev(mmc), SDC_DAT1_ENWAKE);
2372 msmsdcc_enable_irq_wake(host);
2373 } else if (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2374 writel_relaxed(0, host->base + MMCIMASK0);
2375 } else {
2376 writel_relaxed(MCI_SDIOINTMASK,
2377 host->base + MMCIMASK0);
2378 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302379 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002380 }
2381 msmsdcc_setup_clocks(host, false);
2382 host->clks_on = 0;
2383 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302384
2385 if (host->cmd19_tuning_in_progress)
2386 WARN(!host->clks_on,
2387 "cmd19_tuning_in_progress but SDCC clocks are OFF\n");
2388
San Mehat4adbbcc2009-11-08 13:00:37 -08002389 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002390}
2391
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002392int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2393{
2394 struct msmsdcc_host *host = mmc_priv(mmc);
2395 u32 clk;
2396
2397 clk = readl_relaxed(host->base + MMCICLOCK);
2398 pr_debug("Changing to pwr_save=%d", pwrsave);
2399 if (pwrsave && msmsdcc_is_pwrsave(host))
2400 clk |= MCI_CLK_PWRSAVE;
2401 else
2402 clk &= ~MCI_CLK_PWRSAVE;
2403 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302404 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002405
2406 return 0;
2407}
2408
2409static int msmsdcc_get_ro(struct mmc_host *mmc)
2410{
2411 int status = -ENOSYS;
2412 struct msmsdcc_host *host = mmc_priv(mmc);
2413
2414 if (host->plat->wpswitch) {
2415 status = host->plat->wpswitch(mmc_dev(mmc));
2416 } else if (host->plat->wpswitch_gpio) {
2417 status = gpio_request(host->plat->wpswitch_gpio,
2418 "SD_WP_Switch");
2419 if (status) {
2420 pr_err("%s: %s: Failed to request GPIO %d\n",
2421 mmc_hostname(mmc), __func__,
2422 host->plat->wpswitch_gpio);
2423 } else {
2424 status = gpio_direction_input(
2425 host->plat->wpswitch_gpio);
2426 if (!status) {
2427 /*
2428 * Wait for atleast 300ms as debounce
2429 * time for GPIO input to stabilize.
2430 */
2431 msleep(300);
2432 status = gpio_get_value_cansleep(
2433 host->plat->wpswitch_gpio);
2434 status ^= !host->plat->wpswitch_polarity;
2435 }
2436 gpio_free(host->plat->wpswitch_gpio);
2437 }
2438 }
2439
2440 if (status < 0)
2441 status = -ENOSYS;
2442 pr_debug("%s: Card read-only status %d\n", __func__, status);
2443
2444 return status;
2445}
2446
2447#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002448static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2449{
2450 struct msmsdcc_host *host = mmc_priv(mmc);
2451 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002452
2453 if (enable) {
2454 spin_lock_irqsave(&host->lock, flags);
2455 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
2456 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
2457 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2458 spin_unlock_irqrestore(&host->lock, flags);
2459 } else {
2460 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
2461 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
2462 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2463 }
2464 mb();
2465}
2466#endif /* CONFIG_MMC_MSM_SDIO_SUPPORT */
2467
2468#ifdef CONFIG_PM_RUNTIME
2469static int msmsdcc_enable(struct mmc_host *mmc)
2470{
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302471 int rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002472 struct device *dev = mmc->parent;
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302473 struct msmsdcc_host *host = mmc_priv(mmc);
2474
2475 msmsdcc_pm_qos_update_latency(host, 1);
2476
2477 if (mmc->card && mmc_card_sdio(mmc->card) && host->is_resumed)
2478 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002479
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302480 if (dev->power.runtime_status == RPM_SUSPENDING) {
2481 if (mmc->suspend_task == current) {
2482 pm_runtime_get_noresume(dev);
2483 goto out;
2484 }
2485 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002486
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302487 rc = pm_runtime_get_sync(dev);
2488
2489 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002490 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2491 __func__, rc);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302492 return rc;
2493 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302494
2495 host->is_resumed = true;
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302496out:
2497 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002498}
2499
2500static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2501{
2502 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302503 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002504
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302505 msmsdcc_pm_qos_update_latency(host, 0);
2506
2507 if (mmc->card && mmc_card_sdio(mmc->card))
2508 return 0;
2509
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302510 if (host->plat->disable_runtime_pm)
2511 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002512
2513 rc = pm_runtime_put_sync(mmc->parent);
2514
2515 if (rc < 0)
2516 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2517 __func__, rc);
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302518 else
2519 host->is_resumed = false;
2520
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002521 return rc;
2522}
2523#else
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302524static int msmsdcc_enable(struct mmc_host *mmc)
2525{
2526 struct msmsdcc_host *host = mmc_priv(mmc);
2527 unsigned long flags;
2528
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302529 msmsdcc_pm_qos_update_latency(host, 1);
2530
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302531 spin_lock_irqsave(&host->lock, flags);
2532 if (!host->clks_on) {
2533 msmsdcc_setup_clocks(host, true);
2534 host->clks_on = 1;
2535 }
2536 spin_unlock_irqrestore(&host->lock, flags);
2537
2538 return 0;
2539}
2540
2541static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2542{
2543 struct msmsdcc_host *host = mmc_priv(mmc);
2544 unsigned long flags;
2545
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302546 msmsdcc_pm_qos_update_latency(host, 0);
2547
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302548 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302549 return 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302550
2551 spin_lock_irqsave(&host->lock, flags);
2552 if (host->clks_on) {
2553 msmsdcc_setup_clocks(host, false);
2554 host->clks_on = 0;
2555 }
2556 spin_unlock_irqrestore(&host->lock, flags);
2557
2558 return 0;
2559}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002560#endif
2561
2562static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2563 struct mmc_ios *ios)
2564{
2565 struct msmsdcc_host *host = mmc_priv(mmc);
2566 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302567 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002568
Subhash Jadavani00083572012-02-15 16:18:01 +05302569 spin_lock_irqsave(&host->lock, flags);
2570 host->io_pad_pwr_switch = 0;
2571 spin_unlock_irqrestore(&host->lock, flags);
2572
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002573 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2574 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302575 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002576 goto out;
2577 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2578 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302579 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002580 goto out;
2581 }
San Mehat9d2bd732009-09-22 16:44:22 -07002582
2583 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002584 /*
2585 * If we are here means voltage switch from high voltage to
2586 * low voltage is required
2587 */
2588
2589 /*
2590 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2591 * register until they become all zeros.
2592 */
2593 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302594 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002595 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2596 mmc_hostname(mmc), __func__);
2597 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002598 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002599
2600 /* Stop SD CLK output. */
2601 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2602 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302603 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002604 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002605
2606 /*
2607 * Switch VDDPX from high voltage to low voltage
2608 * to change the VDD of the SD IO pads.
2609 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302610 rc = msmsdcc_set_vddp_low_vol(host);
2611 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002612 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002613
2614 spin_lock_irqsave(&host->lock, flags);
2615 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2616 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302617 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002618 host->io_pad_pwr_switch = 1;
2619 spin_unlock_irqrestore(&host->lock, flags);
2620
2621 /* Wait 5 ms for the voltage regulater in the card to become stable. */
2622 usleep_range(5000, 5500);
2623
2624 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302625 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002626 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2627 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302628 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002629 spin_unlock_irqrestore(&host->lock, flags);
2630
2631 /*
2632 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
2633 * don't become all ones within 1 ms then a Voltage Switch
2634 * sequence has failed and a power cycle to the card is required.
2635 * Otherwise Voltage Switch sequence is completed successfully.
2636 */
2637 usleep_range(1000, 1500);
2638
2639 spin_lock_irqsave(&host->lock, flags);
2640 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
2641 != (0xF << 1)) {
2642 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
2643 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302644 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002645 goto out_unlock;
2646 }
2647
2648out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302649 /* Enable PWRSAVE */
2650 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2651 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002652 spin_unlock_irqrestore(&host->lock, flags);
2653out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302654 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002655}
2656
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302657static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002658{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002659 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002660
2661 /* Program the MCLK value to MCLK_FREQ bit field */
2662 if (host->clk_rate <= 112000000)
2663 mclk_freq = 0;
2664 else if (host->clk_rate <= 125000000)
2665 mclk_freq = 1;
2666 else if (host->clk_rate <= 137000000)
2667 mclk_freq = 2;
2668 else if (host->clk_rate <= 150000000)
2669 mclk_freq = 3;
2670 else if (host->clk_rate <= 162000000)
2671 mclk_freq = 4;
2672 else if (host->clk_rate <= 175000000)
2673 mclk_freq = 5;
2674 else if (host->clk_rate <= 187000000)
2675 mclk_freq = 6;
2676 else if (host->clk_rate <= 200000000)
2677 mclk_freq = 7;
2678
2679 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2680 & ~(7 << 24)) | (mclk_freq << 24)),
2681 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002682}
2683
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302684/* Initialize the DLL (Programmable Delay Line ) */
2685static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002686{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002687 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302688 unsigned long flags;
2689 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002690
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302691 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002692 /*
2693 * Make sure that clock is always enabled when DLL
2694 * tuning is in progress. Keeping PWRSAVE ON may
2695 * turn off the clock. So let's disable the PWRSAVE
2696 * here and re-enable it once tuning is completed.
2697 */
2698 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2699 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302700
2701 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
2702 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2703 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2704
2705 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
2706 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2707 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2708
2709 msmsdcc_cm_sdc4_dll_set_freq(host);
2710
2711 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
2712 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2713 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2714
2715 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
2716 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2717 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2718
2719 /* Set DLL_EN bit to 1. */
2720 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2721 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
2722
2723 /* Set CK_OUT_EN bit to 1. */
2724 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2725 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2726
2727 wait_cnt = 50;
2728 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
2729 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
2730 /* max. wait for 50us sec for LOCK bit to be set */
2731 if (--wait_cnt == 0) {
2732 pr_err("%s: %s: DLL failed to LOCK\n",
2733 mmc_hostname(host->mmc), __func__);
2734 rc = -ETIMEDOUT;
2735 goto out;
2736 }
2737 /* wait for 1us before polling again */
2738 udelay(1);
2739 }
2740
2741out:
2742 /* re-enable PWRSAVE */
2743 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2744 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2745 spin_unlock_irqrestore(&host->lock, flags);
2746
2747 return rc;
2748}
2749
2750static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
2751 u8 poll)
2752{
2753 int rc = 0;
2754 u32 wait_cnt = 50;
2755 u8 ck_out_en = 0;
2756
2757 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
2758 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
2759 MCI_CK_OUT_EN);
2760
2761 while (ck_out_en != poll) {
2762 if (--wait_cnt == 0) {
2763 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
2764 mmc_hostname(host->mmc), __func__, poll);
2765 rc = -ETIMEDOUT;
2766 goto out;
2767 }
2768 udelay(1);
2769
2770 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
2771 MCI_CK_OUT_EN);
2772 }
2773out:
2774 return rc;
2775}
2776
2777/*
2778 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
2779 * calibration sequence. This function should be called before
2780 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
2781 * commands (CMD17/CMD18).
2782 *
2783 * This function gets called when host spinlock acquired.
2784 */
2785static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
2786{
2787 int rc = 0;
2788 u32 config;
2789
2790 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
2791 config |= MCI_CDR_EN;
2792 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
2793 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
2794
2795 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2796 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
2797 if (rc)
2798 goto err_out;
2799
2800 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2801 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2802 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2803
2804 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
2805 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
2806 if (rc)
2807 goto err_out;
2808
2809 goto out;
2810
2811err_out:
2812 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
2813out:
2814 return rc;
2815}
2816
2817static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2818 u8 phase)
2819{
2820 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05302821 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
2822 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
2823 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302824 unsigned long flags;
2825 u32 config;
2826
2827 spin_lock_irqsave(&host->lock, flags);
2828
2829 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
2830 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
2831 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
2832 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
2833
2834 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2835 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
2836 if (rc)
2837 goto err_out;
2838
2839 /*
2840 * Write the selected DLL clock output phase (0 ... 15)
2841 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
2842 */
2843 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2844 & ~(0xF << 20))
2845 | (grey_coded_phase_table[phase] << 20)),
2846 host->base + MCI_DLL_CONFIG);
2847
2848 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2849 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2850 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2851
2852 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
2853 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
2854 if (rc)
2855 goto err_out;
2856
2857 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
2858 config |= MCI_CDR_EN;
2859 config &= ~MCI_CDR_EXT_EN;
2860 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
2861 goto out;
2862
2863err_out:
2864 pr_err("%s: %s: Failed to set DLL phase: %d\n",
2865 mmc_hostname(host->mmc), __func__, phase);
2866out:
2867 spin_unlock_irqrestore(&host->lock, flags);
2868 return rc;
2869}
2870
2871/*
2872 * Find out the greatest range of consecuitive selected
2873 * DLL clock output phases that can be used as sampling
2874 * setting for SD3.0 UHS-I card read operation (in SDR104
2875 * timing mode) or for eMMC4.5 card read operation (in HS200
2876 * timing mode).
2877 * Select the 3/4 of the range and configure the DLL with the
2878 * selected DLL clock output phase.
2879*/
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302880static u8 find_most_appropriate_phase(struct msmsdcc_host *host,
2881 u8 *phase_table, u8 total_phases)
2882{
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05302883 u8 ret, ranges[16][16] = { {0}, {0} };
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302884 u8 phases_per_row[16] = {0};
2885 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05302886 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
2887 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302888
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05302889 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302890 ranges[row_index][col_index] = phase_table[cnt];
2891 phases_per_row[row_index] += 1;
2892 col_index++;
2893
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05302894 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302895 continue;
2896 /* check if next phase in phase_table is consecutive or not */
2897 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
2898 row_index++;
2899 col_index = 0;
2900 }
2901 }
2902
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05302903 /* Check if phase-0 is present in first valid window? */
2904 if (!ranges[0][0]) {
2905 phase_0_found = true;
2906 phase_0_raw_index = 0;
2907 /* Check if cycle exist between 2 valid windows */
2908 for (cnt = 1; cnt <= row_index; cnt++) {
2909 if (phases_per_row[cnt]) {
2910 for (i = 0; i <= phases_per_row[cnt]; i++) {
2911 if (ranges[cnt][i] == 15) {
2912 phase_15_found = true;
2913 phase_15_raw_index = cnt;
2914 break;
2915 }
2916 }
2917 }
2918 }
2919 }
2920
2921 /* If 2 valid windows form cycle then merge them as single window */
2922 if (phase_0_found && phase_15_found) {
2923 /* number of phases in raw where phase 0 is present */
2924 u8 phases_0 = phases_per_row[phase_0_raw_index];
2925 /* number of phases in raw where phase 15 is present */
2926 u8 phases_15 = phases_per_row[phase_15_raw_index];
2927
2928 cnt = 0;
2929 for (i = phases_15; i < (phases_15 + phases_0); i++) {
2930 ranges[phase_15_raw_index][i] =
2931 ranges[phase_0_raw_index][cnt];
2932 cnt++;
2933 }
2934 phases_per_row[phase_0_raw_index] = 0;
2935 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
2936 }
2937
2938 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302939 if (phases_per_row[cnt] > curr_max) {
2940 curr_max = phases_per_row[cnt];
2941 selected_row_index = cnt;
2942 }
2943 }
2944
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05302945 i = ((curr_max * 3) / 4) - 1;
2946 ret = ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302947
2948 return ret;
2949}
2950
2951static int msmsdcc_execute_tuning(struct mmc_host *mmc)
2952{
2953 int rc = 0;
2954 struct msmsdcc_host *host = mmc_priv(mmc);
2955 unsigned long flags;
2956 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
2957
2958 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
2959
2960 /* Tuning is only required for SDR104 modes */
2961 if (!host->tuning_needed) {
2962 rc = 0;
2963 goto exit;
2964 }
2965
2966 spin_lock_irqsave(&host->lock, flags);
2967 WARN(!host->pwr, "SDCC power is turned off\n");
2968 WARN(!host->clks_on, "SDCC clocks are turned off\n");
2969 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
2970
2971 host->cmd19_tuning_in_progress = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302972 msmsdcc_delay(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302973 spin_unlock_irqrestore(&host->lock, flags);
2974
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002975 /* first of all reset the tuning block */
2976 rc = msmsdcc_init_cm_sdc4_dll(host);
2977 if (rc)
2978 goto out;
2979
2980 data_buf = kmalloc(64, GFP_KERNEL);
2981 if (!data_buf) {
2982 rc = -ENOMEM;
2983 goto out;
2984 }
2985
2986 phase = 0;
2987 do {
2988 struct mmc_command cmd = {0};
2989 struct mmc_data data = {0};
2990 struct mmc_request mrq = {
2991 .cmd = &cmd,
2992 .data = &data
2993 };
2994 struct scatterlist sg;
2995
2996 /* set the phase in delay line hw block */
2997 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2998 if (rc)
2999 goto kfree;
3000
3001 cmd.opcode = MMC_SEND_TUNING_BLOCK;
3002 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
3003
3004 data.blksz = 64;
3005 data.blocks = 1;
3006 data.flags = MMC_DATA_READ;
3007 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
3008
3009 data.sg = &sg;
3010 data.sg_len = 1;
3011 sg_init_one(&sg, data_buf, 64);
3012 memset(data_buf, 0, 64);
3013 mmc_wait_for_req(mmc, &mrq);
3014
3015 if (!cmd.error && !data.error &&
3016 !memcmp(data_buf, cmd19_tuning_block, 64)) {
3017 /* tuning is successful with this tuning point */
3018 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303019 pr_debug("%s: %s: found good phase = %d\n",
3020 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003021 }
3022 } while (++phase < 16);
3023
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003024 if (tuned_phase_cnt) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303025 phase = find_most_appropriate_phase(host, tuned_phases,
3026 tuned_phase_cnt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003027 /*
3028 * Finally set the selected phase in delay
3029 * line hw block.
3030 */
3031 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3032 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303033 goto kfree;
3034 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
3035 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003036 } else {
3037 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303038 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003039 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303040 msmsdcc_dump_sdcc_state(host);
3041 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003042 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003043
3044kfree:
3045 kfree(data_buf);
3046out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303047 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05303048 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003049 host->cmd19_tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303050 spin_unlock_irqrestore(&host->lock, flags);
3051exit:
3052 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003053 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07003054}
3055
3056static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003057 .enable = msmsdcc_enable,
3058 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07003059 .request = msmsdcc_request,
3060 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003061 .get_ro = msmsdcc_get_ro,
3062#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07003063 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003064#endif
3065 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
3066 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07003067};
3068
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003069static unsigned int
3070msmsdcc_slot_status(struct msmsdcc_host *host)
3071{
3072 int status;
3073 unsigned int gpio_no = host->plat->status_gpio;
3074
3075 status = gpio_request(gpio_no, "SD_HW_Detect");
3076 if (status) {
3077 pr_err("%s: %s: Failed to request GPIO %d\n",
3078 mmc_hostname(host->mmc), __func__, gpio_no);
3079 } else {
3080 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003081 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08003082 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003083 if (host->plat->is_status_gpio_active_low)
3084 status = !status;
3085 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003086 gpio_free(gpio_no);
3087 }
3088 return status;
3089}
3090
San Mehat9d2bd732009-09-22 16:44:22 -07003091static void
3092msmsdcc_check_status(unsigned long data)
3093{
3094 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3095 unsigned int status;
3096
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003097 if (host->plat->status || host->plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08003098 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003099 status = host->plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08003100 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003101 status = msmsdcc_slot_status(host);
3102
Krishna Konda941604a2012-01-10 17:46:34 -08003103 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08003104
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003105 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08003106 if (host->plat->status)
3107 pr_info("%s: Slot status change detected "
3108 "(%d -> %d)\n",
3109 mmc_hostname(host->mmc),
3110 host->oldstat, status);
3111 else if (host->plat->is_status_gpio_active_low)
3112 pr_info("%s: Slot status change detected "
3113 "(%d -> %d) and the card detect GPIO"
3114 " is ACTIVE_LOW\n",
3115 mmc_hostname(host->mmc),
3116 host->oldstat, status);
3117 else
3118 pr_info("%s: Slot status change detected "
3119 "(%d -> %d) and the card detect GPIO"
3120 " is ACTIVE_HIGH\n",
3121 mmc_hostname(host->mmc),
3122 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07003123 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003124 }
3125 host->oldstat = status;
3126 } else {
3127 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07003128 }
San Mehat9d2bd732009-09-22 16:44:22 -07003129}
3130
3131static irqreturn_t
3132msmsdcc_platform_status_irq(int irq, void *dev_id)
3133{
3134 struct msmsdcc_host *host = dev_id;
3135
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003136 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07003137 msmsdcc_check_status((unsigned long) host);
3138 return IRQ_HANDLED;
3139}
3140
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003141static irqreturn_t
3142msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
3143{
3144 struct msmsdcc_host *host = dev_id;
3145
3146 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
3147 spin_lock(&host->lock);
3148 if (!host->sdio_irq_disabled) {
3149 disable_irq_nosync(irq);
3150 if (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
3151 wake_lock(&host->sdio_wlock);
3152 msmsdcc_disable_irq_wake(host);
3153 }
3154 host->sdio_irq_disabled = 1;
3155 }
3156 if (host->plat->is_sdio_al_client) {
3157 if (!host->clks_on) {
3158 msmsdcc_setup_clocks(host, true);
3159 host->clks_on = 1;
3160 }
3161 if (host->sdcc_irq_disabled) {
3162 writel_relaxed(host->mci_irqenable,
3163 host->base + MMCIMASK0);
3164 mb();
3165 enable_irq(host->core_irqres->start);
3166 host->sdcc_irq_disabled = 0;
3167 }
3168 wake_lock(&host->sdio_wlock);
3169 }
3170 spin_unlock(&host->lock);
3171
3172 return IRQ_HANDLED;
3173}
3174
San Mehat9d2bd732009-09-22 16:44:22 -07003175static void
3176msmsdcc_status_notify_cb(int card_present, void *dev_id)
3177{
3178 struct msmsdcc_host *host = dev_id;
3179
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003180 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07003181 card_present);
3182 msmsdcc_check_status((unsigned long) host);
3183}
3184
San Mehat9d2bd732009-09-22 16:44:22 -07003185static int
3186msmsdcc_init_dma(struct msmsdcc_host *host)
3187{
3188 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
3189 host->dma.host = host;
3190 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003191 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003192
3193 if (!host->dmares)
3194 return -ENODEV;
3195
3196 host->dma.nc = dma_alloc_coherent(NULL,
3197 sizeof(struct msmsdcc_nc_dmadata),
3198 &host->dma.nc_busaddr,
3199 GFP_KERNEL);
3200 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003201 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07003202 return -ENOMEM;
3203 }
3204 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
3205 host->dma.cmd_busaddr = host->dma.nc_busaddr;
3206 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
3207 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
3208 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07003209 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07003210
3211 return 0;
3212}
3213
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003214#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
3215/**
3216 * Allocate and Connect a SDCC peripheral's SPS endpoint
3217 *
3218 * This function allocates endpoint context and
3219 * connect it with memory endpoint by calling
3220 * appropriate SPS driver APIs.
3221 *
3222 * Also registers a SPS callback function with
3223 * SPS driver
3224 *
3225 * This function should only be called once typically
3226 * during driver probe.
3227 *
3228 * @host - Pointer to sdcc host structure
3229 * @ep - Pointer to sps endpoint data structure
3230 * @is_produce - 1 means Producer endpoint
3231 * 0 means Consumer endpoint
3232 *
3233 * @return - 0 if successful else negative value.
3234 *
3235 */
3236static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
3237 struct msmsdcc_sps_ep_conn_data *ep,
3238 bool is_producer)
3239{
3240 int rc = 0;
3241 struct sps_pipe *sps_pipe_handle;
3242 struct sps_connect *sps_config = &ep->config;
3243 struct sps_register_event *sps_event = &ep->event;
3244
3245 /* Allocate endpoint context */
3246 sps_pipe_handle = sps_alloc_endpoint();
3247 if (!sps_pipe_handle) {
3248 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
3249 mmc_hostname(host->mmc), is_producer);
3250 rc = -ENOMEM;
3251 goto out;
3252 }
3253
3254 /* Get default connection configuration for an endpoint */
3255 rc = sps_get_config(sps_pipe_handle, sps_config);
3256 if (rc) {
3257 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
3258 " rc=%d", mmc_hostname(host->mmc),
3259 (u32)sps_pipe_handle, rc);
3260 goto get_config_err;
3261 }
3262
3263 /* Modify the default connection configuration */
3264 if (is_producer) {
3265 /*
3266 * For SDCC producer transfer, source should be
3267 * SDCC peripheral where as destination should
3268 * be system memory.
3269 */
3270 sps_config->source = host->sps.bam_handle;
3271 sps_config->destination = SPS_DEV_HANDLE_MEM;
3272 /* Producer pipe will handle this connection */
3273 sps_config->mode = SPS_MODE_SRC;
3274 sps_config->options =
3275 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3276 } else {
3277 /*
3278 * For SDCC consumer transfer, source should be
3279 * system memory where as destination should
3280 * SDCC peripheral
3281 */
3282 sps_config->source = SPS_DEV_HANDLE_MEM;
3283 sps_config->destination = host->sps.bam_handle;
3284 sps_config->mode = SPS_MODE_DEST;
3285 sps_config->options =
3286 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3287 }
3288
3289 /* Producer pipe index */
3290 sps_config->src_pipe_index = host->sps.src_pipe_index;
3291 /* Consumer pipe index */
3292 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
3293 /*
3294 * This event thresold value is only significant for BAM-to-BAM
3295 * transfer. It's ignored for BAM-to-System mode transfer.
3296 */
3297 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05303298
3299 /* Allocate maximum descriptor fifo size */
3300 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
3301 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003302 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
3303 sps_config->desc.size,
3304 &sps_config->desc.phys_base,
3305 GFP_KERNEL);
3306
Pratibhasagar V00b94332011-10-18 14:57:27 +05303307 if (!sps_config->desc.base) {
3308 rc = -ENOMEM;
3309 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3310 , mmc_hostname(host->mmc));
3311 goto get_config_err;
3312 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003313 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3314
3315 /* Establish connection between peripheral and memory endpoint */
3316 rc = sps_connect(sps_pipe_handle, sps_config);
3317 if (rc) {
3318 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3319 " rc=%d", mmc_hostname(host->mmc),
3320 (u32)sps_pipe_handle, rc);
3321 goto sps_connect_err;
3322 }
3323
3324 sps_event->mode = SPS_TRIGGER_CALLBACK;
3325 sps_event->options = SPS_O_EOT;
3326 sps_event->callback = msmsdcc_sps_complete_cb;
3327 sps_event->xfer_done = NULL;
3328 sps_event->user = (void *)host;
3329
3330 /* Register callback event for EOT (End of transfer) event. */
3331 rc = sps_register_event(sps_pipe_handle, sps_event);
3332 if (rc) {
3333 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3334 " rc=%d", mmc_hostname(host->mmc),
3335 (u32)sps_pipe_handle, rc);
3336 goto reg_event_err;
3337 }
3338 /* Now save the sps pipe handle */
3339 ep->pipe_handle = sps_pipe_handle;
3340 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3341 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3342 __func__, is_producer ? "READ" : "WRITE",
3343 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3344 goto out;
3345
3346reg_event_err:
3347 sps_disconnect(sps_pipe_handle);
3348sps_connect_err:
3349 dma_free_coherent(mmc_dev(host->mmc),
3350 sps_config->desc.size,
3351 sps_config->desc.base,
3352 sps_config->desc.phys_base);
3353get_config_err:
3354 sps_free_endpoint(sps_pipe_handle);
3355out:
3356 return rc;
3357}
3358
3359/**
3360 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3361 *
3362 * This function disconnect endpoint and deallocates
3363 * endpoint context.
3364 *
3365 * This function should only be called once typically
3366 * during driver remove.
3367 *
3368 * @host - Pointer to sdcc host structure
3369 * @ep - Pointer to sps endpoint data structure
3370 *
3371 */
3372static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3373 struct msmsdcc_sps_ep_conn_data *ep)
3374{
3375 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3376 struct sps_connect *sps_config = &ep->config;
3377 struct sps_register_event *sps_event = &ep->event;
3378
3379 sps_event->xfer_done = NULL;
3380 sps_event->callback = NULL;
3381 sps_register_event(sps_pipe_handle, sps_event);
3382 sps_disconnect(sps_pipe_handle);
3383 dma_free_coherent(mmc_dev(host->mmc),
3384 sps_config->desc.size,
3385 sps_config->desc.base,
3386 sps_config->desc.phys_base);
3387 sps_free_endpoint(sps_pipe_handle);
3388}
3389
3390/**
3391 * Reset SDCC peripheral's SPS endpoint
3392 *
3393 * This function disconnects an endpoint.
3394 *
3395 * This function should be called for reseting
3396 * SPS endpoint when data transfer error is
3397 * encountered during data transfer. This
3398 * can be considered as soft reset to endpoint.
3399 *
3400 * This function should only be called if
3401 * msmsdcc_sps_init() is already called.
3402 *
3403 * @host - Pointer to sdcc host structure
3404 * @ep - Pointer to sps endpoint data structure
3405 *
3406 * @return - 0 if successful else negative value.
3407 */
3408static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3409 struct msmsdcc_sps_ep_conn_data *ep)
3410{
3411 int rc = 0;
3412 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3413
3414 rc = sps_disconnect(sps_pipe_handle);
3415 if (rc) {
3416 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3417 " rc=%d", mmc_hostname(host->mmc), __func__,
3418 (u32)sps_pipe_handle, rc);
3419 goto out;
3420 }
3421 out:
3422 return rc;
3423}
3424
3425/**
3426 * Restore SDCC peripheral's SPS endpoint
3427 *
3428 * This function connects an endpoint.
3429 *
3430 * This function should be called for restoring
3431 * SPS endpoint after data transfer error is
3432 * encountered during data transfer. This
3433 * can be considered as soft reset to endpoint.
3434 *
3435 * This function should only be called if
3436 * msmsdcc_sps_reset_ep() is called before.
3437 *
3438 * @host - Pointer to sdcc host structure
3439 * @ep - Pointer to sps endpoint data structure
3440 *
3441 * @return - 0 if successful else negative value.
3442 */
3443static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3444 struct msmsdcc_sps_ep_conn_data *ep)
3445{
3446 int rc = 0;
3447 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3448 struct sps_connect *sps_config = &ep->config;
3449 struct sps_register_event *sps_event = &ep->event;
3450
3451 /* Establish connection between peripheral and memory endpoint */
3452 rc = sps_connect(sps_pipe_handle, sps_config);
3453 if (rc) {
3454 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3455 " rc=%d", mmc_hostname(host->mmc), __func__,
3456 (u32)sps_pipe_handle, rc);
3457 goto out;
3458 }
3459
3460 /* Register callback event for EOT (End of transfer) event. */
3461 rc = sps_register_event(sps_pipe_handle, sps_event);
3462 if (rc) {
3463 pr_err("%s: %s: sps_register_event() failed!!!"
3464 " pipe_handle=0x%x, rc=%d",
3465 mmc_hostname(host->mmc), __func__,
3466 (u32)sps_pipe_handle, rc);
3467 goto reg_event_err;
3468 }
3469 goto out;
3470
3471reg_event_err:
3472 sps_disconnect(sps_pipe_handle);
3473out:
3474 return rc;
3475}
3476
3477/**
3478 * Initialize SPS HW connected with SDCC core
3479 *
3480 * This function register BAM HW resources with
3481 * SPS driver and then initialize 2 SPS endpoints
3482 *
3483 * This function should only be called once typically
3484 * during driver probe.
3485 *
3486 * @host - Pointer to sdcc host structure
3487 *
3488 * @return - 0 if successful else negative value.
3489 *
3490 */
3491static int msmsdcc_sps_init(struct msmsdcc_host *host)
3492{
3493 int rc = 0;
3494 struct sps_bam_props bam = {0};
3495
3496 host->bam_base = ioremap(host->bam_memres->start,
3497 resource_size(host->bam_memres));
3498 if (!host->bam_base) {
3499 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3500 " size=0x%x", mmc_hostname(host->mmc),
3501 host->bam_memres->start,
3502 (host->bam_memres->end -
3503 host->bam_memres->start));
3504 rc = -ENOMEM;
3505 goto out;
3506 }
3507
3508 bam.phys_addr = host->bam_memres->start;
3509 bam.virt_addr = host->bam_base;
3510 /*
3511 * This event thresold value is only significant for BAM-to-BAM
3512 * transfer. It's ignored for BAM-to-System mode transfer.
3513 */
3514 bam.event_threshold = 0x10; /* Pipe event threshold */
3515 /*
3516 * This threshold controls when the BAM publish
3517 * the descriptor size on the sideband interface.
3518 * SPS HW will only be used when
3519 * data transfer size > MCI_FIFOSIZE (64 bytes).
3520 * PIO mode will be used when
3521 * data transfer size < MCI_FIFOSIZE (64 bytes).
3522 * So set this thresold value to 64 bytes.
3523 */
3524 bam.summing_threshold = 64;
3525 /* SPS driver wll handle the SDCC BAM IRQ */
3526 bam.irq = (u32)host->bam_irqres->start;
3527 bam.manage = SPS_BAM_MGR_LOCAL;
3528
3529 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3530 (u32)bam.phys_addr);
3531 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3532 (u32)bam.virt_addr);
3533
3534 /* Register SDCC Peripheral BAM device to SPS driver */
3535 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3536 if (rc) {
3537 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3538 mmc_hostname(host->mmc), rc);
3539 goto reg_bam_err;
3540 }
3541 pr_info("%s: BAM device registered. bam_handle=0x%x",
3542 mmc_hostname(host->mmc), host->sps.bam_handle);
3543
3544 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3545 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3546
3547 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3548 SPS_PROD_PERIPHERAL);
3549 if (rc)
3550 goto sps_reset_err;
3551 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3552 SPS_CONS_PERIPHERAL);
3553 if (rc)
3554 goto cons_conn_err;
3555
3556 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3557 mmc_hostname(host->mmc),
3558 (unsigned long long)host->bam_memres->start,
3559 (unsigned int)host->bam_irqres->start);
3560 goto out;
3561
3562cons_conn_err:
3563 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3564sps_reset_err:
3565 sps_deregister_bam_device(host->sps.bam_handle);
3566reg_bam_err:
3567 iounmap(host->bam_base);
3568out:
3569 return rc;
3570}
3571
3572/**
3573 * De-initialize SPS HW connected with SDCC core
3574 *
3575 * This function deinitialize SPS endpoints and then
3576 * deregisters BAM resources from SPS driver.
3577 *
3578 * This function should only be called once typically
3579 * during driver remove.
3580 *
3581 * @host - Pointer to sdcc host structure
3582 *
3583 */
3584static void msmsdcc_sps_exit(struct msmsdcc_host *host)
3585{
3586 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
3587 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3588 sps_deregister_bam_device(host->sps.bam_handle);
3589 iounmap(host->bam_base);
3590}
3591#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
3592
3593static ssize_t
3594show_polling(struct device *dev, struct device_attribute *attr, char *buf)
3595{
3596 struct mmc_host *mmc = dev_get_drvdata(dev);
3597 struct msmsdcc_host *host = mmc_priv(mmc);
3598 int poll;
3599 unsigned long flags;
3600
3601 spin_lock_irqsave(&host->lock, flags);
3602 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
3603 spin_unlock_irqrestore(&host->lock, flags);
3604
3605 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
3606}
3607
3608static ssize_t
3609set_polling(struct device *dev, struct device_attribute *attr,
3610 const char *buf, size_t count)
3611{
3612 struct mmc_host *mmc = dev_get_drvdata(dev);
3613 struct msmsdcc_host *host = mmc_priv(mmc);
3614 int value;
3615 unsigned long flags;
3616
3617 sscanf(buf, "%d", &value);
3618
3619 spin_lock_irqsave(&host->lock, flags);
3620 if (value) {
3621 mmc->caps |= MMC_CAP_NEEDS_POLL;
3622 mmc_detect_change(host->mmc, 0);
3623 } else {
3624 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3625 }
3626#ifdef CONFIG_HAS_EARLYSUSPEND
3627 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
3628#endif
3629 spin_unlock_irqrestore(&host->lock, flags);
3630 return count;
3631}
3632
3633static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
3634 show_polling, set_polling);
3635static struct attribute *dev_attrs[] = {
3636 &dev_attr_polling.attr,
3637 NULL,
3638};
3639static struct attribute_group dev_attr_grp = {
3640 .attrs = dev_attrs,
3641};
3642
3643#ifdef CONFIG_HAS_EARLYSUSPEND
3644static void msmsdcc_early_suspend(struct early_suspend *h)
3645{
3646 struct msmsdcc_host *host =
3647 container_of(h, struct msmsdcc_host, early_suspend);
3648 unsigned long flags;
3649
3650 spin_lock_irqsave(&host->lock, flags);
3651 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
3652 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3653 spin_unlock_irqrestore(&host->lock, flags);
3654};
3655static void msmsdcc_late_resume(struct early_suspend *h)
3656{
3657 struct msmsdcc_host *host =
3658 container_of(h, struct msmsdcc_host, early_suspend);
3659 unsigned long flags;
3660
3661 if (host->polling_enabled) {
3662 spin_lock_irqsave(&host->lock, flags);
3663 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
3664 mmc_detect_change(host->mmc, 0);
3665 spin_unlock_irqrestore(&host->lock, flags);
3666 }
3667};
3668#endif
3669
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303670void msmsdcc_print_regs(const char *name, void __iomem *base,
3671 unsigned int no_of_regs)
3672{
3673 unsigned int i;
3674
3675 if (!base)
3676 return;
3677 pr_info("===== %s: Register Dumps @base=0x%x =====\n",
3678 name, (u32)base);
3679 for (i = 0; i < no_of_regs; i = i + 4) {
3680 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x.\n", i*4,
3681 (u32)readl_relaxed(base + i*4),
3682 (u32)readl_relaxed(base + ((i+1)*4)),
3683 (u32)readl_relaxed(base + ((i+2)*4)),
3684 (u32)readl_relaxed(base + ((i+3)*4)));
3685 }
3686}
3687
3688static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
3689{
3690 /* Dump current state of SDCC clocks, power and irq */
3691 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
3692 (host->pwr ? "ON" : "OFF"));
3693 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
3694 mmc_hostname(host->mmc),
3695 (host->clks_on ? "ON" : "OFF"),
3696 (u32)clk_get_rate(host->clk));
3697 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
3698 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
3699
3700 /* Now dump SDCC registers. Don't print FIFO registers */
3701 if (host->clks_on)
3702 msmsdcc_print_regs("SDCC-CORE", host->base, 28);
3703
3704 if (host->curr.data) {
3705 if (msmsdcc_check_dma_op_req(host->curr.data))
3706 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
3707 else if (host->is_dma_mode)
3708 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
3709 mmc_hostname(host->mmc), host->dma.busy,
3710 host->dma.channel, host->dma.crci);
3711 else if (host->is_sps_mode)
3712 pr_info("%s: SPS mode: busy=%d\n",
3713 mmc_hostname(host->mmc), host->sps.busy);
3714
3715 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
3716 mmc_hostname(host->mmc), host->curr.xfer_size,
3717 host->curr.data_xfered, host->curr.xfer_remain);
3718 pr_info("%s: got_dataend=%d, prog_enable=%d,"
3719 " wait_for_auto_prog_done=%d,"
3720 " got_auto_prog_done=%d\n",
3721 mmc_hostname(host->mmc), host->curr.got_dataend,
3722 host->prog_enable, host->curr.wait_for_auto_prog_done,
3723 host->curr.got_auto_prog_done);
3724 }
3725
3726}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003727static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
3728{
3729 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3730 struct mmc_request *mrq;
3731 unsigned long flags;
3732
3733 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003734 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003735 pr_info("%s: %s: dummy CMD52 timeout\n",
3736 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003737 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003738 }
3739
3740 mrq = host->curr.mrq;
3741
3742 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303743 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
3744 mrq->cmd->opcode);
3745 msmsdcc_dump_sdcc_state(host);
3746
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003747 if (!mrq->cmd->error)
3748 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303749 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003750 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003751 if (mrq->data && !mrq->data->error)
3752 mrq->data->error = -ETIMEDOUT;
3753 host->curr.data_xfered = 0;
3754 if (host->dma.sg && host->is_dma_mode) {
3755 msm_dmov_stop_cmd(host->dma.channel,
3756 &host->dma.hdr, 0);
3757 } else if (host->sps.sg && host->is_sps_mode) {
3758 /* Stop current SPS transfer */
3759 msmsdcc_sps_exit_curr_xfer(host);
3760 } else {
3761 msmsdcc_reset_and_restore(host);
3762 msmsdcc_stop_data(host);
3763 if (mrq->data && mrq->data->stop)
3764 msmsdcc_start_command(host,
3765 mrq->data->stop, 0);
3766 else
3767 msmsdcc_request_end(host, mrq);
3768 }
3769 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05303770 host->prog_enable = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003771 msmsdcc_reset_and_restore(host);
3772 msmsdcc_request_end(host, mrq);
3773 }
3774 }
3775 spin_unlock_irqrestore(&host->lock, flags);
3776}
3777
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303778static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
3779{
3780 int i, ret;
3781 struct mmc_platform_data *pdata;
3782 struct device_node *np = dev->of_node;
3783 u32 bus_width = 0;
3784 u32 *clk_table;
3785 int clk_table_len;
3786 u32 *sup_voltages;
3787 int sup_volt_len;
3788
3789 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
3790 if (!pdata) {
3791 dev_err(dev, "could not allocate memory for platform data\n");
3792 goto err;
3793 }
3794
3795 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
3796 if (bus_width == 8) {
3797 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
3798 } else if (bus_width == 4) {
3799 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
3800 } else {
3801 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
3802 pdata->mmc_bus_width = 0;
3803 }
3804
3805 if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
3806 size_t sz;
3807 sz = sup_volt_len / sizeof(*sup_voltages);
3808 if (sz > 0) {
3809 sup_voltages = devm_kzalloc(dev,
3810 sz * sizeof(*sup_voltages), GFP_KERNEL);
3811 if (!sup_voltages) {
3812 dev_err(dev, "No memory for supported voltage\n");
3813 goto err;
3814 }
3815
3816 ret = of_property_read_u32_array(np,
3817 "qcom,sdcc-sup-voltages", sup_voltages, sz);
3818 if (ret < 0) {
3819 dev_err(dev, "error while reading voltage"
3820 "ranges %d\n", ret);
3821 goto err;
3822 }
3823 } else {
3824 dev_err(dev, "No supported voltages\n");
3825 goto err;
3826 }
3827 for (i = 0; i < sz; i += 2) {
3828 u32 mask;
3829
3830 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
3831 sup_voltages[i + 1]);
3832 if (!mask)
3833 dev_err(dev, "Invalide voltage range %d\n", i);
3834 pdata->ocr_mask |= mask;
3835 }
3836 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
3837 } else {
3838 dev_err(dev, "Supported voltage range not specified\n");
3839 }
3840
3841 if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
3842 size_t sz;
3843 sz = clk_table_len / sizeof(*clk_table);
3844
3845 if (sz > 0) {
3846 clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
3847 GFP_KERNEL);
3848 if (!clk_table) {
3849 dev_err(dev, "No memory for clock table\n");
3850 goto err;
3851 }
3852
3853 ret = of_property_read_u32_array(np,
3854 "qcom,sdcc-clk-rates", clk_table, sz);
3855 if (ret < 0) {
3856 dev_err(dev, "error while reading clk"
3857 "table %d\n", ret);
3858 goto err;
3859 }
3860 } else {
3861 dev_err(dev, "clk_table not specified\n");
3862 goto err;
3863 }
3864 pdata->sup_clk_table = clk_table;
3865 pdata->sup_clk_cnt = sz;
3866 } else {
3867 dev_err(dev, "Supported clock rates not specified\n");
3868 }
3869
3870 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
3871 pdata->nonremovable = true;
3872 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
3873 pdata->disable_cmd23 = true;
3874
3875 return pdata;
3876err:
3877 return NULL;
3878}
3879
San Mehat9d2bd732009-09-22 16:44:22 -07003880static int
3881msmsdcc_probe(struct platform_device *pdev)
3882{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303883 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07003884 struct msmsdcc_host *host;
3885 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003886 unsigned long flags;
3887 struct resource *core_irqres = NULL;
3888 struct resource *bam_irqres = NULL;
3889 struct resource *core_memres = NULL;
3890 struct resource *dml_memres = NULL;
3891 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07003892 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07003893 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05303894 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003895 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07003896
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303897 if (pdev->dev.of_node) {
3898 plat = msmsdcc_populate_pdata(&pdev->dev);
3899 of_property_read_u32((&pdev->dev)->of_node,
3900 "cell-index", &pdev->id);
3901 } else {
3902 plat = pdev->dev.platform_data;
3903 }
3904
San Mehat9d2bd732009-09-22 16:44:22 -07003905 /* must have platform data */
3906 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003907 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003908 ret = -EINVAL;
3909 goto out;
3910 }
3911
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003912 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07003913 return -EINVAL;
3914
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05303915 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
3916 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
3917 return -EINVAL;
3918 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003919
San Mehat9d2bd732009-09-22 16:44:22 -07003920 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003921 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003922 return -ENXIO;
3923 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303924 if (pdev->dev.of_node) {
3925 /*
3926 * Device tree iomem resources are only accessible by index.
3927 * index = 0 -> SDCC register interface
3928 * index = 1 -> DML register interface
3929 * index = 2 -> BAM register interface
3930 * IRQ resources:
3931 * index = 0 -> SDCC IRQ
3932 * index = 1 -> BAM IRQ
3933 */
3934 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
3935 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
3936 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
3937 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
3938 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
3939 } else {
3940 for (i = 0; i < pdev->num_resources; i++) {
3941 if (pdev->resource[i].flags & IORESOURCE_MEM) {
3942 if (!strncmp(pdev->resource[i].name,
3943 "sdcc_dml_addr",
3944 sizeof("sdcc_dml_addr")))
3945 dml_memres = &pdev->resource[i];
3946 else if (!strncmp(pdev->resource[i].name,
3947 "sdcc_bam_addr",
3948 sizeof("sdcc_bam_addr")))
3949 bam_memres = &pdev->resource[i];
3950 else
3951 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07003952
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303953 }
3954 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
3955 if (!strncmp(pdev->resource[i].name,
3956 "sdcc_bam_irq",
3957 sizeof("sdcc_bam_irq")))
3958 bam_irqres = &pdev->resource[i];
3959 else
3960 core_irqres = &pdev->resource[i];
3961 }
3962 if (pdev->resource[i].flags & IORESOURCE_DMA) {
3963 if (!strncmp(pdev->resource[i].name,
3964 "sdcc_dma_chnl",
3965 sizeof("sdcc_dma_chnl")))
3966 dmares = &pdev->resource[i];
3967 else if (!strncmp(pdev->resource[i].name,
3968 "sdcc_dma_crci",
3969 sizeof("sdcc_dma_crci")))
3970 dma_crci_res = &pdev->resource[i];
3971 }
Krishna Konda25786ec2011-07-25 16:21:36 -07003972 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003973 }
3974
3975 if (!core_irqres || !core_memres) {
3976 pr_err("%s: Invalid sdcc core resource\n", __func__);
3977 return -ENXIO;
3978 }
3979
3980 /*
3981 * Both BAM and DML memory resource should be preset.
3982 * BAM IRQ resource should also be present.
3983 */
3984 if ((bam_memres && !dml_memres) ||
3985 (!bam_memres && dml_memres) ||
3986 ((bam_memres && dml_memres) && !bam_irqres)) {
3987 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003988 return -ENXIO;
3989 }
3990
3991 /*
3992 * Setup our host structure
3993 */
San Mehat9d2bd732009-09-22 16:44:22 -07003994 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
3995 if (!mmc) {
3996 ret = -ENOMEM;
3997 goto out;
3998 }
3999
4000 host = mmc_priv(mmc);
4001 host->pdev_id = pdev->id;
4002 host->plat = plat;
4003 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08004004 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05304005
4006 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004007 host->is_sps_mode = 1;
4008 else if (dmares)
4009 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07004010
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004011 host->base = ioremap(core_memres->start,
4012 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07004013 if (!host->base) {
4014 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004015 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004016 }
4017
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004018 host->core_irqres = core_irqres;
4019 host->bam_irqres = bam_irqres;
4020 host->core_memres = core_memres;
4021 host->dml_memres = dml_memres;
4022 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07004023 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07004024 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07004025 spin_lock_init(&host->lock);
4026
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004027#ifdef CONFIG_MMC_EMBEDDED_SDIO
4028 if (plat->embedded_sdio)
4029 mmc_set_embedded_sdio_data(mmc,
4030 &plat->embedded_sdio->cis,
4031 &plat->embedded_sdio->cccr,
4032 plat->embedded_sdio->funcs,
4033 plat->embedded_sdio->num_funcs);
4034#endif
4035
Sahitya Tummala62612cf2010-12-08 15:03:03 +05304036 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
4037 (unsigned long)host);
4038
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004039 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
4040 (unsigned long)host);
4041 if (host->is_dma_mode) {
4042 /* Setup DMA */
4043 ret = msmsdcc_init_dma(host);
4044 if (ret)
4045 goto ioremap_free;
4046 } else {
4047 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004048 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004049 }
4050
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004051 /*
4052 * Setup SDCC clock if derived from Dayatona
4053 * fabric core clock.
4054 */
4055 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07004056 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004057 if (!IS_ERR(host->dfab_pclk)) {
4058 /* Set the clock rate to 64MHz for max. performance */
4059 ret = clk_set_rate(host->dfab_pclk, 64000000);
4060 if (ret)
4061 goto dfab_pclk_put;
4062 ret = clk_enable(host->dfab_pclk);
4063 if (ret)
4064 goto dfab_pclk_put;
4065 } else
4066 goto dma_free;
4067 }
4068
4069 /*
4070 * Setup main peripheral bus clock
4071 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004072 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004073 if (!IS_ERR(host->pclk)) {
4074 ret = clk_enable(host->pclk);
4075 if (ret)
4076 goto pclk_put;
4077
4078 host->pclk_rate = clk_get_rate(host->pclk);
4079 }
4080
4081 /*
4082 * Setup SDC MMC clock
4083 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004084 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07004085 if (IS_ERR(host->clk)) {
4086 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004087 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07004088 }
4089
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004090 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
4091 if (ret) {
4092 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
4093 goto clk_put;
4094 }
4095
4096 ret = clk_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004097 if (ret)
4098 goto clk_put;
4099
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004100 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304101 if (!host->clk_rate)
4102 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304103
4104 /*
4105 * Lookup the Controller Version, to identify the supported features
4106 * Version number read as 0 would indicate SDCC3 or earlier versions
4107 */
4108 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
4109 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
4110 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304111 /*
4112 * Set the register write delay according to min. clock frequency
4113 * supported and update later when the host->clk_rate changes.
4114 */
4115 host->reg_write_delay =
4116 (1 + ((3 * USEC_PER_SEC) /
4117 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004118
4119 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05304120 /* Apply Hard reset to SDCC to put it in power on default state */
4121 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004122
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304123 /* pm qos request to prevent apps idle power collapse */
4124 if (host->plat->swfi_latency)
4125 pm_qos_add_request(&host->pm_qos_req_dma,
4126 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
4127
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004128 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07004129 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004130 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07004131 goto clk_disable;
4132 }
4133
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004134
4135 /* Clocks has to be running before accessing SPS/DML HW blocks */
4136 if (host->is_sps_mode) {
4137 /* Initialize SPS */
4138 ret = msmsdcc_sps_init(host);
4139 if (ret)
4140 goto vreg_deinit;
4141 /* Initialize DML */
4142 ret = msmsdcc_dml_init(host);
4143 if (ret)
4144 goto sps_exit;
4145 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05304146 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07004147
San Mehat9d2bd732009-09-22 16:44:22 -07004148 /*
4149 * Setup MMC host structure
4150 */
4151 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004152 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
4153 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004154 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004155 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
4156 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07004157
San Mehat9d2bd732009-09-22 16:44:22 -07004158 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304159 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304160
4161 /*
4162 * If we send the CMD23 before multi block write/read command
4163 * then we need not to send CMD12 at the end of the transfer.
4164 * If we don't send the CMD12 then only way to detect the PROG_DONE
4165 * status is to use the AUTO_PROG_DONE status provided by SDCC4
4166 * controller. So let's enable the CMD23 for SDCC4 only.
4167 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304168 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304169 mmc->caps |= MMC_CAP_CMD23;
4170
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004171 mmc->caps |= plat->uhs_caps;
4172 /*
4173 * XPC controls the maximum current in the default speed mode of SDXC
4174 * card. XPC=0 means 100mA (max.) but speed class is not supported.
4175 * XPC=1 means 150mA (max.) and speed class is supported.
4176 */
4177 if (plat->xpc_cap)
4178 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
4179 MMC_CAP_SET_XPC_180);
4180
4181 if (plat->nonremovable)
4182 mmc->caps |= MMC_CAP_NONREMOVABLE;
4183#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
4184 mmc->caps |= MMC_CAP_SDIO_IRQ;
4185#endif
4186
4187 if (plat->is_sdio_al_client)
4188 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07004189
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304190 mmc->max_segs = msmsdcc_get_nr_sg(host);
4191 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
4192 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07004193
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304194 mmc->max_req_size = MMC_MAX_REQ_SIZE;
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +05304195 mmc->max_seg_size = mmc->max_req_size;
San Mehat9d2bd732009-09-22 16:44:22 -07004196
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004197 writel_relaxed(0, host->base + MMCIMASK0);
4198 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -07004199
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004200 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
4201 mb();
4202 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07004203
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004204 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
4205 DRIVER_NAME " (cmd)", host);
4206 if (ret)
4207 goto dml_exit;
4208
4209 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
4210 DRIVER_NAME " (pio)", host);
4211 if (ret)
4212 goto irq_free;
4213
4214 /*
4215 * Enable SDCC IRQ only when host is powered on. Otherwise, this
4216 * IRQ is un-necessarily being monitored by MPM (Modem power
4217 * management block) during idle-power collapse. The MPM will be
4218 * configured to monitor the DATA1 GPIO line with level-low trigger
4219 * and thus depending on the GPIO status, it prevents TCXO shutdown
4220 * during idle-power collapse.
4221 */
4222 disable_irq(core_irqres->start);
4223 host->sdcc_irq_disabled = 1;
4224
4225 if (plat->sdiowakeup_irq) {
4226 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4227 mmc_hostname(mmc));
4228 ret = request_irq(plat->sdiowakeup_irq,
4229 msmsdcc_platform_sdiowakeup_irq,
4230 IRQF_SHARED | IRQF_TRIGGER_LOW,
4231 DRIVER_NAME "sdiowakeup", host);
4232 if (ret) {
4233 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
4234 plat->sdiowakeup_irq, ret);
4235 goto pio_irq_free;
4236 } else {
4237 spin_lock_irqsave(&host->lock, flags);
4238 if (!host->sdio_irq_disabled) {
4239 disable_irq_nosync(plat->sdiowakeup_irq);
4240 host->sdio_irq_disabled = 1;
4241 }
4242 spin_unlock_irqrestore(&host->lock, flags);
4243 }
4244 }
4245
4246 if (plat->cfg_mpm_sdiowakeup) {
4247 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4248 mmc_hostname(mmc));
4249 }
4250
4251 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
4252 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004253 /*
4254 * Setup card detect change
4255 */
4256
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004257 if (plat->status || plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08004258 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004259 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08004260 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004261 host->oldstat = msmsdcc_slot_status(host);
Krishna Konda360aa422011-12-06 18:27:41 -08004262
Krishna Konda941604a2012-01-10 17:46:34 -08004263 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004264 }
San Mehat9d2bd732009-09-22 16:44:22 -07004265
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004266 if (plat->status_irq) {
4267 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07004268 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004269 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07004270 DRIVER_NAME " (slot)",
4271 host);
4272 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004273 pr_err("Unable to get slot IRQ %d (%d)\n",
4274 plat->status_irq, ret);
4275 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004276 }
4277 } else if (plat->register_status_notify) {
4278 plat->register_status_notify(msmsdcc_status_notify_cb, host);
4279 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004280 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07004281 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004282
4283 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004284
4285 ret = pm_runtime_set_active(&(pdev)->dev);
4286 if (ret < 0)
4287 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
4288 __func__, ret);
4289 /*
4290 * There is no notion of suspend/resume for SD/MMC/SDIO
4291 * cards. So host can be suspended/resumed with out
4292 * worrying about its children.
4293 */
4294 pm_suspend_ignore_children(&(pdev)->dev, true);
4295
4296 /*
4297 * MMC/SD/SDIO bus suspend/resume operations are defined
4298 * only for the slots that will be used for non-removable
4299 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
4300 * defined. Otherwise, they simply become card removal and
4301 * insertion events during suspend and resume respectively.
4302 * Hence, enable run-time PM only for slots for which bus
4303 * suspend/resume operations are defined.
4304 */
4305#ifdef CONFIG_MMC_UNSAFE_RESUME
4306 /*
4307 * If this capability is set, MMC core will enable/disable host
4308 * for every claim/release operation on a host. We use this
4309 * notification to increment/decrement runtime pm usage count.
4310 */
4311 mmc->caps |= MMC_CAP_DISABLE;
4312 pm_runtime_enable(&(pdev)->dev);
4313#else
4314 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
4315 mmc->caps |= MMC_CAP_DISABLE;
4316 pm_runtime_enable(&(pdev)->dev);
4317 }
4318#endif
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05304319#ifndef CONFIG_PM_RUNTIME
4320 mmc_set_disable_delay(mmc, MSM_MMC_DISABLE_TIMEOUT);
4321#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004322 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
4323 (unsigned long)host);
4324
San Mehat9d2bd732009-09-22 16:44:22 -07004325 mmc_add_host(mmc);
4326
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004327#ifdef CONFIG_HAS_EARLYSUSPEND
4328 host->early_suspend.suspend = msmsdcc_early_suspend;
4329 host->early_suspend.resume = msmsdcc_late_resume;
4330 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
4331 register_early_suspend(&host->early_suspend);
4332#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004333
Krishna Konda25786ec2011-07-25 16:21:36 -07004334 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
4335 " dmacrcri %d\n", mmc_hostname(mmc),
4336 (unsigned long long)core_memres->start,
4337 (unsigned int) core_irqres->start,
4338 (unsigned int) plat->status_irq, host->dma.channel,
4339 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004340
4341 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
4342 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
4343 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
4344 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
4345 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
4346 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
4347 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
4348 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
4349 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
4350 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
4351 host->eject);
4352 pr_info("%s: Power save feature enable = %d\n",
4353 mmc_hostname(mmc), msmsdcc_pwrsave);
4354
Krishna Konda25786ec2011-07-25 16:21:36 -07004355 if (host->is_dma_mode && host->dma.channel != -1
4356 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004357 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004358 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004359 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004360 mmc_hostname(mmc), host->dma.cmd_busaddr,
4361 host->dma.cmdptr_busaddr);
4362 } else if (host->is_sps_mode) {
4363 pr_info("%s: SPS-BAM data transfer mode available\n",
4364 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004365 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004366 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004367
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004368#if defined(CONFIG_DEBUG_FS)
4369 msmsdcc_dbg_createhost(host);
4370#endif
4371 if (!plat->status_irq) {
4372 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
4373 if (ret)
4374 goto platform_irq_free;
4375 }
San Mehat9d2bd732009-09-22 16:44:22 -07004376 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004377
4378 platform_irq_free:
4379 del_timer_sync(&host->req_tout_timer);
4380 pm_runtime_disable(&(pdev)->dev);
4381 pm_runtime_set_suspended(&(pdev)->dev);
4382
4383 if (plat->status_irq)
4384 free_irq(plat->status_irq, host);
4385 sdiowakeup_irq_free:
4386 wake_lock_destroy(&host->sdio_suspend_wlock);
4387 if (plat->sdiowakeup_irq)
4388 free_irq(plat->sdiowakeup_irq, host);
4389 pio_irq_free:
4390 if (plat->sdiowakeup_irq)
4391 wake_lock_destroy(&host->sdio_wlock);
4392 free_irq(core_irqres->start, host);
4393 irq_free:
4394 free_irq(core_irqres->start, host);
4395 dml_exit:
4396 if (host->is_sps_mode)
4397 msmsdcc_dml_exit(host);
4398 sps_exit:
4399 if (host->is_sps_mode)
4400 msmsdcc_sps_exit(host);
4401 vreg_deinit:
4402 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07004403 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004404 clk_disable(host->clk);
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304405 if (host->plat->swfi_latency)
4406 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07004407 clk_put:
4408 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004409 pclk_disable:
4410 if (!IS_ERR(host->pclk))
4411 clk_disable(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07004412 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004413 if (!IS_ERR(host->pclk))
4414 clk_put(host->pclk);
4415 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4416 clk_disable(host->dfab_pclk);
4417 dfab_pclk_put:
4418 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4419 clk_put(host->dfab_pclk);
4420 dma_free:
4421 if (host->is_dma_mode) {
4422 if (host->dmares)
4423 dma_free_coherent(NULL,
4424 sizeof(struct msmsdcc_nc_dmadata),
4425 host->dma.nc, host->dma.nc_busaddr);
4426 }
4427 ioremap_free:
4428 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07004429 host_free:
4430 mmc_free_host(mmc);
4431 out:
4432 return ret;
4433}
4434
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004435static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07004436{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004437 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4438 struct mmc_platform_data *plat;
4439 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004440
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004441 if (!mmc)
4442 return -ENXIO;
4443
4444 if (pm_runtime_suspended(&(pdev)->dev))
4445 pm_runtime_resume(&(pdev)->dev);
4446
4447 host = mmc_priv(mmc);
4448
4449 DBG(host, "Removing SDCC device = %d\n", pdev->id);
4450 plat = host->plat;
4451
4452 if (!plat->status_irq)
4453 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
4454
4455 del_timer_sync(&host->req_tout_timer);
4456 tasklet_kill(&host->dma_tlet);
4457 tasklet_kill(&host->sps.tlet);
4458 mmc_remove_host(mmc);
4459
4460 if (plat->status_irq)
4461 free_irq(plat->status_irq, host);
4462
4463 wake_lock_destroy(&host->sdio_suspend_wlock);
4464 if (plat->sdiowakeup_irq) {
4465 wake_lock_destroy(&host->sdio_wlock);
4466 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
4467 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07004468 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004469
4470 free_irq(host->core_irqres->start, host);
4471 free_irq(host->core_irqres->start, host);
4472
4473 clk_put(host->clk);
4474 if (!IS_ERR(host->pclk))
4475 clk_put(host->pclk);
4476 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4477 clk_put(host->dfab_pclk);
4478
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304479 if (host->plat->swfi_latency)
4480 pm_qos_remove_request(&host->pm_qos_req_dma);
4481
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004482 msmsdcc_vreg_init(host, false);
4483
4484 if (host->is_dma_mode) {
4485 if (host->dmares)
4486 dma_free_coherent(NULL,
4487 sizeof(struct msmsdcc_nc_dmadata),
4488 host->dma.nc, host->dma.nc_busaddr);
4489 }
4490
4491 if (host->is_sps_mode) {
4492 msmsdcc_dml_exit(host);
4493 msmsdcc_sps_exit(host);
4494 }
4495
4496 iounmap(host->base);
4497 mmc_free_host(mmc);
4498
4499#ifdef CONFIG_HAS_EARLYSUSPEND
4500 unregister_early_suspend(&host->early_suspend);
4501#endif
4502 pm_runtime_disable(&(pdev)->dev);
4503 pm_runtime_set_suspended(&(pdev)->dev);
4504
4505 return 0;
4506}
4507
4508#ifdef CONFIG_MSM_SDIO_AL
4509int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4510{
4511 struct msmsdcc_host *host = mmc_priv(mmc);
4512 unsigned long flags;
4513
4514 spin_lock_irqsave(&host->lock, flags);
4515 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
4516 enable ? "En" : "Dis");
4517
4518 if (enable) {
4519 if (!host->sdcc_irq_disabled) {
4520 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05304521 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004522 host->sdcc_irq_disabled = 1;
4523 }
4524
4525 if (host->clks_on) {
4526 msmsdcc_setup_clocks(host, false);
4527 host->clks_on = 0;
4528 }
4529
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304530 if (host->plat->sdio_lpm_gpio_setup &&
4531 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004532 spin_unlock_irqrestore(&host->lock, flags);
4533 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
4534 spin_lock_irqsave(&host->lock, flags);
4535 host->sdio_gpio_lpm = 1;
4536 }
4537
4538 if (host->sdio_irq_disabled) {
4539 msmsdcc_enable_irq_wake(host);
4540 enable_irq(host->plat->sdiowakeup_irq);
4541 host->sdio_irq_disabled = 0;
4542 }
4543 } else {
4544 if (!host->sdio_irq_disabled) {
4545 disable_irq_nosync(host->plat->sdiowakeup_irq);
4546 host->sdio_irq_disabled = 1;
4547 msmsdcc_disable_irq_wake(host);
4548 }
4549
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304550 if (host->plat->sdio_lpm_gpio_setup &&
4551 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004552 spin_unlock_irqrestore(&host->lock, flags);
4553 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
4554 spin_lock_irqsave(&host->lock, flags);
4555 host->sdio_gpio_lpm = 0;
4556 }
4557
4558 if (!host->clks_on) {
4559 msmsdcc_setup_clocks(host, true);
4560 host->clks_on = 1;
4561 }
4562
4563 if (host->sdcc_irq_disabled) {
4564 writel_relaxed(host->mci_irqenable,
4565 host->base + MMCIMASK0);
4566 mb();
4567 enable_irq(host->core_irqres->start);
4568 host->sdcc_irq_disabled = 0;
4569 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004570 }
4571 spin_unlock_irqrestore(&host->lock, flags);
4572 return 0;
4573}
4574#else
4575int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4576{
4577 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004578}
4579#endif
4580
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004581#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07004582static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004583msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004584{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004585 struct mmc_host *mmc = dev_get_drvdata(dev);
4586 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07004587 int rc = 0;
4588
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004589 if (host->plat->is_sdio_al_client)
4590 return 0;
Sahitya Tummala7661a452011-07-18 13:28:35 +05304591 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004592 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004593 host->sdcc_suspending = 1;
4594 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07004595
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004596 /*
4597 * If the clocks are already turned off by SDIO clients (as
4598 * part of LPM), then clocks should be turned on before
4599 * calling mmc_suspend_host() because mmc_suspend_host might
4600 * send some commands to the card. The clocks will be turned
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304601 * off again after mmc_suspend_host. Thus for SDIO
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004602 * cards, clocks will be turned on before mmc_suspend_host
4603 * and turned off after mmc_suspend_host.
4604 */
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304605 if (mmc->card && mmc_card_sdio(mmc->card)) {
4606 mmc->ios.clock = host->clk_rate;
4607 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4608 }
San Mehat9d2bd732009-09-22 16:44:22 -07004609
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004610 /*
4611 * MMC core thinks that host is disabled by now since
4612 * runtime suspend is scheduled after msmsdcc_disable()
4613 * is called. Thus, MMC core will try to enable the host
4614 * while suspending it. This results in a synchronous
4615 * runtime resume request while in runtime suspending
4616 * context and hence inorder to complete this resume
4617 * requet, it will wait for suspend to be complete,
4618 * but runtime suspend also can not proceed further
4619 * until the host is resumed. Thus, it leads to a hang.
4620 * Hence, increase the pm usage count before suspending
4621 * the host so that any resume requests after this will
4622 * simple become pm usage counter increment operations.
4623 */
4624 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05304625 /* If there is pending detect work abort runtime suspend */
4626 if (unlikely(work_busy(&mmc->detect.work)))
4627 rc = -EAGAIN;
4628 else
4629 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004630 pm_runtime_put_noidle(dev);
4631
4632 if (!rc) {
4633 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
4634 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ)) {
4635 disable_irq(host->core_irqres->start);
4636 host->sdcc_irq_disabled = 1;
4637
4638 /*
4639 * If MMC core level suspend is not supported,
4640 * turn off clocks to allow deep sleep (TCXO
4641 * shutdown).
4642 */
4643 mmc->ios.clock = 0;
4644 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4645 enable_irq(host->core_irqres->start);
4646 host->sdcc_irq_disabled = 0;
4647
4648 if (host->plat->sdiowakeup_irq) {
4649 host->sdio_irq_disabled = 0;
4650 msmsdcc_enable_irq_wake(host);
4651 enable_irq(host->plat->sdiowakeup_irq);
4652 }
4653 }
4654 }
4655 host->sdcc_suspending = 0;
4656 mmc->suspend_task = NULL;
4657 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
4658 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004659 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05304660 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
San Mehat9d2bd732009-09-22 16:44:22 -07004661 return rc;
4662}
4663
4664static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004665msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004666{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004667 struct mmc_host *mmc = dev_get_drvdata(dev);
4668 struct msmsdcc_host *host = mmc_priv(mmc);
4669 unsigned long flags;
4670
4671 if (host->plat->is_sdio_al_client)
4672 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07004673
Sahitya Tummala7661a452011-07-18 13:28:35 +05304674 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004675 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004676 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
4677 if (host->sdcc_irq_disabled) {
4678 enable_irq(host->core_irqres->start);
4679 host->sdcc_irq_disabled = 0;
4680 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304681 mmc->ios.clock = host->clk_rate;
4682 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07004683
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304684 spin_lock_irqsave(&host->lock, flags);
4685 writel_relaxed(host->mci_irqenable,
4686 host->base + MMCIMASK0);
4687 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07004688
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304689 if ((mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) &&
4690 !host->sdio_irq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004691 if (host->plat->sdiowakeup_irq) {
4692 disable_irq_nosync(
4693 host->plat->sdiowakeup_irq);
4694 msmsdcc_disable_irq_wake(host);
4695 host->sdio_irq_disabled = 1;
4696 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304697 }
San Mehat9d2bd732009-09-22 16:44:22 -07004698
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304699 spin_unlock_irqrestore(&host->lock, flags);
4700 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004701
4702 mmc_resume_host(mmc);
4703
4704 /*
4705 * FIXME: Clearing of flags must be handled in clients
4706 * resume handler.
4707 */
4708 spin_lock_irqsave(&host->lock, flags);
4709 mmc->pm_flags = 0;
4710 spin_unlock_irqrestore(&host->lock, flags);
4711
4712 /*
4713 * After resuming the host wait for sometime so that
4714 * the SDIO work will be processed.
4715 */
4716 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO)) {
4717 if ((host->plat->cfg_mpm_sdiowakeup ||
4718 host->plat->sdiowakeup_irq) &&
4719 wake_lock_active(&host->sdio_wlock))
4720 wake_lock_timeout(&host->sdio_wlock, 1);
4721 }
4722
4723 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004724 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304725 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004726 return 0;
4727}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004728
4729static int msmsdcc_runtime_idle(struct device *dev)
4730{
4731 struct mmc_host *mmc = dev_get_drvdata(dev);
4732 struct msmsdcc_host *host = mmc_priv(mmc);
4733
4734 if (host->plat->is_sdio_al_client)
4735 return 0;
4736
4737 /* Idle timeout is not configurable for now */
4738 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
4739
4740 return -EAGAIN;
4741}
4742
4743static int msmsdcc_pm_suspend(struct device *dev)
4744{
4745 struct mmc_host *mmc = dev_get_drvdata(dev);
4746 struct msmsdcc_host *host = mmc_priv(mmc);
4747 int rc = 0;
4748
4749 if (host->plat->is_sdio_al_client)
4750 return 0;
4751
4752
4753 if (host->plat->status_irq)
4754 disable_irq(host->plat->status_irq);
4755
4756 if (!pm_runtime_suspended(dev))
4757 rc = msmsdcc_runtime_suspend(dev);
4758
4759 return rc;
4760}
4761
4762static int msmsdcc_pm_resume(struct device *dev)
4763{
4764 struct mmc_host *mmc = dev_get_drvdata(dev);
4765 struct msmsdcc_host *host = mmc_priv(mmc);
4766 int rc = 0;
4767
4768 if (host->plat->is_sdio_al_client)
4769 return 0;
4770
Sahitya Tummalafb486372011-09-02 19:01:49 +05304771 if (!pm_runtime_suspended(dev))
4772 rc = msmsdcc_runtime_resume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004773 if (host->plat->status_irq) {
4774 msmsdcc_check_status((unsigned long)host);
4775 enable_irq(host->plat->status_irq);
4776 }
4777
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004778 return rc;
4779}
4780
Daniel Walker08ecfde2010-06-23 12:32:20 -07004781#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004782#define msmsdcc_runtime_suspend NULL
4783#define msmsdcc_runtime_resume NULL
4784#define msmsdcc_runtime_idle NULL
4785#define msmsdcc_pm_suspend NULL
4786#define msmsdcc_pm_resume NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07004787#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004788
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004789static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
4790 .runtime_suspend = msmsdcc_runtime_suspend,
4791 .runtime_resume = msmsdcc_runtime_resume,
4792 .runtime_idle = msmsdcc_runtime_idle,
4793 .suspend = msmsdcc_pm_suspend,
4794 .resume = msmsdcc_pm_resume,
4795};
4796
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304797static const struct of_device_id msmsdcc_dt_match[] = {
4798 {.compatible = "qcom,msm-sdcc"},
4799
4800};
4801MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
4802
San Mehat9d2bd732009-09-22 16:44:22 -07004803static struct platform_driver msmsdcc_driver = {
4804 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004805 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07004806 .driver = {
4807 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004808 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304809 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07004810 },
4811};
4812
4813static int __init msmsdcc_init(void)
4814{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004815#if defined(CONFIG_DEBUG_FS)
4816 int ret = 0;
4817 ret = msmsdcc_dbg_init();
4818 if (ret) {
4819 pr_err("Failed to create debug fs dir \n");
4820 return ret;
4821 }
4822#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004823 return platform_driver_register(&msmsdcc_driver);
4824}
4825
4826static void __exit msmsdcc_exit(void)
4827{
4828 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004829
4830#if defined(CONFIG_DEBUG_FS)
4831 debugfs_remove(debugfs_file);
4832 debugfs_remove(debugfs_dir);
4833#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004834}
4835
4836module_init(msmsdcc_init);
4837module_exit(msmsdcc_exit);
4838
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004839MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07004840MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004841
4842#if defined(CONFIG_DEBUG_FS)
4843
4844static int
4845msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
4846{
4847 file->private_data = inode->i_private;
4848 return 0;
4849}
4850
4851static ssize_t
4852msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
4853 size_t count, loff_t *ppos)
4854{
4855 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08004856 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004857 int max, i;
4858
4859 i = 0;
4860 max = sizeof(buf) - 1;
4861
4862 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
4863 host->curr.cmd, host->curr.data);
4864 if (host->curr.cmd) {
4865 struct mmc_command *cmd = host->curr.cmd;
4866
4867 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
4868 cmd->opcode, cmd->arg, cmd->flags);
4869 }
4870 if (host->curr.data) {
4871 struct mmc_data *data = host->curr.data;
4872 i += scnprintf(buf + i, max - i,
4873 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
4874 data->timeout_ns, data->timeout_clks,
4875 data->blksz, data->blocks, data->error,
4876 data->flags);
4877 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
4878 host->curr.xfer_size, host->curr.xfer_remain,
4879 host->curr.data_xfered, host->dma.sg);
4880 }
4881
4882 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
4883}
4884
4885static const struct file_operations msmsdcc_dbg_state_ops = {
4886 .read = msmsdcc_dbg_state_read,
4887 .open = msmsdcc_dbg_state_open,
4888};
4889
4890static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
4891{
4892 if (debugfs_dir) {
4893 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
4894 0644, debugfs_dir, host,
4895 &msmsdcc_dbg_state_ops);
4896 }
4897}
4898
4899static int __init msmsdcc_dbg_init(void)
4900{
4901 int err;
4902
4903 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
4904 if (IS_ERR(debugfs_dir)) {
4905 err = PTR_ERR(debugfs_dir);
4906 debugfs_dir = NULL;
4907 return err;
4908 }
4909
4910 return 0;
4911}
4912#endif