blob: 9a99cf31b2feafc5045811d4de1c19043dd6c2d1 [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 Jadavani7d8c94d2011-10-18 18:00:07 +05301005 if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301006 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001007 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301008 }
1009
San Mehat56a8b5b2009-11-21 12:29:46 -08001010 if (cmd == cmd->mrq->stop)
1011 *c |= MCI_CSPM_MCIABORT;
1012
San Mehat56a8b5b2009-11-21 12:29:46 -08001013 if (host->curr.cmd != NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001014 pr_err("%s: Overlapping command requests\n",
1015 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -08001016 }
1017 host->curr.cmd = cmd;
1018}
1019
1020static void
1021msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1022 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001023{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301024 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001025 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001026 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001027 unsigned int pio_irqmask = 0;
1028
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301029 BUG_ON(!data->sg);
1030 BUG_ON(!data->sg_len);
1031
San Mehat9d2bd732009-09-22 16:44:22 -07001032 host->curr.data = data;
1033 host->curr.xfer_size = data->blksz * data->blocks;
1034 host->curr.xfer_remain = host->curr.xfer_size;
1035 host->curr.data_xfered = 0;
1036 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301037 host->curr.got_auto_prog_done = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001038
1039 memset(&host->pio, 0, sizeof(host->pio));
1040
San Mehat9d2bd732009-09-22 16:44:22 -07001041 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1042
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301043 if (host->curr.wait_for_auto_prog_done)
1044 datactrl |= MCI_AUTO_PROG_DONE;
1045
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001046 if (!msmsdcc_check_dma_op_req(data)) {
1047 if (host->is_dma_mode && !msmsdcc_config_dma(host, data)) {
1048 datactrl |= MCI_DPSM_DMAENABLE;
1049 } else if (host->is_sps_mode) {
1050 if (!msmsdcc_is_dml_busy(host)) {
1051 if (!msmsdcc_sps_start_xfer(host, data)) {
1052 /* Now kick start DML transfer */
1053 mb();
1054 msmsdcc_dml_start_xfer(host, data);
1055 datactrl |= MCI_DPSM_DMAENABLE;
1056 host->sps.busy = 1;
1057 }
1058 } else {
1059 /*
1060 * Can't proceed with new transfer as
1061 * previous trasnfer is already in progress.
1062 * There is no point of going into PIO mode
1063 * as well. Is this a time to do kernel panic?
1064 */
1065 pr_err("%s: %s: DML HW is busy!!!"
1066 " Can't perform new SPS transfers"
1067 " now\n", mmc_hostname(host->mmc),
1068 __func__);
1069 }
1070 }
1071 }
1072
1073 /* Is data transfer in PIO mode required? */
1074 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001075 host->pio.sg = data->sg;
1076 host->pio.sg_len = data->sg_len;
1077 host->pio.sg_off = 0;
1078
1079 if (data->flags & MMC_DATA_READ) {
1080 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1081 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1082 pio_irqmask |= MCI_RXDATAAVLBLMASK;
1083 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001084 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1085 MCI_TXFIFOEMPTYMASK;
San Mehat9d2bd732009-09-22 16:44:22 -07001086 }
1087
1088 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301089 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
San Mehat9d2bd732009-09-22 16:44:22 -07001090
San Mehat56a8b5b2009-11-21 12:29:46 -08001091 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001092 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001093 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -07001094
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001095 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
1096 /* Use ADM (Application Data Mover) HW for Data transfer */
1097 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001098 host->cmd_timeout = timeout;
1099 host->cmd_pio_irqmask = pio_irqmask;
1100 host->cmd_datactrl = datactrl;
1101 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001102
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001103 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1104 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001105 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001106
1107 if (cmd) {
1108 msmsdcc_start_command_deferred(host, cmd, &c);
1109 host->cmd_c = c;
1110 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001111 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1112 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1113 host->base + MMCIMASK0);
1114 mb();
1115 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001116 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001117 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001118 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001119
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001120 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001121
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001122 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1123 (~(MCI_IRQ_PIO))) | pio_irqmask,
1124 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001125 writel_relaxed(datactrl, base + MMCIDATACTRL);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301126 /*
1127 * We don't need delay after writing to DATA_CTRL register
1128 * if we are not writing to CMD register immediately after
1129 * this. As we already have delay before sending the
1130 * command, we just need mb() here.
1131 */
1132 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001133
1134 if (cmd) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001135 msmsdcc_delay(host); /* Delay between data/command */
San Mehat56a8b5b2009-11-21 12:29:46 -08001136 /* Daisy-chain the command if requested */
1137 msmsdcc_start_command(host, cmd, c);
1138 }
San Mehat9d2bd732009-09-22 16:44:22 -07001139 }
1140}
1141
1142static void
1143msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1144{
San Mehat56a8b5b2009-11-21 12:29:46 -08001145 msmsdcc_start_command_deferred(host, cmd, &c);
1146 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001147}
1148
1149static void
1150msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1151 unsigned int status)
1152{
1153 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001154 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1155 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1156 pr_err("%s: Data CRC error\n",
1157 mmc_hostname(host->mmc));
1158 pr_err("%s: opcode 0x%.8x\n", __func__,
1159 data->mrq->cmd->opcode);
1160 pr_err("%s: blksz %d, blocks %d\n", __func__,
1161 data->blksz, data->blocks);
1162 data->error = -EILSEQ;
1163 }
San Mehat9d2bd732009-09-22 16:44:22 -07001164 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001165 /* CRC is optional for the bus test commands, not all
1166 * cards respond back with CRC. However controller
1167 * waits for the CRC and times out. Hence ignore the
1168 * data timeouts during the Bustest.
1169 */
1170 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1171 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301172 pr_err("%s: CMD%d: Data timeout\n",
1173 mmc_hostname(host->mmc),
1174 data->mrq->cmd->opcode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001175 data->error = -ETIMEDOUT;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301176 msmsdcc_dump_sdcc_state(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001177 }
San Mehat9d2bd732009-09-22 16:44:22 -07001178 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001179 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001180 data->error = -EIO;
1181 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001182 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001183 data->error = -EIO;
1184 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001185 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001186 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001187 data->error = -EIO;
1188 }
San Mehat9d2bd732009-09-22 16:44:22 -07001189
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001190 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001191 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001192 host->dummy_52_needed = 0;
1193}
San Mehat9d2bd732009-09-22 16:44:22 -07001194
1195static int
1196msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1197{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001198 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001199 uint32_t *ptr = (uint32_t *) buffer;
1200 int count = 0;
1201
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301202 if (remain % 4)
1203 remain = ((remain >> 2) + 1) << 2;
1204
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001205 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1206
1207 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001208 ptr++;
1209 count += sizeof(uint32_t);
1210
1211 remain -= sizeof(uint32_t);
1212 if (remain == 0)
1213 break;
1214 }
1215 return count;
1216}
1217
1218static int
1219msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001220 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001221{
1222 void __iomem *base = host->base;
1223 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001224 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001225
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001226 while (readl_relaxed(base + MMCISTATUS) &
1227 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1228 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001229
San Mehat9d2bd732009-09-22 16:44:22 -07001230 count = min(remain, maxcnt);
1231
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301232 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1233 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001234 ptr += count;
1235 remain -= count;
1236
1237 if (remain == 0)
1238 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001239 }
1240 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001241
1242 return ptr - buffer;
1243}
1244
San Mehat1cd22962010-02-03 12:59:29 -08001245static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001246msmsdcc_pio_irq(int irq, void *dev_id)
1247{
1248 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001249 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001250 uint32_t status;
1251
Murali Palnati36448a42011-09-02 15:06:18 +05301252 spin_lock(&host->lock);
1253
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001254 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001255
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001256 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301257 (MCI_IRQ_PIO)) == 0) {
1258 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001259 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301260 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001261
1262#if IRQ_DEBUG
1263 msmsdcc_print_status(host, "irq1-r", status);
1264#endif
1265
San Mehat9d2bd732009-09-22 16:44:22 -07001266 do {
1267 unsigned long flags;
1268 unsigned int remain, len;
1269 char *buffer;
1270
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001271 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1272 | MCI_RXDATAAVLBL)))
1273 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001274
1275 /* Map the current scatter buffer */
1276 local_irq_save(flags);
1277 buffer = kmap_atomic(sg_page(host->pio.sg),
1278 KM_BIO_SRC_IRQ) + host->pio.sg->offset;
1279 buffer += host->pio.sg_off;
1280 remain = host->pio.sg->length - host->pio.sg_off;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001281
San Mehat9d2bd732009-09-22 16:44:22 -07001282 len = 0;
1283 if (status & MCI_RXACTIVE)
1284 len = msmsdcc_pio_read(host, buffer, remain);
1285 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001286 len = msmsdcc_pio_write(host, buffer, remain);
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301287 /* len might have aligned to 32bits above */
1288 if (len > remain)
1289 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001290
1291 /* Unmap the buffer */
1292 kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
1293 local_irq_restore(flags);
1294
1295 host->pio.sg_off += len;
1296 host->curr.xfer_remain -= len;
1297 host->curr.data_xfered += len;
1298 remain -= len;
1299
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001300 if (remain) /* Done with this page? */
1301 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001302
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001303 if (status & MCI_RXACTIVE && host->curr.user_pages)
1304 flush_dcache_page(sg_page(host->pio.sg));
San Mehat9d2bd732009-09-22 16:44:22 -07001305
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001306 if (!--host->pio.sg_len) {
1307 memset(&host->pio, 0, sizeof(host->pio));
1308 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001309 }
1310
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001311 /* Advance to next sg */
1312 host->pio.sg++;
1313 host->pio.sg_off = 0;
1314
1315 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001316 } while (1);
1317
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001318 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1319 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1320 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1321 host->base + MMCIMASK0);
1322 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301323 /*
1324 * back to back write to MASK0 register don't need
1325 * synchronization delay.
1326 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001327 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1328 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1329 }
1330 mb();
1331 } else if (!host->curr.xfer_remain) {
1332 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1333 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1334 mb();
1335 }
San Mehat9d2bd732009-09-22 16:44:22 -07001336
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001337 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001338
1339 return IRQ_HANDLED;
1340}
1341
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001342static void
1343msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1344
1345static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1346 struct mmc_data *data)
1347{
1348 u32 loop_cnt = 0;
1349
1350 /*
1351 * For read commands with data less than fifo size, it is possible to
1352 * get DATAEND first and RXDATA_AVAIL might be set later because of
1353 * synchronization delay through the asynchronous RX FIFO. Thus, for
1354 * such cases, even after DATAEND interrupt is received software
1355 * should poll for RXDATA_AVAIL until the requested data is read out
1356 * of FIFO. This change is needed to get around this abnormal but
1357 * sometimes expected behavior of SDCC3 controller.
1358 *
1359 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1360 * after the data is loaded into RX FIFO. This would amount to less
1361 * than a microsecond and thus looping for 1000 times is good enough
1362 * for that delay.
1363 */
1364 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1365 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1366 spin_unlock(&host->lock);
1367 msmsdcc_pio_irq(1, host);
1368 spin_lock(&host->lock);
1369 }
1370 }
1371 if (loop_cnt == 1000) {
1372 pr_info("%s: Timed out while polling for Rx Data\n",
1373 mmc_hostname(host->mmc));
1374 data->error = -ETIMEDOUT;
1375 msmsdcc_reset_and_restore(host);
1376 }
1377}
1378
San Mehat9d2bd732009-09-22 16:44:22 -07001379static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1380{
1381 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001382
1383 host->curr.cmd = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001384 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1385 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1386 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1387 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -07001388
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001389 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301390 pr_debug("%s: CMD%d: Command timeout\n",
1391 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001392 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001393 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
1394 !host->cmd19_tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301395 pr_err("%s: CMD%d: Command CRC error\n",
1396 mmc_hostname(host->mmc), cmd->opcode);
1397 msmsdcc_dump_sdcc_state(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001398 cmd->error = -EILSEQ;
1399 }
1400
1401 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001402 if (host->curr.data && host->dma.sg &&
1403 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001404 msm_dmov_stop_cmd(host->dma.channel,
1405 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001406 else if (host->curr.data && host->sps.sg &&
1407 host->is_sps_mode){
1408 /* Stop current SPS transfer */
1409 msmsdcc_sps_exit_curr_xfer(host);
1410 }
San Mehat9d2bd732009-09-22 16:44:22 -07001411 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301412 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001413 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301414 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301415 } else { /* host->data == NULL */
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301416 if (!cmd->error && host->prog_enable) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301417 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001418 host->prog_enable = 0;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301419 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001420 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301421 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301422 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301423 host->prog_enable = 0;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001424 if (host->dummy_52_needed)
1425 host->dummy_52_needed = 0;
1426 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001427 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301428 msmsdcc_request_end(host, cmd->mrq);
1429 }
1430 }
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301431 } else if ((cmd == host->curr.mrq->sbc) && cmd->data) {
1432 if (cmd->data->flags & MMC_DATA_READ)
1433 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1434 else
1435 msmsdcc_request_start(host, host->curr.mrq);
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301436 } else if (cmd->data) {
1437 if (!(cmd->data->flags & MMC_DATA_READ))
1438 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001439 }
1440}
1441
San Mehat9d2bd732009-09-22 16:44:22 -07001442static irqreturn_t
1443msmsdcc_irq(int irq, void *dev_id)
1444{
1445 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001446 u32 status;
1447 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001448 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001449
1450 spin_lock(&host->lock);
1451
1452 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001453 struct mmc_command *cmd;
1454 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001455
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001456 if (timer) {
1457 timer = 0;
1458 msmsdcc_delay(host);
1459 }
San Mehat865c8062009-11-13 13:42:06 -08001460
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001461 if (!host->clks_on) {
1462 pr_debug("%s: %s: SDIO async irq received\n",
1463 mmc_hostname(host->mmc), __func__);
1464 host->mmc->ios.clock = host->clk_rate;
1465 spin_unlock(&host->lock);
1466 host->mmc->ops->set_ios(host->mmc, &host->mmc->ios);
1467 spin_lock(&host->lock);
1468 if (host->plat->cfg_mpm_sdiowakeup &&
1469 (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
1470 wake_lock(&host->sdio_wlock);
1471 /* only ansyc interrupt can come when clocks are off */
1472 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301473 if (host->clk_rate <=
1474 msmsdcc_get_min_sup_clk_rate(host))
1475 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001476 }
1477
1478 status = readl_relaxed(host->base + MMCISTATUS);
1479
1480 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1481 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001482 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001483
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001484#if IRQ_DEBUG
1485 msmsdcc_print_status(host, "irq0-r", status);
1486#endif
1487 status &= readl_relaxed(host->base + MMCIMASK0);
1488 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301489 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301490 if (host->clk_rate <=
1491 msmsdcc_get_min_sup_clk_rate(host))
1492 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001493#if IRQ_DEBUG
1494 msmsdcc_print_status(host, "irq0-p", status);
1495#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001496
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001497#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
1498 if (status & MCI_SDIOINTROPE) {
1499 if (host->sdcc_suspending)
1500 wake_lock(&host->sdio_suspend_wlock);
1501 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001502 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001503#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001504 data = host->curr.data;
1505
1506 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001507 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1508 MCI_CMDTIMEOUT)) {
1509 if (status & MCI_CMDTIMEOUT)
1510 pr_debug("%s: dummy CMD52 timeout\n",
1511 mmc_hostname(host->mmc));
1512 if (status & MCI_CMDCRCFAIL)
1513 pr_debug("%s: dummy CMD52 CRC failed\n",
1514 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001515 host->dummy_52_sent = 0;
1516 host->dummy_52_needed = 0;
1517 if (data) {
1518 msmsdcc_stop_data(host);
1519 msmsdcc_request_end(host, data->mrq);
1520 }
1521 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001522 spin_unlock(&host->lock);
1523 return IRQ_HANDLED;
1524 }
1525 break;
1526 }
1527
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001528 /*
1529 * Check for proper command response
1530 */
1531 cmd = host->curr.cmd;
1532 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1533 MCI_CMDTIMEOUT | MCI_PROGDONE |
1534 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1535 msmsdcc_do_cmdirq(host, status);
1536 }
1537
Sathish Ambley081d7842011-11-29 11:19:41 -08001538 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001539 /* Check for data errors */
1540 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1541 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1542 msmsdcc_data_err(host, data, status);
1543 host->curr.data_xfered = 0;
1544 if (host->dma.sg && host->is_dma_mode)
1545 msm_dmov_stop_cmd(host->dma.channel,
1546 &host->dma.hdr, 0);
1547 else if (host->sps.sg && host->is_sps_mode) {
1548 /* Stop current SPS transfer */
1549 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301550 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001551 msmsdcc_reset_and_restore(host);
1552 if (host->curr.data)
1553 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301554 if (!data->stop || (host->curr.mrq->sbc
1555 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001556 timer |=
1557 msmsdcc_request_end(host,
1558 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301559 else if ((host->curr.mrq->sbc
1560 && data->error) ||
1561 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001562 msmsdcc_start_command(host,
1563 data->stop,
1564 0);
1565 timer = 1;
1566 }
1567 }
1568 }
1569
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301570 /* Check for prog done */
1571 if (host->curr.wait_for_auto_prog_done &&
1572 (status & MCI_PROGDONE))
1573 host->curr.got_auto_prog_done = 1;
1574
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001575 /* Check for data done */
1576 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1577 host->curr.got_dataend = 1;
1578
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301579 if (host->curr.got_dataend &&
1580 (!host->curr.wait_for_auto_prog_done ||
1581 (host->curr.wait_for_auto_prog_done &&
1582 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001583 /*
1584 * If DMA is still in progress, we complete
1585 * via the completion handler
1586 */
1587 if (!host->dma.busy && !host->sps.busy) {
1588 /*
1589 * There appears to be an issue in the
1590 * controller where if you request a
1591 * small block transfer (< fifo size),
1592 * you may get your DATAEND/DATABLKEND
1593 * irq without the PIO data irq.
1594 *
1595 * Check to see if theres still data
1596 * to be read, and simulate a PIO irq.
1597 */
1598 if (data->flags & MMC_DATA_READ)
1599 msmsdcc_wait_for_rxdata(host,
1600 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001601 if (!data->error) {
1602 host->curr.data_xfered =
1603 host->curr.xfer_size;
1604 host->curr.xfer_remain -=
1605 host->curr.xfer_size;
1606 }
1607
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001608 if (!host->dummy_52_needed) {
1609 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301610 if (!data->stop ||
1611 (host->curr.mrq->sbc
1612 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001613 msmsdcc_request_end(
1614 host,
1615 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301616 else if ((host->curr.mrq->sbc
1617 && data->error) ||
1618 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001619 msmsdcc_start_command(
1620 host,
1621 data->stop, 0);
1622 timer = 1;
1623 }
1624 } else {
1625 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001626 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001627 &dummy52cmd,
1628 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001629 }
1630 }
1631 }
1632 }
1633
San Mehat9d2bd732009-09-22 16:44:22 -07001634 ret = 1;
1635 } while (status);
1636
1637 spin_unlock(&host->lock);
1638
San Mehat9d2bd732009-09-22 16:44:22 -07001639 return IRQ_RETVAL(ret);
1640}
1641
1642static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001643msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1644{
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301645 if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001646 /* Queue/read data, daisy-chain command when data starts */
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301647 if (mrq->sbc)
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301648 msmsdcc_start_data(host, mrq->data, mrq->sbc, 0);
1649 else
1650 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001651 } else {
1652 msmsdcc_start_command(host, mrq->cmd, 0);
1653 }
1654}
1655
1656static void
San Mehat9d2bd732009-09-22 16:44:22 -07001657msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1658{
1659 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001660 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001661
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001662 /*
1663 * Get the SDIO AL client out of LPM.
1664 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001665 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001666 if (host->plat->is_sdio_al_client)
1667 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001668
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301669 /* check if sps pipe reset is pending? */
1670 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1671 msmsdcc_sps_pipes_reset_and_restore(host);
1672 host->sps.pipe_reset_pending = false;
1673 }
1674
San Mehat9d2bd732009-09-22 16:44:22 -07001675 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001676 WARN(host->curr.mrq, "Request in progress\n");
1677 WARN(!host->pwr, "SDCC power is turned off\n");
1678 WARN(!host->clks_on, "SDCC clocks are turned off\n");
1679 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
San Mehat9d2bd732009-09-22 16:44:22 -07001680
1681 if (host->eject) {
1682 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1683 mrq->cmd->error = 0;
1684 mrq->data->bytes_xfered = mrq->data->blksz *
1685 mrq->data->blocks;
1686 } else
1687 mrq->cmd->error = -ENOMEDIUM;
1688
1689 spin_unlock_irqrestore(&host->lock, flags);
1690 mmc_request_done(mmc, mrq);
1691 return;
1692 }
1693
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301694 /*
1695 * Kick the software command timeout timer here.
1696 * Timer expires in 10 secs.
1697 */
1698 mod_timer(&host->req_tout_timer,
1699 (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
San Mehat9d2bd732009-09-22 16:44:22 -07001700
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301701 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301702 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301703 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
1704 mrq->cmd->opcode == 54) {
Pratibhasagar V1c11da62011-11-14 12:36:35 +05301705 if (!host->sdcc_version)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001706 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301707 else
1708 /*
1709 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
1710 * write operations using CMD53 and CMD54.
1711 * Setting this bit with CMD53 would
1712 * automatically triggers PROG_DONE interrupt
1713 * without the need of sending dummy CMD52.
1714 */
1715 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani758cf8c2011-11-13 11:59:55 +05301716 } else if (mrq->cmd->opcode == MMC_WRITE_BLOCK &&
1717 host->sdcc_version) {
1718 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001719 }
San Mehat9d2bd732009-09-22 16:44:22 -07001720 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301721
Pratibhasagar V00b94332011-10-18 14:57:27 +05301722 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301723 mrq->sbc->mrq = mrq;
1724 mrq->sbc->data = mrq->data;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301725 if (mrq->data->flags & MMC_DATA_WRITE) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301726 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301727 msmsdcc_start_command(host, mrq->sbc, 0);
1728 } else {
1729 msmsdcc_request_start(host, mrq);
1730 }
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301731 } else {
1732 msmsdcc_request_start(host, mrq);
1733 }
1734
San Mehat9d2bd732009-09-22 16:44:22 -07001735 spin_unlock_irqrestore(&host->lock, flags);
1736}
1737
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001738static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1739 int min_uV, int max_uV)
1740{
1741 int rc = 0;
1742
1743 if (vreg->set_voltage_sup) {
1744 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1745 if (rc) {
1746 pr_err("%s: regulator_set_voltage(%s) failed."
1747 " min_uV=%d, max_uV=%d, rc=%d\n",
1748 __func__, vreg->name, min_uV, max_uV, rc);
1749 }
1750 }
1751
1752 return rc;
1753}
1754
1755static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1756 int uA_load)
1757{
1758 int rc = 0;
1759
Krishna Kondafea60182011-11-01 16:01:34 -07001760 /* regulators that do not support regulator_set_voltage also
1761 do not support regulator_set_optimum_mode */
1762 if (vreg->set_voltage_sup) {
1763 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1764 if (rc < 0)
1765 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
1766 "uA_load=%d) failed. rc=%d\n", __func__,
1767 vreg->name, uA_load, rc);
1768 else
1769 /* regulator_set_optimum_mode() can return non zero
1770 * value even for success case.
1771 */
1772 rc = 0;
1773 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001774
1775 return rc;
1776}
1777
1778static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1779 struct device *dev)
1780{
1781 int rc = 0;
1782
1783 /* check if regulator is already initialized? */
1784 if (vreg->reg)
1785 goto out;
1786
1787 /* Get the regulator handle */
1788 vreg->reg = regulator_get(dev, vreg->name);
1789 if (IS_ERR(vreg->reg)) {
1790 rc = PTR_ERR(vreg->reg);
1791 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
1792 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001793 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001794 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001795
1796 if (regulator_count_voltages(vreg->reg) > 0)
1797 vreg->set_voltage_sup = 1;
1798
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001799out:
1800 return rc;
1801}
1802
1803static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
1804{
1805 if (vreg->reg)
1806 regulator_put(vreg->reg);
1807}
1808
1809/* This init function should be called only once for each SDCC slot */
1810static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
1811{
1812 int rc = 0;
1813 struct msm_mmc_slot_reg_data *curr_slot;
1814 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1815 struct device *dev = mmc_dev(host->mmc);
1816
1817 curr_slot = host->plat->vreg_data;
1818 if (!curr_slot)
1819 goto out;
1820
1821 curr_vdd_reg = curr_slot->vdd_data;
1822 curr_vccq_reg = curr_slot->vccq_data;
1823 curr_vddp_reg = curr_slot->vddp_data;
1824
1825 if (is_init) {
1826 /*
1827 * Get the regulator handle from voltage regulator framework
1828 * and then try to set the voltage level for the regulator
1829 */
1830 if (curr_vdd_reg) {
1831 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
1832 if (rc)
1833 goto out;
1834 }
1835 if (curr_vccq_reg) {
1836 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
1837 if (rc)
1838 goto vdd_reg_deinit;
1839 }
1840 if (curr_vddp_reg) {
1841 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
1842 if (rc)
1843 goto vccq_reg_deinit;
1844 }
1845 goto out;
1846 } else {
1847 /* Deregister all regulators from regulator framework */
1848 goto vddp_reg_deinit;
1849 }
1850vddp_reg_deinit:
1851 if (curr_vddp_reg)
1852 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
1853vccq_reg_deinit:
1854 if (curr_vccq_reg)
1855 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
1856vdd_reg_deinit:
1857 if (curr_vdd_reg)
1858 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
1859out:
1860 return rc;
1861}
1862
1863static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
1864{
1865 int rc = 0;
1866
Subhash Jadavanicc922692011-08-01 23:05:01 +05301867 /* Put regulator in HPM (high power mode) */
1868 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
1869 if (rc < 0)
1870 goto out;
1871
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001872 if (!vreg->is_enabled) {
1873 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301874 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
1875 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001876 if (rc)
1877 goto out;
1878
1879 rc = regulator_enable(vreg->reg);
1880 if (rc) {
1881 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
1882 __func__, vreg->name, rc);
1883 goto out;
1884 }
1885 vreg->is_enabled = true;
1886 }
1887
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001888out:
1889 return rc;
1890}
1891
1892static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
1893{
1894 int rc = 0;
1895
1896 /* Never disable regulator marked as always_on */
1897 if (vreg->is_enabled && !vreg->always_on) {
1898 rc = regulator_disable(vreg->reg);
1899 if (rc) {
1900 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
1901 __func__, vreg->name, rc);
1902 goto out;
1903 }
1904 vreg->is_enabled = false;
1905
1906 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
1907 if (rc < 0)
1908 goto out;
1909
1910 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301911 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001912 if (rc)
1913 goto out;
1914 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
1915 /* Put always_on regulator in LPM (low power mode) */
1916 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
1917 if (rc < 0)
1918 goto out;
1919 }
1920out:
1921 return rc;
1922}
1923
1924static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
1925{
1926 int rc = 0, i;
1927 struct msm_mmc_slot_reg_data *curr_slot;
1928 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1929 struct msm_mmc_reg_data *vreg_table[3];
1930
1931 curr_slot = host->plat->vreg_data;
1932 if (!curr_slot)
1933 goto out;
1934
1935 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
1936 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
1937 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
1938
1939 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
1940 if (vreg_table[i]) {
1941 if (enable)
1942 rc = msmsdcc_vreg_enable(vreg_table[i]);
1943 else
1944 rc = msmsdcc_vreg_disable(vreg_table[i]);
1945 if (rc)
1946 goto out;
1947 }
1948 }
1949out:
1950 return rc;
1951}
1952
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301953static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001954{
1955 int rc = 0;
1956
1957 if (host->plat->vreg_data) {
1958 struct msm_mmc_reg_data *vddp_reg =
1959 host->plat->vreg_data->vddp_data;
1960
1961 if (vddp_reg && vddp_reg->is_enabled)
1962 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
1963 }
1964
1965 return rc;
1966}
1967
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301968static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
1969{
1970 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1971 int rc = 0;
1972
1973 if (curr_slot && curr_slot->vddp_data) {
1974 rc = msmsdcc_set_vddp_level(host,
1975 curr_slot->vddp_data->low_vol_level);
1976
1977 if (rc)
1978 pr_err("%s: %s: failed to change vddp level to %d",
1979 mmc_hostname(host->mmc), __func__,
1980 curr_slot->vddp_data->low_vol_level);
1981 }
1982
1983 return rc;
1984}
1985
1986static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
1987{
1988 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1989 int rc = 0;
1990
1991 if (curr_slot && curr_slot->vddp_data) {
1992 rc = msmsdcc_set_vddp_level(host,
1993 curr_slot->vddp_data->high_vol_level);
1994
1995 if (rc)
1996 pr_err("%s: %s: failed to change vddp level to %d",
1997 mmc_hostname(host->mmc), __func__,
1998 curr_slot->vddp_data->high_vol_level);
1999 }
2000
2001 return rc;
2002}
2003
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002004static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2005{
2006 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2007 return 1;
2008 return 0;
2009}
2010
2011static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
2012{
2013 if (enable) {
2014 if (!IS_ERR_OR_NULL(host->dfab_pclk))
2015 clk_enable(host->dfab_pclk);
2016 if (!IS_ERR(host->pclk))
2017 clk_enable(host->pclk);
2018 clk_enable(host->clk);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302019 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002020 } else {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302021 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002022 clk_disable(host->clk);
2023 if (!IS_ERR(host->pclk))
2024 clk_disable(host->pclk);
2025 if (!IS_ERR_OR_NULL(host->dfab_pclk))
2026 clk_disable(host->dfab_pclk);
2027 }
2028}
2029
2030static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2031 unsigned int req_clk)
2032{
2033 unsigned int sel_clk = -1;
2034
2035 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2036 unsigned char cnt;
2037
2038 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2039 if (host->plat->sup_clk_table[cnt] > req_clk)
2040 break;
2041 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2042 sel_clk = host->plat->sup_clk_table[cnt];
2043 break;
2044 } else
2045 sel_clk = host->plat->sup_clk_table[cnt];
2046 }
2047 } else {
2048 if ((req_clk < host->plat->msmsdcc_fmax) &&
2049 (req_clk > host->plat->msmsdcc_fmid))
2050 sel_clk = host->plat->msmsdcc_fmid;
2051 else
2052 sel_clk = req_clk;
2053 }
2054
2055 return sel_clk;
2056}
2057
2058static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2059 struct msmsdcc_host *host)
2060{
2061 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2062 return host->plat->sup_clk_table[0];
2063 else
2064 return host->plat->msmsdcc_fmin;
2065}
2066
2067static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2068 struct msmsdcc_host *host)
2069{
2070 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2071 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2072 else
2073 return host->plat->msmsdcc_fmax;
2074}
2075
2076static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302077{
2078 struct msm_mmc_gpio_data *curr;
2079 int i, rc = 0;
2080
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002081 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302082 for (i = 0; i < curr->size; i++) {
2083 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002084 if (curr->gpio[i].is_always_on &&
2085 curr->gpio[i].is_enabled)
2086 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302087 rc = gpio_request(curr->gpio[i].no,
2088 curr->gpio[i].name);
2089 if (rc) {
2090 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2091 mmc_hostname(host->mmc),
2092 curr->gpio[i].no,
2093 curr->gpio[i].name, rc);
2094 goto free_gpios;
2095 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002096 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302097 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002098 if (curr->gpio[i].is_always_on)
2099 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302100 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002101 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302102 }
2103 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002104 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302105
2106free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002107 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302108 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002109 curr->gpio[i].is_enabled = false;
2110 }
2111out:
2112 return rc;
2113}
2114
2115static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2116{
2117 struct msm_mmc_pad_data *curr;
2118 int i;
2119
2120 curr = host->plat->pin_data->pad_data;
2121 for (i = 0; i < curr->drv->size; i++) {
2122 if (enable)
2123 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2124 curr->drv->on[i].val);
2125 else
2126 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2127 curr->drv->off[i].val);
2128 }
2129
2130 for (i = 0; i < curr->pull->size; i++) {
2131 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002132 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002133 curr->pull->on[i].val);
2134 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002135 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002136 curr->pull->off[i].val);
2137 }
2138
2139 return 0;
2140}
2141
2142static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2143{
2144 int rc = 0;
2145
2146 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2147 return 0;
2148
2149 if (host->plat->pin_data->is_gpio)
2150 rc = msmsdcc_setup_gpio(host, enable);
2151 else
2152 rc = msmsdcc_setup_pad(host, enable);
2153
2154 if (!rc)
2155 host->plat->pin_data->cfg_sts = enable;
2156
2157 return rc;
2158}
2159
2160static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2161{
2162 unsigned int wakeup_irq;
2163
2164 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2165 host->plat->sdiowakeup_irq :
2166 host->core_irqres->start;
2167
2168 if (!host->irq_wake_enabled) {
2169 enable_irq_wake(wakeup_irq);
2170 host->irq_wake_enabled = true;
2171 }
2172}
2173
2174static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2175{
2176 unsigned int wakeup_irq;
2177
2178 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2179 host->plat->sdiowakeup_irq :
2180 host->core_irqres->start;
2181
2182 if (host->irq_wake_enabled) {
2183 disable_irq_wake(wakeup_irq);
2184 host->irq_wake_enabled = false;
2185 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302186}
2187
San Mehat9d2bd732009-09-22 16:44:22 -07002188static void
2189msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2190{
2191 struct msmsdcc_host *host = mmc_priv(mmc);
2192 u32 clk = 0, pwr = 0;
2193 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002194 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002195 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002196
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002197 DBG(host, "ios->clock = %u\n", ios->clock);
Sahitya Tummala7a892482011-01-18 11:22:49 +05302198
San Mehat9d2bd732009-09-22 16:44:22 -07002199 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002200 spin_lock_irqsave(&host->lock, flags);
2201 if (!host->clks_on) {
2202 msmsdcc_setup_clocks(host, true);
2203 host->clks_on = 1;
2204 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2205 if (!host->plat->sdiowakeup_irq) {
2206 writel_relaxed(host->mci_irqenable,
2207 host->base + MMCIMASK0);
2208 mb();
2209 if (host->plat->cfg_mpm_sdiowakeup &&
2210 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2211 host->plat->cfg_mpm_sdiowakeup(
2212 mmc_dev(mmc), SDC_DAT1_DISWAKE);
2213 msmsdcc_disable_irq_wake(host);
2214 } else if (!(mmc->pm_flags &
2215 MMC_PM_WAKE_SDIO_IRQ)) {
2216 writel_relaxed(host->mci_irqenable,
2217 host->base + MMCIMASK0);
2218 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05302219 } else {
2220 writel_relaxed(host->mci_irqenable,
2221 host->base + MMCIMASK0);
2222 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002223 }
San Mehat9d2bd732009-09-22 16:44:22 -07002224 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002225 spin_unlock_irqrestore(&host->lock, flags);
2226
2227 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2228 /*
2229 * For DDR50 mode, controller needs clock rate to be
2230 * double than what is required on the SD card CLK pin.
2231 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302232 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002233 /*
2234 * Make sure that we don't double the clock if
2235 * doubled clock rate is already set
2236 */
2237 if (!host->ddr_doubled_clk_rate ||
2238 (host->ddr_doubled_clk_rate &&
2239 (host->ddr_doubled_clk_rate != ios->clock))) {
2240 host->ddr_doubled_clk_rate =
2241 msmsdcc_get_sup_clk_rate(
2242 host, (ios->clock * 2));
2243 clock = host->ddr_doubled_clk_rate;
2244 }
2245 } else {
2246 host->ddr_doubled_clk_rate = 0;
2247 }
2248
2249 if (clock != host->clk_rate) {
2250 rc = clk_set_rate(host->clk, clock);
2251 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302252 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002253 mmc_hostname(mmc), clock);
2254 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302255 host->reg_write_delay =
2256 (1 + ((3 * USEC_PER_SEC) /
2257 (host->clk_rate ? host->clk_rate :
2258 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002259 }
2260 /*
2261 * give atleast 2 MCLK cycles delay for clocks
2262 * and SDCC core to stabilize
2263 */
2264 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002265 clk |= MCI_CLK_ENABLE;
2266 }
2267
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002268 if (ios->bus_width == MMC_BUS_WIDTH_8)
2269 clk |= MCI_CLK_WIDEBUS_8;
2270 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2271 clk |= MCI_CLK_WIDEBUS_4;
2272 else
2273 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002274
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002275 if (msmsdcc_is_pwrsave(host))
2276 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002277
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002278 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002279
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002280 host->tuning_needed = 0;
2281 /*
2282 * Select the controller timing mode according
2283 * to current bus speed mode
2284 */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302285 if (ios->timing == MMC_TIMING_UHS_SDR104) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002286 clk |= (4 << 14);
2287 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302288 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002289 clk |= (3 << 14);
2290 } else {
2291 clk |= (2 << 14); /* feedback clock */
2292 }
2293
2294 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2295 clk |= (2 << 23);
2296
2297 if (host->io_pad_pwr_switch)
2298 clk |= IO_PAD_PWR_SWITCH;
2299
2300 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
San Mehat9d2bd732009-09-22 16:44:22 -07002301 pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002302 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2303 pwr |= msmsdcc_setup_vreg(host, !!ios->vdd);
San Mehat9d2bd732009-09-22 16:44:22 -07002304
2305 switch (ios->power_mode) {
2306 case MMC_POWER_OFF:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002307 htc_pwrsink_set(PWRSINK_SDCARD, 0);
2308 if (!host->sdcc_irq_disabled) {
2309 if (host->plat->cfg_mpm_sdiowakeup)
2310 host->plat->cfg_mpm_sdiowakeup(
2311 mmc_dev(mmc), SDC_DAT1_DISABLE);
2312 disable_irq(host->core_irqres->start);
2313 host->sdcc_irq_disabled = 1;
2314 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302315 /*
2316 * As VDD pad rail is always on, set low voltage for VDD
2317 * pad rail when slot is unused (when card is not present
2318 * or during system suspend).
2319 */
2320 msmsdcc_set_vddp_low_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002321 msmsdcc_setup_pins(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002322 break;
2323 case MMC_POWER_UP:
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302324 /* writing PWR_UP bit is redundant */
San Mehat9d2bd732009-09-22 16:44:22 -07002325 pwr |= MCI_PWR_UP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002326 if (host->sdcc_irq_disabled) {
2327 if (host->plat->cfg_mpm_sdiowakeup)
2328 host->plat->cfg_mpm_sdiowakeup(
2329 mmc_dev(mmc), SDC_DAT1_ENABLE);
2330 enable_irq(host->core_irqres->start);
2331 host->sdcc_irq_disabled = 0;
2332 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302333 msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002334 msmsdcc_setup_pins(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07002335 break;
2336 case MMC_POWER_ON:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002337 htc_pwrsink_set(PWRSINK_SDCARD, 100);
San Mehat9d2bd732009-09-22 16:44:22 -07002338 pwr |= MCI_PWR_ON;
2339 break;
2340 }
2341
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002342 spin_lock_irqsave(&host->lock, flags);
2343 if (!host->clks_on) {
2344 /* force the clocks to be on */
2345 msmsdcc_setup_clocks(host, true);
2346 /*
2347 * give atleast 2 MCLK cycles delay for clocks
2348 * and SDCC core to stabilize
2349 */
2350 msmsdcc_delay(host);
2351 }
2352 writel_relaxed(clk, host->base + MMCICLOCK);
2353 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002354
2355 if (host->pwr != pwr) {
2356 host->pwr = pwr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002357 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302358 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002359 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002360 if (!host->clks_on) {
2361 /* force the clocks to be off */
2362 msmsdcc_setup_clocks(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002363 }
2364
2365 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
2366 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2367 if (!host->plat->sdiowakeup_irq) {
2368 writel_relaxed(MCI_SDIOINTMASK,
2369 host->base + MMCIMASK0);
2370 mb();
2371 if (host->plat->cfg_mpm_sdiowakeup &&
2372 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2373 host->plat->cfg_mpm_sdiowakeup(
2374 mmc_dev(mmc), SDC_DAT1_ENWAKE);
2375 msmsdcc_enable_irq_wake(host);
2376 } else if (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2377 writel_relaxed(0, host->base + MMCIMASK0);
2378 } else {
2379 writel_relaxed(MCI_SDIOINTMASK,
2380 host->base + MMCIMASK0);
2381 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302382 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002383 }
2384 msmsdcc_setup_clocks(host, false);
2385 host->clks_on = 0;
2386 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302387
2388 if (host->cmd19_tuning_in_progress)
2389 WARN(!host->clks_on,
2390 "cmd19_tuning_in_progress but SDCC clocks are OFF\n");
2391
San Mehat4adbbcc2009-11-08 13:00:37 -08002392 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002393}
2394
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002395int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2396{
2397 struct msmsdcc_host *host = mmc_priv(mmc);
2398 u32 clk;
2399
2400 clk = readl_relaxed(host->base + MMCICLOCK);
2401 pr_debug("Changing to pwr_save=%d", pwrsave);
2402 if (pwrsave && msmsdcc_is_pwrsave(host))
2403 clk |= MCI_CLK_PWRSAVE;
2404 else
2405 clk &= ~MCI_CLK_PWRSAVE;
2406 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302407 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002408
2409 return 0;
2410}
2411
2412static int msmsdcc_get_ro(struct mmc_host *mmc)
2413{
2414 int status = -ENOSYS;
2415 struct msmsdcc_host *host = mmc_priv(mmc);
2416
2417 if (host->plat->wpswitch) {
2418 status = host->plat->wpswitch(mmc_dev(mmc));
2419 } else if (host->plat->wpswitch_gpio) {
2420 status = gpio_request(host->plat->wpswitch_gpio,
2421 "SD_WP_Switch");
2422 if (status) {
2423 pr_err("%s: %s: Failed to request GPIO %d\n",
2424 mmc_hostname(mmc), __func__,
2425 host->plat->wpswitch_gpio);
2426 } else {
2427 status = gpio_direction_input(
2428 host->plat->wpswitch_gpio);
2429 if (!status) {
2430 /*
2431 * Wait for atleast 300ms as debounce
2432 * time for GPIO input to stabilize.
2433 */
2434 msleep(300);
2435 status = gpio_get_value_cansleep(
2436 host->plat->wpswitch_gpio);
2437 status ^= !host->plat->wpswitch_polarity;
2438 }
2439 gpio_free(host->plat->wpswitch_gpio);
2440 }
2441 }
2442
2443 if (status < 0)
2444 status = -ENOSYS;
2445 pr_debug("%s: Card read-only status %d\n", __func__, status);
2446
2447 return status;
2448}
2449
2450#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002451static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2452{
2453 struct msmsdcc_host *host = mmc_priv(mmc);
2454 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002455
2456 if (enable) {
2457 spin_lock_irqsave(&host->lock, flags);
2458 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
2459 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
2460 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2461 spin_unlock_irqrestore(&host->lock, flags);
2462 } else {
2463 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
2464 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
2465 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2466 }
2467 mb();
2468}
2469#endif /* CONFIG_MMC_MSM_SDIO_SUPPORT */
2470
2471#ifdef CONFIG_PM_RUNTIME
2472static int msmsdcc_enable(struct mmc_host *mmc)
2473{
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302474 int rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002475 struct device *dev = mmc->parent;
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302476 struct msmsdcc_host *host = mmc_priv(mmc);
2477
2478 msmsdcc_pm_qos_update_latency(host, 1);
2479
2480 if (mmc->card && mmc_card_sdio(mmc->card) && host->is_resumed)
2481 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002482
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302483 if (dev->power.runtime_status == RPM_SUSPENDING) {
2484 if (mmc->suspend_task == current) {
2485 pm_runtime_get_noresume(dev);
2486 goto out;
2487 }
2488 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002489
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302490 rc = pm_runtime_get_sync(dev);
2491
2492 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002493 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2494 __func__, rc);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302495 return rc;
2496 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302497
2498 host->is_resumed = true;
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302499out:
2500 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002501}
2502
2503static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2504{
2505 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302506 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002507
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302508 msmsdcc_pm_qos_update_latency(host, 0);
2509
2510 if (mmc->card && mmc_card_sdio(mmc->card))
2511 return 0;
2512
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302513 if (host->plat->disable_runtime_pm)
2514 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002515
2516 rc = pm_runtime_put_sync(mmc->parent);
2517
2518 if (rc < 0)
2519 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2520 __func__, rc);
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302521 else
2522 host->is_resumed = false;
2523
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002524 return rc;
2525}
2526#else
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302527static int msmsdcc_enable(struct mmc_host *mmc)
2528{
2529 struct msmsdcc_host *host = mmc_priv(mmc);
2530 unsigned long flags;
2531
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302532 msmsdcc_pm_qos_update_latency(host, 1);
2533
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302534 spin_lock_irqsave(&host->lock, flags);
2535 if (!host->clks_on) {
2536 msmsdcc_setup_clocks(host, true);
2537 host->clks_on = 1;
2538 }
2539 spin_unlock_irqrestore(&host->lock, flags);
2540
2541 return 0;
2542}
2543
2544static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2545{
2546 struct msmsdcc_host *host = mmc_priv(mmc);
2547 unsigned long flags;
2548
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302549 msmsdcc_pm_qos_update_latency(host, 0);
2550
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302551 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302552 return 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302553
2554 spin_lock_irqsave(&host->lock, flags);
2555 if (host->clks_on) {
2556 msmsdcc_setup_clocks(host, false);
2557 host->clks_on = 0;
2558 }
2559 spin_unlock_irqrestore(&host->lock, flags);
2560
2561 return 0;
2562}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002563#endif
2564
2565static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2566 struct mmc_ios *ios)
2567{
2568 struct msmsdcc_host *host = mmc_priv(mmc);
2569 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302570 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002571
2572 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2573 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302574 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002575 goto out;
2576 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2577 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302578 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002579 goto out;
2580 }
San Mehat9d2bd732009-09-22 16:44:22 -07002581
2582 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002583 /*
2584 * If we are here means voltage switch from high voltage to
2585 * low voltage is required
2586 */
2587
2588 /*
2589 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2590 * register until they become all zeros.
2591 */
2592 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302593 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002594 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2595 mmc_hostname(mmc), __func__);
2596 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002597 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002598
2599 /* Stop SD CLK output. */
2600 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2601 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302602 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002603 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002604
2605 /*
2606 * Switch VDDPX from high voltage to low voltage
2607 * to change the VDD of the SD IO pads.
2608 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302609 rc = msmsdcc_set_vddp_low_vol(host);
2610 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002611 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002612
2613 spin_lock_irqsave(&host->lock, flags);
2614 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2615 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302616 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002617 host->io_pad_pwr_switch = 1;
2618 spin_unlock_irqrestore(&host->lock, flags);
2619
2620 /* Wait 5 ms for the voltage regulater in the card to become stable. */
2621 usleep_range(5000, 5500);
2622
2623 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302624 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002625 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2626 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302627 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002628 spin_unlock_irqrestore(&host->lock, flags);
2629
2630 /*
2631 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
2632 * don't become all ones within 1 ms then a Voltage Switch
2633 * sequence has failed and a power cycle to the card is required.
2634 * Otherwise Voltage Switch sequence is completed successfully.
2635 */
2636 usleep_range(1000, 1500);
2637
2638 spin_lock_irqsave(&host->lock, flags);
2639 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
2640 != (0xF << 1)) {
2641 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
2642 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302643 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002644 goto out_unlock;
2645 }
2646
2647out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302648 /* Enable PWRSAVE */
2649 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2650 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002651 spin_unlock_irqrestore(&host->lock, flags);
2652out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302653 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002654}
2655
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302656static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002657{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002658 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002659
2660 /* Program the MCLK value to MCLK_FREQ bit field */
2661 if (host->clk_rate <= 112000000)
2662 mclk_freq = 0;
2663 else if (host->clk_rate <= 125000000)
2664 mclk_freq = 1;
2665 else if (host->clk_rate <= 137000000)
2666 mclk_freq = 2;
2667 else if (host->clk_rate <= 150000000)
2668 mclk_freq = 3;
2669 else if (host->clk_rate <= 162000000)
2670 mclk_freq = 4;
2671 else if (host->clk_rate <= 175000000)
2672 mclk_freq = 5;
2673 else if (host->clk_rate <= 187000000)
2674 mclk_freq = 6;
2675 else if (host->clk_rate <= 200000000)
2676 mclk_freq = 7;
2677
2678 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2679 & ~(7 << 24)) | (mclk_freq << 24)),
2680 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002681}
2682
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302683/* Initialize the DLL (Programmable Delay Line ) */
2684static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002685{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002686 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302687 unsigned long flags;
2688 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002689
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302690 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002691 /*
2692 * Make sure that clock is always enabled when DLL
2693 * tuning is in progress. Keeping PWRSAVE ON may
2694 * turn off the clock. So let's disable the PWRSAVE
2695 * here and re-enable it once tuning is completed.
2696 */
2697 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2698 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302699
2700 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
2701 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2702 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2703
2704 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
2705 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2706 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2707
2708 msmsdcc_cm_sdc4_dll_set_freq(host);
2709
2710 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
2711 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2712 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2713
2714 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
2715 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2716 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2717
2718 /* Set DLL_EN bit to 1. */
2719 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2720 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
2721
2722 /* Set CK_OUT_EN bit to 1. */
2723 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2724 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2725
2726 wait_cnt = 50;
2727 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
2728 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
2729 /* max. wait for 50us sec for LOCK bit to be set */
2730 if (--wait_cnt == 0) {
2731 pr_err("%s: %s: DLL failed to LOCK\n",
2732 mmc_hostname(host->mmc), __func__);
2733 rc = -ETIMEDOUT;
2734 goto out;
2735 }
2736 /* wait for 1us before polling again */
2737 udelay(1);
2738 }
2739
2740out:
2741 /* re-enable PWRSAVE */
2742 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2743 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2744 spin_unlock_irqrestore(&host->lock, flags);
2745
2746 return rc;
2747}
2748
2749static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
2750 u8 poll)
2751{
2752 int rc = 0;
2753 u32 wait_cnt = 50;
2754 u8 ck_out_en = 0;
2755
2756 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
2757 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
2758 MCI_CK_OUT_EN);
2759
2760 while (ck_out_en != poll) {
2761 if (--wait_cnt == 0) {
2762 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
2763 mmc_hostname(host->mmc), __func__, poll);
2764 rc = -ETIMEDOUT;
2765 goto out;
2766 }
2767 udelay(1);
2768
2769 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
2770 MCI_CK_OUT_EN);
2771 }
2772out:
2773 return rc;
2774}
2775
2776/*
2777 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
2778 * calibration sequence. This function should be called before
2779 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
2780 * commands (CMD17/CMD18).
2781 *
2782 * This function gets called when host spinlock acquired.
2783 */
2784static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
2785{
2786 int rc = 0;
2787 u32 config;
2788
2789 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
2790 config |= MCI_CDR_EN;
2791 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
2792 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
2793
2794 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2795 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
2796 if (rc)
2797 goto err_out;
2798
2799 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2800 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2801 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2802
2803 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
2804 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
2805 if (rc)
2806 goto err_out;
2807
2808 goto out;
2809
2810err_out:
2811 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
2812out:
2813 return rc;
2814}
2815
2816static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2817 u8 phase)
2818{
2819 int rc = 0;
2820 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6,
2821 0x7, 0x5, 0x4, 0x8, 0x9,
2822 0xB, 0xA, 0xE, 0xF, 0xD,
2823 0xC};
2824 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*/
2880
2881static u8 find_most_appropriate_phase(struct msmsdcc_host *host,
2882 u8 *phase_table, u8 total_phases)
2883{
2884 u8 ret, temp;
2885 u8 ranges[16][16] = { {0}, {0} };
2886 u8 phases_per_row[16] = {0};
2887 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
2888 int cnt;
2889
2890 for (cnt = 0; cnt <= total_phases; cnt++) {
2891 ranges[row_index][col_index] = phase_table[cnt];
2892 phases_per_row[row_index] += 1;
2893 col_index++;
2894
2895 if ((cnt + 1) > total_phases) {
2896 continue;
2897 /* check if next phase in phase_table is consecutive or not */
2898 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
2899 row_index++;
2900 col_index = 0;
2901 }
2902 }
2903
2904 for (cnt = 0; cnt <= total_phases; cnt++) {
2905 if (phases_per_row[cnt] > curr_max) {
2906 curr_max = phases_per_row[cnt];
2907 selected_row_index = cnt;
2908 }
2909 }
2910
2911 temp = ((curr_max * 3) / 4);
2912 ret = ranges[selected_row_index][temp];
2913
2914 return ret;
2915}
2916
2917static int msmsdcc_execute_tuning(struct mmc_host *mmc)
2918{
2919 int rc = 0;
2920 struct msmsdcc_host *host = mmc_priv(mmc);
2921 unsigned long flags;
2922 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
2923
2924 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
2925
2926 /* Tuning is only required for SDR104 modes */
2927 if (!host->tuning_needed) {
2928 rc = 0;
2929 goto exit;
2930 }
2931
2932 spin_lock_irqsave(&host->lock, flags);
2933 WARN(!host->pwr, "SDCC power is turned off\n");
2934 WARN(!host->clks_on, "SDCC clocks are turned off\n");
2935 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
2936
2937 host->cmd19_tuning_in_progress = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302938 msmsdcc_delay(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302939 spin_unlock_irqrestore(&host->lock, flags);
2940
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002941 /* first of all reset the tuning block */
2942 rc = msmsdcc_init_cm_sdc4_dll(host);
2943 if (rc)
2944 goto out;
2945
2946 data_buf = kmalloc(64, GFP_KERNEL);
2947 if (!data_buf) {
2948 rc = -ENOMEM;
2949 goto out;
2950 }
2951
2952 phase = 0;
2953 do {
2954 struct mmc_command cmd = {0};
2955 struct mmc_data data = {0};
2956 struct mmc_request mrq = {
2957 .cmd = &cmd,
2958 .data = &data
2959 };
2960 struct scatterlist sg;
2961
2962 /* set the phase in delay line hw block */
2963 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2964 if (rc)
2965 goto kfree;
2966
2967 cmd.opcode = MMC_SEND_TUNING_BLOCK;
2968 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
2969
2970 data.blksz = 64;
2971 data.blocks = 1;
2972 data.flags = MMC_DATA_READ;
2973 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
2974
2975 data.sg = &sg;
2976 data.sg_len = 1;
2977 sg_init_one(&sg, data_buf, 64);
2978 memset(data_buf, 0, 64);
2979 mmc_wait_for_req(mmc, &mrq);
2980
2981 if (!cmd.error && !data.error &&
2982 !memcmp(data_buf, cmd19_tuning_block, 64)) {
2983 /* tuning is successful with this tuning point */
2984 tuned_phases[tuned_phase_cnt++] = phase;
2985 }
2986 } while (++phase < 16);
2987
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002988 if (tuned_phase_cnt) {
2989 tuned_phase_cnt--;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302990 phase = find_most_appropriate_phase(host, tuned_phases,
2991 tuned_phase_cnt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002992 /*
2993 * Finally set the selected phase in delay
2994 * line hw block.
2995 */
2996 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2997 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302998 goto kfree;
2999 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
3000 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003001 } else {
3002 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303003 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003004 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303005 msmsdcc_dump_sdcc_state(host);
3006 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003007 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003008
3009kfree:
3010 kfree(data_buf);
3011out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303012 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05303013 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003014 host->cmd19_tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303015 spin_unlock_irqrestore(&host->lock, flags);
3016exit:
3017 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003018 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07003019}
3020
3021static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003022 .enable = msmsdcc_enable,
3023 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07003024 .request = msmsdcc_request,
3025 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003026 .get_ro = msmsdcc_get_ro,
3027#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07003028 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003029#endif
3030 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
3031 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07003032};
3033
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003034static unsigned int
3035msmsdcc_slot_status(struct msmsdcc_host *host)
3036{
3037 int status;
3038 unsigned int gpio_no = host->plat->status_gpio;
3039
3040 status = gpio_request(gpio_no, "SD_HW_Detect");
3041 if (status) {
3042 pr_err("%s: %s: Failed to request GPIO %d\n",
3043 mmc_hostname(host->mmc), __func__, gpio_no);
3044 } else {
3045 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003046 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08003047 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003048 if (host->plat->is_status_gpio_active_low)
3049 status = !status;
3050 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003051 gpio_free(gpio_no);
3052 }
3053 return status;
3054}
3055
San Mehat9d2bd732009-09-22 16:44:22 -07003056static void
3057msmsdcc_check_status(unsigned long data)
3058{
3059 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3060 unsigned int status;
3061
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003062 if (host->plat->status || host->plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08003063 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003064 status = host->plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08003065 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003066 status = msmsdcc_slot_status(host);
3067
Krishna Konda941604a2012-01-10 17:46:34 -08003068 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08003069
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003070 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08003071 if (host->plat->status)
3072 pr_info("%s: Slot status change detected "
3073 "(%d -> %d)\n",
3074 mmc_hostname(host->mmc),
3075 host->oldstat, status);
3076 else if (host->plat->is_status_gpio_active_low)
3077 pr_info("%s: Slot status change detected "
3078 "(%d -> %d) and the card detect GPIO"
3079 " is ACTIVE_LOW\n",
3080 mmc_hostname(host->mmc),
3081 host->oldstat, status);
3082 else
3083 pr_info("%s: Slot status change detected "
3084 "(%d -> %d) and the card detect GPIO"
3085 " is ACTIVE_HIGH\n",
3086 mmc_hostname(host->mmc),
3087 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07003088 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003089 }
3090 host->oldstat = status;
3091 } else {
3092 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07003093 }
San Mehat9d2bd732009-09-22 16:44:22 -07003094}
3095
3096static irqreturn_t
3097msmsdcc_platform_status_irq(int irq, void *dev_id)
3098{
3099 struct msmsdcc_host *host = dev_id;
3100
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003101 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07003102 msmsdcc_check_status((unsigned long) host);
3103 return IRQ_HANDLED;
3104}
3105
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003106static irqreturn_t
3107msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
3108{
3109 struct msmsdcc_host *host = dev_id;
3110
3111 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
3112 spin_lock(&host->lock);
3113 if (!host->sdio_irq_disabled) {
3114 disable_irq_nosync(irq);
3115 if (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
3116 wake_lock(&host->sdio_wlock);
3117 msmsdcc_disable_irq_wake(host);
3118 }
3119 host->sdio_irq_disabled = 1;
3120 }
3121 if (host->plat->is_sdio_al_client) {
3122 if (!host->clks_on) {
3123 msmsdcc_setup_clocks(host, true);
3124 host->clks_on = 1;
3125 }
3126 if (host->sdcc_irq_disabled) {
3127 writel_relaxed(host->mci_irqenable,
3128 host->base + MMCIMASK0);
3129 mb();
3130 enable_irq(host->core_irqres->start);
3131 host->sdcc_irq_disabled = 0;
3132 }
3133 wake_lock(&host->sdio_wlock);
3134 }
3135 spin_unlock(&host->lock);
3136
3137 return IRQ_HANDLED;
3138}
3139
San Mehat9d2bd732009-09-22 16:44:22 -07003140static void
3141msmsdcc_status_notify_cb(int card_present, void *dev_id)
3142{
3143 struct msmsdcc_host *host = dev_id;
3144
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003145 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07003146 card_present);
3147 msmsdcc_check_status((unsigned long) host);
3148}
3149
San Mehat9d2bd732009-09-22 16:44:22 -07003150static int
3151msmsdcc_init_dma(struct msmsdcc_host *host)
3152{
3153 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
3154 host->dma.host = host;
3155 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003156 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003157
3158 if (!host->dmares)
3159 return -ENODEV;
3160
3161 host->dma.nc = dma_alloc_coherent(NULL,
3162 sizeof(struct msmsdcc_nc_dmadata),
3163 &host->dma.nc_busaddr,
3164 GFP_KERNEL);
3165 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003166 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07003167 return -ENOMEM;
3168 }
3169 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
3170 host->dma.cmd_busaddr = host->dma.nc_busaddr;
3171 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
3172 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
3173 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07003174 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07003175
3176 return 0;
3177}
3178
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003179#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
3180/**
3181 * Allocate and Connect a SDCC peripheral's SPS endpoint
3182 *
3183 * This function allocates endpoint context and
3184 * connect it with memory endpoint by calling
3185 * appropriate SPS driver APIs.
3186 *
3187 * Also registers a SPS callback function with
3188 * SPS driver
3189 *
3190 * This function should only be called once typically
3191 * during driver probe.
3192 *
3193 * @host - Pointer to sdcc host structure
3194 * @ep - Pointer to sps endpoint data structure
3195 * @is_produce - 1 means Producer endpoint
3196 * 0 means Consumer endpoint
3197 *
3198 * @return - 0 if successful else negative value.
3199 *
3200 */
3201static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
3202 struct msmsdcc_sps_ep_conn_data *ep,
3203 bool is_producer)
3204{
3205 int rc = 0;
3206 struct sps_pipe *sps_pipe_handle;
3207 struct sps_connect *sps_config = &ep->config;
3208 struct sps_register_event *sps_event = &ep->event;
3209
3210 /* Allocate endpoint context */
3211 sps_pipe_handle = sps_alloc_endpoint();
3212 if (!sps_pipe_handle) {
3213 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
3214 mmc_hostname(host->mmc), is_producer);
3215 rc = -ENOMEM;
3216 goto out;
3217 }
3218
3219 /* Get default connection configuration for an endpoint */
3220 rc = sps_get_config(sps_pipe_handle, sps_config);
3221 if (rc) {
3222 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
3223 " rc=%d", mmc_hostname(host->mmc),
3224 (u32)sps_pipe_handle, rc);
3225 goto get_config_err;
3226 }
3227
3228 /* Modify the default connection configuration */
3229 if (is_producer) {
3230 /*
3231 * For SDCC producer transfer, source should be
3232 * SDCC peripheral where as destination should
3233 * be system memory.
3234 */
3235 sps_config->source = host->sps.bam_handle;
3236 sps_config->destination = SPS_DEV_HANDLE_MEM;
3237 /* Producer pipe will handle this connection */
3238 sps_config->mode = SPS_MODE_SRC;
3239 sps_config->options =
3240 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3241 } else {
3242 /*
3243 * For SDCC consumer transfer, source should be
3244 * system memory where as destination should
3245 * SDCC peripheral
3246 */
3247 sps_config->source = SPS_DEV_HANDLE_MEM;
3248 sps_config->destination = host->sps.bam_handle;
3249 sps_config->mode = SPS_MODE_DEST;
3250 sps_config->options =
3251 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3252 }
3253
3254 /* Producer pipe index */
3255 sps_config->src_pipe_index = host->sps.src_pipe_index;
3256 /* Consumer pipe index */
3257 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
3258 /*
3259 * This event thresold value is only significant for BAM-to-BAM
3260 * transfer. It's ignored for BAM-to-System mode transfer.
3261 */
3262 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05303263
3264 /* Allocate maximum descriptor fifo size */
3265 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
3266 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003267 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
3268 sps_config->desc.size,
3269 &sps_config->desc.phys_base,
3270 GFP_KERNEL);
3271
Pratibhasagar V00b94332011-10-18 14:57:27 +05303272 if (!sps_config->desc.base) {
3273 rc = -ENOMEM;
3274 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3275 , mmc_hostname(host->mmc));
3276 goto get_config_err;
3277 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003278 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3279
3280 /* Establish connection between peripheral and memory endpoint */
3281 rc = sps_connect(sps_pipe_handle, sps_config);
3282 if (rc) {
3283 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3284 " rc=%d", mmc_hostname(host->mmc),
3285 (u32)sps_pipe_handle, rc);
3286 goto sps_connect_err;
3287 }
3288
3289 sps_event->mode = SPS_TRIGGER_CALLBACK;
3290 sps_event->options = SPS_O_EOT;
3291 sps_event->callback = msmsdcc_sps_complete_cb;
3292 sps_event->xfer_done = NULL;
3293 sps_event->user = (void *)host;
3294
3295 /* Register callback event for EOT (End of transfer) event. */
3296 rc = sps_register_event(sps_pipe_handle, sps_event);
3297 if (rc) {
3298 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3299 " rc=%d", mmc_hostname(host->mmc),
3300 (u32)sps_pipe_handle, rc);
3301 goto reg_event_err;
3302 }
3303 /* Now save the sps pipe handle */
3304 ep->pipe_handle = sps_pipe_handle;
3305 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3306 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3307 __func__, is_producer ? "READ" : "WRITE",
3308 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3309 goto out;
3310
3311reg_event_err:
3312 sps_disconnect(sps_pipe_handle);
3313sps_connect_err:
3314 dma_free_coherent(mmc_dev(host->mmc),
3315 sps_config->desc.size,
3316 sps_config->desc.base,
3317 sps_config->desc.phys_base);
3318get_config_err:
3319 sps_free_endpoint(sps_pipe_handle);
3320out:
3321 return rc;
3322}
3323
3324/**
3325 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3326 *
3327 * This function disconnect endpoint and deallocates
3328 * endpoint context.
3329 *
3330 * This function should only be called once typically
3331 * during driver remove.
3332 *
3333 * @host - Pointer to sdcc host structure
3334 * @ep - Pointer to sps endpoint data structure
3335 *
3336 */
3337static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3338 struct msmsdcc_sps_ep_conn_data *ep)
3339{
3340 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3341 struct sps_connect *sps_config = &ep->config;
3342 struct sps_register_event *sps_event = &ep->event;
3343
3344 sps_event->xfer_done = NULL;
3345 sps_event->callback = NULL;
3346 sps_register_event(sps_pipe_handle, sps_event);
3347 sps_disconnect(sps_pipe_handle);
3348 dma_free_coherent(mmc_dev(host->mmc),
3349 sps_config->desc.size,
3350 sps_config->desc.base,
3351 sps_config->desc.phys_base);
3352 sps_free_endpoint(sps_pipe_handle);
3353}
3354
3355/**
3356 * Reset SDCC peripheral's SPS endpoint
3357 *
3358 * This function disconnects an endpoint.
3359 *
3360 * This function should be called for reseting
3361 * SPS endpoint when data transfer error is
3362 * encountered during data transfer. This
3363 * can be considered as soft reset to endpoint.
3364 *
3365 * This function should only be called if
3366 * msmsdcc_sps_init() is already called.
3367 *
3368 * @host - Pointer to sdcc host structure
3369 * @ep - Pointer to sps endpoint data structure
3370 *
3371 * @return - 0 if successful else negative value.
3372 */
3373static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3374 struct msmsdcc_sps_ep_conn_data *ep)
3375{
3376 int rc = 0;
3377 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3378
3379 rc = sps_disconnect(sps_pipe_handle);
3380 if (rc) {
3381 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3382 " rc=%d", mmc_hostname(host->mmc), __func__,
3383 (u32)sps_pipe_handle, rc);
3384 goto out;
3385 }
3386 out:
3387 return rc;
3388}
3389
3390/**
3391 * Restore SDCC peripheral's SPS endpoint
3392 *
3393 * This function connects an endpoint.
3394 *
3395 * This function should be called for restoring
3396 * SPS endpoint after data transfer error is
3397 * encountered during data transfer. This
3398 * can be considered as soft reset to endpoint.
3399 *
3400 * This function should only be called if
3401 * msmsdcc_sps_reset_ep() is called before.
3402 *
3403 * @host - Pointer to sdcc host structure
3404 * @ep - Pointer to sps endpoint data structure
3405 *
3406 * @return - 0 if successful else negative value.
3407 */
3408static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3409 struct msmsdcc_sps_ep_conn_data *ep)
3410{
3411 int rc = 0;
3412 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3413 struct sps_connect *sps_config = &ep->config;
3414 struct sps_register_event *sps_event = &ep->event;
3415
3416 /* Establish connection between peripheral and memory endpoint */
3417 rc = sps_connect(sps_pipe_handle, sps_config);
3418 if (rc) {
3419 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3420 " rc=%d", mmc_hostname(host->mmc), __func__,
3421 (u32)sps_pipe_handle, rc);
3422 goto out;
3423 }
3424
3425 /* Register callback event for EOT (End of transfer) event. */
3426 rc = sps_register_event(sps_pipe_handle, sps_event);
3427 if (rc) {
3428 pr_err("%s: %s: sps_register_event() failed!!!"
3429 " pipe_handle=0x%x, rc=%d",
3430 mmc_hostname(host->mmc), __func__,
3431 (u32)sps_pipe_handle, rc);
3432 goto reg_event_err;
3433 }
3434 goto out;
3435
3436reg_event_err:
3437 sps_disconnect(sps_pipe_handle);
3438out:
3439 return rc;
3440}
3441
3442/**
3443 * Initialize SPS HW connected with SDCC core
3444 *
3445 * This function register BAM HW resources with
3446 * SPS driver and then initialize 2 SPS endpoints
3447 *
3448 * This function should only be called once typically
3449 * during driver probe.
3450 *
3451 * @host - Pointer to sdcc host structure
3452 *
3453 * @return - 0 if successful else negative value.
3454 *
3455 */
3456static int msmsdcc_sps_init(struct msmsdcc_host *host)
3457{
3458 int rc = 0;
3459 struct sps_bam_props bam = {0};
3460
3461 host->bam_base = ioremap(host->bam_memres->start,
3462 resource_size(host->bam_memres));
3463 if (!host->bam_base) {
3464 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3465 " size=0x%x", mmc_hostname(host->mmc),
3466 host->bam_memres->start,
3467 (host->bam_memres->end -
3468 host->bam_memres->start));
3469 rc = -ENOMEM;
3470 goto out;
3471 }
3472
3473 bam.phys_addr = host->bam_memres->start;
3474 bam.virt_addr = host->bam_base;
3475 /*
3476 * This event thresold value is only significant for BAM-to-BAM
3477 * transfer. It's ignored for BAM-to-System mode transfer.
3478 */
3479 bam.event_threshold = 0x10; /* Pipe event threshold */
3480 /*
3481 * This threshold controls when the BAM publish
3482 * the descriptor size on the sideband interface.
3483 * SPS HW will only be used when
3484 * data transfer size > MCI_FIFOSIZE (64 bytes).
3485 * PIO mode will be used when
3486 * data transfer size < MCI_FIFOSIZE (64 bytes).
3487 * So set this thresold value to 64 bytes.
3488 */
3489 bam.summing_threshold = 64;
3490 /* SPS driver wll handle the SDCC BAM IRQ */
3491 bam.irq = (u32)host->bam_irqres->start;
3492 bam.manage = SPS_BAM_MGR_LOCAL;
3493
3494 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3495 (u32)bam.phys_addr);
3496 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3497 (u32)bam.virt_addr);
3498
3499 /* Register SDCC Peripheral BAM device to SPS driver */
3500 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3501 if (rc) {
3502 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3503 mmc_hostname(host->mmc), rc);
3504 goto reg_bam_err;
3505 }
3506 pr_info("%s: BAM device registered. bam_handle=0x%x",
3507 mmc_hostname(host->mmc), host->sps.bam_handle);
3508
3509 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3510 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3511
3512 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3513 SPS_PROD_PERIPHERAL);
3514 if (rc)
3515 goto sps_reset_err;
3516 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3517 SPS_CONS_PERIPHERAL);
3518 if (rc)
3519 goto cons_conn_err;
3520
3521 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3522 mmc_hostname(host->mmc),
3523 (unsigned long long)host->bam_memres->start,
3524 (unsigned int)host->bam_irqres->start);
3525 goto out;
3526
3527cons_conn_err:
3528 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3529sps_reset_err:
3530 sps_deregister_bam_device(host->sps.bam_handle);
3531reg_bam_err:
3532 iounmap(host->bam_base);
3533out:
3534 return rc;
3535}
3536
3537/**
3538 * De-initialize SPS HW connected with SDCC core
3539 *
3540 * This function deinitialize SPS endpoints and then
3541 * deregisters BAM resources from SPS driver.
3542 *
3543 * This function should only be called once typically
3544 * during driver remove.
3545 *
3546 * @host - Pointer to sdcc host structure
3547 *
3548 */
3549static void msmsdcc_sps_exit(struct msmsdcc_host *host)
3550{
3551 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
3552 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3553 sps_deregister_bam_device(host->sps.bam_handle);
3554 iounmap(host->bam_base);
3555}
3556#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
3557
3558static ssize_t
3559show_polling(struct device *dev, struct device_attribute *attr, char *buf)
3560{
3561 struct mmc_host *mmc = dev_get_drvdata(dev);
3562 struct msmsdcc_host *host = mmc_priv(mmc);
3563 int poll;
3564 unsigned long flags;
3565
3566 spin_lock_irqsave(&host->lock, flags);
3567 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
3568 spin_unlock_irqrestore(&host->lock, flags);
3569
3570 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
3571}
3572
3573static ssize_t
3574set_polling(struct device *dev, struct device_attribute *attr,
3575 const char *buf, size_t count)
3576{
3577 struct mmc_host *mmc = dev_get_drvdata(dev);
3578 struct msmsdcc_host *host = mmc_priv(mmc);
3579 int value;
3580 unsigned long flags;
3581
3582 sscanf(buf, "%d", &value);
3583
3584 spin_lock_irqsave(&host->lock, flags);
3585 if (value) {
3586 mmc->caps |= MMC_CAP_NEEDS_POLL;
3587 mmc_detect_change(host->mmc, 0);
3588 } else {
3589 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3590 }
3591#ifdef CONFIG_HAS_EARLYSUSPEND
3592 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
3593#endif
3594 spin_unlock_irqrestore(&host->lock, flags);
3595 return count;
3596}
3597
3598static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
3599 show_polling, set_polling);
3600static struct attribute *dev_attrs[] = {
3601 &dev_attr_polling.attr,
3602 NULL,
3603};
3604static struct attribute_group dev_attr_grp = {
3605 .attrs = dev_attrs,
3606};
3607
3608#ifdef CONFIG_HAS_EARLYSUSPEND
3609static void msmsdcc_early_suspend(struct early_suspend *h)
3610{
3611 struct msmsdcc_host *host =
3612 container_of(h, struct msmsdcc_host, early_suspend);
3613 unsigned long flags;
3614
3615 spin_lock_irqsave(&host->lock, flags);
3616 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
3617 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3618 spin_unlock_irqrestore(&host->lock, flags);
3619};
3620static void msmsdcc_late_resume(struct early_suspend *h)
3621{
3622 struct msmsdcc_host *host =
3623 container_of(h, struct msmsdcc_host, early_suspend);
3624 unsigned long flags;
3625
3626 if (host->polling_enabled) {
3627 spin_lock_irqsave(&host->lock, flags);
3628 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
3629 mmc_detect_change(host->mmc, 0);
3630 spin_unlock_irqrestore(&host->lock, flags);
3631 }
3632};
3633#endif
3634
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303635void msmsdcc_print_regs(const char *name, void __iomem *base,
3636 unsigned int no_of_regs)
3637{
3638 unsigned int i;
3639
3640 if (!base)
3641 return;
3642 pr_info("===== %s: Register Dumps @base=0x%x =====\n",
3643 name, (u32)base);
3644 for (i = 0; i < no_of_regs; i = i + 4) {
3645 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x.\n", i*4,
3646 (u32)readl_relaxed(base + i*4),
3647 (u32)readl_relaxed(base + ((i+1)*4)),
3648 (u32)readl_relaxed(base + ((i+2)*4)),
3649 (u32)readl_relaxed(base + ((i+3)*4)));
3650 }
3651}
3652
3653static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
3654{
3655 /* Dump current state of SDCC clocks, power and irq */
3656 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
3657 (host->pwr ? "ON" : "OFF"));
3658 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
3659 mmc_hostname(host->mmc),
3660 (host->clks_on ? "ON" : "OFF"),
3661 (u32)clk_get_rate(host->clk));
3662 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
3663 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
3664
3665 /* Now dump SDCC registers. Don't print FIFO registers */
3666 if (host->clks_on)
3667 msmsdcc_print_regs("SDCC-CORE", host->base, 28);
3668
3669 if (host->curr.data) {
3670 if (msmsdcc_check_dma_op_req(host->curr.data))
3671 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
3672 else if (host->is_dma_mode)
3673 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
3674 mmc_hostname(host->mmc), host->dma.busy,
3675 host->dma.channel, host->dma.crci);
3676 else if (host->is_sps_mode)
3677 pr_info("%s: SPS mode: busy=%d\n",
3678 mmc_hostname(host->mmc), host->sps.busy);
3679
3680 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
3681 mmc_hostname(host->mmc), host->curr.xfer_size,
3682 host->curr.data_xfered, host->curr.xfer_remain);
3683 pr_info("%s: got_dataend=%d, prog_enable=%d,"
3684 " wait_for_auto_prog_done=%d,"
3685 " got_auto_prog_done=%d\n",
3686 mmc_hostname(host->mmc), host->curr.got_dataend,
3687 host->prog_enable, host->curr.wait_for_auto_prog_done,
3688 host->curr.got_auto_prog_done);
3689 }
3690
3691}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003692static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
3693{
3694 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3695 struct mmc_request *mrq;
3696 unsigned long flags;
3697
3698 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003699 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003700 pr_info("%s: %s: dummy CMD52 timeout\n",
3701 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003702 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003703 }
3704
3705 mrq = host->curr.mrq;
3706
3707 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303708 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
3709 mrq->cmd->opcode);
3710 msmsdcc_dump_sdcc_state(host);
3711
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003712 if (!mrq->cmd->error)
3713 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303714 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003715 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003716 if (mrq->data && !mrq->data->error)
3717 mrq->data->error = -ETIMEDOUT;
3718 host->curr.data_xfered = 0;
3719 if (host->dma.sg && host->is_dma_mode) {
3720 msm_dmov_stop_cmd(host->dma.channel,
3721 &host->dma.hdr, 0);
3722 } else if (host->sps.sg && host->is_sps_mode) {
3723 /* Stop current SPS transfer */
3724 msmsdcc_sps_exit_curr_xfer(host);
3725 } else {
3726 msmsdcc_reset_and_restore(host);
3727 msmsdcc_stop_data(host);
3728 if (mrq->data && mrq->data->stop)
3729 msmsdcc_start_command(host,
3730 mrq->data->stop, 0);
3731 else
3732 msmsdcc_request_end(host, mrq);
3733 }
3734 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05303735 host->prog_enable = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003736 msmsdcc_reset_and_restore(host);
3737 msmsdcc_request_end(host, mrq);
3738 }
3739 }
3740 spin_unlock_irqrestore(&host->lock, flags);
3741}
3742
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303743static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
3744{
3745 int i, ret;
3746 struct mmc_platform_data *pdata;
3747 struct device_node *np = dev->of_node;
3748 u32 bus_width = 0;
3749 u32 *clk_table;
3750 int clk_table_len;
3751 u32 *sup_voltages;
3752 int sup_volt_len;
3753
3754 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
3755 if (!pdata) {
3756 dev_err(dev, "could not allocate memory for platform data\n");
3757 goto err;
3758 }
3759
3760 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
3761 if (bus_width == 8) {
3762 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
3763 } else if (bus_width == 4) {
3764 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
3765 } else {
3766 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
3767 pdata->mmc_bus_width = 0;
3768 }
3769
3770 if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
3771 size_t sz;
3772 sz = sup_volt_len / sizeof(*sup_voltages);
3773 if (sz > 0) {
3774 sup_voltages = devm_kzalloc(dev,
3775 sz * sizeof(*sup_voltages), GFP_KERNEL);
3776 if (!sup_voltages) {
3777 dev_err(dev, "No memory for supported voltage\n");
3778 goto err;
3779 }
3780
3781 ret = of_property_read_u32_array(np,
3782 "qcom,sdcc-sup-voltages", sup_voltages, sz);
3783 if (ret < 0) {
3784 dev_err(dev, "error while reading voltage"
3785 "ranges %d\n", ret);
3786 goto err;
3787 }
3788 } else {
3789 dev_err(dev, "No supported voltages\n");
3790 goto err;
3791 }
3792 for (i = 0; i < sz; i += 2) {
3793 u32 mask;
3794
3795 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
3796 sup_voltages[i + 1]);
3797 if (!mask)
3798 dev_err(dev, "Invalide voltage range %d\n", i);
3799 pdata->ocr_mask |= mask;
3800 }
3801 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
3802 } else {
3803 dev_err(dev, "Supported voltage range not specified\n");
3804 }
3805
3806 if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
3807 size_t sz;
3808 sz = clk_table_len / sizeof(*clk_table);
3809
3810 if (sz > 0) {
3811 clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
3812 GFP_KERNEL);
3813 if (!clk_table) {
3814 dev_err(dev, "No memory for clock table\n");
3815 goto err;
3816 }
3817
3818 ret = of_property_read_u32_array(np,
3819 "qcom,sdcc-clk-rates", clk_table, sz);
3820 if (ret < 0) {
3821 dev_err(dev, "error while reading clk"
3822 "table %d\n", ret);
3823 goto err;
3824 }
3825 } else {
3826 dev_err(dev, "clk_table not specified\n");
3827 goto err;
3828 }
3829 pdata->sup_clk_table = clk_table;
3830 pdata->sup_clk_cnt = sz;
3831 } else {
3832 dev_err(dev, "Supported clock rates not specified\n");
3833 }
3834
3835 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
3836 pdata->nonremovable = true;
3837 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
3838 pdata->disable_cmd23 = true;
3839
3840 return pdata;
3841err:
3842 return NULL;
3843}
3844
San Mehat9d2bd732009-09-22 16:44:22 -07003845static int
3846msmsdcc_probe(struct platform_device *pdev)
3847{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303848 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07003849 struct msmsdcc_host *host;
3850 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003851 unsigned long flags;
3852 struct resource *core_irqres = NULL;
3853 struct resource *bam_irqres = NULL;
3854 struct resource *core_memres = NULL;
3855 struct resource *dml_memres = NULL;
3856 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07003857 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07003858 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05303859 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003860 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07003861
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303862 if (pdev->dev.of_node) {
3863 plat = msmsdcc_populate_pdata(&pdev->dev);
3864 of_property_read_u32((&pdev->dev)->of_node,
3865 "cell-index", &pdev->id);
3866 } else {
3867 plat = pdev->dev.platform_data;
3868 }
3869
San Mehat9d2bd732009-09-22 16:44:22 -07003870 /* must have platform data */
3871 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003872 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003873 ret = -EINVAL;
3874 goto out;
3875 }
3876
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003877 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07003878 return -EINVAL;
3879
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05303880 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
3881 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
3882 return -EINVAL;
3883 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003884
San Mehat9d2bd732009-09-22 16:44:22 -07003885 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003886 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003887 return -ENXIO;
3888 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303889 if (pdev->dev.of_node) {
3890 /*
3891 * Device tree iomem resources are only accessible by index.
3892 * index = 0 -> SDCC register interface
3893 * index = 1 -> DML register interface
3894 * index = 2 -> BAM register interface
3895 * IRQ resources:
3896 * index = 0 -> SDCC IRQ
3897 * index = 1 -> BAM IRQ
3898 */
3899 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
3900 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
3901 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
3902 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
3903 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
3904 } else {
3905 for (i = 0; i < pdev->num_resources; i++) {
3906 if (pdev->resource[i].flags & IORESOURCE_MEM) {
3907 if (!strncmp(pdev->resource[i].name,
3908 "sdcc_dml_addr",
3909 sizeof("sdcc_dml_addr")))
3910 dml_memres = &pdev->resource[i];
3911 else if (!strncmp(pdev->resource[i].name,
3912 "sdcc_bam_addr",
3913 sizeof("sdcc_bam_addr")))
3914 bam_memres = &pdev->resource[i];
3915 else
3916 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07003917
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303918 }
3919 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
3920 if (!strncmp(pdev->resource[i].name,
3921 "sdcc_bam_irq",
3922 sizeof("sdcc_bam_irq")))
3923 bam_irqres = &pdev->resource[i];
3924 else
3925 core_irqres = &pdev->resource[i];
3926 }
3927 if (pdev->resource[i].flags & IORESOURCE_DMA) {
3928 if (!strncmp(pdev->resource[i].name,
3929 "sdcc_dma_chnl",
3930 sizeof("sdcc_dma_chnl")))
3931 dmares = &pdev->resource[i];
3932 else if (!strncmp(pdev->resource[i].name,
3933 "sdcc_dma_crci",
3934 sizeof("sdcc_dma_crci")))
3935 dma_crci_res = &pdev->resource[i];
3936 }
Krishna Konda25786ec2011-07-25 16:21:36 -07003937 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003938 }
3939
3940 if (!core_irqres || !core_memres) {
3941 pr_err("%s: Invalid sdcc core resource\n", __func__);
3942 return -ENXIO;
3943 }
3944
3945 /*
3946 * Both BAM and DML memory resource should be preset.
3947 * BAM IRQ resource should also be present.
3948 */
3949 if ((bam_memres && !dml_memres) ||
3950 (!bam_memres && dml_memres) ||
3951 ((bam_memres && dml_memres) && !bam_irqres)) {
3952 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003953 return -ENXIO;
3954 }
3955
3956 /*
3957 * Setup our host structure
3958 */
San Mehat9d2bd732009-09-22 16:44:22 -07003959 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
3960 if (!mmc) {
3961 ret = -ENOMEM;
3962 goto out;
3963 }
3964
3965 host = mmc_priv(mmc);
3966 host->pdev_id = pdev->id;
3967 host->plat = plat;
3968 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08003969 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05303970
3971 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003972 host->is_sps_mode = 1;
3973 else if (dmares)
3974 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07003975
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003976 host->base = ioremap(core_memres->start,
3977 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07003978 if (!host->base) {
3979 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003980 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003981 }
3982
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003983 host->core_irqres = core_irqres;
3984 host->bam_irqres = bam_irqres;
3985 host->core_memres = core_memres;
3986 host->dml_memres = dml_memres;
3987 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07003988 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07003989 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07003990 spin_lock_init(&host->lock);
3991
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003992#ifdef CONFIG_MMC_EMBEDDED_SDIO
3993 if (plat->embedded_sdio)
3994 mmc_set_embedded_sdio_data(mmc,
3995 &plat->embedded_sdio->cis,
3996 &plat->embedded_sdio->cccr,
3997 plat->embedded_sdio->funcs,
3998 plat->embedded_sdio->num_funcs);
3999#endif
4000
Sahitya Tummala62612cf2010-12-08 15:03:03 +05304001 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
4002 (unsigned long)host);
4003
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004004 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
4005 (unsigned long)host);
4006 if (host->is_dma_mode) {
4007 /* Setup DMA */
4008 ret = msmsdcc_init_dma(host);
4009 if (ret)
4010 goto ioremap_free;
4011 } else {
4012 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004013 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004014 }
4015
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004016 /*
4017 * Setup SDCC clock if derived from Dayatona
4018 * fabric core clock.
4019 */
4020 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07004021 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004022 if (!IS_ERR(host->dfab_pclk)) {
4023 /* Set the clock rate to 64MHz for max. performance */
4024 ret = clk_set_rate(host->dfab_pclk, 64000000);
4025 if (ret)
4026 goto dfab_pclk_put;
4027 ret = clk_enable(host->dfab_pclk);
4028 if (ret)
4029 goto dfab_pclk_put;
4030 } else
4031 goto dma_free;
4032 }
4033
4034 /*
4035 * Setup main peripheral bus clock
4036 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004037 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004038 if (!IS_ERR(host->pclk)) {
4039 ret = clk_enable(host->pclk);
4040 if (ret)
4041 goto pclk_put;
4042
4043 host->pclk_rate = clk_get_rate(host->pclk);
4044 }
4045
4046 /*
4047 * Setup SDC MMC clock
4048 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004049 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07004050 if (IS_ERR(host->clk)) {
4051 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004052 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07004053 }
4054
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004055 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
4056 if (ret) {
4057 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
4058 goto clk_put;
4059 }
4060
4061 ret = clk_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004062 if (ret)
4063 goto clk_put;
4064
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004065 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304066 if (!host->clk_rate)
4067 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304068
4069 /*
4070 * Lookup the Controller Version, to identify the supported features
4071 * Version number read as 0 would indicate SDCC3 or earlier versions
4072 */
4073 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
4074 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
4075 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304076 /*
4077 * Set the register write delay according to min. clock frequency
4078 * supported and update later when the host->clk_rate changes.
4079 */
4080 host->reg_write_delay =
4081 (1 + ((3 * USEC_PER_SEC) /
4082 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004083
4084 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05304085 /* Apply Hard reset to SDCC to put it in power on default state */
4086 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004087
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304088 /* pm qos request to prevent apps idle power collapse */
4089 if (host->plat->swfi_latency)
4090 pm_qos_add_request(&host->pm_qos_req_dma,
4091 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
4092
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004093 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07004094 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004095 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07004096 goto clk_disable;
4097 }
4098
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004099
4100 /* Clocks has to be running before accessing SPS/DML HW blocks */
4101 if (host->is_sps_mode) {
4102 /* Initialize SPS */
4103 ret = msmsdcc_sps_init(host);
4104 if (ret)
4105 goto vreg_deinit;
4106 /* Initialize DML */
4107 ret = msmsdcc_dml_init(host);
4108 if (ret)
4109 goto sps_exit;
4110 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05304111 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07004112
San Mehat9d2bd732009-09-22 16:44:22 -07004113 /*
4114 * Setup MMC host structure
4115 */
4116 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004117 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
4118 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004119 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004120 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
4121 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07004122
San Mehat9d2bd732009-09-22 16:44:22 -07004123 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304124 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304125
4126 /*
4127 * If we send the CMD23 before multi block write/read command
4128 * then we need not to send CMD12 at the end of the transfer.
4129 * If we don't send the CMD12 then only way to detect the PROG_DONE
4130 * status is to use the AUTO_PROG_DONE status provided by SDCC4
4131 * controller. So let's enable the CMD23 for SDCC4 only.
4132 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304133 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304134 mmc->caps |= MMC_CAP_CMD23;
4135
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004136 mmc->caps |= plat->uhs_caps;
4137 /*
4138 * XPC controls the maximum current in the default speed mode of SDXC
4139 * card. XPC=0 means 100mA (max.) but speed class is not supported.
4140 * XPC=1 means 150mA (max.) and speed class is supported.
4141 */
4142 if (plat->xpc_cap)
4143 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
4144 MMC_CAP_SET_XPC_180);
4145
4146 if (plat->nonremovable)
4147 mmc->caps |= MMC_CAP_NONREMOVABLE;
4148#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
4149 mmc->caps |= MMC_CAP_SDIO_IRQ;
4150#endif
4151
4152 if (plat->is_sdio_al_client)
4153 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07004154
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304155 mmc->max_segs = msmsdcc_get_nr_sg(host);
4156 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
4157 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07004158
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304159 mmc->max_req_size = MMC_MAX_REQ_SIZE;
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +05304160 mmc->max_seg_size = mmc->max_req_size;
San Mehat9d2bd732009-09-22 16:44:22 -07004161
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004162 writel_relaxed(0, host->base + MMCIMASK0);
4163 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -07004164
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004165 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
4166 mb();
4167 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07004168
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004169 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
4170 DRIVER_NAME " (cmd)", host);
4171 if (ret)
4172 goto dml_exit;
4173
4174 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
4175 DRIVER_NAME " (pio)", host);
4176 if (ret)
4177 goto irq_free;
4178
4179 /*
4180 * Enable SDCC IRQ only when host is powered on. Otherwise, this
4181 * IRQ is un-necessarily being monitored by MPM (Modem power
4182 * management block) during idle-power collapse. The MPM will be
4183 * configured to monitor the DATA1 GPIO line with level-low trigger
4184 * and thus depending on the GPIO status, it prevents TCXO shutdown
4185 * during idle-power collapse.
4186 */
4187 disable_irq(core_irqres->start);
4188 host->sdcc_irq_disabled = 1;
4189
4190 if (plat->sdiowakeup_irq) {
4191 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4192 mmc_hostname(mmc));
4193 ret = request_irq(plat->sdiowakeup_irq,
4194 msmsdcc_platform_sdiowakeup_irq,
4195 IRQF_SHARED | IRQF_TRIGGER_LOW,
4196 DRIVER_NAME "sdiowakeup", host);
4197 if (ret) {
4198 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
4199 plat->sdiowakeup_irq, ret);
4200 goto pio_irq_free;
4201 } else {
4202 spin_lock_irqsave(&host->lock, flags);
4203 if (!host->sdio_irq_disabled) {
4204 disable_irq_nosync(plat->sdiowakeup_irq);
4205 host->sdio_irq_disabled = 1;
4206 }
4207 spin_unlock_irqrestore(&host->lock, flags);
4208 }
4209 }
4210
4211 if (plat->cfg_mpm_sdiowakeup) {
4212 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4213 mmc_hostname(mmc));
4214 }
4215
4216 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
4217 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004218 /*
4219 * Setup card detect change
4220 */
4221
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004222 if (plat->status || plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08004223 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004224 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08004225 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004226 host->oldstat = msmsdcc_slot_status(host);
Krishna Konda360aa422011-12-06 18:27:41 -08004227
Krishna Konda941604a2012-01-10 17:46:34 -08004228 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004229 }
San Mehat9d2bd732009-09-22 16:44:22 -07004230
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004231 if (plat->status_irq) {
4232 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07004233 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004234 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07004235 DRIVER_NAME " (slot)",
4236 host);
4237 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004238 pr_err("Unable to get slot IRQ %d (%d)\n",
4239 plat->status_irq, ret);
4240 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004241 }
4242 } else if (plat->register_status_notify) {
4243 plat->register_status_notify(msmsdcc_status_notify_cb, host);
4244 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004245 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07004246 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004247
4248 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004249
4250 ret = pm_runtime_set_active(&(pdev)->dev);
4251 if (ret < 0)
4252 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
4253 __func__, ret);
4254 /*
4255 * There is no notion of suspend/resume for SD/MMC/SDIO
4256 * cards. So host can be suspended/resumed with out
4257 * worrying about its children.
4258 */
4259 pm_suspend_ignore_children(&(pdev)->dev, true);
4260
4261 /*
4262 * MMC/SD/SDIO bus suspend/resume operations are defined
4263 * only for the slots that will be used for non-removable
4264 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
4265 * defined. Otherwise, they simply become card removal and
4266 * insertion events during suspend and resume respectively.
4267 * Hence, enable run-time PM only for slots for which bus
4268 * suspend/resume operations are defined.
4269 */
4270#ifdef CONFIG_MMC_UNSAFE_RESUME
4271 /*
4272 * If this capability is set, MMC core will enable/disable host
4273 * for every claim/release operation on a host. We use this
4274 * notification to increment/decrement runtime pm usage count.
4275 */
4276 mmc->caps |= MMC_CAP_DISABLE;
4277 pm_runtime_enable(&(pdev)->dev);
4278#else
4279 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
4280 mmc->caps |= MMC_CAP_DISABLE;
4281 pm_runtime_enable(&(pdev)->dev);
4282 }
4283#endif
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05304284#ifndef CONFIG_PM_RUNTIME
4285 mmc_set_disable_delay(mmc, MSM_MMC_DISABLE_TIMEOUT);
4286#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004287 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
4288 (unsigned long)host);
4289
San Mehat9d2bd732009-09-22 16:44:22 -07004290 mmc_add_host(mmc);
4291
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004292#ifdef CONFIG_HAS_EARLYSUSPEND
4293 host->early_suspend.suspend = msmsdcc_early_suspend;
4294 host->early_suspend.resume = msmsdcc_late_resume;
4295 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
4296 register_early_suspend(&host->early_suspend);
4297#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004298
Krishna Konda25786ec2011-07-25 16:21:36 -07004299 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
4300 " dmacrcri %d\n", mmc_hostname(mmc),
4301 (unsigned long long)core_memres->start,
4302 (unsigned int) core_irqres->start,
4303 (unsigned int) plat->status_irq, host->dma.channel,
4304 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004305
4306 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
4307 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
4308 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
4309 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
4310 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
4311 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
4312 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
4313 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
4314 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
4315 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
4316 host->eject);
4317 pr_info("%s: Power save feature enable = %d\n",
4318 mmc_hostname(mmc), msmsdcc_pwrsave);
4319
Krishna Konda25786ec2011-07-25 16:21:36 -07004320 if (host->is_dma_mode && host->dma.channel != -1
4321 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004322 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004323 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004324 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004325 mmc_hostname(mmc), host->dma.cmd_busaddr,
4326 host->dma.cmdptr_busaddr);
4327 } else if (host->is_sps_mode) {
4328 pr_info("%s: SPS-BAM data transfer mode available\n",
4329 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004330 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004331 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004332
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004333#if defined(CONFIG_DEBUG_FS)
4334 msmsdcc_dbg_createhost(host);
4335#endif
4336 if (!plat->status_irq) {
4337 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
4338 if (ret)
4339 goto platform_irq_free;
4340 }
San Mehat9d2bd732009-09-22 16:44:22 -07004341 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004342
4343 platform_irq_free:
4344 del_timer_sync(&host->req_tout_timer);
4345 pm_runtime_disable(&(pdev)->dev);
4346 pm_runtime_set_suspended(&(pdev)->dev);
4347
4348 if (plat->status_irq)
4349 free_irq(plat->status_irq, host);
4350 sdiowakeup_irq_free:
4351 wake_lock_destroy(&host->sdio_suspend_wlock);
4352 if (plat->sdiowakeup_irq)
4353 free_irq(plat->sdiowakeup_irq, host);
4354 pio_irq_free:
4355 if (plat->sdiowakeup_irq)
4356 wake_lock_destroy(&host->sdio_wlock);
4357 free_irq(core_irqres->start, host);
4358 irq_free:
4359 free_irq(core_irqres->start, host);
4360 dml_exit:
4361 if (host->is_sps_mode)
4362 msmsdcc_dml_exit(host);
4363 sps_exit:
4364 if (host->is_sps_mode)
4365 msmsdcc_sps_exit(host);
4366 vreg_deinit:
4367 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07004368 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004369 clk_disable(host->clk);
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304370 if (host->plat->swfi_latency)
4371 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07004372 clk_put:
4373 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004374 pclk_disable:
4375 if (!IS_ERR(host->pclk))
4376 clk_disable(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07004377 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004378 if (!IS_ERR(host->pclk))
4379 clk_put(host->pclk);
4380 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4381 clk_disable(host->dfab_pclk);
4382 dfab_pclk_put:
4383 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4384 clk_put(host->dfab_pclk);
4385 dma_free:
4386 if (host->is_dma_mode) {
4387 if (host->dmares)
4388 dma_free_coherent(NULL,
4389 sizeof(struct msmsdcc_nc_dmadata),
4390 host->dma.nc, host->dma.nc_busaddr);
4391 }
4392 ioremap_free:
4393 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07004394 host_free:
4395 mmc_free_host(mmc);
4396 out:
4397 return ret;
4398}
4399
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004400static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07004401{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004402 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4403 struct mmc_platform_data *plat;
4404 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004405
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004406 if (!mmc)
4407 return -ENXIO;
4408
4409 if (pm_runtime_suspended(&(pdev)->dev))
4410 pm_runtime_resume(&(pdev)->dev);
4411
4412 host = mmc_priv(mmc);
4413
4414 DBG(host, "Removing SDCC device = %d\n", pdev->id);
4415 plat = host->plat;
4416
4417 if (!plat->status_irq)
4418 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
4419
4420 del_timer_sync(&host->req_tout_timer);
4421 tasklet_kill(&host->dma_tlet);
4422 tasklet_kill(&host->sps.tlet);
4423 mmc_remove_host(mmc);
4424
4425 if (plat->status_irq)
4426 free_irq(plat->status_irq, host);
4427
4428 wake_lock_destroy(&host->sdio_suspend_wlock);
4429 if (plat->sdiowakeup_irq) {
4430 wake_lock_destroy(&host->sdio_wlock);
4431 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
4432 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07004433 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004434
4435 free_irq(host->core_irqres->start, host);
4436 free_irq(host->core_irqres->start, host);
4437
4438 clk_put(host->clk);
4439 if (!IS_ERR(host->pclk))
4440 clk_put(host->pclk);
4441 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4442 clk_put(host->dfab_pclk);
4443
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304444 if (host->plat->swfi_latency)
4445 pm_qos_remove_request(&host->pm_qos_req_dma);
4446
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004447 msmsdcc_vreg_init(host, false);
4448
4449 if (host->is_dma_mode) {
4450 if (host->dmares)
4451 dma_free_coherent(NULL,
4452 sizeof(struct msmsdcc_nc_dmadata),
4453 host->dma.nc, host->dma.nc_busaddr);
4454 }
4455
4456 if (host->is_sps_mode) {
4457 msmsdcc_dml_exit(host);
4458 msmsdcc_sps_exit(host);
4459 }
4460
4461 iounmap(host->base);
4462 mmc_free_host(mmc);
4463
4464#ifdef CONFIG_HAS_EARLYSUSPEND
4465 unregister_early_suspend(&host->early_suspend);
4466#endif
4467 pm_runtime_disable(&(pdev)->dev);
4468 pm_runtime_set_suspended(&(pdev)->dev);
4469
4470 return 0;
4471}
4472
4473#ifdef CONFIG_MSM_SDIO_AL
4474int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4475{
4476 struct msmsdcc_host *host = mmc_priv(mmc);
4477 unsigned long flags;
4478
4479 spin_lock_irqsave(&host->lock, flags);
4480 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
4481 enable ? "En" : "Dis");
4482
4483 if (enable) {
4484 if (!host->sdcc_irq_disabled) {
4485 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05304486 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004487 host->sdcc_irq_disabled = 1;
4488 }
4489
4490 if (host->clks_on) {
4491 msmsdcc_setup_clocks(host, false);
4492 host->clks_on = 0;
4493 }
4494
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304495 if (host->plat->sdio_lpm_gpio_setup &&
4496 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004497 spin_unlock_irqrestore(&host->lock, flags);
4498 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
4499 spin_lock_irqsave(&host->lock, flags);
4500 host->sdio_gpio_lpm = 1;
4501 }
4502
4503 if (host->sdio_irq_disabled) {
4504 msmsdcc_enable_irq_wake(host);
4505 enable_irq(host->plat->sdiowakeup_irq);
4506 host->sdio_irq_disabled = 0;
4507 }
4508 } else {
4509 if (!host->sdio_irq_disabled) {
4510 disable_irq_nosync(host->plat->sdiowakeup_irq);
4511 host->sdio_irq_disabled = 1;
4512 msmsdcc_disable_irq_wake(host);
4513 }
4514
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304515 if (host->plat->sdio_lpm_gpio_setup &&
4516 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004517 spin_unlock_irqrestore(&host->lock, flags);
4518 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
4519 spin_lock_irqsave(&host->lock, flags);
4520 host->sdio_gpio_lpm = 0;
4521 }
4522
4523 if (!host->clks_on) {
4524 msmsdcc_setup_clocks(host, true);
4525 host->clks_on = 1;
4526 }
4527
4528 if (host->sdcc_irq_disabled) {
4529 writel_relaxed(host->mci_irqenable,
4530 host->base + MMCIMASK0);
4531 mb();
4532 enable_irq(host->core_irqres->start);
4533 host->sdcc_irq_disabled = 0;
4534 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004535 }
4536 spin_unlock_irqrestore(&host->lock, flags);
4537 return 0;
4538}
4539#else
4540int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4541{
4542 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004543}
4544#endif
4545
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004546#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07004547static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004548msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004549{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004550 struct mmc_host *mmc = dev_get_drvdata(dev);
4551 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07004552 int rc = 0;
4553
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004554 if (host->plat->is_sdio_al_client)
4555 return 0;
Sahitya Tummala7661a452011-07-18 13:28:35 +05304556 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004557 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004558 host->sdcc_suspending = 1;
4559 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07004560
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004561 /*
4562 * If the clocks are already turned off by SDIO clients (as
4563 * part of LPM), then clocks should be turned on before
4564 * calling mmc_suspend_host() because mmc_suspend_host might
4565 * send some commands to the card. The clocks will be turned
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304566 * off again after mmc_suspend_host. Thus for SDIO
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004567 * cards, clocks will be turned on before mmc_suspend_host
4568 * and turned off after mmc_suspend_host.
4569 */
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304570 if (mmc->card && mmc_card_sdio(mmc->card)) {
4571 mmc->ios.clock = host->clk_rate;
4572 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4573 }
San Mehat9d2bd732009-09-22 16:44:22 -07004574
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004575 /*
4576 * MMC core thinks that host is disabled by now since
4577 * runtime suspend is scheduled after msmsdcc_disable()
4578 * is called. Thus, MMC core will try to enable the host
4579 * while suspending it. This results in a synchronous
4580 * runtime resume request while in runtime suspending
4581 * context and hence inorder to complete this resume
4582 * requet, it will wait for suspend to be complete,
4583 * but runtime suspend also can not proceed further
4584 * until the host is resumed. Thus, it leads to a hang.
4585 * Hence, increase the pm usage count before suspending
4586 * the host so that any resume requests after this will
4587 * simple become pm usage counter increment operations.
4588 */
4589 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05304590 /* If there is pending detect work abort runtime suspend */
4591 if (unlikely(work_busy(&mmc->detect.work)))
4592 rc = -EAGAIN;
4593 else
4594 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004595 pm_runtime_put_noidle(dev);
4596
4597 if (!rc) {
4598 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
4599 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ)) {
4600 disable_irq(host->core_irqres->start);
4601 host->sdcc_irq_disabled = 1;
4602
4603 /*
4604 * If MMC core level suspend is not supported,
4605 * turn off clocks to allow deep sleep (TCXO
4606 * shutdown).
4607 */
4608 mmc->ios.clock = 0;
4609 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4610 enable_irq(host->core_irqres->start);
4611 host->sdcc_irq_disabled = 0;
4612
4613 if (host->plat->sdiowakeup_irq) {
4614 host->sdio_irq_disabled = 0;
4615 msmsdcc_enable_irq_wake(host);
4616 enable_irq(host->plat->sdiowakeup_irq);
4617 }
4618 }
4619 }
4620 host->sdcc_suspending = 0;
4621 mmc->suspend_task = NULL;
4622 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
4623 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004624 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05304625 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
San Mehat9d2bd732009-09-22 16:44:22 -07004626 return rc;
4627}
4628
4629static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004630msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004631{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004632 struct mmc_host *mmc = dev_get_drvdata(dev);
4633 struct msmsdcc_host *host = mmc_priv(mmc);
4634 unsigned long flags;
4635
4636 if (host->plat->is_sdio_al_client)
4637 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07004638
Sahitya Tummala7661a452011-07-18 13:28:35 +05304639 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004640 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004641 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
4642 if (host->sdcc_irq_disabled) {
4643 enable_irq(host->core_irqres->start);
4644 host->sdcc_irq_disabled = 0;
4645 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304646 mmc->ios.clock = host->clk_rate;
4647 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07004648
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304649 spin_lock_irqsave(&host->lock, flags);
4650 writel_relaxed(host->mci_irqenable,
4651 host->base + MMCIMASK0);
4652 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07004653
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304654 if ((mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) &&
4655 !host->sdio_irq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004656 if (host->plat->sdiowakeup_irq) {
4657 disable_irq_nosync(
4658 host->plat->sdiowakeup_irq);
4659 msmsdcc_disable_irq_wake(host);
4660 host->sdio_irq_disabled = 1;
4661 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304662 }
San Mehat9d2bd732009-09-22 16:44:22 -07004663
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304664 spin_unlock_irqrestore(&host->lock, flags);
4665 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004666
4667 mmc_resume_host(mmc);
4668
4669 /*
4670 * FIXME: Clearing of flags must be handled in clients
4671 * resume handler.
4672 */
4673 spin_lock_irqsave(&host->lock, flags);
4674 mmc->pm_flags = 0;
4675 spin_unlock_irqrestore(&host->lock, flags);
4676
4677 /*
4678 * After resuming the host wait for sometime so that
4679 * the SDIO work will be processed.
4680 */
4681 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO)) {
4682 if ((host->plat->cfg_mpm_sdiowakeup ||
4683 host->plat->sdiowakeup_irq) &&
4684 wake_lock_active(&host->sdio_wlock))
4685 wake_lock_timeout(&host->sdio_wlock, 1);
4686 }
4687
4688 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004689 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304690 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004691 return 0;
4692}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004693
4694static int msmsdcc_runtime_idle(struct device *dev)
4695{
4696 struct mmc_host *mmc = dev_get_drvdata(dev);
4697 struct msmsdcc_host *host = mmc_priv(mmc);
4698
4699 if (host->plat->is_sdio_al_client)
4700 return 0;
4701
4702 /* Idle timeout is not configurable for now */
4703 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
4704
4705 return -EAGAIN;
4706}
4707
4708static int msmsdcc_pm_suspend(struct device *dev)
4709{
4710 struct mmc_host *mmc = dev_get_drvdata(dev);
4711 struct msmsdcc_host *host = mmc_priv(mmc);
4712 int rc = 0;
4713
4714 if (host->plat->is_sdio_al_client)
4715 return 0;
4716
4717
4718 if (host->plat->status_irq)
4719 disable_irq(host->plat->status_irq);
4720
4721 if (!pm_runtime_suspended(dev))
4722 rc = msmsdcc_runtime_suspend(dev);
4723
4724 return rc;
4725}
4726
4727static int msmsdcc_pm_resume(struct device *dev)
4728{
4729 struct mmc_host *mmc = dev_get_drvdata(dev);
4730 struct msmsdcc_host *host = mmc_priv(mmc);
4731 int rc = 0;
4732
4733 if (host->plat->is_sdio_al_client)
4734 return 0;
4735
Sahitya Tummalafb486372011-09-02 19:01:49 +05304736 if (!pm_runtime_suspended(dev))
4737 rc = msmsdcc_runtime_resume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004738 if (host->plat->status_irq) {
4739 msmsdcc_check_status((unsigned long)host);
4740 enable_irq(host->plat->status_irq);
4741 }
4742
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004743 return rc;
4744}
4745
Daniel Walker08ecfde2010-06-23 12:32:20 -07004746#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004747#define msmsdcc_runtime_suspend NULL
4748#define msmsdcc_runtime_resume NULL
4749#define msmsdcc_runtime_idle NULL
4750#define msmsdcc_pm_suspend NULL
4751#define msmsdcc_pm_resume NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07004752#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004753
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004754static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
4755 .runtime_suspend = msmsdcc_runtime_suspend,
4756 .runtime_resume = msmsdcc_runtime_resume,
4757 .runtime_idle = msmsdcc_runtime_idle,
4758 .suspend = msmsdcc_pm_suspend,
4759 .resume = msmsdcc_pm_resume,
4760};
4761
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304762static const struct of_device_id msmsdcc_dt_match[] = {
4763 {.compatible = "qcom,msm-sdcc"},
4764
4765};
4766MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
4767
San Mehat9d2bd732009-09-22 16:44:22 -07004768static struct platform_driver msmsdcc_driver = {
4769 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004770 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07004771 .driver = {
4772 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004773 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304774 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07004775 },
4776};
4777
4778static int __init msmsdcc_init(void)
4779{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004780#if defined(CONFIG_DEBUG_FS)
4781 int ret = 0;
4782 ret = msmsdcc_dbg_init();
4783 if (ret) {
4784 pr_err("Failed to create debug fs dir \n");
4785 return ret;
4786 }
4787#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004788 return platform_driver_register(&msmsdcc_driver);
4789}
4790
4791static void __exit msmsdcc_exit(void)
4792{
4793 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004794
4795#if defined(CONFIG_DEBUG_FS)
4796 debugfs_remove(debugfs_file);
4797 debugfs_remove(debugfs_dir);
4798#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004799}
4800
4801module_init(msmsdcc_init);
4802module_exit(msmsdcc_exit);
4803
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004804MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07004805MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004806
4807#if defined(CONFIG_DEBUG_FS)
4808
4809static int
4810msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
4811{
4812 file->private_data = inode->i_private;
4813 return 0;
4814}
4815
4816static ssize_t
4817msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
4818 size_t count, loff_t *ppos)
4819{
4820 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08004821 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004822 int max, i;
4823
4824 i = 0;
4825 max = sizeof(buf) - 1;
4826
4827 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
4828 host->curr.cmd, host->curr.data);
4829 if (host->curr.cmd) {
4830 struct mmc_command *cmd = host->curr.cmd;
4831
4832 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
4833 cmd->opcode, cmd->arg, cmd->flags);
4834 }
4835 if (host->curr.data) {
4836 struct mmc_data *data = host->curr.data;
4837 i += scnprintf(buf + i, max - i,
4838 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
4839 data->timeout_ns, data->timeout_clks,
4840 data->blksz, data->blocks, data->error,
4841 data->flags);
4842 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
4843 host->curr.xfer_size, host->curr.xfer_remain,
4844 host->curr.data_xfered, host->dma.sg);
4845 }
4846
4847 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
4848}
4849
4850static const struct file_operations msmsdcc_dbg_state_ops = {
4851 .read = msmsdcc_dbg_state_read,
4852 .open = msmsdcc_dbg_state_open,
4853};
4854
4855static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
4856{
4857 if (debugfs_dir) {
4858 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
4859 0644, debugfs_dir, host,
4860 &msmsdcc_dbg_state_ops);
4861 }
4862}
4863
4864static int __init msmsdcc_dbg_init(void)
4865{
4866 int err;
4867
4868 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
4869 if (IS_ERR(debugfs_dir)) {
4870 err = PTR_ERR(debugfs_dir);
4871 debugfs_dir = NULL;
4872 return err;
4873 }
4874
4875 return 0;
4876}
4877#endif