blob: 0d2b11d0fbfd89fb5be32c7ebd680d0d5db16606 [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 Jadavani34187042012-03-02 10:59:49 +05302880static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302881 u8 *phase_table, u8 total_phases)
2882{
Subhash Jadavani34187042012-03-02 10:59:49 +05302883 int ret;
2884 u8 ranges[16][16] = { {0}, {0} };
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302885 u8 phases_per_row[16] = {0};
2886 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05302887 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
2888 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302889
Subhash Jadavani34187042012-03-02 10:59:49 +05302890 if (total_phases > 16) {
2891 pr_err("%s: %s: invalid argument: total_phases=%d\n",
2892 mmc_hostname(host->mmc), __func__, total_phases);
2893 return -EINVAL;
2894 }
2895
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05302896 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302897 ranges[row_index][col_index] = phase_table[cnt];
2898 phases_per_row[row_index] += 1;
2899 col_index++;
2900
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05302901 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302902 continue;
2903 /* check if next phase in phase_table is consecutive or not */
2904 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
2905 row_index++;
2906 col_index = 0;
2907 }
2908 }
2909
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05302910 /* Check if phase-0 is present in first valid window? */
2911 if (!ranges[0][0]) {
2912 phase_0_found = true;
2913 phase_0_raw_index = 0;
2914 /* Check if cycle exist between 2 valid windows */
2915 for (cnt = 1; cnt <= row_index; cnt++) {
2916 if (phases_per_row[cnt]) {
2917 for (i = 0; i <= phases_per_row[cnt]; i++) {
2918 if (ranges[cnt][i] == 15) {
2919 phase_15_found = true;
2920 phase_15_raw_index = cnt;
2921 break;
2922 }
2923 }
2924 }
2925 }
2926 }
2927
2928 /* If 2 valid windows form cycle then merge them as single window */
2929 if (phase_0_found && phase_15_found) {
2930 /* number of phases in raw where phase 0 is present */
2931 u8 phases_0 = phases_per_row[phase_0_raw_index];
2932 /* number of phases in raw where phase 15 is present */
2933 u8 phases_15 = phases_per_row[phase_15_raw_index];
2934
2935 cnt = 0;
2936 for (i = phases_15; i < (phases_15 + phases_0); i++) {
2937 ranges[phase_15_raw_index][i] =
2938 ranges[phase_0_raw_index][cnt];
2939 cnt++;
2940 }
2941 phases_per_row[phase_0_raw_index] = 0;
2942 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
2943 }
2944
2945 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302946 if (phases_per_row[cnt] > curr_max) {
2947 curr_max = phases_per_row[cnt];
2948 selected_row_index = cnt;
2949 }
2950 }
2951
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05302952 i = ((curr_max * 3) / 4) - 1;
Subhash Jadavani34187042012-03-02 10:59:49 +05302953 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302954
2955 return ret;
2956}
2957
2958static int msmsdcc_execute_tuning(struct mmc_host *mmc)
2959{
2960 int rc = 0;
2961 struct msmsdcc_host *host = mmc_priv(mmc);
2962 unsigned long flags;
2963 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
2964
2965 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
2966
2967 /* Tuning is only required for SDR104 modes */
2968 if (!host->tuning_needed) {
2969 rc = 0;
2970 goto exit;
2971 }
2972
2973 spin_lock_irqsave(&host->lock, flags);
2974 WARN(!host->pwr, "SDCC power is turned off\n");
2975 WARN(!host->clks_on, "SDCC clocks are turned off\n");
2976 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
2977
2978 host->cmd19_tuning_in_progress = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302979 msmsdcc_delay(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302980 spin_unlock_irqrestore(&host->lock, flags);
2981
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002982 /* first of all reset the tuning block */
2983 rc = msmsdcc_init_cm_sdc4_dll(host);
2984 if (rc)
2985 goto out;
2986
2987 data_buf = kmalloc(64, GFP_KERNEL);
2988 if (!data_buf) {
2989 rc = -ENOMEM;
2990 goto out;
2991 }
2992
2993 phase = 0;
2994 do {
2995 struct mmc_command cmd = {0};
2996 struct mmc_data data = {0};
2997 struct mmc_request mrq = {
2998 .cmd = &cmd,
2999 .data = &data
3000 };
3001 struct scatterlist sg;
3002
3003 /* set the phase in delay line hw block */
3004 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3005 if (rc)
3006 goto kfree;
3007
3008 cmd.opcode = MMC_SEND_TUNING_BLOCK;
3009 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
3010
3011 data.blksz = 64;
3012 data.blocks = 1;
3013 data.flags = MMC_DATA_READ;
3014 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
3015
3016 data.sg = &sg;
3017 data.sg_len = 1;
3018 sg_init_one(&sg, data_buf, 64);
3019 memset(data_buf, 0, 64);
3020 mmc_wait_for_req(mmc, &mrq);
3021
3022 if (!cmd.error && !data.error &&
3023 !memcmp(data_buf, cmd19_tuning_block, 64)) {
3024 /* tuning is successful with this tuning point */
3025 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303026 pr_debug("%s: %s: found good phase = %d\n",
3027 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003028 }
3029 } while (++phase < 16);
3030
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003031 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303032 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303033 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05303034 if (rc < 0)
3035 goto kfree;
3036 else
3037 phase = (u8)rc;
3038
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003039 /*
3040 * Finally set the selected phase in delay
3041 * line hw block.
3042 */
3043 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3044 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303045 goto kfree;
3046 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
3047 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003048 } else {
3049 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303050 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003051 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303052 msmsdcc_dump_sdcc_state(host);
3053 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003054 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003055
3056kfree:
3057 kfree(data_buf);
3058out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303059 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05303060 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003061 host->cmd19_tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303062 spin_unlock_irqrestore(&host->lock, flags);
3063exit:
3064 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003065 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07003066}
3067
3068static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003069 .enable = msmsdcc_enable,
3070 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07003071 .request = msmsdcc_request,
3072 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003073 .get_ro = msmsdcc_get_ro,
3074#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07003075 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003076#endif
3077 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
3078 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07003079};
3080
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003081static unsigned int
3082msmsdcc_slot_status(struct msmsdcc_host *host)
3083{
3084 int status;
3085 unsigned int gpio_no = host->plat->status_gpio;
3086
3087 status = gpio_request(gpio_no, "SD_HW_Detect");
3088 if (status) {
3089 pr_err("%s: %s: Failed to request GPIO %d\n",
3090 mmc_hostname(host->mmc), __func__, gpio_no);
3091 } else {
3092 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003093 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08003094 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003095 if (host->plat->is_status_gpio_active_low)
3096 status = !status;
3097 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003098 gpio_free(gpio_no);
3099 }
3100 return status;
3101}
3102
San Mehat9d2bd732009-09-22 16:44:22 -07003103static void
3104msmsdcc_check_status(unsigned long data)
3105{
3106 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3107 unsigned int status;
3108
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003109 if (host->plat->status || host->plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08003110 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003111 status = host->plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08003112 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003113 status = msmsdcc_slot_status(host);
3114
Krishna Konda941604a2012-01-10 17:46:34 -08003115 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08003116
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003117 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08003118 if (host->plat->status)
3119 pr_info("%s: Slot status change detected "
3120 "(%d -> %d)\n",
3121 mmc_hostname(host->mmc),
3122 host->oldstat, status);
3123 else if (host->plat->is_status_gpio_active_low)
3124 pr_info("%s: Slot status change detected "
3125 "(%d -> %d) and the card detect GPIO"
3126 " is ACTIVE_LOW\n",
3127 mmc_hostname(host->mmc),
3128 host->oldstat, status);
3129 else
3130 pr_info("%s: Slot status change detected "
3131 "(%d -> %d) and the card detect GPIO"
3132 " is ACTIVE_HIGH\n",
3133 mmc_hostname(host->mmc),
3134 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07003135 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003136 }
3137 host->oldstat = status;
3138 } else {
3139 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07003140 }
San Mehat9d2bd732009-09-22 16:44:22 -07003141}
3142
3143static irqreturn_t
3144msmsdcc_platform_status_irq(int irq, void *dev_id)
3145{
3146 struct msmsdcc_host *host = dev_id;
3147
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003148 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07003149 msmsdcc_check_status((unsigned long) host);
3150 return IRQ_HANDLED;
3151}
3152
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003153static irqreturn_t
3154msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
3155{
3156 struct msmsdcc_host *host = dev_id;
3157
3158 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
3159 spin_lock(&host->lock);
3160 if (!host->sdio_irq_disabled) {
3161 disable_irq_nosync(irq);
3162 if (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
3163 wake_lock(&host->sdio_wlock);
3164 msmsdcc_disable_irq_wake(host);
3165 }
3166 host->sdio_irq_disabled = 1;
3167 }
3168 if (host->plat->is_sdio_al_client) {
3169 if (!host->clks_on) {
3170 msmsdcc_setup_clocks(host, true);
3171 host->clks_on = 1;
3172 }
3173 if (host->sdcc_irq_disabled) {
3174 writel_relaxed(host->mci_irqenable,
3175 host->base + MMCIMASK0);
3176 mb();
3177 enable_irq(host->core_irqres->start);
3178 host->sdcc_irq_disabled = 0;
3179 }
3180 wake_lock(&host->sdio_wlock);
3181 }
3182 spin_unlock(&host->lock);
3183
3184 return IRQ_HANDLED;
3185}
3186
San Mehat9d2bd732009-09-22 16:44:22 -07003187static void
3188msmsdcc_status_notify_cb(int card_present, void *dev_id)
3189{
3190 struct msmsdcc_host *host = dev_id;
3191
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003192 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07003193 card_present);
3194 msmsdcc_check_status((unsigned long) host);
3195}
3196
San Mehat9d2bd732009-09-22 16:44:22 -07003197static int
3198msmsdcc_init_dma(struct msmsdcc_host *host)
3199{
3200 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
3201 host->dma.host = host;
3202 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003203 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003204
3205 if (!host->dmares)
3206 return -ENODEV;
3207
3208 host->dma.nc = dma_alloc_coherent(NULL,
3209 sizeof(struct msmsdcc_nc_dmadata),
3210 &host->dma.nc_busaddr,
3211 GFP_KERNEL);
3212 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003213 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07003214 return -ENOMEM;
3215 }
3216 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
3217 host->dma.cmd_busaddr = host->dma.nc_busaddr;
3218 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
3219 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
3220 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07003221 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07003222
3223 return 0;
3224}
3225
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003226#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
3227/**
3228 * Allocate and Connect a SDCC peripheral's SPS endpoint
3229 *
3230 * This function allocates endpoint context and
3231 * connect it with memory endpoint by calling
3232 * appropriate SPS driver APIs.
3233 *
3234 * Also registers a SPS callback function with
3235 * SPS driver
3236 *
3237 * This function should only be called once typically
3238 * during driver probe.
3239 *
3240 * @host - Pointer to sdcc host structure
3241 * @ep - Pointer to sps endpoint data structure
3242 * @is_produce - 1 means Producer endpoint
3243 * 0 means Consumer endpoint
3244 *
3245 * @return - 0 if successful else negative value.
3246 *
3247 */
3248static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
3249 struct msmsdcc_sps_ep_conn_data *ep,
3250 bool is_producer)
3251{
3252 int rc = 0;
3253 struct sps_pipe *sps_pipe_handle;
3254 struct sps_connect *sps_config = &ep->config;
3255 struct sps_register_event *sps_event = &ep->event;
3256
3257 /* Allocate endpoint context */
3258 sps_pipe_handle = sps_alloc_endpoint();
3259 if (!sps_pipe_handle) {
3260 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
3261 mmc_hostname(host->mmc), is_producer);
3262 rc = -ENOMEM;
3263 goto out;
3264 }
3265
3266 /* Get default connection configuration for an endpoint */
3267 rc = sps_get_config(sps_pipe_handle, sps_config);
3268 if (rc) {
3269 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
3270 " rc=%d", mmc_hostname(host->mmc),
3271 (u32)sps_pipe_handle, rc);
3272 goto get_config_err;
3273 }
3274
3275 /* Modify the default connection configuration */
3276 if (is_producer) {
3277 /*
3278 * For SDCC producer transfer, source should be
3279 * SDCC peripheral where as destination should
3280 * be system memory.
3281 */
3282 sps_config->source = host->sps.bam_handle;
3283 sps_config->destination = SPS_DEV_HANDLE_MEM;
3284 /* Producer pipe will handle this connection */
3285 sps_config->mode = SPS_MODE_SRC;
3286 sps_config->options =
3287 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3288 } else {
3289 /*
3290 * For SDCC consumer transfer, source should be
3291 * system memory where as destination should
3292 * SDCC peripheral
3293 */
3294 sps_config->source = SPS_DEV_HANDLE_MEM;
3295 sps_config->destination = host->sps.bam_handle;
3296 sps_config->mode = SPS_MODE_DEST;
3297 sps_config->options =
3298 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3299 }
3300
3301 /* Producer pipe index */
3302 sps_config->src_pipe_index = host->sps.src_pipe_index;
3303 /* Consumer pipe index */
3304 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
3305 /*
3306 * This event thresold value is only significant for BAM-to-BAM
3307 * transfer. It's ignored for BAM-to-System mode transfer.
3308 */
3309 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05303310
3311 /* Allocate maximum descriptor fifo size */
3312 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
3313 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003314 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
3315 sps_config->desc.size,
3316 &sps_config->desc.phys_base,
3317 GFP_KERNEL);
3318
Pratibhasagar V00b94332011-10-18 14:57:27 +05303319 if (!sps_config->desc.base) {
3320 rc = -ENOMEM;
3321 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3322 , mmc_hostname(host->mmc));
3323 goto get_config_err;
3324 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003325 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3326
3327 /* Establish connection between peripheral and memory endpoint */
3328 rc = sps_connect(sps_pipe_handle, sps_config);
3329 if (rc) {
3330 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3331 " rc=%d", mmc_hostname(host->mmc),
3332 (u32)sps_pipe_handle, rc);
3333 goto sps_connect_err;
3334 }
3335
3336 sps_event->mode = SPS_TRIGGER_CALLBACK;
3337 sps_event->options = SPS_O_EOT;
3338 sps_event->callback = msmsdcc_sps_complete_cb;
3339 sps_event->xfer_done = NULL;
3340 sps_event->user = (void *)host;
3341
3342 /* Register callback event for EOT (End of transfer) event. */
3343 rc = sps_register_event(sps_pipe_handle, sps_event);
3344 if (rc) {
3345 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3346 " rc=%d", mmc_hostname(host->mmc),
3347 (u32)sps_pipe_handle, rc);
3348 goto reg_event_err;
3349 }
3350 /* Now save the sps pipe handle */
3351 ep->pipe_handle = sps_pipe_handle;
3352 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3353 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3354 __func__, is_producer ? "READ" : "WRITE",
3355 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3356 goto out;
3357
3358reg_event_err:
3359 sps_disconnect(sps_pipe_handle);
3360sps_connect_err:
3361 dma_free_coherent(mmc_dev(host->mmc),
3362 sps_config->desc.size,
3363 sps_config->desc.base,
3364 sps_config->desc.phys_base);
3365get_config_err:
3366 sps_free_endpoint(sps_pipe_handle);
3367out:
3368 return rc;
3369}
3370
3371/**
3372 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3373 *
3374 * This function disconnect endpoint and deallocates
3375 * endpoint context.
3376 *
3377 * This function should only be called once typically
3378 * during driver remove.
3379 *
3380 * @host - Pointer to sdcc host structure
3381 * @ep - Pointer to sps endpoint data structure
3382 *
3383 */
3384static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3385 struct msmsdcc_sps_ep_conn_data *ep)
3386{
3387 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3388 struct sps_connect *sps_config = &ep->config;
3389 struct sps_register_event *sps_event = &ep->event;
3390
3391 sps_event->xfer_done = NULL;
3392 sps_event->callback = NULL;
3393 sps_register_event(sps_pipe_handle, sps_event);
3394 sps_disconnect(sps_pipe_handle);
3395 dma_free_coherent(mmc_dev(host->mmc),
3396 sps_config->desc.size,
3397 sps_config->desc.base,
3398 sps_config->desc.phys_base);
3399 sps_free_endpoint(sps_pipe_handle);
3400}
3401
3402/**
3403 * Reset SDCC peripheral's SPS endpoint
3404 *
3405 * This function disconnects an endpoint.
3406 *
3407 * This function should be called for reseting
3408 * SPS endpoint when data transfer error is
3409 * encountered during data transfer. This
3410 * can be considered as soft reset to endpoint.
3411 *
3412 * This function should only be called if
3413 * msmsdcc_sps_init() is already called.
3414 *
3415 * @host - Pointer to sdcc host structure
3416 * @ep - Pointer to sps endpoint data structure
3417 *
3418 * @return - 0 if successful else negative value.
3419 */
3420static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3421 struct msmsdcc_sps_ep_conn_data *ep)
3422{
3423 int rc = 0;
3424 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3425
3426 rc = sps_disconnect(sps_pipe_handle);
3427 if (rc) {
3428 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3429 " rc=%d", mmc_hostname(host->mmc), __func__,
3430 (u32)sps_pipe_handle, rc);
3431 goto out;
3432 }
3433 out:
3434 return rc;
3435}
3436
3437/**
3438 * Restore SDCC peripheral's SPS endpoint
3439 *
3440 * This function connects an endpoint.
3441 *
3442 * This function should be called for restoring
3443 * SPS endpoint after data transfer error is
3444 * encountered during data transfer. This
3445 * can be considered as soft reset to endpoint.
3446 *
3447 * This function should only be called if
3448 * msmsdcc_sps_reset_ep() is called before.
3449 *
3450 * @host - Pointer to sdcc host structure
3451 * @ep - Pointer to sps endpoint data structure
3452 *
3453 * @return - 0 if successful else negative value.
3454 */
3455static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3456 struct msmsdcc_sps_ep_conn_data *ep)
3457{
3458 int rc = 0;
3459 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3460 struct sps_connect *sps_config = &ep->config;
3461 struct sps_register_event *sps_event = &ep->event;
3462
3463 /* Establish connection between peripheral and memory endpoint */
3464 rc = sps_connect(sps_pipe_handle, sps_config);
3465 if (rc) {
3466 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3467 " rc=%d", mmc_hostname(host->mmc), __func__,
3468 (u32)sps_pipe_handle, rc);
3469 goto out;
3470 }
3471
3472 /* Register callback event for EOT (End of transfer) event. */
3473 rc = sps_register_event(sps_pipe_handle, sps_event);
3474 if (rc) {
3475 pr_err("%s: %s: sps_register_event() failed!!!"
3476 " pipe_handle=0x%x, rc=%d",
3477 mmc_hostname(host->mmc), __func__,
3478 (u32)sps_pipe_handle, rc);
3479 goto reg_event_err;
3480 }
3481 goto out;
3482
3483reg_event_err:
3484 sps_disconnect(sps_pipe_handle);
3485out:
3486 return rc;
3487}
3488
3489/**
3490 * Initialize SPS HW connected with SDCC core
3491 *
3492 * This function register BAM HW resources with
3493 * SPS driver and then initialize 2 SPS endpoints
3494 *
3495 * This function should only be called once typically
3496 * during driver probe.
3497 *
3498 * @host - Pointer to sdcc host structure
3499 *
3500 * @return - 0 if successful else negative value.
3501 *
3502 */
3503static int msmsdcc_sps_init(struct msmsdcc_host *host)
3504{
3505 int rc = 0;
3506 struct sps_bam_props bam = {0};
3507
3508 host->bam_base = ioremap(host->bam_memres->start,
3509 resource_size(host->bam_memres));
3510 if (!host->bam_base) {
3511 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3512 " size=0x%x", mmc_hostname(host->mmc),
3513 host->bam_memres->start,
3514 (host->bam_memres->end -
3515 host->bam_memres->start));
3516 rc = -ENOMEM;
3517 goto out;
3518 }
3519
3520 bam.phys_addr = host->bam_memres->start;
3521 bam.virt_addr = host->bam_base;
3522 /*
3523 * This event thresold value is only significant for BAM-to-BAM
3524 * transfer. It's ignored for BAM-to-System mode transfer.
3525 */
3526 bam.event_threshold = 0x10; /* Pipe event threshold */
3527 /*
3528 * This threshold controls when the BAM publish
3529 * the descriptor size on the sideband interface.
3530 * SPS HW will only be used when
3531 * data transfer size > MCI_FIFOSIZE (64 bytes).
3532 * PIO mode will be used when
3533 * data transfer size < MCI_FIFOSIZE (64 bytes).
3534 * So set this thresold value to 64 bytes.
3535 */
3536 bam.summing_threshold = 64;
3537 /* SPS driver wll handle the SDCC BAM IRQ */
3538 bam.irq = (u32)host->bam_irqres->start;
3539 bam.manage = SPS_BAM_MGR_LOCAL;
3540
3541 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3542 (u32)bam.phys_addr);
3543 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3544 (u32)bam.virt_addr);
3545
3546 /* Register SDCC Peripheral BAM device to SPS driver */
3547 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3548 if (rc) {
3549 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3550 mmc_hostname(host->mmc), rc);
3551 goto reg_bam_err;
3552 }
3553 pr_info("%s: BAM device registered. bam_handle=0x%x",
3554 mmc_hostname(host->mmc), host->sps.bam_handle);
3555
3556 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3557 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3558
3559 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3560 SPS_PROD_PERIPHERAL);
3561 if (rc)
3562 goto sps_reset_err;
3563 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3564 SPS_CONS_PERIPHERAL);
3565 if (rc)
3566 goto cons_conn_err;
3567
3568 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3569 mmc_hostname(host->mmc),
3570 (unsigned long long)host->bam_memres->start,
3571 (unsigned int)host->bam_irqres->start);
3572 goto out;
3573
3574cons_conn_err:
3575 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3576sps_reset_err:
3577 sps_deregister_bam_device(host->sps.bam_handle);
3578reg_bam_err:
3579 iounmap(host->bam_base);
3580out:
3581 return rc;
3582}
3583
3584/**
3585 * De-initialize SPS HW connected with SDCC core
3586 *
3587 * This function deinitialize SPS endpoints and then
3588 * deregisters BAM resources from SPS driver.
3589 *
3590 * This function should only be called once typically
3591 * during driver remove.
3592 *
3593 * @host - Pointer to sdcc host structure
3594 *
3595 */
3596static void msmsdcc_sps_exit(struct msmsdcc_host *host)
3597{
3598 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
3599 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3600 sps_deregister_bam_device(host->sps.bam_handle);
3601 iounmap(host->bam_base);
3602}
3603#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
3604
3605static ssize_t
3606show_polling(struct device *dev, struct device_attribute *attr, char *buf)
3607{
3608 struct mmc_host *mmc = dev_get_drvdata(dev);
3609 struct msmsdcc_host *host = mmc_priv(mmc);
3610 int poll;
3611 unsigned long flags;
3612
3613 spin_lock_irqsave(&host->lock, flags);
3614 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
3615 spin_unlock_irqrestore(&host->lock, flags);
3616
3617 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
3618}
3619
3620static ssize_t
3621set_polling(struct device *dev, struct device_attribute *attr,
3622 const char *buf, size_t count)
3623{
3624 struct mmc_host *mmc = dev_get_drvdata(dev);
3625 struct msmsdcc_host *host = mmc_priv(mmc);
3626 int value;
3627 unsigned long flags;
3628
3629 sscanf(buf, "%d", &value);
3630
3631 spin_lock_irqsave(&host->lock, flags);
3632 if (value) {
3633 mmc->caps |= MMC_CAP_NEEDS_POLL;
3634 mmc_detect_change(host->mmc, 0);
3635 } else {
3636 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3637 }
3638#ifdef CONFIG_HAS_EARLYSUSPEND
3639 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
3640#endif
3641 spin_unlock_irqrestore(&host->lock, flags);
3642 return count;
3643}
3644
3645static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
3646 show_polling, set_polling);
3647static struct attribute *dev_attrs[] = {
3648 &dev_attr_polling.attr,
3649 NULL,
3650};
3651static struct attribute_group dev_attr_grp = {
3652 .attrs = dev_attrs,
3653};
3654
3655#ifdef CONFIG_HAS_EARLYSUSPEND
3656static void msmsdcc_early_suspend(struct early_suspend *h)
3657{
3658 struct msmsdcc_host *host =
3659 container_of(h, struct msmsdcc_host, early_suspend);
3660 unsigned long flags;
3661
3662 spin_lock_irqsave(&host->lock, flags);
3663 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
3664 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3665 spin_unlock_irqrestore(&host->lock, flags);
3666};
3667static void msmsdcc_late_resume(struct early_suspend *h)
3668{
3669 struct msmsdcc_host *host =
3670 container_of(h, struct msmsdcc_host, early_suspend);
3671 unsigned long flags;
3672
3673 if (host->polling_enabled) {
3674 spin_lock_irqsave(&host->lock, flags);
3675 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
3676 mmc_detect_change(host->mmc, 0);
3677 spin_unlock_irqrestore(&host->lock, flags);
3678 }
3679};
3680#endif
3681
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303682void msmsdcc_print_regs(const char *name, void __iomem *base,
3683 unsigned int no_of_regs)
3684{
3685 unsigned int i;
3686
3687 if (!base)
3688 return;
3689 pr_info("===== %s: Register Dumps @base=0x%x =====\n",
3690 name, (u32)base);
3691 for (i = 0; i < no_of_regs; i = i + 4) {
3692 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x.\n", i*4,
3693 (u32)readl_relaxed(base + i*4),
3694 (u32)readl_relaxed(base + ((i+1)*4)),
3695 (u32)readl_relaxed(base + ((i+2)*4)),
3696 (u32)readl_relaxed(base + ((i+3)*4)));
3697 }
3698}
3699
3700static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
3701{
3702 /* Dump current state of SDCC clocks, power and irq */
3703 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
3704 (host->pwr ? "ON" : "OFF"));
3705 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
3706 mmc_hostname(host->mmc),
3707 (host->clks_on ? "ON" : "OFF"),
3708 (u32)clk_get_rate(host->clk));
3709 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
3710 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
3711
3712 /* Now dump SDCC registers. Don't print FIFO registers */
3713 if (host->clks_on)
3714 msmsdcc_print_regs("SDCC-CORE", host->base, 28);
3715
3716 if (host->curr.data) {
3717 if (msmsdcc_check_dma_op_req(host->curr.data))
3718 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
3719 else if (host->is_dma_mode)
3720 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
3721 mmc_hostname(host->mmc), host->dma.busy,
3722 host->dma.channel, host->dma.crci);
3723 else if (host->is_sps_mode)
3724 pr_info("%s: SPS mode: busy=%d\n",
3725 mmc_hostname(host->mmc), host->sps.busy);
3726
3727 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
3728 mmc_hostname(host->mmc), host->curr.xfer_size,
3729 host->curr.data_xfered, host->curr.xfer_remain);
3730 pr_info("%s: got_dataend=%d, prog_enable=%d,"
3731 " wait_for_auto_prog_done=%d,"
3732 " got_auto_prog_done=%d\n",
3733 mmc_hostname(host->mmc), host->curr.got_dataend,
3734 host->prog_enable, host->curr.wait_for_auto_prog_done,
3735 host->curr.got_auto_prog_done);
3736 }
3737
3738}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003739static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
3740{
3741 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3742 struct mmc_request *mrq;
3743 unsigned long flags;
3744
3745 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003746 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003747 pr_info("%s: %s: dummy CMD52 timeout\n",
3748 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003749 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003750 }
3751
3752 mrq = host->curr.mrq;
3753
3754 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303755 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
3756 mrq->cmd->opcode);
3757 msmsdcc_dump_sdcc_state(host);
3758
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003759 if (!mrq->cmd->error)
3760 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303761 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003762 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003763 if (mrq->data && !mrq->data->error)
3764 mrq->data->error = -ETIMEDOUT;
3765 host->curr.data_xfered = 0;
3766 if (host->dma.sg && host->is_dma_mode) {
3767 msm_dmov_stop_cmd(host->dma.channel,
3768 &host->dma.hdr, 0);
3769 } else if (host->sps.sg && host->is_sps_mode) {
3770 /* Stop current SPS transfer */
3771 msmsdcc_sps_exit_curr_xfer(host);
3772 } else {
3773 msmsdcc_reset_and_restore(host);
3774 msmsdcc_stop_data(host);
3775 if (mrq->data && mrq->data->stop)
3776 msmsdcc_start_command(host,
3777 mrq->data->stop, 0);
3778 else
3779 msmsdcc_request_end(host, mrq);
3780 }
3781 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05303782 host->prog_enable = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003783 msmsdcc_reset_and_restore(host);
3784 msmsdcc_request_end(host, mrq);
3785 }
3786 }
3787 spin_unlock_irqrestore(&host->lock, flags);
3788}
3789
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303790static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
3791{
3792 int i, ret;
3793 struct mmc_platform_data *pdata;
3794 struct device_node *np = dev->of_node;
3795 u32 bus_width = 0;
3796 u32 *clk_table;
3797 int clk_table_len;
3798 u32 *sup_voltages;
3799 int sup_volt_len;
3800
3801 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
3802 if (!pdata) {
3803 dev_err(dev, "could not allocate memory for platform data\n");
3804 goto err;
3805 }
3806
3807 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
3808 if (bus_width == 8) {
3809 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
3810 } else if (bus_width == 4) {
3811 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
3812 } else {
3813 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
3814 pdata->mmc_bus_width = 0;
3815 }
3816
3817 if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
3818 size_t sz;
3819 sz = sup_volt_len / sizeof(*sup_voltages);
3820 if (sz > 0) {
3821 sup_voltages = devm_kzalloc(dev,
3822 sz * sizeof(*sup_voltages), GFP_KERNEL);
3823 if (!sup_voltages) {
3824 dev_err(dev, "No memory for supported voltage\n");
3825 goto err;
3826 }
3827
3828 ret = of_property_read_u32_array(np,
3829 "qcom,sdcc-sup-voltages", sup_voltages, sz);
3830 if (ret < 0) {
3831 dev_err(dev, "error while reading voltage"
3832 "ranges %d\n", ret);
3833 goto err;
3834 }
3835 } else {
3836 dev_err(dev, "No supported voltages\n");
3837 goto err;
3838 }
3839 for (i = 0; i < sz; i += 2) {
3840 u32 mask;
3841
3842 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
3843 sup_voltages[i + 1]);
3844 if (!mask)
3845 dev_err(dev, "Invalide voltage range %d\n", i);
3846 pdata->ocr_mask |= mask;
3847 }
3848 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
3849 } else {
3850 dev_err(dev, "Supported voltage range not specified\n");
3851 }
3852
3853 if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
3854 size_t sz;
3855 sz = clk_table_len / sizeof(*clk_table);
3856
3857 if (sz > 0) {
3858 clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
3859 GFP_KERNEL);
3860 if (!clk_table) {
3861 dev_err(dev, "No memory for clock table\n");
3862 goto err;
3863 }
3864
3865 ret = of_property_read_u32_array(np,
3866 "qcom,sdcc-clk-rates", clk_table, sz);
3867 if (ret < 0) {
3868 dev_err(dev, "error while reading clk"
3869 "table %d\n", ret);
3870 goto err;
3871 }
3872 } else {
3873 dev_err(dev, "clk_table not specified\n");
3874 goto err;
3875 }
3876 pdata->sup_clk_table = clk_table;
3877 pdata->sup_clk_cnt = sz;
3878 } else {
3879 dev_err(dev, "Supported clock rates not specified\n");
3880 }
3881
3882 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
3883 pdata->nonremovable = true;
3884 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
3885 pdata->disable_cmd23 = true;
3886
3887 return pdata;
3888err:
3889 return NULL;
3890}
3891
San Mehat9d2bd732009-09-22 16:44:22 -07003892static int
3893msmsdcc_probe(struct platform_device *pdev)
3894{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303895 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07003896 struct msmsdcc_host *host;
3897 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003898 unsigned long flags;
3899 struct resource *core_irqres = NULL;
3900 struct resource *bam_irqres = NULL;
3901 struct resource *core_memres = NULL;
3902 struct resource *dml_memres = NULL;
3903 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07003904 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07003905 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05303906 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003907 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07003908
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303909 if (pdev->dev.of_node) {
3910 plat = msmsdcc_populate_pdata(&pdev->dev);
3911 of_property_read_u32((&pdev->dev)->of_node,
3912 "cell-index", &pdev->id);
3913 } else {
3914 plat = pdev->dev.platform_data;
3915 }
3916
San Mehat9d2bd732009-09-22 16:44:22 -07003917 /* must have platform data */
3918 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003919 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003920 ret = -EINVAL;
3921 goto out;
3922 }
3923
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003924 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07003925 return -EINVAL;
3926
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05303927 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
3928 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
3929 return -EINVAL;
3930 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003931
San Mehat9d2bd732009-09-22 16:44:22 -07003932 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003933 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003934 return -ENXIO;
3935 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303936 if (pdev->dev.of_node) {
3937 /*
3938 * Device tree iomem resources are only accessible by index.
3939 * index = 0 -> SDCC register interface
3940 * index = 1 -> DML register interface
3941 * index = 2 -> BAM register interface
3942 * IRQ resources:
3943 * index = 0 -> SDCC IRQ
3944 * index = 1 -> BAM IRQ
3945 */
3946 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
3947 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
3948 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
3949 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
3950 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
3951 } else {
3952 for (i = 0; i < pdev->num_resources; i++) {
3953 if (pdev->resource[i].flags & IORESOURCE_MEM) {
3954 if (!strncmp(pdev->resource[i].name,
3955 "sdcc_dml_addr",
3956 sizeof("sdcc_dml_addr")))
3957 dml_memres = &pdev->resource[i];
3958 else if (!strncmp(pdev->resource[i].name,
3959 "sdcc_bam_addr",
3960 sizeof("sdcc_bam_addr")))
3961 bam_memres = &pdev->resource[i];
3962 else
3963 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07003964
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303965 }
3966 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
3967 if (!strncmp(pdev->resource[i].name,
3968 "sdcc_bam_irq",
3969 sizeof("sdcc_bam_irq")))
3970 bam_irqres = &pdev->resource[i];
3971 else
3972 core_irqres = &pdev->resource[i];
3973 }
3974 if (pdev->resource[i].flags & IORESOURCE_DMA) {
3975 if (!strncmp(pdev->resource[i].name,
3976 "sdcc_dma_chnl",
3977 sizeof("sdcc_dma_chnl")))
3978 dmares = &pdev->resource[i];
3979 else if (!strncmp(pdev->resource[i].name,
3980 "sdcc_dma_crci",
3981 sizeof("sdcc_dma_crci")))
3982 dma_crci_res = &pdev->resource[i];
3983 }
Krishna Konda25786ec2011-07-25 16:21:36 -07003984 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003985 }
3986
3987 if (!core_irqres || !core_memres) {
3988 pr_err("%s: Invalid sdcc core resource\n", __func__);
3989 return -ENXIO;
3990 }
3991
3992 /*
3993 * Both BAM and DML memory resource should be preset.
3994 * BAM IRQ resource should also be present.
3995 */
3996 if ((bam_memres && !dml_memres) ||
3997 (!bam_memres && dml_memres) ||
3998 ((bam_memres && dml_memres) && !bam_irqres)) {
3999 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004000 return -ENXIO;
4001 }
4002
4003 /*
4004 * Setup our host structure
4005 */
San Mehat9d2bd732009-09-22 16:44:22 -07004006 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
4007 if (!mmc) {
4008 ret = -ENOMEM;
4009 goto out;
4010 }
4011
4012 host = mmc_priv(mmc);
4013 host->pdev_id = pdev->id;
4014 host->plat = plat;
4015 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08004016 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05304017
4018 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004019 host->is_sps_mode = 1;
4020 else if (dmares)
4021 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07004022
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004023 host->base = ioremap(core_memres->start,
4024 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07004025 if (!host->base) {
4026 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004027 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004028 }
4029
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004030 host->core_irqres = core_irqres;
4031 host->bam_irqres = bam_irqres;
4032 host->core_memres = core_memres;
4033 host->dml_memres = dml_memres;
4034 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07004035 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07004036 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07004037 spin_lock_init(&host->lock);
4038
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004039#ifdef CONFIG_MMC_EMBEDDED_SDIO
4040 if (plat->embedded_sdio)
4041 mmc_set_embedded_sdio_data(mmc,
4042 &plat->embedded_sdio->cis,
4043 &plat->embedded_sdio->cccr,
4044 plat->embedded_sdio->funcs,
4045 plat->embedded_sdio->num_funcs);
4046#endif
4047
Sahitya Tummala62612cf2010-12-08 15:03:03 +05304048 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
4049 (unsigned long)host);
4050
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004051 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
4052 (unsigned long)host);
4053 if (host->is_dma_mode) {
4054 /* Setup DMA */
4055 ret = msmsdcc_init_dma(host);
4056 if (ret)
4057 goto ioremap_free;
4058 } else {
4059 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004060 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004061 }
4062
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004063 /*
4064 * Setup SDCC clock if derived from Dayatona
4065 * fabric core clock.
4066 */
4067 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07004068 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004069 if (!IS_ERR(host->dfab_pclk)) {
4070 /* Set the clock rate to 64MHz for max. performance */
4071 ret = clk_set_rate(host->dfab_pclk, 64000000);
4072 if (ret)
4073 goto dfab_pclk_put;
4074 ret = clk_enable(host->dfab_pclk);
4075 if (ret)
4076 goto dfab_pclk_put;
4077 } else
4078 goto dma_free;
4079 }
4080
4081 /*
4082 * Setup main peripheral bus clock
4083 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004084 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004085 if (!IS_ERR(host->pclk)) {
4086 ret = clk_enable(host->pclk);
4087 if (ret)
4088 goto pclk_put;
4089
4090 host->pclk_rate = clk_get_rate(host->pclk);
4091 }
4092
4093 /*
4094 * Setup SDC MMC clock
4095 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004096 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07004097 if (IS_ERR(host->clk)) {
4098 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004099 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07004100 }
4101
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004102 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
4103 if (ret) {
4104 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
4105 goto clk_put;
4106 }
4107
4108 ret = clk_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004109 if (ret)
4110 goto clk_put;
4111
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004112 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304113 if (!host->clk_rate)
4114 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304115
4116 /*
4117 * Lookup the Controller Version, to identify the supported features
4118 * Version number read as 0 would indicate SDCC3 or earlier versions
4119 */
4120 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
4121 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
4122 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304123 /*
4124 * Set the register write delay according to min. clock frequency
4125 * supported and update later when the host->clk_rate changes.
4126 */
4127 host->reg_write_delay =
4128 (1 + ((3 * USEC_PER_SEC) /
4129 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004130
4131 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05304132 /* Apply Hard reset to SDCC to put it in power on default state */
4133 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004134
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304135 /* pm qos request to prevent apps idle power collapse */
4136 if (host->plat->swfi_latency)
4137 pm_qos_add_request(&host->pm_qos_req_dma,
4138 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
4139
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004140 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07004141 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004142 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07004143 goto clk_disable;
4144 }
4145
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004146
4147 /* Clocks has to be running before accessing SPS/DML HW blocks */
4148 if (host->is_sps_mode) {
4149 /* Initialize SPS */
4150 ret = msmsdcc_sps_init(host);
4151 if (ret)
4152 goto vreg_deinit;
4153 /* Initialize DML */
4154 ret = msmsdcc_dml_init(host);
4155 if (ret)
4156 goto sps_exit;
4157 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05304158 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07004159
San Mehat9d2bd732009-09-22 16:44:22 -07004160 /*
4161 * Setup MMC host structure
4162 */
4163 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004164 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
4165 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004166 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004167 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
4168 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07004169
San Mehat9d2bd732009-09-22 16:44:22 -07004170 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304171 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304172
4173 /*
4174 * If we send the CMD23 before multi block write/read command
4175 * then we need not to send CMD12 at the end of the transfer.
4176 * If we don't send the CMD12 then only way to detect the PROG_DONE
4177 * status is to use the AUTO_PROG_DONE status provided by SDCC4
4178 * controller. So let's enable the CMD23 for SDCC4 only.
4179 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304180 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304181 mmc->caps |= MMC_CAP_CMD23;
4182
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004183 mmc->caps |= plat->uhs_caps;
4184 /*
4185 * XPC controls the maximum current in the default speed mode of SDXC
4186 * card. XPC=0 means 100mA (max.) but speed class is not supported.
4187 * XPC=1 means 150mA (max.) and speed class is supported.
4188 */
4189 if (plat->xpc_cap)
4190 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
4191 MMC_CAP_SET_XPC_180);
4192
4193 if (plat->nonremovable)
4194 mmc->caps |= MMC_CAP_NONREMOVABLE;
4195#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
4196 mmc->caps |= MMC_CAP_SDIO_IRQ;
4197#endif
4198
4199 if (plat->is_sdio_al_client)
4200 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07004201
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304202 mmc->max_segs = msmsdcc_get_nr_sg(host);
4203 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
4204 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07004205
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304206 mmc->max_req_size = MMC_MAX_REQ_SIZE;
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +05304207 mmc->max_seg_size = mmc->max_req_size;
San Mehat9d2bd732009-09-22 16:44:22 -07004208
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004209 writel_relaxed(0, host->base + MMCIMASK0);
4210 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -07004211
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004212 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
4213 mb();
4214 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07004215
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004216 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
4217 DRIVER_NAME " (cmd)", host);
4218 if (ret)
4219 goto dml_exit;
4220
4221 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
4222 DRIVER_NAME " (pio)", host);
4223 if (ret)
4224 goto irq_free;
4225
4226 /*
4227 * Enable SDCC IRQ only when host is powered on. Otherwise, this
4228 * IRQ is un-necessarily being monitored by MPM (Modem power
4229 * management block) during idle-power collapse. The MPM will be
4230 * configured to monitor the DATA1 GPIO line with level-low trigger
4231 * and thus depending on the GPIO status, it prevents TCXO shutdown
4232 * during idle-power collapse.
4233 */
4234 disable_irq(core_irqres->start);
4235 host->sdcc_irq_disabled = 1;
4236
4237 if (plat->sdiowakeup_irq) {
4238 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4239 mmc_hostname(mmc));
4240 ret = request_irq(plat->sdiowakeup_irq,
4241 msmsdcc_platform_sdiowakeup_irq,
4242 IRQF_SHARED | IRQF_TRIGGER_LOW,
4243 DRIVER_NAME "sdiowakeup", host);
4244 if (ret) {
4245 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
4246 plat->sdiowakeup_irq, ret);
4247 goto pio_irq_free;
4248 } else {
4249 spin_lock_irqsave(&host->lock, flags);
4250 if (!host->sdio_irq_disabled) {
4251 disable_irq_nosync(plat->sdiowakeup_irq);
4252 host->sdio_irq_disabled = 1;
4253 }
4254 spin_unlock_irqrestore(&host->lock, flags);
4255 }
4256 }
4257
4258 if (plat->cfg_mpm_sdiowakeup) {
4259 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4260 mmc_hostname(mmc));
4261 }
4262
4263 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
4264 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004265 /*
4266 * Setup card detect change
4267 */
4268
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004269 if (plat->status || plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08004270 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004271 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08004272 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004273 host->oldstat = msmsdcc_slot_status(host);
Krishna Konda360aa422011-12-06 18:27:41 -08004274
Krishna Konda941604a2012-01-10 17:46:34 -08004275 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004276 }
San Mehat9d2bd732009-09-22 16:44:22 -07004277
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004278 if (plat->status_irq) {
4279 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07004280 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004281 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07004282 DRIVER_NAME " (slot)",
4283 host);
4284 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004285 pr_err("Unable to get slot IRQ %d (%d)\n",
4286 plat->status_irq, ret);
4287 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004288 }
4289 } else if (plat->register_status_notify) {
4290 plat->register_status_notify(msmsdcc_status_notify_cb, host);
4291 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004292 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07004293 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004294
4295 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004296
4297 ret = pm_runtime_set_active(&(pdev)->dev);
4298 if (ret < 0)
4299 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
4300 __func__, ret);
4301 /*
4302 * There is no notion of suspend/resume for SD/MMC/SDIO
4303 * cards. So host can be suspended/resumed with out
4304 * worrying about its children.
4305 */
4306 pm_suspend_ignore_children(&(pdev)->dev, true);
4307
4308 /*
4309 * MMC/SD/SDIO bus suspend/resume operations are defined
4310 * only for the slots that will be used for non-removable
4311 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
4312 * defined. Otherwise, they simply become card removal and
4313 * insertion events during suspend and resume respectively.
4314 * Hence, enable run-time PM only for slots for which bus
4315 * suspend/resume operations are defined.
4316 */
4317#ifdef CONFIG_MMC_UNSAFE_RESUME
4318 /*
4319 * If this capability is set, MMC core will enable/disable host
4320 * for every claim/release operation on a host. We use this
4321 * notification to increment/decrement runtime pm usage count.
4322 */
4323 mmc->caps |= MMC_CAP_DISABLE;
4324 pm_runtime_enable(&(pdev)->dev);
4325#else
4326 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
4327 mmc->caps |= MMC_CAP_DISABLE;
4328 pm_runtime_enable(&(pdev)->dev);
4329 }
4330#endif
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05304331#ifndef CONFIG_PM_RUNTIME
4332 mmc_set_disable_delay(mmc, MSM_MMC_DISABLE_TIMEOUT);
4333#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004334 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
4335 (unsigned long)host);
4336
San Mehat9d2bd732009-09-22 16:44:22 -07004337 mmc_add_host(mmc);
4338
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004339#ifdef CONFIG_HAS_EARLYSUSPEND
4340 host->early_suspend.suspend = msmsdcc_early_suspend;
4341 host->early_suspend.resume = msmsdcc_late_resume;
4342 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
4343 register_early_suspend(&host->early_suspend);
4344#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004345
Krishna Konda25786ec2011-07-25 16:21:36 -07004346 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
4347 " dmacrcri %d\n", mmc_hostname(mmc),
4348 (unsigned long long)core_memres->start,
4349 (unsigned int) core_irqres->start,
4350 (unsigned int) plat->status_irq, host->dma.channel,
4351 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004352
4353 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
4354 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
4355 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
4356 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
4357 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
4358 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
4359 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
4360 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
4361 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
4362 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
4363 host->eject);
4364 pr_info("%s: Power save feature enable = %d\n",
4365 mmc_hostname(mmc), msmsdcc_pwrsave);
4366
Krishna Konda25786ec2011-07-25 16:21:36 -07004367 if (host->is_dma_mode && host->dma.channel != -1
4368 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004369 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004370 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004371 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004372 mmc_hostname(mmc), host->dma.cmd_busaddr,
4373 host->dma.cmdptr_busaddr);
4374 } else if (host->is_sps_mode) {
4375 pr_info("%s: SPS-BAM data transfer mode available\n",
4376 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004377 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004378 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004379
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004380#if defined(CONFIG_DEBUG_FS)
4381 msmsdcc_dbg_createhost(host);
4382#endif
4383 if (!plat->status_irq) {
4384 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
4385 if (ret)
4386 goto platform_irq_free;
4387 }
San Mehat9d2bd732009-09-22 16:44:22 -07004388 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004389
4390 platform_irq_free:
4391 del_timer_sync(&host->req_tout_timer);
4392 pm_runtime_disable(&(pdev)->dev);
4393 pm_runtime_set_suspended(&(pdev)->dev);
4394
4395 if (plat->status_irq)
4396 free_irq(plat->status_irq, host);
4397 sdiowakeup_irq_free:
4398 wake_lock_destroy(&host->sdio_suspend_wlock);
4399 if (plat->sdiowakeup_irq)
4400 free_irq(plat->sdiowakeup_irq, host);
4401 pio_irq_free:
4402 if (plat->sdiowakeup_irq)
4403 wake_lock_destroy(&host->sdio_wlock);
4404 free_irq(core_irqres->start, host);
4405 irq_free:
4406 free_irq(core_irqres->start, host);
4407 dml_exit:
4408 if (host->is_sps_mode)
4409 msmsdcc_dml_exit(host);
4410 sps_exit:
4411 if (host->is_sps_mode)
4412 msmsdcc_sps_exit(host);
4413 vreg_deinit:
4414 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07004415 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004416 clk_disable(host->clk);
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304417 if (host->plat->swfi_latency)
4418 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07004419 clk_put:
4420 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004421 pclk_disable:
4422 if (!IS_ERR(host->pclk))
4423 clk_disable(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07004424 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004425 if (!IS_ERR(host->pclk))
4426 clk_put(host->pclk);
4427 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4428 clk_disable(host->dfab_pclk);
4429 dfab_pclk_put:
4430 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4431 clk_put(host->dfab_pclk);
4432 dma_free:
4433 if (host->is_dma_mode) {
4434 if (host->dmares)
4435 dma_free_coherent(NULL,
4436 sizeof(struct msmsdcc_nc_dmadata),
4437 host->dma.nc, host->dma.nc_busaddr);
4438 }
4439 ioremap_free:
4440 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07004441 host_free:
4442 mmc_free_host(mmc);
4443 out:
4444 return ret;
4445}
4446
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004447static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07004448{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004449 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4450 struct mmc_platform_data *plat;
4451 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004452
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004453 if (!mmc)
4454 return -ENXIO;
4455
4456 if (pm_runtime_suspended(&(pdev)->dev))
4457 pm_runtime_resume(&(pdev)->dev);
4458
4459 host = mmc_priv(mmc);
4460
4461 DBG(host, "Removing SDCC device = %d\n", pdev->id);
4462 plat = host->plat;
4463
4464 if (!plat->status_irq)
4465 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
4466
4467 del_timer_sync(&host->req_tout_timer);
4468 tasklet_kill(&host->dma_tlet);
4469 tasklet_kill(&host->sps.tlet);
4470 mmc_remove_host(mmc);
4471
4472 if (plat->status_irq)
4473 free_irq(plat->status_irq, host);
4474
4475 wake_lock_destroy(&host->sdio_suspend_wlock);
4476 if (plat->sdiowakeup_irq) {
4477 wake_lock_destroy(&host->sdio_wlock);
4478 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
4479 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07004480 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004481
4482 free_irq(host->core_irqres->start, host);
4483 free_irq(host->core_irqres->start, host);
4484
4485 clk_put(host->clk);
4486 if (!IS_ERR(host->pclk))
4487 clk_put(host->pclk);
4488 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4489 clk_put(host->dfab_pclk);
4490
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304491 if (host->plat->swfi_latency)
4492 pm_qos_remove_request(&host->pm_qos_req_dma);
4493
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004494 msmsdcc_vreg_init(host, false);
4495
4496 if (host->is_dma_mode) {
4497 if (host->dmares)
4498 dma_free_coherent(NULL,
4499 sizeof(struct msmsdcc_nc_dmadata),
4500 host->dma.nc, host->dma.nc_busaddr);
4501 }
4502
4503 if (host->is_sps_mode) {
4504 msmsdcc_dml_exit(host);
4505 msmsdcc_sps_exit(host);
4506 }
4507
4508 iounmap(host->base);
4509 mmc_free_host(mmc);
4510
4511#ifdef CONFIG_HAS_EARLYSUSPEND
4512 unregister_early_suspend(&host->early_suspend);
4513#endif
4514 pm_runtime_disable(&(pdev)->dev);
4515 pm_runtime_set_suspended(&(pdev)->dev);
4516
4517 return 0;
4518}
4519
4520#ifdef CONFIG_MSM_SDIO_AL
4521int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4522{
4523 struct msmsdcc_host *host = mmc_priv(mmc);
4524 unsigned long flags;
4525
4526 spin_lock_irqsave(&host->lock, flags);
4527 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
4528 enable ? "En" : "Dis");
4529
4530 if (enable) {
4531 if (!host->sdcc_irq_disabled) {
4532 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05304533 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004534 host->sdcc_irq_disabled = 1;
4535 }
4536
4537 if (host->clks_on) {
4538 msmsdcc_setup_clocks(host, false);
4539 host->clks_on = 0;
4540 }
4541
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304542 if (host->plat->sdio_lpm_gpio_setup &&
4543 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004544 spin_unlock_irqrestore(&host->lock, flags);
4545 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
4546 spin_lock_irqsave(&host->lock, flags);
4547 host->sdio_gpio_lpm = 1;
4548 }
4549
4550 if (host->sdio_irq_disabled) {
4551 msmsdcc_enable_irq_wake(host);
4552 enable_irq(host->plat->sdiowakeup_irq);
4553 host->sdio_irq_disabled = 0;
4554 }
4555 } else {
4556 if (!host->sdio_irq_disabled) {
4557 disable_irq_nosync(host->plat->sdiowakeup_irq);
4558 host->sdio_irq_disabled = 1;
4559 msmsdcc_disable_irq_wake(host);
4560 }
4561
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304562 if (host->plat->sdio_lpm_gpio_setup &&
4563 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004564 spin_unlock_irqrestore(&host->lock, flags);
4565 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
4566 spin_lock_irqsave(&host->lock, flags);
4567 host->sdio_gpio_lpm = 0;
4568 }
4569
4570 if (!host->clks_on) {
4571 msmsdcc_setup_clocks(host, true);
4572 host->clks_on = 1;
4573 }
4574
4575 if (host->sdcc_irq_disabled) {
4576 writel_relaxed(host->mci_irqenable,
4577 host->base + MMCIMASK0);
4578 mb();
4579 enable_irq(host->core_irqres->start);
4580 host->sdcc_irq_disabled = 0;
4581 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004582 }
4583 spin_unlock_irqrestore(&host->lock, flags);
4584 return 0;
4585}
4586#else
4587int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4588{
4589 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004590}
4591#endif
4592
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004593#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07004594static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004595msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004596{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004597 struct mmc_host *mmc = dev_get_drvdata(dev);
4598 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07004599 int rc = 0;
4600
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004601 if (host->plat->is_sdio_al_client)
4602 return 0;
Sahitya Tummala7661a452011-07-18 13:28:35 +05304603 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004604 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004605 host->sdcc_suspending = 1;
4606 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07004607
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004608 /*
4609 * If the clocks are already turned off by SDIO clients (as
4610 * part of LPM), then clocks should be turned on before
4611 * calling mmc_suspend_host() because mmc_suspend_host might
4612 * send some commands to the card. The clocks will be turned
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304613 * off again after mmc_suspend_host. Thus for SDIO
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004614 * cards, clocks will be turned on before mmc_suspend_host
4615 * and turned off after mmc_suspend_host.
4616 */
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304617 if (mmc->card && mmc_card_sdio(mmc->card)) {
4618 mmc->ios.clock = host->clk_rate;
4619 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4620 }
San Mehat9d2bd732009-09-22 16:44:22 -07004621
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004622 /*
4623 * MMC core thinks that host is disabled by now since
4624 * runtime suspend is scheduled after msmsdcc_disable()
4625 * is called. Thus, MMC core will try to enable the host
4626 * while suspending it. This results in a synchronous
4627 * runtime resume request while in runtime suspending
4628 * context and hence inorder to complete this resume
4629 * requet, it will wait for suspend to be complete,
4630 * but runtime suspend also can not proceed further
4631 * until the host is resumed. Thus, it leads to a hang.
4632 * Hence, increase the pm usage count before suspending
4633 * the host so that any resume requests after this will
4634 * simple become pm usage counter increment operations.
4635 */
4636 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05304637 /* If there is pending detect work abort runtime suspend */
4638 if (unlikely(work_busy(&mmc->detect.work)))
4639 rc = -EAGAIN;
4640 else
4641 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004642 pm_runtime_put_noidle(dev);
4643
4644 if (!rc) {
4645 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
4646 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ)) {
4647 disable_irq(host->core_irqres->start);
4648 host->sdcc_irq_disabled = 1;
4649
4650 /*
4651 * If MMC core level suspend is not supported,
4652 * turn off clocks to allow deep sleep (TCXO
4653 * shutdown).
4654 */
4655 mmc->ios.clock = 0;
4656 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4657 enable_irq(host->core_irqres->start);
4658 host->sdcc_irq_disabled = 0;
4659
4660 if (host->plat->sdiowakeup_irq) {
4661 host->sdio_irq_disabled = 0;
4662 msmsdcc_enable_irq_wake(host);
4663 enable_irq(host->plat->sdiowakeup_irq);
4664 }
4665 }
4666 }
4667 host->sdcc_suspending = 0;
4668 mmc->suspend_task = NULL;
4669 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
4670 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004671 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05304672 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
San Mehat9d2bd732009-09-22 16:44:22 -07004673 return rc;
4674}
4675
4676static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004677msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004678{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004679 struct mmc_host *mmc = dev_get_drvdata(dev);
4680 struct msmsdcc_host *host = mmc_priv(mmc);
4681 unsigned long flags;
4682
4683 if (host->plat->is_sdio_al_client)
4684 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07004685
Sahitya Tummala7661a452011-07-18 13:28:35 +05304686 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004687 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004688 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
4689 if (host->sdcc_irq_disabled) {
4690 enable_irq(host->core_irqres->start);
4691 host->sdcc_irq_disabled = 0;
4692 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304693 mmc->ios.clock = host->clk_rate;
4694 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07004695
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304696 spin_lock_irqsave(&host->lock, flags);
4697 writel_relaxed(host->mci_irqenable,
4698 host->base + MMCIMASK0);
4699 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07004700
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304701 if ((mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) &&
4702 !host->sdio_irq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004703 if (host->plat->sdiowakeup_irq) {
4704 disable_irq_nosync(
4705 host->plat->sdiowakeup_irq);
4706 msmsdcc_disable_irq_wake(host);
4707 host->sdio_irq_disabled = 1;
4708 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304709 }
San Mehat9d2bd732009-09-22 16:44:22 -07004710
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304711 spin_unlock_irqrestore(&host->lock, flags);
4712 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004713
4714 mmc_resume_host(mmc);
4715
4716 /*
4717 * FIXME: Clearing of flags must be handled in clients
4718 * resume handler.
4719 */
4720 spin_lock_irqsave(&host->lock, flags);
4721 mmc->pm_flags = 0;
4722 spin_unlock_irqrestore(&host->lock, flags);
4723
4724 /*
4725 * After resuming the host wait for sometime so that
4726 * the SDIO work will be processed.
4727 */
4728 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO)) {
4729 if ((host->plat->cfg_mpm_sdiowakeup ||
4730 host->plat->sdiowakeup_irq) &&
4731 wake_lock_active(&host->sdio_wlock))
4732 wake_lock_timeout(&host->sdio_wlock, 1);
4733 }
4734
4735 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004736 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304737 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004738 return 0;
4739}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004740
4741static int msmsdcc_runtime_idle(struct device *dev)
4742{
4743 struct mmc_host *mmc = dev_get_drvdata(dev);
4744 struct msmsdcc_host *host = mmc_priv(mmc);
4745
4746 if (host->plat->is_sdio_al_client)
4747 return 0;
4748
4749 /* Idle timeout is not configurable for now */
4750 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
4751
4752 return -EAGAIN;
4753}
4754
4755static int msmsdcc_pm_suspend(struct device *dev)
4756{
4757 struct mmc_host *mmc = dev_get_drvdata(dev);
4758 struct msmsdcc_host *host = mmc_priv(mmc);
4759 int rc = 0;
4760
4761 if (host->plat->is_sdio_al_client)
4762 return 0;
4763
4764
4765 if (host->plat->status_irq)
4766 disable_irq(host->plat->status_irq);
4767
4768 if (!pm_runtime_suspended(dev))
4769 rc = msmsdcc_runtime_suspend(dev);
4770
4771 return rc;
4772}
4773
4774static int msmsdcc_pm_resume(struct device *dev)
4775{
4776 struct mmc_host *mmc = dev_get_drvdata(dev);
4777 struct msmsdcc_host *host = mmc_priv(mmc);
4778 int rc = 0;
4779
4780 if (host->plat->is_sdio_al_client)
4781 return 0;
4782
Sahitya Tummalafb486372011-09-02 19:01:49 +05304783 if (!pm_runtime_suspended(dev))
4784 rc = msmsdcc_runtime_resume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004785 if (host->plat->status_irq) {
4786 msmsdcc_check_status((unsigned long)host);
4787 enable_irq(host->plat->status_irq);
4788 }
4789
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004790 return rc;
4791}
4792
Daniel Walker08ecfde2010-06-23 12:32:20 -07004793#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004794#define msmsdcc_runtime_suspend NULL
4795#define msmsdcc_runtime_resume NULL
4796#define msmsdcc_runtime_idle NULL
4797#define msmsdcc_pm_suspend NULL
4798#define msmsdcc_pm_resume NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07004799#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004800
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004801static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
4802 .runtime_suspend = msmsdcc_runtime_suspend,
4803 .runtime_resume = msmsdcc_runtime_resume,
4804 .runtime_idle = msmsdcc_runtime_idle,
4805 .suspend = msmsdcc_pm_suspend,
4806 .resume = msmsdcc_pm_resume,
4807};
4808
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304809static const struct of_device_id msmsdcc_dt_match[] = {
4810 {.compatible = "qcom,msm-sdcc"},
4811
4812};
4813MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
4814
San Mehat9d2bd732009-09-22 16:44:22 -07004815static struct platform_driver msmsdcc_driver = {
4816 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004817 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07004818 .driver = {
4819 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004820 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304821 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07004822 },
4823};
4824
4825static int __init msmsdcc_init(void)
4826{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004827#if defined(CONFIG_DEBUG_FS)
4828 int ret = 0;
4829 ret = msmsdcc_dbg_init();
4830 if (ret) {
4831 pr_err("Failed to create debug fs dir \n");
4832 return ret;
4833 }
4834#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004835 return platform_driver_register(&msmsdcc_driver);
4836}
4837
4838static void __exit msmsdcc_exit(void)
4839{
4840 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004841
4842#if defined(CONFIG_DEBUG_FS)
4843 debugfs_remove(debugfs_file);
4844 debugfs_remove(debugfs_dir);
4845#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004846}
4847
4848module_init(msmsdcc_init);
4849module_exit(msmsdcc_exit);
4850
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004851MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07004852MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004853
4854#if defined(CONFIG_DEBUG_FS)
4855
4856static int
4857msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
4858{
4859 file->private_data = inode->i_private;
4860 return 0;
4861}
4862
4863static ssize_t
4864msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
4865 size_t count, loff_t *ppos)
4866{
4867 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08004868 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004869 int max, i;
4870
4871 i = 0;
4872 max = sizeof(buf) - 1;
4873
4874 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
4875 host->curr.cmd, host->curr.data);
4876 if (host->curr.cmd) {
4877 struct mmc_command *cmd = host->curr.cmd;
4878
4879 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
4880 cmd->opcode, cmd->arg, cmd->flags);
4881 }
4882 if (host->curr.data) {
4883 struct mmc_data *data = host->curr.data;
4884 i += scnprintf(buf + i, max - i,
4885 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
4886 data->timeout_ns, data->timeout_clks,
4887 data->blksz, data->blocks, data->error,
4888 data->flags);
4889 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
4890 host->curr.xfer_size, host->curr.xfer_remain,
4891 host->curr.data_xfered, host->dma.sg);
4892 }
4893
4894 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
4895}
4896
4897static const struct file_operations msmsdcc_dbg_state_ops = {
4898 .read = msmsdcc_dbg_state_read,
4899 .open = msmsdcc_dbg_state_open,
4900};
4901
4902static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
4903{
4904 if (debugfs_dir) {
4905 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
4906 0644, debugfs_dir, host,
4907 &msmsdcc_dbg_state_ops);
4908 }
4909}
4910
4911static int __init msmsdcc_dbg_init(void)
4912{
4913 int err;
4914
4915 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
4916 if (IS_ERR(debugfs_dir)) {
4917 err = PTR_ERR(debugfs_dir);
4918 debugfs_dir = NULL;
4919 return err;
4920 }
4921
4922 return 0;
4923}
4924#endif