blob: a1ad63e31c2b0bccaf53ef65e9b80a501c9d17f1 [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);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -0800137static void msmsdcc_sg_start(struct msmsdcc_host *host);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530138
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530139static inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
140{
141 unsigned short ret = NR_SG;
142
143 if (host->is_sps_mode) {
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +0530144 ret = SPS_MAX_DESCS;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530145 } else { /* DMA or PIO mode */
146 if (NR_SG > MAX_NR_SG_DMA_PIO)
147 ret = MAX_NR_SG_DMA_PIO;
148 }
149
150 return ret;
151}
152
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530153/* Prevent idle power collapse(pc) while operating in peripheral mode */
154static void msmsdcc_pm_qos_update_latency(struct msmsdcc_host *host, int vote)
155{
156 u32 swfi_latency = 0;
157
158 if (!host->plat->swfi_latency)
159 return;
160
161 swfi_latency = host->plat->swfi_latency + 1;
162
163 if (vote)
164 pm_qos_update_request(&host->pm_qos_req_dma,
165 swfi_latency);
166 else
167 pm_qos_update_request(&host->pm_qos_req_dma,
168 PM_QOS_DEFAULT_VALUE);
169}
170
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700171#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
172static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
173 struct msmsdcc_sps_ep_conn_data *ep);
174static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
175 struct msmsdcc_sps_ep_conn_data *ep);
176#else
177static inline int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
178 struct msmsdcc_sps_ep_conn_data *ep,
179 bool is_producer) { return 0; }
180static inline void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
181 struct msmsdcc_sps_ep_conn_data *ep) { }
182static inline int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
183 struct msmsdcc_sps_ep_conn_data *ep)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530184{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700185 return 0;
186}
187static inline int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
188 struct msmsdcc_sps_ep_conn_data *ep)
189{
190 return 0;
191}
192static inline int msmsdcc_sps_init(struct msmsdcc_host *host) { return 0; }
193static inline void msmsdcc_sps_exit(struct msmsdcc_host *host) {}
194#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530195
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700196/**
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530197 * Apply soft reset to all SDCC BAM pipes
198 *
199 * This function applies soft reset to SDCC BAM pipe.
200 *
201 * This function should be called to recover from error
202 * conditions encountered during CMD/DATA tranfsers with card.
203 *
204 * @host - Pointer to driver's host structure
205 *
206 */
207static void msmsdcc_sps_pipes_reset_and_restore(struct msmsdcc_host *host)
208{
209 int rc;
210
211 /* Reset all SDCC BAM pipes */
212 rc = msmsdcc_sps_reset_ep(host, &host->sps.prod);
213 if (rc)
214 pr_err("%s:msmsdcc_sps_reset_ep(prod) error=%d\n",
215 mmc_hostname(host->mmc), rc);
216 rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
217 if (rc)
218 pr_err("%s:msmsdcc_sps_reset_ep(cons) error=%d\n",
219 mmc_hostname(host->mmc), rc);
220
221 /* Restore all BAM pipes connections */
222 rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
223 if (rc)
224 pr_err("%s:msmsdcc_sps_restore_ep(prod) error=%d\n",
225 mmc_hostname(host->mmc), rc);
226 rc = msmsdcc_sps_restore_ep(host, &host->sps.cons);
227 if (rc)
228 pr_err("%s:msmsdcc_sps_restore_ep(cons) error=%d\n",
229 mmc_hostname(host->mmc), rc);
230}
231
232/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700233 * Apply soft reset
234 *
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530235 * This function applies soft reset to SDCC core and DML core.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700236 *
237 * This function should be called to recover from error
238 * conditions encountered with CMD/DATA tranfsers with card.
239 *
240 * Soft reset should only be used with SDCC controller v4.
241 *
242 * @host - Pointer to driver's host structure
243 *
244 */
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530245static void msmsdcc_soft_reset(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700246{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700247 /*
248 * Reset SDCC controller's DPSM (data path state machine
249 * and CPSM (command path state machine).
250 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700251 writel_relaxed(0, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530252 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700253 writel_relaxed(0, host->base + MMCIDATACTRL);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530254 msmsdcc_delay(host);
255}
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530256
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530257static void msmsdcc_hard_reset(struct msmsdcc_host *host)
258{
259 int ret;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530260
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530261 /* Reset the controller */
262 ret = clk_reset(host->clk, CLK_RESET_ASSERT);
263 if (ret)
264 pr_err("%s: Clock assert failed at %u Hz"
265 " with err %d\n", mmc_hostname(host->mmc),
266 host->clk_rate, ret);
267
268 ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
269 if (ret)
270 pr_err("%s: Clock deassert failed at %u Hz"
271 " with err %d\n", mmc_hostname(host->mmc),
272 host->clk_rate, ret);
273
274 /* Give some delay for clock reset to propogate to controller */
275 msmsdcc_delay(host);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530276}
277
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700278static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
279{
Pratibhasagar V1c11da62011-11-14 12:36:35 +0530280 if (host->sdcc_version) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530281 if (host->is_sps_mode) {
282 /* Reset DML first */
283 msmsdcc_dml_reset(host);
284 /*
285 * delay the SPS pipe reset in thread context as
286 * sps_connect/sps_disconnect APIs can be called
287 * only from non-atomic context.
288 */
289 host->sps.pipe_reset_pending = true;
290 }
291 mb();
292 msmsdcc_soft_reset(host);
293
294 pr_debug("%s: Applied soft reset to Controller\n",
295 mmc_hostname(host->mmc));
296
297 if (host->is_sps_mode)
298 msmsdcc_dml_init(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700299 } else {
300 /* Give Clock reset (hard reset) to controller */
301 u32 mci_clk = 0;
302 u32 mci_mask0 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700303
304 /* Save the controller state */
305 mci_clk = readl_relaxed(host->base + MMCICLOCK);
306 mci_mask0 = readl_relaxed(host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700307 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700308
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530309 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700310 pr_debug("%s: Controller has been reinitialized\n",
311 mmc_hostname(host->mmc));
312
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700313 /* Restore the contoller state */
314 writel_relaxed(host->pwr, host->base + MMCIPOWER);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530315 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700316 writel_relaxed(mci_clk, host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530317 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700318 writel_relaxed(mci_mask0, host->base + MMCIMASK0);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530319 mb(); /* no delay required after writing to MASK0 register */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700320 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530321
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700322 if (host->dummy_52_needed)
323 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700324}
325
326static int
San Mehat9d2bd732009-09-22 16:44:22 -0700327msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
328{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700329 int retval = 0;
330
San Mehat9d2bd732009-09-22 16:44:22 -0700331 BUG_ON(host->curr.data);
332
333 host->curr.mrq = NULL;
334 host->curr.cmd = NULL;
335
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700336 del_timer(&host->req_tout_timer);
337
San Mehat9d2bd732009-09-22 16:44:22 -0700338 if (mrq->data)
339 mrq->data->bytes_xfered = host->curr.data_xfered;
340 if (mrq->cmd->error == -ETIMEDOUT)
341 mdelay(5);
342
343 /*
344 * Need to drop the host lock here; mmc_request_done may call
345 * back into the driver...
346 */
347 spin_unlock(&host->lock);
348 mmc_request_done(host->mmc, mrq);
349 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700350
351 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700352}
353
354static void
355msmsdcc_stop_data(struct msmsdcc_host *host)
356{
San Mehat9d2bd732009-09-22 16:44:22 -0700357 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530358 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530359 host->curr.wait_for_auto_prog_done = 0;
360 host->curr.got_auto_prog_done = 0;
Krishna Konda3f5d48f2011-07-27 10:47:31 -0700361 writel_relaxed(readl_relaxed(host->base + MMCIDATACTRL) &
362 (~(MCI_DPSM_ENABLE)), host->base + MMCIDATACTRL);
Krishna Konda3e5c4d02011-07-11 16:31:45 -0700363 msmsdcc_delay(host); /* Allow the DPSM to be reset */
San Mehat9d2bd732009-09-22 16:44:22 -0700364}
365
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700366static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700367{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700368 return host->core_memres->start + MMCIFIFO;
369}
370
371static inline unsigned int msmsdcc_get_min_sup_clk_rate(
372 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530373
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700374static inline void msmsdcc_delay(struct msmsdcc_host *host)
375{
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530376 ktime_t start, diff;
377
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700378 mb();
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +0530379 udelay(host->reg_write_delay);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530380
Pratibhasagar V1c11da62011-11-14 12:36:35 +0530381 if (host->sdcc_version &&
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530382 (readl_relaxed(host->base + MCI_STATUS2) &
383 MCI_MCLK_REG_WR_ACTIVE)) {
384 start = ktime_get();
385 while (readl_relaxed(host->base + MCI_STATUS2) &
386 MCI_MCLK_REG_WR_ACTIVE) {
387 diff = ktime_sub(ktime_get(), start);
388 /* poll for max. 1 ms */
389 if (ktime_to_us(diff) > 1000) {
390 pr_warning("%s: previous reg. write is"
391 " still active\n",
392 mmc_hostname(host->mmc));
393 break;
394 }
395 }
396 }
San Mehat9d2bd732009-09-22 16:44:22 -0700397}
398
San Mehat56a8b5b2009-11-21 12:29:46 -0800399static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700400msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
401{
402 writel_relaxed(arg, host->base + MMCIARGUMENT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700403 writel_relaxed(c, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530404 /*
405 * As after sending the command, we don't write any of the
406 * controller registers and just wait for the
407 * CMD_RESPOND_END/CMD_SENT/Command failure notication
408 * from Controller.
409 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700410 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800411}
412
413static void
414msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
415{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700416 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800417
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700418 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
419 writel_relaxed((unsigned int)host->curr.xfer_size,
420 host->base + MMCIDATALENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700421 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
422 msmsdcc_delay(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800423
San Mehat6ac9ea62009-12-02 17:24:58 -0800424 if (host->cmd_cmd) {
425 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700426 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800427 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800428}
429
San Mehat9d2bd732009-09-22 16:44:22 -0700430static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530431msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700432{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530433 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700434 unsigned long flags;
435 struct mmc_request *mrq;
436
437 spin_lock_irqsave(&host->lock, flags);
438 mrq = host->curr.mrq;
439 BUG_ON(!mrq);
440
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530441 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700442 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700443 goto out;
444 }
445
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530446 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700447 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700448 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700449 } else {
450 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530451 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700452 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530453 mmc_hostname(host->mmc), host->dma.result);
454 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700455 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530456 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530457 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700458 host->dma.err.flush[0], host->dma.err.flush[1],
459 host->dma.err.flush[2], host->dma.err.flush[3],
460 host->dma.err.flush[4],
461 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530462 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700463 if (!mrq->data->error)
464 mrq->data->error = -EIO;
465 }
San Mehat9d2bd732009-09-22 16:44:22 -0700466 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents,
467 host->dma.dir);
468
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700469 if (host->curr.user_pages) {
470 struct scatterlist *sg = host->dma.sg;
471 int i;
472
473 for (i = 0; i < host->dma.num_ents; i++, sg++)
474 flush_dcache_page(sg_page(sg));
475 }
476
San Mehat9d2bd732009-09-22 16:44:22 -0700477 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800478 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700479
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530480 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
481 (host->curr.wait_for_auto_prog_done &&
482 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700483 /*
484 * If we've already gotten our DATAEND / DATABLKEND
485 * for this request, then complete it through here.
486 */
San Mehat9d2bd732009-09-22 16:44:22 -0700487
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700488 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700489 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700490 host->curr.xfer_remain -= host->curr.xfer_size;
491 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700492 if (host->dummy_52_needed) {
493 mrq->data->bytes_xfered = host->curr.data_xfered;
494 host->dummy_52_sent = 1;
495 msmsdcc_start_command(host, &dummy52cmd,
496 MCI_CPSM_PROGENA);
497 goto out;
498 }
499 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530500 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530501 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700502 host->curr.mrq = NULL;
503 host->curr.cmd = NULL;
504 mrq->data->bytes_xfered = host->curr.data_xfered;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700505 del_timer(&host->req_tout_timer);
San Mehat9d2bd732009-09-22 16:44:22 -0700506 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700507
San Mehat9d2bd732009-09-22 16:44:22 -0700508 mmc_request_done(host->mmc, mrq);
509 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530510 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
511 || !mrq->sbc)) {
512 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530513 }
San Mehat9d2bd732009-09-22 16:44:22 -0700514 }
515
516out:
517 spin_unlock_irqrestore(&host->lock, flags);
518 return;
519}
520
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700521#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
522/**
523 * Callback notification from SPS driver
524 *
525 * This callback function gets triggered called from
526 * SPS driver when requested SPS data transfer is
527 * completed.
528 *
529 * SPS driver invokes this callback in BAM irq context so
530 * SDCC driver schedule a tasklet for further processing
531 * this callback notification at later point of time in
532 * tasklet context and immediately returns control back
533 * to SPS driver.
534 *
535 * @nofity - Pointer to sps event notify sturcture
536 *
537 */
538static void
539msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
540{
541 struct msmsdcc_host *host =
542 (struct msmsdcc_host *)
543 ((struct sps_event_notify *)notify)->user;
544
545 host->sps.notify = *notify;
546 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
547 mmc_hostname(host->mmc), __func__, notify->event_id,
548 notify->data.transfer.iovec.addr,
549 notify->data.transfer.iovec.size,
550 notify->data.transfer.iovec.flags);
551 /* Schedule a tasklet for completing data transfer */
552 tasklet_schedule(&host->sps.tlet);
553}
554
555/**
556 * Tasklet handler for processing SPS callback event
557 *
558 * This function processing SPS event notification and
559 * checks if the SPS transfer is completed or not and
560 * then accordingly notifies status to MMC core layer.
561 *
562 * This function is called in tasklet context.
563 *
564 * @data - Pointer to sdcc driver data
565 *
566 */
567static void msmsdcc_sps_complete_tlet(unsigned long data)
568{
569 unsigned long flags;
570 int i, rc;
571 u32 data_xfered = 0;
572 struct mmc_request *mrq;
573 struct sps_iovec iovec;
574 struct sps_pipe *sps_pipe_handle;
575 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
576 struct sps_event_notify *notify = &host->sps.notify;
577
578 spin_lock_irqsave(&host->lock, flags);
579 if (host->sps.dir == DMA_FROM_DEVICE)
580 sps_pipe_handle = host->sps.prod.pipe_handle;
581 else
582 sps_pipe_handle = host->sps.cons.pipe_handle;
583 mrq = host->curr.mrq;
584
585 if (!mrq) {
586 spin_unlock_irqrestore(&host->lock, flags);
587 return;
588 }
589
590 pr_debug("%s: %s: sps event_id=%d\n",
591 mmc_hostname(host->mmc), __func__,
592 notify->event_id);
593
594 if (msmsdcc_is_dml_busy(host)) {
595 /* oops !!! this should never happen. */
596 pr_err("%s: %s: Received SPS EOT event"
597 " but DML HW is still busy !!!\n",
598 mmc_hostname(host->mmc), __func__);
599 }
600 /*
601 * Got End of transfer event!!! Check if all of the data
602 * has been transferred?
603 */
604 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
605 rc = sps_get_iovec(sps_pipe_handle, &iovec);
606 if (rc) {
607 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
608 mmc_hostname(host->mmc), __func__, rc, i);
609 break;
610 }
611 data_xfered += iovec.size;
612 }
613
614 if (data_xfered == host->curr.xfer_size) {
615 host->curr.data_xfered = host->curr.xfer_size;
616 host->curr.xfer_remain -= host->curr.xfer_size;
617 pr_debug("%s: Data xfer success. data_xfered=0x%x",
618 mmc_hostname(host->mmc),
619 host->curr.xfer_size);
620 } else {
621 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
622 " xfer_size=%d", mmc_hostname(host->mmc),
623 data_xfered, host->curr.xfer_size);
624 msmsdcc_reset_and_restore(host);
625 if (!mrq->data->error)
626 mrq->data->error = -EIO;
627 }
628
629 /* Unmap sg buffers */
630 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
631 host->sps.dir);
632
633 host->sps.sg = NULL;
634 host->sps.busy = 0;
635
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530636 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
637 (host->curr.wait_for_auto_prog_done &&
638 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700639 /*
640 * If we've already gotten our DATAEND / DATABLKEND
641 * for this request, then complete it through here.
642 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700643
644 if (!mrq->data->error) {
645 host->curr.data_xfered = host->curr.xfer_size;
646 host->curr.xfer_remain -= host->curr.xfer_size;
647 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700648 if (host->dummy_52_needed) {
649 mrq->data->bytes_xfered = host->curr.data_xfered;
650 host->dummy_52_sent = 1;
651 msmsdcc_start_command(host, &dummy52cmd,
652 MCI_CPSM_PROGENA);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700653 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700654 return;
655 }
656 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530657 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530658 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700659 host->curr.mrq = NULL;
660 host->curr.cmd = NULL;
661 mrq->data->bytes_xfered = host->curr.data_xfered;
662 del_timer(&host->req_tout_timer);
663 spin_unlock_irqrestore(&host->lock, flags);
664
665 mmc_request_done(host->mmc, mrq);
666 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530667 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
668 || !mrq->sbc)) {
669 msmsdcc_start_command(host, mrq->data->stop, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700670 }
671 }
672 spin_unlock_irqrestore(&host->lock, flags);
673}
674
675/**
676 * Exit from current SPS data transfer
677 *
678 * This function exits from current SPS data transfer.
679 *
680 * This function should be called when error condition
681 * is encountered during data transfer.
682 *
683 * @host - Pointer to sdcc host structure
684 *
685 */
686static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
687{
688 struct mmc_request *mrq;
689
690 mrq = host->curr.mrq;
691 BUG_ON(!mrq);
692
693 msmsdcc_reset_and_restore(host);
694 if (!mrq->data->error)
695 mrq->data->error = -EIO;
696
697 /* Unmap sg buffers */
698 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
699 host->sps.dir);
700
701 host->sps.sg = NULL;
702 host->sps.busy = 0;
703 if (host->curr.data)
704 msmsdcc_stop_data(host);
705
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530706 if (!mrq->data->stop || mrq->cmd->error ||
707 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700708 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530709 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
710 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700711 msmsdcc_start_command(host, mrq->data->stop, 0);
712
713}
714#else
715static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
716static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
717static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
718#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
719
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530720static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700721
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530722static void
723msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
724 unsigned int result,
725 struct msm_dmov_errdata *err)
726{
727 struct msmsdcc_dma_data *dma_data =
728 container_of(cmd, struct msmsdcc_dma_data, hdr);
729 struct msmsdcc_host *host = dma_data->host;
730
731 dma_data->result = result;
732 if (err)
733 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
734
735 tasklet_schedule(&host->dma_tlet);
736}
737
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700738static int msmsdcc_check_dma_op_req(struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700739{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700740 if (((data->blksz * data->blocks) < MCI_FIFOSIZE) ||
741 ((data->blksz * data->blocks) % MCI_FIFOSIZE))
San Mehat9d2bd732009-09-22 16:44:22 -0700742 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700743 else
744 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700745}
746
747static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
748{
749 struct msmsdcc_nc_dmadata *nc;
750 dmov_box *box;
751 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700752 unsigned int n;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530753 int i, err = 0, box_cmd_cnt = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700754 struct scatterlist *sg = data->sg;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530755 unsigned int len, offset;
San Mehat9d2bd732009-09-22 16:44:22 -0700756
Krishna Konda25786ec2011-07-25 16:21:36 -0700757 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700758 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700759
Krishna Konda25786ec2011-07-25 16:21:36 -0700760 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
761
San Mehat9d2bd732009-09-22 16:44:22 -0700762 host->dma.sg = data->sg;
763 host->dma.num_ents = data->sg_len;
764
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530765 /* Prevent memory corruption */
766 BUG_ON(host->dma.num_ents > msmsdcc_get_nr_sg(host));
San Mehat56a8b5b2009-11-21 12:29:46 -0800767
San Mehat9d2bd732009-09-22 16:44:22 -0700768 nc = host->dma.nc;
769
San Mehat9d2bd732009-09-22 16:44:22 -0700770 if (data->flags & MMC_DATA_READ)
771 host->dma.dir = DMA_FROM_DEVICE;
772 else
773 host->dma.dir = DMA_TO_DEVICE;
774
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700775 n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
776 host->dma.num_ents, host->dma.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700777
778 if (n != host->dma.num_ents) {
779 pr_err("%s: Unable to map in all sg elements\n",
780 mmc_hostname(host->mmc));
781 host->dma.sg = NULL;
782 host->dma.num_ents = 0;
783 return -ENOMEM;
San Mehat56a8b5b2009-11-21 12:29:46 -0800784 }
San Mehat9d2bd732009-09-22 16:44:22 -0700785
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530786 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
787 host->curr.user_pages = 0;
788 box = &nc->cmd[0];
789 for (i = 0; i < host->dma.num_ents; i++) {
790 len = sg_dma_len(sg);
791 offset = 0;
792
793 do {
794 /* Check if we can do DMA */
795 if (!len || (box_cmd_cnt >= MMC_MAX_DMA_CMDS)) {
796 err = -ENOTSUPP;
797 goto unmap;
798 }
799
800 box->cmd = CMD_MODE_BOX;
801
802 if (len >= MMC_MAX_DMA_BOX_LENGTH) {
803 len = MMC_MAX_DMA_BOX_LENGTH;
804 len -= len % data->blksz;
805 }
806 rows = (len % MCI_FIFOSIZE) ?
807 (len / MCI_FIFOSIZE) + 1 :
808 (len / MCI_FIFOSIZE);
809
810 if (data->flags & MMC_DATA_READ) {
811 box->src_row_addr = msmsdcc_fifo_addr(host);
812 box->dst_row_addr = sg_dma_address(sg) + offset;
813 box->src_dst_len = (MCI_FIFOSIZE << 16) |
814 (MCI_FIFOSIZE);
815 box->row_offset = MCI_FIFOSIZE;
816 box->num_rows = rows * ((1 << 16) + 1);
817 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
818 } else {
819 box->src_row_addr = sg_dma_address(sg) + offset;
820 box->dst_row_addr = msmsdcc_fifo_addr(host);
821 box->src_dst_len = (MCI_FIFOSIZE << 16) |
822 (MCI_FIFOSIZE);
823 box->row_offset = (MCI_FIFOSIZE << 16);
824 box->num_rows = rows * ((1 << 16) + 1);
825 box->cmd |= CMD_DST_CRCI(host->dma.crci);
826 }
827
828 offset += len;
829 len = sg_dma_len(sg) - offset;
830 box++;
831 box_cmd_cnt++;
832 } while (len);
833 sg++;
834 }
835 /* Mark last command */
836 box--;
837 box->cmd |= CMD_LC;
838
839 /* location of command block must be 64 bit aligned */
840 BUG_ON(host->dma.cmd_busaddr & 0x07);
841
842 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
843 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
844 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
845 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
846
847 /* Flush all data to memory before starting dma */
848 mb();
849
850unmap:
851 if (err) {
852 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
853 host->dma.num_ents, host->dma.dir);
854 pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
855 mmc_hostname(host->mmc), err);
856 }
857
858 return err;
San Mehat9d2bd732009-09-22 16:44:22 -0700859}
860
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700861#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
862/**
863 * Submits data transfer request to SPS driver
864 *
865 * This function make sg (scatter gather) data buffers
866 * DMA ready and then submits them to SPS driver for
867 * transfer.
868 *
869 * @host - Pointer to sdcc host structure
870 * @data - Pointer to mmc_data structure
871 *
872 * @return 0 if success else negative value
873 */
874static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
875 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -0800876{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700877 int rc = 0;
878 u32 flags;
879 int i;
880 u32 addr, len, data_cnt;
881 struct scatterlist *sg = data->sg;
882 struct sps_pipe *sps_pipe_handle;
883
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530884 /* Prevent memory corruption */
885 BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700886
887 host->sps.sg = data->sg;
888 host->sps.num_ents = data->sg_len;
889 host->sps.xfer_req_cnt = 0;
890 if (data->flags & MMC_DATA_READ) {
891 host->sps.dir = DMA_FROM_DEVICE;
892 sps_pipe_handle = host->sps.prod.pipe_handle;
893 } else {
894 host->sps.dir = DMA_TO_DEVICE;
895 sps_pipe_handle = host->sps.cons.pipe_handle;
896 }
897
898 /* Make sg buffers DMA ready */
899 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
900 host->sps.dir);
901
902 if (rc != data->sg_len) {
903 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
904 mmc_hostname(host->mmc), rc);
905 host->sps.sg = NULL;
906 host->sps.num_ents = 0;
907 rc = -ENOMEM;
908 goto dma_map_err;
909 }
910
911 pr_debug("%s: %s: %s: pipe=0x%x, total_xfer=0x%x, sg_len=%d\n",
912 mmc_hostname(host->mmc), __func__,
913 host->sps.dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
914 (u32)sps_pipe_handle, host->curr.xfer_size, data->sg_len);
915
916 for (i = 0; i < data->sg_len; i++) {
917 /*
918 * Check if this is the last buffer to transfer?
919 * If yes then set the INT and EOT flags.
920 */
921 len = sg_dma_len(sg);
922 addr = sg_dma_address(sg);
923 flags = 0;
924 while (len > 0) {
925 if (len > SPS_MAX_DESC_SIZE) {
926 data_cnt = SPS_MAX_DESC_SIZE;
927 } else {
928 data_cnt = len;
929 if (i == data->sg_len - 1)
930 flags = SPS_IOVEC_FLAG_INT |
931 SPS_IOVEC_FLAG_EOT;
932 }
933 rc = sps_transfer_one(sps_pipe_handle, addr,
934 data_cnt, host, flags);
935 if (rc) {
936 pr_err("%s: sps_transfer_one() error! rc=%d,"
937 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
938 mmc_hostname(host->mmc), rc,
939 (u32)sps_pipe_handle, (u32)sg, i);
940 goto dma_map_err;
941 }
942 addr += data_cnt;
943 len -= data_cnt;
944 host->sps.xfer_req_cnt++;
945 }
946 sg++;
947 }
948 goto out;
949
950dma_map_err:
951 /* unmap sg buffers */
952 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
953 host->sps.dir);
954out:
955 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -0700956}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700957#else
958static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
959 struct mmc_data *data) { return 0; }
960#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -0700961
962static void
San Mehat56a8b5b2009-11-21 12:29:46 -0800963msmsdcc_start_command_deferred(struct msmsdcc_host *host,
964 struct mmc_command *cmd, u32 *c)
965{
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530966 DBG(host, "op %02x arg %08x flags %08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700967 cmd->opcode, cmd->arg, cmd->flags);
968
San Mehat56a8b5b2009-11-21 12:29:46 -0800969 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
970
971 if (cmd->flags & MMC_RSP_PRESENT) {
972 if (cmd->flags & MMC_RSP_136)
973 *c |= MCI_CPSM_LONGRSP;
974 *c |= MCI_CPSM_RESPONSE;
975 }
976
977 if (/*interrupt*/0)
978 *c |= MCI_CPSM_INTERRUPT;
979
Subhash Jadavanide0fc772011-11-13 12:27:52 +0530980 if (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
981 cmd->opcode == MMC_READ_MULTIPLE_BLOCK ||
982 cmd->opcode == MMC_WRITE_BLOCK ||
983 cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK ||
984 cmd->opcode == SD_IO_RW_EXTENDED)
San Mehat56a8b5b2009-11-21 12:29:46 -0800985 *c |= MCI_CSPM_DATCMD;
986
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700987 /* Check if AUTO CMD19 is required or not? */
Subhash Jadavani1d6ba602011-09-21 18:10:54 +0530988 if (host->tuning_needed) {
989 /*
990 * For open ended block read operation (without CMD23),
991 * AUTO_CMD19 bit should be set while sending the READ command.
992 * For close ended block read operation (with CMD23),
993 * AUTO_CMD19 bit should be set while sending CMD23.
994 */
Subhash Jadavanide0fc772011-11-13 12:27:52 +0530995 if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
996 host->curr.mrq->cmd->opcode ==
997 MMC_READ_MULTIPLE_BLOCK) ||
Subhash Jadavani1d6ba602011-09-21 18:10:54 +0530998 (!host->curr.mrq->sbc &&
Subhash Jadavanide0fc772011-11-13 12:27:52 +0530999 (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
1000 cmd->opcode == MMC_READ_MULTIPLE_BLOCK))) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301001 msmsdcc_enable_cdr_cm_sdc4_dll(host);
1002 *c |= MCI_CSPM_AUTO_CMD19;
1003 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001004 }
1005
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05301006 /* Clear CDR_EN bit for write operations */
1007 if (host->tuning_needed && cmd->mrq->data &&
1008 (cmd->mrq->data->flags & MMC_DATA_WRITE))
1009 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) &
1010 ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
1011
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301012 if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301013 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001014 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301015 }
1016
San Mehat56a8b5b2009-11-21 12:29:46 -08001017 if (cmd == cmd->mrq->stop)
1018 *c |= MCI_CSPM_MCIABORT;
1019
San Mehat56a8b5b2009-11-21 12:29:46 -08001020 if (host->curr.cmd != NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001021 pr_err("%s: Overlapping command requests\n",
1022 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -08001023 }
1024 host->curr.cmd = cmd;
1025}
1026
1027static void
1028msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1029 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001030{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301031 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001032 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001033 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001034 unsigned int pio_irqmask = 0;
1035
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301036 BUG_ON(!data->sg);
1037 BUG_ON(!data->sg_len);
1038
San Mehat9d2bd732009-09-22 16:44:22 -07001039 host->curr.data = data;
1040 host->curr.xfer_size = data->blksz * data->blocks;
1041 host->curr.xfer_remain = host->curr.xfer_size;
1042 host->curr.data_xfered = 0;
1043 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301044 host->curr.got_auto_prog_done = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001045
San Mehat9d2bd732009-09-22 16:44:22 -07001046 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1047
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301048 if (host->curr.wait_for_auto_prog_done)
1049 datactrl |= MCI_AUTO_PROG_DONE;
1050
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001051 if (!msmsdcc_check_dma_op_req(data)) {
1052 if (host->is_dma_mode && !msmsdcc_config_dma(host, data)) {
1053 datactrl |= MCI_DPSM_DMAENABLE;
1054 } else if (host->is_sps_mode) {
1055 if (!msmsdcc_is_dml_busy(host)) {
1056 if (!msmsdcc_sps_start_xfer(host, data)) {
1057 /* Now kick start DML transfer */
1058 mb();
1059 msmsdcc_dml_start_xfer(host, data);
1060 datactrl |= MCI_DPSM_DMAENABLE;
1061 host->sps.busy = 1;
1062 }
1063 } else {
1064 /*
1065 * Can't proceed with new transfer as
1066 * previous trasnfer is already in progress.
1067 * There is no point of going into PIO mode
1068 * as well. Is this a time to do kernel panic?
1069 */
1070 pr_err("%s: %s: DML HW is busy!!!"
1071 " Can't perform new SPS transfers"
1072 " now\n", mmc_hostname(host->mmc),
1073 __func__);
1074 }
1075 }
1076 }
1077
1078 /* Is data transfer in PIO mode required? */
1079 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001080 if (data->flags & MMC_DATA_READ) {
1081 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1082 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1083 pio_irqmask |= MCI_RXDATAAVLBLMASK;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001084 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001085 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1086 MCI_TXFIFOEMPTYMASK;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001087
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001088 msmsdcc_sg_start(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001089 }
1090
1091 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301092 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
San Mehat9d2bd732009-09-22 16:44:22 -07001093
San Mehat56a8b5b2009-11-21 12:29:46 -08001094 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001095 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001096 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -07001097
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001098 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
1099 /* Use ADM (Application Data Mover) HW for Data transfer */
1100 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001101 host->cmd_timeout = timeout;
1102 host->cmd_pio_irqmask = pio_irqmask;
1103 host->cmd_datactrl = datactrl;
1104 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001105
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001106 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1107 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001108 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001109
1110 if (cmd) {
1111 msmsdcc_start_command_deferred(host, cmd, &c);
1112 host->cmd_c = c;
1113 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001114 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1115 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1116 host->base + MMCIMASK0);
1117 mb();
1118 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001119 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001120 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001121 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001122
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001123 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001124
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001125 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1126 (~(MCI_IRQ_PIO))) | pio_irqmask,
1127 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001128 writel_relaxed(datactrl, base + MMCIDATACTRL);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301129 /*
1130 * We don't need delay after writing to DATA_CTRL register
1131 * if we are not writing to CMD register immediately after
1132 * this. As we already have delay before sending the
1133 * command, we just need mb() here.
1134 */
1135 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001136
1137 if (cmd) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001138 msmsdcc_delay(host); /* Delay between data/command */
San Mehat56a8b5b2009-11-21 12:29:46 -08001139 /* Daisy-chain the command if requested */
1140 msmsdcc_start_command(host, cmd, c);
1141 }
San Mehat9d2bd732009-09-22 16:44:22 -07001142 }
1143}
1144
1145static void
1146msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1147{
San Mehat56a8b5b2009-11-21 12:29:46 -08001148 msmsdcc_start_command_deferred(host, cmd, &c);
1149 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001150}
1151
1152static void
1153msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1154 unsigned int status)
1155{
1156 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001157 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1158 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1159 pr_err("%s: Data CRC error\n",
1160 mmc_hostname(host->mmc));
1161 pr_err("%s: opcode 0x%.8x\n", __func__,
1162 data->mrq->cmd->opcode);
1163 pr_err("%s: blksz %d, blocks %d\n", __func__,
1164 data->blksz, data->blocks);
1165 data->error = -EILSEQ;
1166 }
San Mehat9d2bd732009-09-22 16:44:22 -07001167 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001168 /* CRC is optional for the bus test commands, not all
1169 * cards respond back with CRC. However controller
1170 * waits for the CRC and times out. Hence ignore the
1171 * data timeouts during the Bustest.
1172 */
1173 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1174 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301175 pr_err("%s: CMD%d: Data timeout\n",
1176 mmc_hostname(host->mmc),
1177 data->mrq->cmd->opcode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001178 data->error = -ETIMEDOUT;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301179 msmsdcc_dump_sdcc_state(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001180 }
San Mehat9d2bd732009-09-22 16:44:22 -07001181 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001182 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001183 data->error = -EIO;
1184 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001185 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001186 data->error = -EIO;
1187 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001188 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001189 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001190 data->error = -EIO;
1191 }
San Mehat9d2bd732009-09-22 16:44:22 -07001192
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001193 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001194 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001195 host->dummy_52_needed = 0;
1196}
San Mehat9d2bd732009-09-22 16:44:22 -07001197
1198static int
1199msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1200{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001201 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001202 uint32_t *ptr = (uint32_t *) buffer;
1203 int count = 0;
1204
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301205 if (remain % 4)
1206 remain = ((remain >> 2) + 1) << 2;
1207
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001208 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1209
1210 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001211 ptr++;
1212 count += sizeof(uint32_t);
1213
1214 remain -= sizeof(uint32_t);
1215 if (remain == 0)
1216 break;
1217 }
1218 return count;
1219}
1220
1221static int
1222msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001223 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001224{
1225 void __iomem *base = host->base;
1226 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001227 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001228
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001229 while (readl_relaxed(base + MMCISTATUS) &
1230 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1231 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001232
San Mehat9d2bd732009-09-22 16:44:22 -07001233 count = min(remain, maxcnt);
1234
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301235 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1236 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001237 ptr += count;
1238 remain -= count;
1239
1240 if (remain == 0)
1241 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001242 }
1243 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001244
1245 return ptr - buffer;
1246}
1247
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001248/*
1249 * Copy up to a word (4 bytes) between a scatterlist
1250 * and a temporary bounce buffer when the word lies across
1251 * two pages. The temporary buffer can then be read to/
1252 * written from the FIFO once.
1253 */
1254static void _msmsdcc_sg_consume_word(struct msmsdcc_host *host)
1255{
1256 struct msmsdcc_pio_data *pio = &host->pio;
1257 unsigned int bytes_avail;
1258
1259 if (host->curr.data->flags & MMC_DATA_READ)
1260 memcpy(pio->sg_miter.addr, pio->bounce_buf,
1261 pio->bounce_buf_len);
1262 else
1263 memcpy(pio->bounce_buf, pio->sg_miter.addr,
1264 pio->bounce_buf_len);
1265
1266 while (pio->bounce_buf_len != 4) {
1267 if (!sg_miter_next(&pio->sg_miter))
1268 break;
1269 bytes_avail = min_t(unsigned int, pio->sg_miter.length,
1270 4 - pio->bounce_buf_len);
1271 if (host->curr.data->flags & MMC_DATA_READ)
1272 memcpy(pio->sg_miter.addr,
1273 &pio->bounce_buf[pio->bounce_buf_len],
1274 bytes_avail);
1275 else
1276 memcpy(&pio->bounce_buf[pio->bounce_buf_len],
1277 pio->sg_miter.addr, bytes_avail);
1278
1279 pio->sg_miter.consumed = bytes_avail;
1280 pio->bounce_buf_len += bytes_avail;
1281 }
1282}
1283
1284/*
1285 * Use sg_miter_next to return as many 4-byte aligned
1286 * chunks as possible, using a temporary 4 byte buffer
1287 * for alignment if necessary
1288 */
1289static int msmsdcc_sg_next(struct msmsdcc_host *host, char **buf, int *len)
1290{
1291 struct msmsdcc_pio_data *pio = &host->pio;
1292 unsigned int length, rlength;
1293 char *buffer;
1294
1295 if (!sg_miter_next(&pio->sg_miter))
1296 return 0;
1297
1298 buffer = pio->sg_miter.addr;
1299 length = pio->sg_miter.length;
1300
1301 if (length < host->curr.xfer_remain) {
1302 rlength = round_down(length, 4);
1303 if (rlength) {
1304 /*
1305 * We have a 4-byte aligned chunk.
1306 * The rounding will be reflected by
1307 * a call to msmsdcc_sg_consumed
1308 */
1309 length = rlength;
1310 goto sg_next_end;
1311 }
1312 /*
1313 * We have a length less than 4 bytes. Check to
1314 * see if more buffer is available, and combine
1315 * to make 4 bytes if possible.
1316 */
1317 pio->bounce_buf_len = length;
1318 memset(pio->bounce_buf, 0, 4);
1319
1320 /*
1321 * On a read, get 4 bytes from FIFO, and distribute
1322 * (4-bouce_buf_len) bytes into consecutive
1323 * sgl buffers when msmsdcc_sg_consumed is called
1324 */
1325 if (host->curr.data->flags & MMC_DATA_READ) {
1326 buffer = pio->bounce_buf;
1327 length = 4;
1328 goto sg_next_end;
1329 } else {
1330 _msmsdcc_sg_consume_word(host);
1331 buffer = pio->bounce_buf;
1332 length = pio->bounce_buf_len;
1333 }
1334 }
1335
1336sg_next_end:
1337 *buf = buffer;
1338 *len = length;
1339 return 1;
1340}
1341
1342/*
1343 * Update sg_miter.consumed based on how many bytes were
1344 * consumed. If the bounce buffer was used to read from FIFO,
1345 * redistribute into sgls.
1346 */
1347static void msmsdcc_sg_consumed(struct msmsdcc_host *host,
1348 unsigned int length)
1349{
1350 struct msmsdcc_pio_data *pio = &host->pio;
1351
1352 if (host->curr.data->flags & MMC_DATA_READ) {
1353 if (length > pio->sg_miter.consumed)
1354 /*
1355 * consumed 4 bytes, but sgl
1356 * describes < 4 bytes
1357 */
1358 _msmsdcc_sg_consume_word(host);
1359 else
1360 pio->sg_miter.consumed = length;
1361 } else
1362 if (length < pio->sg_miter.consumed)
1363 pio->sg_miter.consumed = length;
1364}
1365
1366static void msmsdcc_sg_start(struct msmsdcc_host *host)
1367{
1368 unsigned int sg_miter_flags = SG_MITER_ATOMIC;
1369
1370 host->pio.bounce_buf_len = 0;
1371
1372 if (host->curr.data->flags & MMC_DATA_READ)
1373 sg_miter_flags |= SG_MITER_TO_SG;
1374 else
1375 sg_miter_flags |= SG_MITER_FROM_SG;
1376
1377 sg_miter_start(&host->pio.sg_miter, host->curr.data->sg,
1378 host->curr.data->sg_len, sg_miter_flags);
1379}
1380
1381static void msmsdcc_sg_stop(struct msmsdcc_host *host)
1382{
1383 sg_miter_stop(&host->pio.sg_miter);
1384}
1385
San Mehat1cd22962010-02-03 12:59:29 -08001386static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001387msmsdcc_pio_irq(int irq, void *dev_id)
1388{
1389 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001390 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001391 uint32_t status;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001392 unsigned long flags;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001393 unsigned int remain;
1394 char *buffer;
San Mehat9d2bd732009-09-22 16:44:22 -07001395
Murali Palnati36448a42011-09-02 15:06:18 +05301396 spin_lock(&host->lock);
1397
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001398 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001399
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001400 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301401 (MCI_IRQ_PIO)) == 0) {
1402 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001403 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301404 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001405#if IRQ_DEBUG
1406 msmsdcc_print_status(host, "irq1-r", status);
1407#endif
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001408 local_irq_save(flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001409
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001410 do {
1411 unsigned int len;
San Mehat9d2bd732009-09-22 16:44:22 -07001412
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001413 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1414 | MCI_RXDATAAVLBL)))
1415 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001416
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001417 if (!msmsdcc_sg_next(host, &buffer, &remain))
1418 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001419
San Mehat9d2bd732009-09-22 16:44:22 -07001420 len = 0;
1421 if (status & MCI_RXACTIVE)
1422 len = msmsdcc_pio_read(host, buffer, remain);
1423 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001424 len = msmsdcc_pio_write(host, buffer, remain);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001425
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301426 /* len might have aligned to 32bits above */
1427 if (len > remain)
1428 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001429
San Mehat9d2bd732009-09-22 16:44:22 -07001430 host->curr.xfer_remain -= len;
1431 host->curr.data_xfered += len;
1432 remain -= len;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001433 msmsdcc_sg_consumed(host, len);
San Mehat9d2bd732009-09-22 16:44:22 -07001434
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001435 if (remain) /* Done with this page? */
1436 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001437
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001438 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001439 } while (1);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001440
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001441 msmsdcc_sg_stop(host);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001442 local_irq_restore(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001443
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001444 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1445 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1446 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1447 host->base + MMCIMASK0);
1448 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301449 /*
1450 * back to back write to MASK0 register don't need
1451 * synchronization delay.
1452 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001453 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1454 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1455 }
1456 mb();
1457 } else if (!host->curr.xfer_remain) {
1458 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1459 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1460 mb();
1461 }
San Mehat9d2bd732009-09-22 16:44:22 -07001462
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001463 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001464
1465 return IRQ_HANDLED;
1466}
1467
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001468static void
1469msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1470
1471static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1472 struct mmc_data *data)
1473{
1474 u32 loop_cnt = 0;
1475
1476 /*
1477 * For read commands with data less than fifo size, it is possible to
1478 * get DATAEND first and RXDATA_AVAIL might be set later because of
1479 * synchronization delay through the asynchronous RX FIFO. Thus, for
1480 * such cases, even after DATAEND interrupt is received software
1481 * should poll for RXDATA_AVAIL until the requested data is read out
1482 * of FIFO. This change is needed to get around this abnormal but
1483 * sometimes expected behavior of SDCC3 controller.
1484 *
1485 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1486 * after the data is loaded into RX FIFO. This would amount to less
1487 * than a microsecond and thus looping for 1000 times is good enough
1488 * for that delay.
1489 */
1490 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1491 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1492 spin_unlock(&host->lock);
1493 msmsdcc_pio_irq(1, host);
1494 spin_lock(&host->lock);
1495 }
1496 }
1497 if (loop_cnt == 1000) {
1498 pr_info("%s: Timed out while polling for Rx Data\n",
1499 mmc_hostname(host->mmc));
1500 data->error = -ETIMEDOUT;
1501 msmsdcc_reset_and_restore(host);
1502 }
1503}
1504
San Mehat9d2bd732009-09-22 16:44:22 -07001505static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1506{
1507 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001508
1509 host->curr.cmd = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001510 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1511 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1512 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1513 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -07001514
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001515 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301516 pr_debug("%s: CMD%d: Command timeout\n",
1517 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001518 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001519 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
1520 !host->cmd19_tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301521 pr_err("%s: CMD%d: Command CRC error\n",
1522 mmc_hostname(host->mmc), cmd->opcode);
1523 msmsdcc_dump_sdcc_state(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001524 cmd->error = -EILSEQ;
1525 }
1526
1527 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001528 if (host->curr.data && host->dma.sg &&
1529 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001530 msm_dmov_stop_cmd(host->dma.channel,
1531 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001532 else if (host->curr.data && host->sps.sg &&
1533 host->is_sps_mode){
1534 /* Stop current SPS transfer */
1535 msmsdcc_sps_exit_curr_xfer(host);
1536 }
San Mehat9d2bd732009-09-22 16:44:22 -07001537 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301538 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001539 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301540 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301541 } else { /* host->data == NULL */
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301542 if (!cmd->error && host->prog_enable) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301543 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001544 host->prog_enable = 0;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301545 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001546 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301547 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301548 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301549 host->prog_enable = 0;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001550 if (host->dummy_52_needed)
1551 host->dummy_52_needed = 0;
1552 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001553 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301554 msmsdcc_request_end(host, cmd->mrq);
1555 }
1556 }
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301557 } else if ((cmd == host->curr.mrq->sbc) && cmd->data) {
1558 if (cmd->data->flags & MMC_DATA_READ)
1559 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1560 else
1561 msmsdcc_request_start(host, host->curr.mrq);
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301562 } else if (cmd->data) {
1563 if (!(cmd->data->flags & MMC_DATA_READ))
1564 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001565 }
1566}
1567
San Mehat9d2bd732009-09-22 16:44:22 -07001568static irqreturn_t
1569msmsdcc_irq(int irq, void *dev_id)
1570{
1571 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001572 u32 status;
1573 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001574 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001575
1576 spin_lock(&host->lock);
1577
1578 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001579 struct mmc_command *cmd;
1580 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001581
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001582 if (timer) {
1583 timer = 0;
1584 msmsdcc_delay(host);
1585 }
San Mehat865c8062009-11-13 13:42:06 -08001586
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001587 if (!host->clks_on) {
1588 pr_debug("%s: %s: SDIO async irq received\n",
1589 mmc_hostname(host->mmc), __func__);
1590 host->mmc->ios.clock = host->clk_rate;
1591 spin_unlock(&host->lock);
1592 host->mmc->ops->set_ios(host->mmc, &host->mmc->ios);
1593 spin_lock(&host->lock);
1594 if (host->plat->cfg_mpm_sdiowakeup &&
1595 (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
1596 wake_lock(&host->sdio_wlock);
1597 /* only ansyc interrupt can come when clocks are off */
1598 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301599 if (host->clk_rate <=
1600 msmsdcc_get_min_sup_clk_rate(host))
1601 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001602 }
1603
1604 status = readl_relaxed(host->base + MMCISTATUS);
1605
1606 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1607 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001608 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001609
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001610#if IRQ_DEBUG
1611 msmsdcc_print_status(host, "irq0-r", status);
1612#endif
1613 status &= readl_relaxed(host->base + MMCIMASK0);
1614 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301615 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301616 if (host->clk_rate <=
1617 msmsdcc_get_min_sup_clk_rate(host))
1618 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001619#if IRQ_DEBUG
1620 msmsdcc_print_status(host, "irq0-p", status);
1621#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001622
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001623#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
1624 if (status & MCI_SDIOINTROPE) {
1625 if (host->sdcc_suspending)
1626 wake_lock(&host->sdio_suspend_wlock);
1627 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001628 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001629#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001630 data = host->curr.data;
1631
1632 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001633 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1634 MCI_CMDTIMEOUT)) {
1635 if (status & MCI_CMDTIMEOUT)
1636 pr_debug("%s: dummy CMD52 timeout\n",
1637 mmc_hostname(host->mmc));
1638 if (status & MCI_CMDCRCFAIL)
1639 pr_debug("%s: dummy CMD52 CRC failed\n",
1640 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001641 host->dummy_52_sent = 0;
1642 host->dummy_52_needed = 0;
1643 if (data) {
1644 msmsdcc_stop_data(host);
1645 msmsdcc_request_end(host, data->mrq);
1646 }
1647 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001648 spin_unlock(&host->lock);
1649 return IRQ_HANDLED;
1650 }
1651 break;
1652 }
1653
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001654 /*
1655 * Check for proper command response
1656 */
1657 cmd = host->curr.cmd;
1658 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1659 MCI_CMDTIMEOUT | MCI_PROGDONE |
1660 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1661 msmsdcc_do_cmdirq(host, status);
1662 }
1663
Sathish Ambley081d7842011-11-29 11:19:41 -08001664 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001665 /* Check for data errors */
1666 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1667 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1668 msmsdcc_data_err(host, data, status);
1669 host->curr.data_xfered = 0;
1670 if (host->dma.sg && host->is_dma_mode)
1671 msm_dmov_stop_cmd(host->dma.channel,
1672 &host->dma.hdr, 0);
1673 else if (host->sps.sg && host->is_sps_mode) {
1674 /* Stop current SPS transfer */
1675 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301676 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001677 msmsdcc_reset_and_restore(host);
1678 if (host->curr.data)
1679 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301680 if (!data->stop || (host->curr.mrq->sbc
1681 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001682 timer |=
1683 msmsdcc_request_end(host,
1684 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301685 else if ((host->curr.mrq->sbc
1686 && data->error) ||
1687 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001688 msmsdcc_start_command(host,
1689 data->stop,
1690 0);
1691 timer = 1;
1692 }
1693 }
1694 }
1695
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301696 /* Check for prog done */
1697 if (host->curr.wait_for_auto_prog_done &&
1698 (status & MCI_PROGDONE))
1699 host->curr.got_auto_prog_done = 1;
1700
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001701 /* Check for data done */
1702 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1703 host->curr.got_dataend = 1;
1704
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301705 if (host->curr.got_dataend &&
1706 (!host->curr.wait_for_auto_prog_done ||
1707 (host->curr.wait_for_auto_prog_done &&
1708 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001709 /*
1710 * If DMA is still in progress, we complete
1711 * via the completion handler
1712 */
1713 if (!host->dma.busy && !host->sps.busy) {
1714 /*
1715 * There appears to be an issue in the
1716 * controller where if you request a
1717 * small block transfer (< fifo size),
1718 * you may get your DATAEND/DATABLKEND
1719 * irq without the PIO data irq.
1720 *
1721 * Check to see if theres still data
1722 * to be read, and simulate a PIO irq.
1723 */
1724 if (data->flags & MMC_DATA_READ)
1725 msmsdcc_wait_for_rxdata(host,
1726 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001727 if (!data->error) {
1728 host->curr.data_xfered =
1729 host->curr.xfer_size;
1730 host->curr.xfer_remain -=
1731 host->curr.xfer_size;
1732 }
1733
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001734 if (!host->dummy_52_needed) {
1735 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301736 if (!data->stop ||
1737 (host->curr.mrq->sbc
1738 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001739 msmsdcc_request_end(
1740 host,
1741 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301742 else if ((host->curr.mrq->sbc
1743 && data->error) ||
1744 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001745 msmsdcc_start_command(
1746 host,
1747 data->stop, 0);
1748 timer = 1;
1749 }
1750 } else {
1751 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001752 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001753 &dummy52cmd,
1754 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001755 }
1756 }
1757 }
1758 }
1759
San Mehat9d2bd732009-09-22 16:44:22 -07001760 ret = 1;
1761 } while (status);
1762
1763 spin_unlock(&host->lock);
1764
San Mehat9d2bd732009-09-22 16:44:22 -07001765 return IRQ_RETVAL(ret);
1766}
1767
1768static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001769msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1770{
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301771 if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001772 /* Queue/read data, daisy-chain command when data starts */
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301773 if (mrq->sbc)
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301774 msmsdcc_start_data(host, mrq->data, mrq->sbc, 0);
1775 else
1776 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001777 } else {
1778 msmsdcc_start_command(host, mrq->cmd, 0);
1779 }
1780}
1781
1782static void
San Mehat9d2bd732009-09-22 16:44:22 -07001783msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1784{
1785 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001786 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001787
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001788 /*
1789 * Get the SDIO AL client out of LPM.
1790 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001791 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001792 if (host->plat->is_sdio_al_client)
1793 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001794
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301795 /* check if sps pipe reset is pending? */
1796 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1797 msmsdcc_sps_pipes_reset_and_restore(host);
1798 host->sps.pipe_reset_pending = false;
1799 }
1800
San Mehat9d2bd732009-09-22 16:44:22 -07001801 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001802 WARN(host->curr.mrq, "Request in progress\n");
1803 WARN(!host->pwr, "SDCC power is turned off\n");
1804 WARN(!host->clks_on, "SDCC clocks are turned off\n");
1805 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
San Mehat9d2bd732009-09-22 16:44:22 -07001806
1807 if (host->eject) {
1808 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1809 mrq->cmd->error = 0;
1810 mrq->data->bytes_xfered = mrq->data->blksz *
1811 mrq->data->blocks;
1812 } else
1813 mrq->cmd->error = -ENOMEDIUM;
1814
1815 spin_unlock_irqrestore(&host->lock, flags);
1816 mmc_request_done(mmc, mrq);
1817 return;
1818 }
1819
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301820 /*
1821 * Kick the software command timeout timer here.
1822 * Timer expires in 10 secs.
1823 */
1824 mod_timer(&host->req_tout_timer,
1825 (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
San Mehat9d2bd732009-09-22 16:44:22 -07001826
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301827 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301828 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301829 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
1830 mrq->cmd->opcode == 54) {
Pratibhasagar V1c11da62011-11-14 12:36:35 +05301831 if (!host->sdcc_version)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001832 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301833 else
1834 /*
1835 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
1836 * write operations using CMD53 and CMD54.
1837 * Setting this bit with CMD53 would
1838 * automatically triggers PROG_DONE interrupt
1839 * without the need of sending dummy CMD52.
1840 */
1841 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani758cf8c2011-11-13 11:59:55 +05301842 } else if (mrq->cmd->opcode == MMC_WRITE_BLOCK &&
1843 host->sdcc_version) {
1844 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001845 }
San Mehat9d2bd732009-09-22 16:44:22 -07001846 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301847
Pratibhasagar V00b94332011-10-18 14:57:27 +05301848 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301849 mrq->sbc->mrq = mrq;
1850 mrq->sbc->data = mrq->data;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301851 if (mrq->data->flags & MMC_DATA_WRITE) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301852 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301853 msmsdcc_start_command(host, mrq->sbc, 0);
1854 } else {
1855 msmsdcc_request_start(host, mrq);
1856 }
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301857 } else {
1858 msmsdcc_request_start(host, mrq);
1859 }
1860
San Mehat9d2bd732009-09-22 16:44:22 -07001861 spin_unlock_irqrestore(&host->lock, flags);
1862}
1863
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001864static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1865 int min_uV, int max_uV)
1866{
1867 int rc = 0;
1868
1869 if (vreg->set_voltage_sup) {
1870 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1871 if (rc) {
1872 pr_err("%s: regulator_set_voltage(%s) failed."
1873 " min_uV=%d, max_uV=%d, rc=%d\n",
1874 __func__, vreg->name, min_uV, max_uV, rc);
1875 }
1876 }
1877
1878 return rc;
1879}
1880
1881static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1882 int uA_load)
1883{
1884 int rc = 0;
1885
Krishna Kondafea60182011-11-01 16:01:34 -07001886 /* regulators that do not support regulator_set_voltage also
1887 do not support regulator_set_optimum_mode */
1888 if (vreg->set_voltage_sup) {
1889 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1890 if (rc < 0)
1891 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
1892 "uA_load=%d) failed. rc=%d\n", __func__,
1893 vreg->name, uA_load, rc);
1894 else
1895 /* regulator_set_optimum_mode() can return non zero
1896 * value even for success case.
1897 */
1898 rc = 0;
1899 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001900
1901 return rc;
1902}
1903
1904static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1905 struct device *dev)
1906{
1907 int rc = 0;
1908
1909 /* check if regulator is already initialized? */
1910 if (vreg->reg)
1911 goto out;
1912
1913 /* Get the regulator handle */
1914 vreg->reg = regulator_get(dev, vreg->name);
1915 if (IS_ERR(vreg->reg)) {
1916 rc = PTR_ERR(vreg->reg);
1917 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
1918 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001919 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001920 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001921
1922 if (regulator_count_voltages(vreg->reg) > 0)
1923 vreg->set_voltage_sup = 1;
1924
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001925out:
1926 return rc;
1927}
1928
1929static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
1930{
1931 if (vreg->reg)
1932 regulator_put(vreg->reg);
1933}
1934
1935/* This init function should be called only once for each SDCC slot */
1936static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
1937{
1938 int rc = 0;
1939 struct msm_mmc_slot_reg_data *curr_slot;
1940 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1941 struct device *dev = mmc_dev(host->mmc);
1942
1943 curr_slot = host->plat->vreg_data;
1944 if (!curr_slot)
1945 goto out;
1946
1947 curr_vdd_reg = curr_slot->vdd_data;
1948 curr_vccq_reg = curr_slot->vccq_data;
1949 curr_vddp_reg = curr_slot->vddp_data;
1950
1951 if (is_init) {
1952 /*
1953 * Get the regulator handle from voltage regulator framework
1954 * and then try to set the voltage level for the regulator
1955 */
1956 if (curr_vdd_reg) {
1957 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
1958 if (rc)
1959 goto out;
1960 }
1961 if (curr_vccq_reg) {
1962 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
1963 if (rc)
1964 goto vdd_reg_deinit;
1965 }
1966 if (curr_vddp_reg) {
1967 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
1968 if (rc)
1969 goto vccq_reg_deinit;
1970 }
1971 goto out;
1972 } else {
1973 /* Deregister all regulators from regulator framework */
1974 goto vddp_reg_deinit;
1975 }
1976vddp_reg_deinit:
1977 if (curr_vddp_reg)
1978 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
1979vccq_reg_deinit:
1980 if (curr_vccq_reg)
1981 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
1982vdd_reg_deinit:
1983 if (curr_vdd_reg)
1984 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
1985out:
1986 return rc;
1987}
1988
1989static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
1990{
1991 int rc = 0;
1992
Subhash Jadavanicc922692011-08-01 23:05:01 +05301993 /* Put regulator in HPM (high power mode) */
1994 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
1995 if (rc < 0)
1996 goto out;
1997
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001998 if (!vreg->is_enabled) {
1999 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302000 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2001 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002002 if (rc)
2003 goto out;
2004
2005 rc = regulator_enable(vreg->reg);
2006 if (rc) {
2007 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2008 __func__, vreg->name, rc);
2009 goto out;
2010 }
2011 vreg->is_enabled = true;
2012 }
2013
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002014out:
2015 return rc;
2016}
2017
2018static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
2019{
2020 int rc = 0;
2021
2022 /* Never disable regulator marked as always_on */
2023 if (vreg->is_enabled && !vreg->always_on) {
2024 rc = regulator_disable(vreg->reg);
2025 if (rc) {
2026 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2027 __func__, vreg->name, rc);
2028 goto out;
2029 }
2030 vreg->is_enabled = false;
2031
2032 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2033 if (rc < 0)
2034 goto out;
2035
2036 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302037 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002038 if (rc)
2039 goto out;
2040 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
2041 /* Put always_on regulator in LPM (low power mode) */
2042 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2043 if (rc < 0)
2044 goto out;
2045 }
2046out:
2047 return rc;
2048}
2049
2050static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
2051{
2052 int rc = 0, i;
2053 struct msm_mmc_slot_reg_data *curr_slot;
2054 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
2055 struct msm_mmc_reg_data *vreg_table[3];
2056
2057 curr_slot = host->plat->vreg_data;
2058 if (!curr_slot)
2059 goto out;
2060
2061 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
2062 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
2063 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
2064
2065 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2066 if (vreg_table[i]) {
2067 if (enable)
2068 rc = msmsdcc_vreg_enable(vreg_table[i]);
2069 else
2070 rc = msmsdcc_vreg_disable(vreg_table[i]);
2071 if (rc)
2072 goto out;
2073 }
2074 }
2075out:
2076 return rc;
2077}
2078
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302079static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002080{
2081 int rc = 0;
2082
2083 if (host->plat->vreg_data) {
2084 struct msm_mmc_reg_data *vddp_reg =
2085 host->plat->vreg_data->vddp_data;
2086
2087 if (vddp_reg && vddp_reg->is_enabled)
2088 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
2089 }
2090
2091 return rc;
2092}
2093
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302094static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
2095{
2096 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2097 int rc = 0;
2098
2099 if (curr_slot && curr_slot->vddp_data) {
2100 rc = msmsdcc_set_vddp_level(host,
2101 curr_slot->vddp_data->low_vol_level);
2102
2103 if (rc)
2104 pr_err("%s: %s: failed to change vddp level to %d",
2105 mmc_hostname(host->mmc), __func__,
2106 curr_slot->vddp_data->low_vol_level);
2107 }
2108
2109 return rc;
2110}
2111
2112static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
2113{
2114 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2115 int rc = 0;
2116
2117 if (curr_slot && curr_slot->vddp_data) {
2118 rc = msmsdcc_set_vddp_level(host,
2119 curr_slot->vddp_data->high_vol_level);
2120
2121 if (rc)
2122 pr_err("%s: %s: failed to change vddp level to %d",
2123 mmc_hostname(host->mmc), __func__,
2124 curr_slot->vddp_data->high_vol_level);
2125 }
2126
2127 return rc;
2128}
2129
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002130static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2131{
2132 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2133 return 1;
2134 return 0;
2135}
2136
2137static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
2138{
2139 if (enable) {
2140 if (!IS_ERR_OR_NULL(host->dfab_pclk))
2141 clk_enable(host->dfab_pclk);
2142 if (!IS_ERR(host->pclk))
2143 clk_enable(host->pclk);
2144 clk_enable(host->clk);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302145 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002146 } else {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302147 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002148 clk_disable(host->clk);
2149 if (!IS_ERR(host->pclk))
2150 clk_disable(host->pclk);
2151 if (!IS_ERR_OR_NULL(host->dfab_pclk))
2152 clk_disable(host->dfab_pclk);
2153 }
2154}
2155
2156static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2157 unsigned int req_clk)
2158{
2159 unsigned int sel_clk = -1;
2160
2161 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2162 unsigned char cnt;
2163
2164 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2165 if (host->plat->sup_clk_table[cnt] > req_clk)
2166 break;
2167 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2168 sel_clk = host->plat->sup_clk_table[cnt];
2169 break;
2170 } else
2171 sel_clk = host->plat->sup_clk_table[cnt];
2172 }
2173 } else {
2174 if ((req_clk < host->plat->msmsdcc_fmax) &&
2175 (req_clk > host->plat->msmsdcc_fmid))
2176 sel_clk = host->plat->msmsdcc_fmid;
2177 else
2178 sel_clk = req_clk;
2179 }
2180
2181 return sel_clk;
2182}
2183
2184static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2185 struct msmsdcc_host *host)
2186{
2187 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2188 return host->plat->sup_clk_table[0];
2189 else
2190 return host->plat->msmsdcc_fmin;
2191}
2192
2193static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2194 struct msmsdcc_host *host)
2195{
2196 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2197 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2198 else
2199 return host->plat->msmsdcc_fmax;
2200}
2201
2202static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302203{
2204 struct msm_mmc_gpio_data *curr;
2205 int i, rc = 0;
2206
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002207 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302208 for (i = 0; i < curr->size; i++) {
2209 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002210 if (curr->gpio[i].is_always_on &&
2211 curr->gpio[i].is_enabled)
2212 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302213 rc = gpio_request(curr->gpio[i].no,
2214 curr->gpio[i].name);
2215 if (rc) {
2216 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2217 mmc_hostname(host->mmc),
2218 curr->gpio[i].no,
2219 curr->gpio[i].name, rc);
2220 goto free_gpios;
2221 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002222 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302223 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002224 if (curr->gpio[i].is_always_on)
2225 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302226 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002227 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302228 }
2229 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002230 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302231
2232free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002233 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302234 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002235 curr->gpio[i].is_enabled = false;
2236 }
2237out:
2238 return rc;
2239}
2240
2241static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2242{
2243 struct msm_mmc_pad_data *curr;
2244 int i;
2245
2246 curr = host->plat->pin_data->pad_data;
2247 for (i = 0; i < curr->drv->size; i++) {
2248 if (enable)
2249 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2250 curr->drv->on[i].val);
2251 else
2252 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2253 curr->drv->off[i].val);
2254 }
2255
2256 for (i = 0; i < curr->pull->size; i++) {
2257 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002258 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002259 curr->pull->on[i].val);
2260 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002261 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002262 curr->pull->off[i].val);
2263 }
2264
2265 return 0;
2266}
2267
2268static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2269{
2270 int rc = 0;
2271
2272 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2273 return 0;
2274
2275 if (host->plat->pin_data->is_gpio)
2276 rc = msmsdcc_setup_gpio(host, enable);
2277 else
2278 rc = msmsdcc_setup_pad(host, enable);
2279
2280 if (!rc)
2281 host->plat->pin_data->cfg_sts = enable;
2282
2283 return rc;
2284}
2285
2286static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2287{
2288 unsigned int wakeup_irq;
2289
2290 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2291 host->plat->sdiowakeup_irq :
2292 host->core_irqres->start;
2293
2294 if (!host->irq_wake_enabled) {
2295 enable_irq_wake(wakeup_irq);
2296 host->irq_wake_enabled = true;
2297 }
2298}
2299
2300static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2301{
2302 unsigned int wakeup_irq;
2303
2304 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2305 host->plat->sdiowakeup_irq :
2306 host->core_irqres->start;
2307
2308 if (host->irq_wake_enabled) {
2309 disable_irq_wake(wakeup_irq);
2310 host->irq_wake_enabled = false;
2311 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302312}
2313
San Mehat9d2bd732009-09-22 16:44:22 -07002314static void
2315msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2316{
2317 struct msmsdcc_host *host = mmc_priv(mmc);
2318 u32 clk = 0, pwr = 0;
2319 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002320 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002321 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002322
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002323 DBG(host, "ios->clock = %u\n", ios->clock);
Sahitya Tummala7a892482011-01-18 11:22:49 +05302324
San Mehat9d2bd732009-09-22 16:44:22 -07002325 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002326 spin_lock_irqsave(&host->lock, flags);
2327 if (!host->clks_on) {
2328 msmsdcc_setup_clocks(host, true);
2329 host->clks_on = 1;
2330 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2331 if (!host->plat->sdiowakeup_irq) {
2332 writel_relaxed(host->mci_irqenable,
2333 host->base + MMCIMASK0);
2334 mb();
2335 if (host->plat->cfg_mpm_sdiowakeup &&
2336 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2337 host->plat->cfg_mpm_sdiowakeup(
2338 mmc_dev(mmc), SDC_DAT1_DISWAKE);
2339 msmsdcc_disable_irq_wake(host);
2340 } else if (!(mmc->pm_flags &
2341 MMC_PM_WAKE_SDIO_IRQ)) {
2342 writel_relaxed(host->mci_irqenable,
2343 host->base + MMCIMASK0);
2344 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05302345 } else {
2346 writel_relaxed(host->mci_irqenable,
2347 host->base + MMCIMASK0);
2348 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002349 }
San Mehat9d2bd732009-09-22 16:44:22 -07002350 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002351 spin_unlock_irqrestore(&host->lock, flags);
2352
2353 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2354 /*
2355 * For DDR50 mode, controller needs clock rate to be
2356 * double than what is required on the SD card CLK pin.
2357 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302358 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002359 /*
2360 * Make sure that we don't double the clock if
2361 * doubled clock rate is already set
2362 */
2363 if (!host->ddr_doubled_clk_rate ||
2364 (host->ddr_doubled_clk_rate &&
2365 (host->ddr_doubled_clk_rate != ios->clock))) {
2366 host->ddr_doubled_clk_rate =
2367 msmsdcc_get_sup_clk_rate(
2368 host, (ios->clock * 2));
2369 clock = host->ddr_doubled_clk_rate;
2370 }
2371 } else {
2372 host->ddr_doubled_clk_rate = 0;
2373 }
2374
2375 if (clock != host->clk_rate) {
2376 rc = clk_set_rate(host->clk, clock);
2377 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302378 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002379 mmc_hostname(mmc), clock);
2380 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302381 host->reg_write_delay =
2382 (1 + ((3 * USEC_PER_SEC) /
2383 (host->clk_rate ? host->clk_rate :
2384 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002385 }
2386 /*
2387 * give atleast 2 MCLK cycles delay for clocks
2388 * and SDCC core to stabilize
2389 */
2390 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002391 clk |= MCI_CLK_ENABLE;
2392 }
2393
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002394 if (ios->bus_width == MMC_BUS_WIDTH_8)
2395 clk |= MCI_CLK_WIDEBUS_8;
2396 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2397 clk |= MCI_CLK_WIDEBUS_4;
2398 else
2399 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002400
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002401 if (msmsdcc_is_pwrsave(host))
2402 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002403
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002404 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002405
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002406 host->tuning_needed = 0;
2407 /*
2408 * Select the controller timing mode according
2409 * to current bus speed mode
2410 */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302411 if (ios->timing == MMC_TIMING_UHS_SDR104) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002412 clk |= (4 << 14);
2413 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302414 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002415 clk |= (3 << 14);
2416 } else {
2417 clk |= (2 << 14); /* feedback clock */
2418 }
2419
2420 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2421 clk |= (2 << 23);
2422
Subhash Jadavani00083572012-02-15 16:18:01 +05302423 /* Clear IO_PAD_PWR_SWITCH while powering off the card */
2424 if (!ios->vdd)
2425 host->io_pad_pwr_switch = 0;
2426
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002427 if (host->io_pad_pwr_switch)
2428 clk |= IO_PAD_PWR_SWITCH;
2429
2430 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
San Mehat9d2bd732009-09-22 16:44:22 -07002431 pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002432 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2433 pwr |= msmsdcc_setup_vreg(host, !!ios->vdd);
San Mehat9d2bd732009-09-22 16:44:22 -07002434
2435 switch (ios->power_mode) {
2436 case MMC_POWER_OFF:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002437 htc_pwrsink_set(PWRSINK_SDCARD, 0);
2438 if (!host->sdcc_irq_disabled) {
2439 if (host->plat->cfg_mpm_sdiowakeup)
2440 host->plat->cfg_mpm_sdiowakeup(
2441 mmc_dev(mmc), SDC_DAT1_DISABLE);
2442 disable_irq(host->core_irqres->start);
2443 host->sdcc_irq_disabled = 1;
2444 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302445 /*
2446 * As VDD pad rail is always on, set low voltage for VDD
2447 * pad rail when slot is unused (when card is not present
2448 * or during system suspend).
2449 */
2450 msmsdcc_set_vddp_low_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002451 msmsdcc_setup_pins(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002452 break;
2453 case MMC_POWER_UP:
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302454 /* writing PWR_UP bit is redundant */
San Mehat9d2bd732009-09-22 16:44:22 -07002455 pwr |= MCI_PWR_UP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002456 if (host->sdcc_irq_disabled) {
2457 if (host->plat->cfg_mpm_sdiowakeup)
2458 host->plat->cfg_mpm_sdiowakeup(
2459 mmc_dev(mmc), SDC_DAT1_ENABLE);
2460 enable_irq(host->core_irqres->start);
2461 host->sdcc_irq_disabled = 0;
2462 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302463 msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002464 msmsdcc_setup_pins(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07002465 break;
2466 case MMC_POWER_ON:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002467 htc_pwrsink_set(PWRSINK_SDCARD, 100);
San Mehat9d2bd732009-09-22 16:44:22 -07002468 pwr |= MCI_PWR_ON;
2469 break;
2470 }
2471
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002472 spin_lock_irqsave(&host->lock, flags);
2473 if (!host->clks_on) {
2474 /* force the clocks to be on */
2475 msmsdcc_setup_clocks(host, true);
2476 /*
2477 * give atleast 2 MCLK cycles delay for clocks
2478 * and SDCC core to stabilize
2479 */
2480 msmsdcc_delay(host);
2481 }
2482 writel_relaxed(clk, host->base + MMCICLOCK);
2483 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002484
2485 if (host->pwr != pwr) {
2486 host->pwr = pwr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002487 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302488 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002489 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002490 if (!host->clks_on) {
2491 /* force the clocks to be off */
2492 msmsdcc_setup_clocks(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002493 }
2494
2495 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
2496 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2497 if (!host->plat->sdiowakeup_irq) {
2498 writel_relaxed(MCI_SDIOINTMASK,
2499 host->base + MMCIMASK0);
2500 mb();
2501 if (host->plat->cfg_mpm_sdiowakeup &&
2502 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2503 host->plat->cfg_mpm_sdiowakeup(
2504 mmc_dev(mmc), SDC_DAT1_ENWAKE);
2505 msmsdcc_enable_irq_wake(host);
2506 } else if (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2507 writel_relaxed(0, host->base + MMCIMASK0);
2508 } else {
2509 writel_relaxed(MCI_SDIOINTMASK,
2510 host->base + MMCIMASK0);
2511 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302512 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002513 }
2514 msmsdcc_setup_clocks(host, false);
2515 host->clks_on = 0;
2516 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302517
2518 if (host->cmd19_tuning_in_progress)
2519 WARN(!host->clks_on,
2520 "cmd19_tuning_in_progress but SDCC clocks are OFF\n");
2521
San Mehat4adbbcc2009-11-08 13:00:37 -08002522 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002523}
2524
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002525int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2526{
2527 struct msmsdcc_host *host = mmc_priv(mmc);
2528 u32 clk;
2529
2530 clk = readl_relaxed(host->base + MMCICLOCK);
2531 pr_debug("Changing to pwr_save=%d", pwrsave);
2532 if (pwrsave && msmsdcc_is_pwrsave(host))
2533 clk |= MCI_CLK_PWRSAVE;
2534 else
2535 clk &= ~MCI_CLK_PWRSAVE;
2536 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302537 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002538
2539 return 0;
2540}
2541
2542static int msmsdcc_get_ro(struct mmc_host *mmc)
2543{
2544 int status = -ENOSYS;
2545 struct msmsdcc_host *host = mmc_priv(mmc);
2546
2547 if (host->plat->wpswitch) {
2548 status = host->plat->wpswitch(mmc_dev(mmc));
2549 } else if (host->plat->wpswitch_gpio) {
2550 status = gpio_request(host->plat->wpswitch_gpio,
2551 "SD_WP_Switch");
2552 if (status) {
2553 pr_err("%s: %s: Failed to request GPIO %d\n",
2554 mmc_hostname(mmc), __func__,
2555 host->plat->wpswitch_gpio);
2556 } else {
2557 status = gpio_direction_input(
2558 host->plat->wpswitch_gpio);
2559 if (!status) {
2560 /*
2561 * Wait for atleast 300ms as debounce
2562 * time for GPIO input to stabilize.
2563 */
2564 msleep(300);
2565 status = gpio_get_value_cansleep(
2566 host->plat->wpswitch_gpio);
2567 status ^= !host->plat->wpswitch_polarity;
2568 }
2569 gpio_free(host->plat->wpswitch_gpio);
2570 }
2571 }
2572
2573 if (status < 0)
2574 status = -ENOSYS;
2575 pr_debug("%s: Card read-only status %d\n", __func__, status);
2576
2577 return status;
2578}
2579
2580#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002581static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2582{
2583 struct msmsdcc_host *host = mmc_priv(mmc);
2584 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002585
2586 if (enable) {
2587 spin_lock_irqsave(&host->lock, flags);
2588 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
2589 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
2590 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2591 spin_unlock_irqrestore(&host->lock, flags);
2592 } else {
2593 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
2594 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
2595 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2596 }
2597 mb();
2598}
2599#endif /* CONFIG_MMC_MSM_SDIO_SUPPORT */
2600
2601#ifdef CONFIG_PM_RUNTIME
2602static int msmsdcc_enable(struct mmc_host *mmc)
2603{
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302604 int rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002605 struct device *dev = mmc->parent;
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302606 struct msmsdcc_host *host = mmc_priv(mmc);
2607
2608 msmsdcc_pm_qos_update_latency(host, 1);
2609
2610 if (mmc->card && mmc_card_sdio(mmc->card) && host->is_resumed)
2611 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002612
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302613 if (dev->power.runtime_status == RPM_SUSPENDING) {
2614 if (mmc->suspend_task == current) {
2615 pm_runtime_get_noresume(dev);
2616 goto out;
2617 }
2618 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002619
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302620 rc = pm_runtime_get_sync(dev);
2621
2622 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002623 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2624 __func__, rc);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302625 return rc;
2626 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302627
2628 host->is_resumed = true;
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302629out:
2630 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002631}
2632
2633static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2634{
2635 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302636 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002637
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302638 msmsdcc_pm_qos_update_latency(host, 0);
2639
2640 if (mmc->card && mmc_card_sdio(mmc->card))
2641 return 0;
2642
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302643 if (host->plat->disable_runtime_pm)
2644 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002645
2646 rc = pm_runtime_put_sync(mmc->parent);
2647
2648 if (rc < 0)
2649 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2650 __func__, rc);
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302651 else
2652 host->is_resumed = false;
2653
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002654 return rc;
2655}
2656#else
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302657static int msmsdcc_enable(struct mmc_host *mmc)
2658{
2659 struct msmsdcc_host *host = mmc_priv(mmc);
2660 unsigned long flags;
2661
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302662 msmsdcc_pm_qos_update_latency(host, 1);
2663
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302664 spin_lock_irqsave(&host->lock, flags);
2665 if (!host->clks_on) {
2666 msmsdcc_setup_clocks(host, true);
2667 host->clks_on = 1;
2668 }
2669 spin_unlock_irqrestore(&host->lock, flags);
2670
2671 return 0;
2672}
2673
2674static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2675{
2676 struct msmsdcc_host *host = mmc_priv(mmc);
2677 unsigned long flags;
2678
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302679 msmsdcc_pm_qos_update_latency(host, 0);
2680
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302681 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302682 return 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302683
2684 spin_lock_irqsave(&host->lock, flags);
2685 if (host->clks_on) {
2686 msmsdcc_setup_clocks(host, false);
2687 host->clks_on = 0;
2688 }
2689 spin_unlock_irqrestore(&host->lock, flags);
2690
2691 return 0;
2692}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002693#endif
2694
2695static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2696 struct mmc_ios *ios)
2697{
2698 struct msmsdcc_host *host = mmc_priv(mmc);
2699 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302700 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002701
Subhash Jadavani00083572012-02-15 16:18:01 +05302702 spin_lock_irqsave(&host->lock, flags);
2703 host->io_pad_pwr_switch = 0;
2704 spin_unlock_irqrestore(&host->lock, flags);
2705
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002706 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2707 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302708 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002709 goto out;
2710 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2711 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302712 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002713 goto out;
2714 }
San Mehat9d2bd732009-09-22 16:44:22 -07002715
2716 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002717 /*
2718 * If we are here means voltage switch from high voltage to
2719 * low voltage is required
2720 */
2721
2722 /*
2723 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2724 * register until they become all zeros.
2725 */
2726 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302727 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002728 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2729 mmc_hostname(mmc), __func__);
2730 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002731 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002732
2733 /* Stop SD CLK output. */
2734 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2735 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302736 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002737 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002738
2739 /*
2740 * Switch VDDPX from high voltage to low voltage
2741 * to change the VDD of the SD IO pads.
2742 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302743 rc = msmsdcc_set_vddp_low_vol(host);
2744 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002745 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002746
2747 spin_lock_irqsave(&host->lock, flags);
2748 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2749 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302750 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002751 host->io_pad_pwr_switch = 1;
2752 spin_unlock_irqrestore(&host->lock, flags);
2753
2754 /* Wait 5 ms for the voltage regulater in the card to become stable. */
2755 usleep_range(5000, 5500);
2756
2757 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302758 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002759 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2760 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302761 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002762 spin_unlock_irqrestore(&host->lock, flags);
2763
2764 /*
2765 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
2766 * don't become all ones within 1 ms then a Voltage Switch
2767 * sequence has failed and a power cycle to the card is required.
2768 * Otherwise Voltage Switch sequence is completed successfully.
2769 */
2770 usleep_range(1000, 1500);
2771
2772 spin_lock_irqsave(&host->lock, flags);
2773 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
2774 != (0xF << 1)) {
2775 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
2776 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302777 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002778 goto out_unlock;
2779 }
2780
2781out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302782 /* Enable PWRSAVE */
2783 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2784 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002785 spin_unlock_irqrestore(&host->lock, flags);
2786out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302787 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002788}
2789
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302790static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002791{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002792 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002793
2794 /* Program the MCLK value to MCLK_FREQ bit field */
2795 if (host->clk_rate <= 112000000)
2796 mclk_freq = 0;
2797 else if (host->clk_rate <= 125000000)
2798 mclk_freq = 1;
2799 else if (host->clk_rate <= 137000000)
2800 mclk_freq = 2;
2801 else if (host->clk_rate <= 150000000)
2802 mclk_freq = 3;
2803 else if (host->clk_rate <= 162000000)
2804 mclk_freq = 4;
2805 else if (host->clk_rate <= 175000000)
2806 mclk_freq = 5;
2807 else if (host->clk_rate <= 187000000)
2808 mclk_freq = 6;
2809 else if (host->clk_rate <= 200000000)
2810 mclk_freq = 7;
2811
2812 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2813 & ~(7 << 24)) | (mclk_freq << 24)),
2814 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002815}
2816
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302817/* Initialize the DLL (Programmable Delay Line ) */
2818static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002819{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002820 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302821 unsigned long flags;
2822 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002823
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302824 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002825 /*
2826 * Make sure that clock is always enabled when DLL
2827 * tuning is in progress. Keeping PWRSAVE ON may
2828 * turn off the clock. So let's disable the PWRSAVE
2829 * here and re-enable it once tuning is completed.
2830 */
2831 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2832 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302833
2834 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
2835 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2836 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2837
2838 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
2839 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2840 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2841
2842 msmsdcc_cm_sdc4_dll_set_freq(host);
2843
2844 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
2845 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2846 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2847
2848 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
2849 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2850 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2851
2852 /* Set DLL_EN bit to 1. */
2853 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2854 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
2855
2856 /* Set CK_OUT_EN bit to 1. */
2857 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2858 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2859
2860 wait_cnt = 50;
2861 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
2862 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
2863 /* max. wait for 50us sec for LOCK bit to be set */
2864 if (--wait_cnt == 0) {
2865 pr_err("%s: %s: DLL failed to LOCK\n",
2866 mmc_hostname(host->mmc), __func__);
2867 rc = -ETIMEDOUT;
2868 goto out;
2869 }
2870 /* wait for 1us before polling again */
2871 udelay(1);
2872 }
2873
2874out:
2875 /* re-enable PWRSAVE */
2876 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2877 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2878 spin_unlock_irqrestore(&host->lock, flags);
2879
2880 return rc;
2881}
2882
2883static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
2884 u8 poll)
2885{
2886 int rc = 0;
2887 u32 wait_cnt = 50;
2888 u8 ck_out_en = 0;
2889
2890 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
2891 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
2892 MCI_CK_OUT_EN);
2893
2894 while (ck_out_en != poll) {
2895 if (--wait_cnt == 0) {
2896 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
2897 mmc_hostname(host->mmc), __func__, poll);
2898 rc = -ETIMEDOUT;
2899 goto out;
2900 }
2901 udelay(1);
2902
2903 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
2904 MCI_CK_OUT_EN);
2905 }
2906out:
2907 return rc;
2908}
2909
2910/*
2911 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
2912 * calibration sequence. This function should be called before
2913 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
2914 * commands (CMD17/CMD18).
2915 *
2916 * This function gets called when host spinlock acquired.
2917 */
2918static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
2919{
2920 int rc = 0;
2921 u32 config;
2922
2923 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
2924 config |= MCI_CDR_EN;
2925 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
2926 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
2927
2928 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2929 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
2930 if (rc)
2931 goto err_out;
2932
2933 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2934 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2935 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2936
2937 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
2938 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
2939 if (rc)
2940 goto err_out;
2941
2942 goto out;
2943
2944err_out:
2945 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
2946out:
2947 return rc;
2948}
2949
2950static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2951 u8 phase)
2952{
2953 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05302954 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
2955 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
2956 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302957 unsigned long flags;
2958 u32 config;
2959
2960 spin_lock_irqsave(&host->lock, flags);
2961
2962 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
2963 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
2964 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
2965 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
2966
2967 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2968 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
2969 if (rc)
2970 goto err_out;
2971
2972 /*
2973 * Write the selected DLL clock output phase (0 ... 15)
2974 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
2975 */
2976 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2977 & ~(0xF << 20))
2978 | (grey_coded_phase_table[phase] << 20)),
2979 host->base + MCI_DLL_CONFIG);
2980
2981 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2982 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2983 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2984
2985 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
2986 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
2987 if (rc)
2988 goto err_out;
2989
2990 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
2991 config |= MCI_CDR_EN;
2992 config &= ~MCI_CDR_EXT_EN;
2993 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
2994 goto out;
2995
2996err_out:
2997 pr_err("%s: %s: Failed to set DLL phase: %d\n",
2998 mmc_hostname(host->mmc), __func__, phase);
2999out:
3000 spin_unlock_irqrestore(&host->lock, flags);
3001 return rc;
3002}
3003
3004/*
3005 * Find out the greatest range of consecuitive selected
3006 * DLL clock output phases that can be used as sampling
3007 * setting for SD3.0 UHS-I card read operation (in SDR104
3008 * timing mode) or for eMMC4.5 card read operation (in HS200
3009 * timing mode).
3010 * Select the 3/4 of the range and configure the DLL with the
3011 * selected DLL clock output phase.
3012*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303013static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303014 u8 *phase_table, u8 total_phases)
3015{
Subhash Jadavani34187042012-03-02 10:59:49 +05303016 int ret;
3017 u8 ranges[16][16] = { {0}, {0} };
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303018 u8 phases_per_row[16] = {0};
3019 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303020 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3021 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303022
Subhash Jadavani34187042012-03-02 10:59:49 +05303023 if (total_phases > 16) {
3024 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3025 mmc_hostname(host->mmc), __func__, total_phases);
3026 return -EINVAL;
3027 }
3028
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303029 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303030 ranges[row_index][col_index] = phase_table[cnt];
3031 phases_per_row[row_index] += 1;
3032 col_index++;
3033
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303034 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303035 continue;
3036 /* check if next phase in phase_table is consecutive or not */
3037 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3038 row_index++;
3039 col_index = 0;
3040 }
3041 }
3042
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303043 /* Check if phase-0 is present in first valid window? */
3044 if (!ranges[0][0]) {
3045 phase_0_found = true;
3046 phase_0_raw_index = 0;
3047 /* Check if cycle exist between 2 valid windows */
3048 for (cnt = 1; cnt <= row_index; cnt++) {
3049 if (phases_per_row[cnt]) {
3050 for (i = 0; i <= phases_per_row[cnt]; i++) {
3051 if (ranges[cnt][i] == 15) {
3052 phase_15_found = true;
3053 phase_15_raw_index = cnt;
3054 break;
3055 }
3056 }
3057 }
3058 }
3059 }
3060
3061 /* If 2 valid windows form cycle then merge them as single window */
3062 if (phase_0_found && phase_15_found) {
3063 /* number of phases in raw where phase 0 is present */
3064 u8 phases_0 = phases_per_row[phase_0_raw_index];
3065 /* number of phases in raw where phase 15 is present */
3066 u8 phases_15 = phases_per_row[phase_15_raw_index];
3067
3068 cnt = 0;
3069 for (i = phases_15; i < (phases_15 + phases_0); i++) {
3070 ranges[phase_15_raw_index][i] =
3071 ranges[phase_0_raw_index][cnt];
3072 cnt++;
3073 }
3074 phases_per_row[phase_0_raw_index] = 0;
3075 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
3076 }
3077
3078 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303079 if (phases_per_row[cnt] > curr_max) {
3080 curr_max = phases_per_row[cnt];
3081 selected_row_index = cnt;
3082 }
3083 }
3084
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303085 i = ((curr_max * 3) / 4) - 1;
Subhash Jadavani34187042012-03-02 10:59:49 +05303086 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303087
3088 return ret;
3089}
3090
Girish K Sa3f41692012-02-29 12:00:09 +05303091static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303092{
3093 int rc = 0;
3094 struct msmsdcc_host *host = mmc_priv(mmc);
3095 unsigned long flags;
3096 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
3097
3098 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
3099
3100 /* Tuning is only required for SDR104 modes */
3101 if (!host->tuning_needed) {
3102 rc = 0;
3103 goto exit;
3104 }
3105
3106 spin_lock_irqsave(&host->lock, flags);
3107 WARN(!host->pwr, "SDCC power is turned off\n");
3108 WARN(!host->clks_on, "SDCC clocks are turned off\n");
3109 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
3110
3111 host->cmd19_tuning_in_progress = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05303112 msmsdcc_delay(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303113 spin_unlock_irqrestore(&host->lock, flags);
3114
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003115 /* first of all reset the tuning block */
3116 rc = msmsdcc_init_cm_sdc4_dll(host);
3117 if (rc)
3118 goto out;
3119
3120 data_buf = kmalloc(64, GFP_KERNEL);
3121 if (!data_buf) {
3122 rc = -ENOMEM;
3123 goto out;
3124 }
3125
3126 phase = 0;
3127 do {
3128 struct mmc_command cmd = {0};
3129 struct mmc_data data = {0};
3130 struct mmc_request mrq = {
3131 .cmd = &cmd,
3132 .data = &data
3133 };
3134 struct scatterlist sg;
3135
3136 /* set the phase in delay line hw block */
3137 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3138 if (rc)
3139 goto kfree;
3140
3141 cmd.opcode = MMC_SEND_TUNING_BLOCK;
3142 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
3143
3144 data.blksz = 64;
3145 data.blocks = 1;
3146 data.flags = MMC_DATA_READ;
3147 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
3148
3149 data.sg = &sg;
3150 data.sg_len = 1;
3151 sg_init_one(&sg, data_buf, 64);
3152 memset(data_buf, 0, 64);
3153 mmc_wait_for_req(mmc, &mrq);
3154
3155 if (!cmd.error && !data.error &&
3156 !memcmp(data_buf, cmd19_tuning_block, 64)) {
3157 /* tuning is successful with this tuning point */
3158 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303159 pr_debug("%s: %s: found good phase = %d\n",
3160 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003161 }
3162 } while (++phase < 16);
3163
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003164 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303165 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303166 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05303167 if (rc < 0)
3168 goto kfree;
3169 else
3170 phase = (u8)rc;
3171
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003172 /*
3173 * Finally set the selected phase in delay
3174 * line hw block.
3175 */
3176 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3177 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303178 goto kfree;
3179 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
3180 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003181 } else {
3182 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303183 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003184 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303185 msmsdcc_dump_sdcc_state(host);
3186 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003187 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003188
3189kfree:
3190 kfree(data_buf);
3191out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303192 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05303193 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003194 host->cmd19_tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303195 spin_unlock_irqrestore(&host->lock, flags);
3196exit:
3197 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003198 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07003199}
3200
3201static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003202 .enable = msmsdcc_enable,
3203 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07003204 .request = msmsdcc_request,
3205 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003206 .get_ro = msmsdcc_get_ro,
3207#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07003208 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003209#endif
3210 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
3211 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07003212};
3213
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003214static unsigned int
3215msmsdcc_slot_status(struct msmsdcc_host *host)
3216{
3217 int status;
3218 unsigned int gpio_no = host->plat->status_gpio;
3219
3220 status = gpio_request(gpio_no, "SD_HW_Detect");
3221 if (status) {
3222 pr_err("%s: %s: Failed to request GPIO %d\n",
3223 mmc_hostname(host->mmc), __func__, gpio_no);
3224 } else {
3225 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003226 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08003227 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003228 if (host->plat->is_status_gpio_active_low)
3229 status = !status;
3230 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003231 gpio_free(gpio_no);
3232 }
3233 return status;
3234}
3235
San Mehat9d2bd732009-09-22 16:44:22 -07003236static void
3237msmsdcc_check_status(unsigned long data)
3238{
3239 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3240 unsigned int status;
3241
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003242 if (host->plat->status || host->plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08003243 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003244 status = host->plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08003245 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003246 status = msmsdcc_slot_status(host);
3247
Krishna Konda941604a2012-01-10 17:46:34 -08003248 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08003249
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003250 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08003251 if (host->plat->status)
3252 pr_info("%s: Slot status change detected "
3253 "(%d -> %d)\n",
3254 mmc_hostname(host->mmc),
3255 host->oldstat, status);
3256 else if (host->plat->is_status_gpio_active_low)
3257 pr_info("%s: Slot status change detected "
3258 "(%d -> %d) and the card detect GPIO"
3259 " is ACTIVE_LOW\n",
3260 mmc_hostname(host->mmc),
3261 host->oldstat, status);
3262 else
3263 pr_info("%s: Slot status change detected "
3264 "(%d -> %d) and the card detect GPIO"
3265 " is ACTIVE_HIGH\n",
3266 mmc_hostname(host->mmc),
3267 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07003268 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003269 }
3270 host->oldstat = status;
3271 } else {
3272 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07003273 }
San Mehat9d2bd732009-09-22 16:44:22 -07003274}
3275
3276static irqreturn_t
3277msmsdcc_platform_status_irq(int irq, void *dev_id)
3278{
3279 struct msmsdcc_host *host = dev_id;
3280
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003281 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07003282 msmsdcc_check_status((unsigned long) host);
3283 return IRQ_HANDLED;
3284}
3285
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003286static irqreturn_t
3287msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
3288{
3289 struct msmsdcc_host *host = dev_id;
3290
3291 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
3292 spin_lock(&host->lock);
3293 if (!host->sdio_irq_disabled) {
3294 disable_irq_nosync(irq);
3295 if (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
3296 wake_lock(&host->sdio_wlock);
3297 msmsdcc_disable_irq_wake(host);
3298 }
3299 host->sdio_irq_disabled = 1;
3300 }
3301 if (host->plat->is_sdio_al_client) {
3302 if (!host->clks_on) {
3303 msmsdcc_setup_clocks(host, true);
3304 host->clks_on = 1;
3305 }
3306 if (host->sdcc_irq_disabled) {
3307 writel_relaxed(host->mci_irqenable,
3308 host->base + MMCIMASK0);
3309 mb();
3310 enable_irq(host->core_irqres->start);
3311 host->sdcc_irq_disabled = 0;
3312 }
3313 wake_lock(&host->sdio_wlock);
3314 }
3315 spin_unlock(&host->lock);
3316
3317 return IRQ_HANDLED;
3318}
3319
San Mehat9d2bd732009-09-22 16:44:22 -07003320static void
3321msmsdcc_status_notify_cb(int card_present, void *dev_id)
3322{
3323 struct msmsdcc_host *host = dev_id;
3324
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003325 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07003326 card_present);
3327 msmsdcc_check_status((unsigned long) host);
3328}
3329
San Mehat9d2bd732009-09-22 16:44:22 -07003330static int
3331msmsdcc_init_dma(struct msmsdcc_host *host)
3332{
3333 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
3334 host->dma.host = host;
3335 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003336 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003337
3338 if (!host->dmares)
3339 return -ENODEV;
3340
3341 host->dma.nc = dma_alloc_coherent(NULL,
3342 sizeof(struct msmsdcc_nc_dmadata),
3343 &host->dma.nc_busaddr,
3344 GFP_KERNEL);
3345 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003346 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07003347 return -ENOMEM;
3348 }
3349 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
3350 host->dma.cmd_busaddr = host->dma.nc_busaddr;
3351 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
3352 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
3353 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07003354 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07003355
3356 return 0;
3357}
3358
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003359#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
3360/**
3361 * Allocate and Connect a SDCC peripheral's SPS endpoint
3362 *
3363 * This function allocates endpoint context and
3364 * connect it with memory endpoint by calling
3365 * appropriate SPS driver APIs.
3366 *
3367 * Also registers a SPS callback function with
3368 * SPS driver
3369 *
3370 * This function should only be called once typically
3371 * during driver probe.
3372 *
3373 * @host - Pointer to sdcc host structure
3374 * @ep - Pointer to sps endpoint data structure
3375 * @is_produce - 1 means Producer endpoint
3376 * 0 means Consumer endpoint
3377 *
3378 * @return - 0 if successful else negative value.
3379 *
3380 */
3381static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
3382 struct msmsdcc_sps_ep_conn_data *ep,
3383 bool is_producer)
3384{
3385 int rc = 0;
3386 struct sps_pipe *sps_pipe_handle;
3387 struct sps_connect *sps_config = &ep->config;
3388 struct sps_register_event *sps_event = &ep->event;
3389
3390 /* Allocate endpoint context */
3391 sps_pipe_handle = sps_alloc_endpoint();
3392 if (!sps_pipe_handle) {
3393 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
3394 mmc_hostname(host->mmc), is_producer);
3395 rc = -ENOMEM;
3396 goto out;
3397 }
3398
3399 /* Get default connection configuration for an endpoint */
3400 rc = sps_get_config(sps_pipe_handle, sps_config);
3401 if (rc) {
3402 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
3403 " rc=%d", mmc_hostname(host->mmc),
3404 (u32)sps_pipe_handle, rc);
3405 goto get_config_err;
3406 }
3407
3408 /* Modify the default connection configuration */
3409 if (is_producer) {
3410 /*
3411 * For SDCC producer transfer, source should be
3412 * SDCC peripheral where as destination should
3413 * be system memory.
3414 */
3415 sps_config->source = host->sps.bam_handle;
3416 sps_config->destination = SPS_DEV_HANDLE_MEM;
3417 /* Producer pipe will handle this connection */
3418 sps_config->mode = SPS_MODE_SRC;
3419 sps_config->options =
3420 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3421 } else {
3422 /*
3423 * For SDCC consumer transfer, source should be
3424 * system memory where as destination should
3425 * SDCC peripheral
3426 */
3427 sps_config->source = SPS_DEV_HANDLE_MEM;
3428 sps_config->destination = host->sps.bam_handle;
3429 sps_config->mode = SPS_MODE_DEST;
3430 sps_config->options =
3431 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3432 }
3433
3434 /* Producer pipe index */
3435 sps_config->src_pipe_index = host->sps.src_pipe_index;
3436 /* Consumer pipe index */
3437 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
3438 /*
3439 * This event thresold value is only significant for BAM-to-BAM
3440 * transfer. It's ignored for BAM-to-System mode transfer.
3441 */
3442 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05303443
3444 /* Allocate maximum descriptor fifo size */
3445 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
3446 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003447 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
3448 sps_config->desc.size,
3449 &sps_config->desc.phys_base,
3450 GFP_KERNEL);
3451
Pratibhasagar V00b94332011-10-18 14:57:27 +05303452 if (!sps_config->desc.base) {
3453 rc = -ENOMEM;
3454 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3455 , mmc_hostname(host->mmc));
3456 goto get_config_err;
3457 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003458 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3459
3460 /* Establish connection between peripheral and memory endpoint */
3461 rc = sps_connect(sps_pipe_handle, sps_config);
3462 if (rc) {
3463 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3464 " rc=%d", mmc_hostname(host->mmc),
3465 (u32)sps_pipe_handle, rc);
3466 goto sps_connect_err;
3467 }
3468
3469 sps_event->mode = SPS_TRIGGER_CALLBACK;
3470 sps_event->options = SPS_O_EOT;
3471 sps_event->callback = msmsdcc_sps_complete_cb;
3472 sps_event->xfer_done = NULL;
3473 sps_event->user = (void *)host;
3474
3475 /* Register callback event for EOT (End of transfer) event. */
3476 rc = sps_register_event(sps_pipe_handle, sps_event);
3477 if (rc) {
3478 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3479 " rc=%d", mmc_hostname(host->mmc),
3480 (u32)sps_pipe_handle, rc);
3481 goto reg_event_err;
3482 }
3483 /* Now save the sps pipe handle */
3484 ep->pipe_handle = sps_pipe_handle;
3485 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3486 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3487 __func__, is_producer ? "READ" : "WRITE",
3488 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3489 goto out;
3490
3491reg_event_err:
3492 sps_disconnect(sps_pipe_handle);
3493sps_connect_err:
3494 dma_free_coherent(mmc_dev(host->mmc),
3495 sps_config->desc.size,
3496 sps_config->desc.base,
3497 sps_config->desc.phys_base);
3498get_config_err:
3499 sps_free_endpoint(sps_pipe_handle);
3500out:
3501 return rc;
3502}
3503
3504/**
3505 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3506 *
3507 * This function disconnect endpoint and deallocates
3508 * endpoint context.
3509 *
3510 * This function should only be called once typically
3511 * during driver remove.
3512 *
3513 * @host - Pointer to sdcc host structure
3514 * @ep - Pointer to sps endpoint data structure
3515 *
3516 */
3517static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3518 struct msmsdcc_sps_ep_conn_data *ep)
3519{
3520 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3521 struct sps_connect *sps_config = &ep->config;
3522 struct sps_register_event *sps_event = &ep->event;
3523
3524 sps_event->xfer_done = NULL;
3525 sps_event->callback = NULL;
3526 sps_register_event(sps_pipe_handle, sps_event);
3527 sps_disconnect(sps_pipe_handle);
3528 dma_free_coherent(mmc_dev(host->mmc),
3529 sps_config->desc.size,
3530 sps_config->desc.base,
3531 sps_config->desc.phys_base);
3532 sps_free_endpoint(sps_pipe_handle);
3533}
3534
3535/**
3536 * Reset SDCC peripheral's SPS endpoint
3537 *
3538 * This function disconnects an endpoint.
3539 *
3540 * This function should be called for reseting
3541 * SPS endpoint when data transfer error is
3542 * encountered during data transfer. This
3543 * can be considered as soft reset to endpoint.
3544 *
3545 * This function should only be called if
3546 * msmsdcc_sps_init() is already called.
3547 *
3548 * @host - Pointer to sdcc host structure
3549 * @ep - Pointer to sps endpoint data structure
3550 *
3551 * @return - 0 if successful else negative value.
3552 */
3553static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3554 struct msmsdcc_sps_ep_conn_data *ep)
3555{
3556 int rc = 0;
3557 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3558
3559 rc = sps_disconnect(sps_pipe_handle);
3560 if (rc) {
3561 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3562 " rc=%d", mmc_hostname(host->mmc), __func__,
3563 (u32)sps_pipe_handle, rc);
3564 goto out;
3565 }
3566 out:
3567 return rc;
3568}
3569
3570/**
3571 * Restore SDCC peripheral's SPS endpoint
3572 *
3573 * This function connects an endpoint.
3574 *
3575 * This function should be called for restoring
3576 * SPS endpoint after data transfer error is
3577 * encountered during data transfer. This
3578 * can be considered as soft reset to endpoint.
3579 *
3580 * This function should only be called if
3581 * msmsdcc_sps_reset_ep() is called before.
3582 *
3583 * @host - Pointer to sdcc host structure
3584 * @ep - Pointer to sps endpoint data structure
3585 *
3586 * @return - 0 if successful else negative value.
3587 */
3588static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3589 struct msmsdcc_sps_ep_conn_data *ep)
3590{
3591 int rc = 0;
3592 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3593 struct sps_connect *sps_config = &ep->config;
3594 struct sps_register_event *sps_event = &ep->event;
3595
3596 /* Establish connection between peripheral and memory endpoint */
3597 rc = sps_connect(sps_pipe_handle, sps_config);
3598 if (rc) {
3599 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3600 " rc=%d", mmc_hostname(host->mmc), __func__,
3601 (u32)sps_pipe_handle, rc);
3602 goto out;
3603 }
3604
3605 /* Register callback event for EOT (End of transfer) event. */
3606 rc = sps_register_event(sps_pipe_handle, sps_event);
3607 if (rc) {
3608 pr_err("%s: %s: sps_register_event() failed!!!"
3609 " pipe_handle=0x%x, rc=%d",
3610 mmc_hostname(host->mmc), __func__,
3611 (u32)sps_pipe_handle, rc);
3612 goto reg_event_err;
3613 }
3614 goto out;
3615
3616reg_event_err:
3617 sps_disconnect(sps_pipe_handle);
3618out:
3619 return rc;
3620}
3621
3622/**
3623 * Initialize SPS HW connected with SDCC core
3624 *
3625 * This function register BAM HW resources with
3626 * SPS driver and then initialize 2 SPS endpoints
3627 *
3628 * This function should only be called once typically
3629 * during driver probe.
3630 *
3631 * @host - Pointer to sdcc host structure
3632 *
3633 * @return - 0 if successful else negative value.
3634 *
3635 */
3636static int msmsdcc_sps_init(struct msmsdcc_host *host)
3637{
3638 int rc = 0;
3639 struct sps_bam_props bam = {0};
3640
3641 host->bam_base = ioremap(host->bam_memres->start,
3642 resource_size(host->bam_memres));
3643 if (!host->bam_base) {
3644 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3645 " size=0x%x", mmc_hostname(host->mmc),
3646 host->bam_memres->start,
3647 (host->bam_memres->end -
3648 host->bam_memres->start));
3649 rc = -ENOMEM;
3650 goto out;
3651 }
3652
3653 bam.phys_addr = host->bam_memres->start;
3654 bam.virt_addr = host->bam_base;
3655 /*
3656 * This event thresold value is only significant for BAM-to-BAM
3657 * transfer. It's ignored for BAM-to-System mode transfer.
3658 */
3659 bam.event_threshold = 0x10; /* Pipe event threshold */
3660 /*
3661 * This threshold controls when the BAM publish
3662 * the descriptor size on the sideband interface.
3663 * SPS HW will only be used when
3664 * data transfer size > MCI_FIFOSIZE (64 bytes).
3665 * PIO mode will be used when
3666 * data transfer size < MCI_FIFOSIZE (64 bytes).
3667 * So set this thresold value to 64 bytes.
3668 */
3669 bam.summing_threshold = 64;
3670 /* SPS driver wll handle the SDCC BAM IRQ */
3671 bam.irq = (u32)host->bam_irqres->start;
3672 bam.manage = SPS_BAM_MGR_LOCAL;
3673
3674 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3675 (u32)bam.phys_addr);
3676 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3677 (u32)bam.virt_addr);
3678
3679 /* Register SDCC Peripheral BAM device to SPS driver */
3680 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3681 if (rc) {
3682 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3683 mmc_hostname(host->mmc), rc);
3684 goto reg_bam_err;
3685 }
3686 pr_info("%s: BAM device registered. bam_handle=0x%x",
3687 mmc_hostname(host->mmc), host->sps.bam_handle);
3688
3689 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3690 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3691
3692 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3693 SPS_PROD_PERIPHERAL);
3694 if (rc)
3695 goto sps_reset_err;
3696 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3697 SPS_CONS_PERIPHERAL);
3698 if (rc)
3699 goto cons_conn_err;
3700
3701 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3702 mmc_hostname(host->mmc),
3703 (unsigned long long)host->bam_memres->start,
3704 (unsigned int)host->bam_irqres->start);
3705 goto out;
3706
3707cons_conn_err:
3708 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3709sps_reset_err:
3710 sps_deregister_bam_device(host->sps.bam_handle);
3711reg_bam_err:
3712 iounmap(host->bam_base);
3713out:
3714 return rc;
3715}
3716
3717/**
3718 * De-initialize SPS HW connected with SDCC core
3719 *
3720 * This function deinitialize SPS endpoints and then
3721 * deregisters BAM resources from SPS driver.
3722 *
3723 * This function should only be called once typically
3724 * during driver remove.
3725 *
3726 * @host - Pointer to sdcc host structure
3727 *
3728 */
3729static void msmsdcc_sps_exit(struct msmsdcc_host *host)
3730{
3731 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
3732 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3733 sps_deregister_bam_device(host->sps.bam_handle);
3734 iounmap(host->bam_base);
3735}
3736#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
3737
3738static ssize_t
3739show_polling(struct device *dev, struct device_attribute *attr, char *buf)
3740{
3741 struct mmc_host *mmc = dev_get_drvdata(dev);
3742 struct msmsdcc_host *host = mmc_priv(mmc);
3743 int poll;
3744 unsigned long flags;
3745
3746 spin_lock_irqsave(&host->lock, flags);
3747 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
3748 spin_unlock_irqrestore(&host->lock, flags);
3749
3750 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
3751}
3752
3753static ssize_t
3754set_polling(struct device *dev, struct device_attribute *attr,
3755 const char *buf, size_t count)
3756{
3757 struct mmc_host *mmc = dev_get_drvdata(dev);
3758 struct msmsdcc_host *host = mmc_priv(mmc);
3759 int value;
3760 unsigned long flags;
3761
3762 sscanf(buf, "%d", &value);
3763
3764 spin_lock_irqsave(&host->lock, flags);
3765 if (value) {
3766 mmc->caps |= MMC_CAP_NEEDS_POLL;
3767 mmc_detect_change(host->mmc, 0);
3768 } else {
3769 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3770 }
3771#ifdef CONFIG_HAS_EARLYSUSPEND
3772 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
3773#endif
3774 spin_unlock_irqrestore(&host->lock, flags);
3775 return count;
3776}
3777
3778static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
3779 show_polling, set_polling);
3780static struct attribute *dev_attrs[] = {
3781 &dev_attr_polling.attr,
3782 NULL,
3783};
3784static struct attribute_group dev_attr_grp = {
3785 .attrs = dev_attrs,
3786};
3787
3788#ifdef CONFIG_HAS_EARLYSUSPEND
3789static void msmsdcc_early_suspend(struct early_suspend *h)
3790{
3791 struct msmsdcc_host *host =
3792 container_of(h, struct msmsdcc_host, early_suspend);
3793 unsigned long flags;
3794
3795 spin_lock_irqsave(&host->lock, flags);
3796 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
3797 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3798 spin_unlock_irqrestore(&host->lock, flags);
3799};
3800static void msmsdcc_late_resume(struct early_suspend *h)
3801{
3802 struct msmsdcc_host *host =
3803 container_of(h, struct msmsdcc_host, early_suspend);
3804 unsigned long flags;
3805
3806 if (host->polling_enabled) {
3807 spin_lock_irqsave(&host->lock, flags);
3808 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
3809 mmc_detect_change(host->mmc, 0);
3810 spin_unlock_irqrestore(&host->lock, flags);
3811 }
3812};
3813#endif
3814
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303815void msmsdcc_print_regs(const char *name, void __iomem *base,
3816 unsigned int no_of_regs)
3817{
3818 unsigned int i;
3819
3820 if (!base)
3821 return;
3822 pr_info("===== %s: Register Dumps @base=0x%x =====\n",
3823 name, (u32)base);
3824 for (i = 0; i < no_of_regs; i = i + 4) {
3825 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x.\n", i*4,
3826 (u32)readl_relaxed(base + i*4),
3827 (u32)readl_relaxed(base + ((i+1)*4)),
3828 (u32)readl_relaxed(base + ((i+2)*4)),
3829 (u32)readl_relaxed(base + ((i+3)*4)));
3830 }
3831}
3832
3833static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
3834{
3835 /* Dump current state of SDCC clocks, power and irq */
3836 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
3837 (host->pwr ? "ON" : "OFF"));
3838 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
3839 mmc_hostname(host->mmc),
3840 (host->clks_on ? "ON" : "OFF"),
3841 (u32)clk_get_rate(host->clk));
3842 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
3843 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
3844
3845 /* Now dump SDCC registers. Don't print FIFO registers */
3846 if (host->clks_on)
3847 msmsdcc_print_regs("SDCC-CORE", host->base, 28);
3848
3849 if (host->curr.data) {
3850 if (msmsdcc_check_dma_op_req(host->curr.data))
3851 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
3852 else if (host->is_dma_mode)
3853 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
3854 mmc_hostname(host->mmc), host->dma.busy,
3855 host->dma.channel, host->dma.crci);
3856 else if (host->is_sps_mode)
3857 pr_info("%s: SPS mode: busy=%d\n",
3858 mmc_hostname(host->mmc), host->sps.busy);
3859
3860 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
3861 mmc_hostname(host->mmc), host->curr.xfer_size,
3862 host->curr.data_xfered, host->curr.xfer_remain);
3863 pr_info("%s: got_dataend=%d, prog_enable=%d,"
3864 " wait_for_auto_prog_done=%d,"
3865 " got_auto_prog_done=%d\n",
3866 mmc_hostname(host->mmc), host->curr.got_dataend,
3867 host->prog_enable, host->curr.wait_for_auto_prog_done,
3868 host->curr.got_auto_prog_done);
3869 }
3870
3871}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003872static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
3873{
3874 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3875 struct mmc_request *mrq;
3876 unsigned long flags;
3877
3878 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003879 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003880 pr_info("%s: %s: dummy CMD52 timeout\n",
3881 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003882 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003883 }
3884
3885 mrq = host->curr.mrq;
3886
3887 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303888 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
3889 mrq->cmd->opcode);
3890 msmsdcc_dump_sdcc_state(host);
3891
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003892 if (!mrq->cmd->error)
3893 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303894 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003895 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003896 if (mrq->data && !mrq->data->error)
3897 mrq->data->error = -ETIMEDOUT;
3898 host->curr.data_xfered = 0;
3899 if (host->dma.sg && host->is_dma_mode) {
3900 msm_dmov_stop_cmd(host->dma.channel,
3901 &host->dma.hdr, 0);
3902 } else if (host->sps.sg && host->is_sps_mode) {
3903 /* Stop current SPS transfer */
3904 msmsdcc_sps_exit_curr_xfer(host);
3905 } else {
3906 msmsdcc_reset_and_restore(host);
3907 msmsdcc_stop_data(host);
3908 if (mrq->data && mrq->data->stop)
3909 msmsdcc_start_command(host,
3910 mrq->data->stop, 0);
3911 else
3912 msmsdcc_request_end(host, mrq);
3913 }
3914 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05303915 host->prog_enable = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003916 msmsdcc_reset_and_restore(host);
3917 msmsdcc_request_end(host, mrq);
3918 }
3919 }
3920 spin_unlock_irqrestore(&host->lock, flags);
3921}
3922
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303923static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
3924{
3925 int i, ret;
3926 struct mmc_platform_data *pdata;
3927 struct device_node *np = dev->of_node;
3928 u32 bus_width = 0;
3929 u32 *clk_table;
3930 int clk_table_len;
3931 u32 *sup_voltages;
3932 int sup_volt_len;
3933
3934 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
3935 if (!pdata) {
3936 dev_err(dev, "could not allocate memory for platform data\n");
3937 goto err;
3938 }
3939
3940 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
3941 if (bus_width == 8) {
3942 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
3943 } else if (bus_width == 4) {
3944 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
3945 } else {
3946 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
3947 pdata->mmc_bus_width = 0;
3948 }
3949
3950 if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
3951 size_t sz;
3952 sz = sup_volt_len / sizeof(*sup_voltages);
3953 if (sz > 0) {
3954 sup_voltages = devm_kzalloc(dev,
3955 sz * sizeof(*sup_voltages), GFP_KERNEL);
3956 if (!sup_voltages) {
3957 dev_err(dev, "No memory for supported voltage\n");
3958 goto err;
3959 }
3960
3961 ret = of_property_read_u32_array(np,
3962 "qcom,sdcc-sup-voltages", sup_voltages, sz);
3963 if (ret < 0) {
3964 dev_err(dev, "error while reading voltage"
3965 "ranges %d\n", ret);
3966 goto err;
3967 }
3968 } else {
3969 dev_err(dev, "No supported voltages\n");
3970 goto err;
3971 }
3972 for (i = 0; i < sz; i += 2) {
3973 u32 mask;
3974
3975 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
3976 sup_voltages[i + 1]);
3977 if (!mask)
3978 dev_err(dev, "Invalide voltage range %d\n", i);
3979 pdata->ocr_mask |= mask;
3980 }
3981 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
3982 } else {
3983 dev_err(dev, "Supported voltage range not specified\n");
3984 }
3985
3986 if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
3987 size_t sz;
3988 sz = clk_table_len / sizeof(*clk_table);
3989
3990 if (sz > 0) {
3991 clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
3992 GFP_KERNEL);
3993 if (!clk_table) {
3994 dev_err(dev, "No memory for clock table\n");
3995 goto err;
3996 }
3997
3998 ret = of_property_read_u32_array(np,
3999 "qcom,sdcc-clk-rates", clk_table, sz);
4000 if (ret < 0) {
4001 dev_err(dev, "error while reading clk"
4002 "table %d\n", ret);
4003 goto err;
4004 }
4005 } else {
4006 dev_err(dev, "clk_table not specified\n");
4007 goto err;
4008 }
4009 pdata->sup_clk_table = clk_table;
4010 pdata->sup_clk_cnt = sz;
4011 } else {
4012 dev_err(dev, "Supported clock rates not specified\n");
4013 }
4014
4015 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
4016 pdata->nonremovable = true;
4017 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
4018 pdata->disable_cmd23 = true;
4019
4020 return pdata;
4021err:
4022 return NULL;
4023}
4024
San Mehat9d2bd732009-09-22 16:44:22 -07004025static int
4026msmsdcc_probe(struct platform_device *pdev)
4027{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304028 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07004029 struct msmsdcc_host *host;
4030 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004031 unsigned long flags;
4032 struct resource *core_irqres = NULL;
4033 struct resource *bam_irqres = NULL;
4034 struct resource *core_memres = NULL;
4035 struct resource *dml_memres = NULL;
4036 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07004037 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07004038 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05304039 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004040 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07004041
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304042 if (pdev->dev.of_node) {
4043 plat = msmsdcc_populate_pdata(&pdev->dev);
4044 of_property_read_u32((&pdev->dev)->of_node,
4045 "cell-index", &pdev->id);
4046 } else {
4047 plat = pdev->dev.platform_data;
4048 }
4049
San Mehat9d2bd732009-09-22 16:44:22 -07004050 /* must have platform data */
4051 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004052 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004053 ret = -EINVAL;
4054 goto out;
4055 }
4056
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004057 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07004058 return -EINVAL;
4059
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304060 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
4061 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
4062 return -EINVAL;
4063 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004064
San Mehat9d2bd732009-09-22 16:44:22 -07004065 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004066 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004067 return -ENXIO;
4068 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304069 if (pdev->dev.of_node) {
4070 /*
4071 * Device tree iomem resources are only accessible by index.
4072 * index = 0 -> SDCC register interface
4073 * index = 1 -> DML register interface
4074 * index = 2 -> BAM register interface
4075 * IRQ resources:
4076 * index = 0 -> SDCC IRQ
4077 * index = 1 -> BAM IRQ
4078 */
4079 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
4080 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
4081 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
4082 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
4083 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
4084 } else {
4085 for (i = 0; i < pdev->num_resources; i++) {
4086 if (pdev->resource[i].flags & IORESOURCE_MEM) {
4087 if (!strncmp(pdev->resource[i].name,
4088 "sdcc_dml_addr",
4089 sizeof("sdcc_dml_addr")))
4090 dml_memres = &pdev->resource[i];
4091 else if (!strncmp(pdev->resource[i].name,
4092 "sdcc_bam_addr",
4093 sizeof("sdcc_bam_addr")))
4094 bam_memres = &pdev->resource[i];
4095 else
4096 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07004097
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304098 }
4099 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
4100 if (!strncmp(pdev->resource[i].name,
4101 "sdcc_bam_irq",
4102 sizeof("sdcc_bam_irq")))
4103 bam_irqres = &pdev->resource[i];
4104 else
4105 core_irqres = &pdev->resource[i];
4106 }
4107 if (pdev->resource[i].flags & IORESOURCE_DMA) {
4108 if (!strncmp(pdev->resource[i].name,
4109 "sdcc_dma_chnl",
4110 sizeof("sdcc_dma_chnl")))
4111 dmares = &pdev->resource[i];
4112 else if (!strncmp(pdev->resource[i].name,
4113 "sdcc_dma_crci",
4114 sizeof("sdcc_dma_crci")))
4115 dma_crci_res = &pdev->resource[i];
4116 }
Krishna Konda25786ec2011-07-25 16:21:36 -07004117 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004118 }
4119
4120 if (!core_irqres || !core_memres) {
4121 pr_err("%s: Invalid sdcc core resource\n", __func__);
4122 return -ENXIO;
4123 }
4124
4125 /*
4126 * Both BAM and DML memory resource should be preset.
4127 * BAM IRQ resource should also be present.
4128 */
4129 if ((bam_memres && !dml_memres) ||
4130 (!bam_memres && dml_memres) ||
4131 ((bam_memres && dml_memres) && !bam_irqres)) {
4132 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004133 return -ENXIO;
4134 }
4135
4136 /*
4137 * Setup our host structure
4138 */
San Mehat9d2bd732009-09-22 16:44:22 -07004139 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
4140 if (!mmc) {
4141 ret = -ENOMEM;
4142 goto out;
4143 }
4144
4145 host = mmc_priv(mmc);
4146 host->pdev_id = pdev->id;
4147 host->plat = plat;
4148 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08004149 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05304150
4151 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004152 host->is_sps_mode = 1;
4153 else if (dmares)
4154 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07004155
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004156 host->base = ioremap(core_memres->start,
4157 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07004158 if (!host->base) {
4159 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004160 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004161 }
4162
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004163 host->core_irqres = core_irqres;
4164 host->bam_irqres = bam_irqres;
4165 host->core_memres = core_memres;
4166 host->dml_memres = dml_memres;
4167 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07004168 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07004169 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07004170 spin_lock_init(&host->lock);
4171
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004172#ifdef CONFIG_MMC_EMBEDDED_SDIO
4173 if (plat->embedded_sdio)
4174 mmc_set_embedded_sdio_data(mmc,
4175 &plat->embedded_sdio->cis,
4176 &plat->embedded_sdio->cccr,
4177 plat->embedded_sdio->funcs,
4178 plat->embedded_sdio->num_funcs);
4179#endif
4180
Sahitya Tummala62612cf2010-12-08 15:03:03 +05304181 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
4182 (unsigned long)host);
4183
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004184 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
4185 (unsigned long)host);
4186 if (host->is_dma_mode) {
4187 /* Setup DMA */
4188 ret = msmsdcc_init_dma(host);
4189 if (ret)
4190 goto ioremap_free;
4191 } else {
4192 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004193 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004194 }
4195
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004196 /*
4197 * Setup SDCC clock if derived from Dayatona
4198 * fabric core clock.
4199 */
4200 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07004201 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004202 if (!IS_ERR(host->dfab_pclk)) {
4203 /* Set the clock rate to 64MHz for max. performance */
4204 ret = clk_set_rate(host->dfab_pclk, 64000000);
4205 if (ret)
4206 goto dfab_pclk_put;
4207 ret = clk_enable(host->dfab_pclk);
4208 if (ret)
4209 goto dfab_pclk_put;
4210 } else
4211 goto dma_free;
4212 }
4213
4214 /*
4215 * Setup main peripheral bus clock
4216 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004217 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004218 if (!IS_ERR(host->pclk)) {
4219 ret = clk_enable(host->pclk);
4220 if (ret)
4221 goto pclk_put;
4222
4223 host->pclk_rate = clk_get_rate(host->pclk);
4224 }
4225
4226 /*
4227 * Setup SDC MMC clock
4228 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004229 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07004230 if (IS_ERR(host->clk)) {
4231 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004232 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07004233 }
4234
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004235 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
4236 if (ret) {
4237 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
4238 goto clk_put;
4239 }
4240
4241 ret = clk_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004242 if (ret)
4243 goto clk_put;
4244
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004245 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304246 if (!host->clk_rate)
4247 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304248
4249 /*
4250 * Lookup the Controller Version, to identify the supported features
4251 * Version number read as 0 would indicate SDCC3 or earlier versions
4252 */
4253 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
4254 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
4255 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304256 /*
4257 * Set the register write delay according to min. clock frequency
4258 * supported and update later when the host->clk_rate changes.
4259 */
4260 host->reg_write_delay =
4261 (1 + ((3 * USEC_PER_SEC) /
4262 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004263
4264 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05304265 /* Apply Hard reset to SDCC to put it in power on default state */
4266 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004267
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304268 /* pm qos request to prevent apps idle power collapse */
4269 if (host->plat->swfi_latency)
4270 pm_qos_add_request(&host->pm_qos_req_dma,
4271 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
4272
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004273 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07004274 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004275 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07004276 goto clk_disable;
4277 }
4278
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004279
4280 /* Clocks has to be running before accessing SPS/DML HW blocks */
4281 if (host->is_sps_mode) {
4282 /* Initialize SPS */
4283 ret = msmsdcc_sps_init(host);
4284 if (ret)
4285 goto vreg_deinit;
4286 /* Initialize DML */
4287 ret = msmsdcc_dml_init(host);
4288 if (ret)
4289 goto sps_exit;
4290 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05304291 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07004292
San Mehat9d2bd732009-09-22 16:44:22 -07004293 /*
4294 * Setup MMC host structure
4295 */
4296 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004297 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
4298 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004299 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004300 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
4301 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07004302
San Mehat9d2bd732009-09-22 16:44:22 -07004303 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304304 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304305
4306 /*
4307 * If we send the CMD23 before multi block write/read command
4308 * then we need not to send CMD12 at the end of the transfer.
4309 * If we don't send the CMD12 then only way to detect the PROG_DONE
4310 * status is to use the AUTO_PROG_DONE status provided by SDCC4
4311 * controller. So let's enable the CMD23 for SDCC4 only.
4312 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304313 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304314 mmc->caps |= MMC_CAP_CMD23;
4315
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004316 mmc->caps |= plat->uhs_caps;
4317 /*
4318 * XPC controls the maximum current in the default speed mode of SDXC
4319 * card. XPC=0 means 100mA (max.) but speed class is not supported.
4320 * XPC=1 means 150mA (max.) and speed class is supported.
4321 */
4322 if (plat->xpc_cap)
4323 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
4324 MMC_CAP_SET_XPC_180);
4325
4326 if (plat->nonremovable)
4327 mmc->caps |= MMC_CAP_NONREMOVABLE;
4328#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
4329 mmc->caps |= MMC_CAP_SDIO_IRQ;
4330#endif
4331
4332 if (plat->is_sdio_al_client)
4333 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07004334
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304335 mmc->max_segs = msmsdcc_get_nr_sg(host);
4336 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
4337 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07004338
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304339 mmc->max_req_size = MMC_MAX_REQ_SIZE;
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +05304340 mmc->max_seg_size = mmc->max_req_size;
San Mehat9d2bd732009-09-22 16:44:22 -07004341
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004342 writel_relaxed(0, host->base + MMCIMASK0);
4343 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -07004344
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004345 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
4346 mb();
4347 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07004348
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004349 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
4350 DRIVER_NAME " (cmd)", host);
4351 if (ret)
4352 goto dml_exit;
4353
4354 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
4355 DRIVER_NAME " (pio)", host);
4356 if (ret)
4357 goto irq_free;
4358
4359 /*
4360 * Enable SDCC IRQ only when host is powered on. Otherwise, this
4361 * IRQ is un-necessarily being monitored by MPM (Modem power
4362 * management block) during idle-power collapse. The MPM will be
4363 * configured to monitor the DATA1 GPIO line with level-low trigger
4364 * and thus depending on the GPIO status, it prevents TCXO shutdown
4365 * during idle-power collapse.
4366 */
4367 disable_irq(core_irqres->start);
4368 host->sdcc_irq_disabled = 1;
4369
4370 if (plat->sdiowakeup_irq) {
4371 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4372 mmc_hostname(mmc));
4373 ret = request_irq(plat->sdiowakeup_irq,
4374 msmsdcc_platform_sdiowakeup_irq,
4375 IRQF_SHARED | IRQF_TRIGGER_LOW,
4376 DRIVER_NAME "sdiowakeup", host);
4377 if (ret) {
4378 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
4379 plat->sdiowakeup_irq, ret);
4380 goto pio_irq_free;
4381 } else {
4382 spin_lock_irqsave(&host->lock, flags);
4383 if (!host->sdio_irq_disabled) {
4384 disable_irq_nosync(plat->sdiowakeup_irq);
4385 host->sdio_irq_disabled = 1;
4386 }
4387 spin_unlock_irqrestore(&host->lock, flags);
4388 }
4389 }
4390
4391 if (plat->cfg_mpm_sdiowakeup) {
4392 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4393 mmc_hostname(mmc));
4394 }
4395
4396 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
4397 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004398 /*
4399 * Setup card detect change
4400 */
4401
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004402 if (plat->status || plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08004403 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004404 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08004405 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004406 host->oldstat = msmsdcc_slot_status(host);
Krishna Konda360aa422011-12-06 18:27:41 -08004407
Krishna Konda941604a2012-01-10 17:46:34 -08004408 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004409 }
San Mehat9d2bd732009-09-22 16:44:22 -07004410
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004411 if (plat->status_irq) {
4412 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07004413 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004414 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07004415 DRIVER_NAME " (slot)",
4416 host);
4417 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004418 pr_err("Unable to get slot IRQ %d (%d)\n",
4419 plat->status_irq, ret);
4420 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004421 }
4422 } else if (plat->register_status_notify) {
4423 plat->register_status_notify(msmsdcc_status_notify_cb, host);
4424 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004425 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07004426 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004427
4428 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004429
4430 ret = pm_runtime_set_active(&(pdev)->dev);
4431 if (ret < 0)
4432 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
4433 __func__, ret);
4434 /*
4435 * There is no notion of suspend/resume for SD/MMC/SDIO
4436 * cards. So host can be suspended/resumed with out
4437 * worrying about its children.
4438 */
4439 pm_suspend_ignore_children(&(pdev)->dev, true);
4440
4441 /*
4442 * MMC/SD/SDIO bus suspend/resume operations are defined
4443 * only for the slots that will be used for non-removable
4444 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
4445 * defined. Otherwise, they simply become card removal and
4446 * insertion events during suspend and resume respectively.
4447 * Hence, enable run-time PM only for slots for which bus
4448 * suspend/resume operations are defined.
4449 */
4450#ifdef CONFIG_MMC_UNSAFE_RESUME
4451 /*
4452 * If this capability is set, MMC core will enable/disable host
4453 * for every claim/release operation on a host. We use this
4454 * notification to increment/decrement runtime pm usage count.
4455 */
4456 mmc->caps |= MMC_CAP_DISABLE;
4457 pm_runtime_enable(&(pdev)->dev);
4458#else
4459 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
4460 mmc->caps |= MMC_CAP_DISABLE;
4461 pm_runtime_enable(&(pdev)->dev);
4462 }
4463#endif
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05304464#ifndef CONFIG_PM_RUNTIME
4465 mmc_set_disable_delay(mmc, MSM_MMC_DISABLE_TIMEOUT);
4466#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004467 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
4468 (unsigned long)host);
4469
San Mehat9d2bd732009-09-22 16:44:22 -07004470 mmc_add_host(mmc);
4471
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004472#ifdef CONFIG_HAS_EARLYSUSPEND
4473 host->early_suspend.suspend = msmsdcc_early_suspend;
4474 host->early_suspend.resume = msmsdcc_late_resume;
4475 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
4476 register_early_suspend(&host->early_suspend);
4477#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004478
Krishna Konda25786ec2011-07-25 16:21:36 -07004479 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
4480 " dmacrcri %d\n", mmc_hostname(mmc),
4481 (unsigned long long)core_memres->start,
4482 (unsigned int) core_irqres->start,
4483 (unsigned int) plat->status_irq, host->dma.channel,
4484 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004485
4486 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
4487 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
4488 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
4489 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
4490 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
4491 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
4492 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
4493 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
4494 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
4495 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
4496 host->eject);
4497 pr_info("%s: Power save feature enable = %d\n",
4498 mmc_hostname(mmc), msmsdcc_pwrsave);
4499
Krishna Konda25786ec2011-07-25 16:21:36 -07004500 if (host->is_dma_mode && host->dma.channel != -1
4501 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004502 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004503 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004504 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004505 mmc_hostname(mmc), host->dma.cmd_busaddr,
4506 host->dma.cmdptr_busaddr);
4507 } else if (host->is_sps_mode) {
4508 pr_info("%s: SPS-BAM data transfer mode available\n",
4509 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004510 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004511 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004512
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004513#if defined(CONFIG_DEBUG_FS)
4514 msmsdcc_dbg_createhost(host);
4515#endif
4516 if (!plat->status_irq) {
4517 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
4518 if (ret)
4519 goto platform_irq_free;
4520 }
San Mehat9d2bd732009-09-22 16:44:22 -07004521 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004522
4523 platform_irq_free:
4524 del_timer_sync(&host->req_tout_timer);
4525 pm_runtime_disable(&(pdev)->dev);
4526 pm_runtime_set_suspended(&(pdev)->dev);
4527
4528 if (plat->status_irq)
4529 free_irq(plat->status_irq, host);
4530 sdiowakeup_irq_free:
4531 wake_lock_destroy(&host->sdio_suspend_wlock);
4532 if (plat->sdiowakeup_irq)
4533 free_irq(plat->sdiowakeup_irq, host);
4534 pio_irq_free:
4535 if (plat->sdiowakeup_irq)
4536 wake_lock_destroy(&host->sdio_wlock);
4537 free_irq(core_irqres->start, host);
4538 irq_free:
4539 free_irq(core_irqres->start, host);
4540 dml_exit:
4541 if (host->is_sps_mode)
4542 msmsdcc_dml_exit(host);
4543 sps_exit:
4544 if (host->is_sps_mode)
4545 msmsdcc_sps_exit(host);
4546 vreg_deinit:
4547 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07004548 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004549 clk_disable(host->clk);
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304550 if (host->plat->swfi_latency)
4551 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07004552 clk_put:
4553 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004554 pclk_disable:
4555 if (!IS_ERR(host->pclk))
4556 clk_disable(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07004557 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004558 if (!IS_ERR(host->pclk))
4559 clk_put(host->pclk);
4560 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4561 clk_disable(host->dfab_pclk);
4562 dfab_pclk_put:
4563 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4564 clk_put(host->dfab_pclk);
4565 dma_free:
4566 if (host->is_dma_mode) {
4567 if (host->dmares)
4568 dma_free_coherent(NULL,
4569 sizeof(struct msmsdcc_nc_dmadata),
4570 host->dma.nc, host->dma.nc_busaddr);
4571 }
4572 ioremap_free:
4573 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07004574 host_free:
4575 mmc_free_host(mmc);
4576 out:
4577 return ret;
4578}
4579
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004580static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07004581{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004582 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4583 struct mmc_platform_data *plat;
4584 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004585
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004586 if (!mmc)
4587 return -ENXIO;
4588
4589 if (pm_runtime_suspended(&(pdev)->dev))
4590 pm_runtime_resume(&(pdev)->dev);
4591
4592 host = mmc_priv(mmc);
4593
4594 DBG(host, "Removing SDCC device = %d\n", pdev->id);
4595 plat = host->plat;
4596
4597 if (!plat->status_irq)
4598 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
4599
4600 del_timer_sync(&host->req_tout_timer);
4601 tasklet_kill(&host->dma_tlet);
4602 tasklet_kill(&host->sps.tlet);
4603 mmc_remove_host(mmc);
4604
4605 if (plat->status_irq)
4606 free_irq(plat->status_irq, host);
4607
4608 wake_lock_destroy(&host->sdio_suspend_wlock);
4609 if (plat->sdiowakeup_irq) {
4610 wake_lock_destroy(&host->sdio_wlock);
4611 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
4612 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07004613 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004614
4615 free_irq(host->core_irqres->start, host);
4616 free_irq(host->core_irqres->start, host);
4617
4618 clk_put(host->clk);
4619 if (!IS_ERR(host->pclk))
4620 clk_put(host->pclk);
4621 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4622 clk_put(host->dfab_pclk);
4623
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304624 if (host->plat->swfi_latency)
4625 pm_qos_remove_request(&host->pm_qos_req_dma);
4626
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004627 msmsdcc_vreg_init(host, false);
4628
4629 if (host->is_dma_mode) {
4630 if (host->dmares)
4631 dma_free_coherent(NULL,
4632 sizeof(struct msmsdcc_nc_dmadata),
4633 host->dma.nc, host->dma.nc_busaddr);
4634 }
4635
4636 if (host->is_sps_mode) {
4637 msmsdcc_dml_exit(host);
4638 msmsdcc_sps_exit(host);
4639 }
4640
4641 iounmap(host->base);
4642 mmc_free_host(mmc);
4643
4644#ifdef CONFIG_HAS_EARLYSUSPEND
4645 unregister_early_suspend(&host->early_suspend);
4646#endif
4647 pm_runtime_disable(&(pdev)->dev);
4648 pm_runtime_set_suspended(&(pdev)->dev);
4649
4650 return 0;
4651}
4652
4653#ifdef CONFIG_MSM_SDIO_AL
4654int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4655{
4656 struct msmsdcc_host *host = mmc_priv(mmc);
4657 unsigned long flags;
4658
4659 spin_lock_irqsave(&host->lock, flags);
4660 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
4661 enable ? "En" : "Dis");
4662
4663 if (enable) {
4664 if (!host->sdcc_irq_disabled) {
4665 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05304666 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004667 host->sdcc_irq_disabled = 1;
4668 }
4669
4670 if (host->clks_on) {
4671 msmsdcc_setup_clocks(host, false);
4672 host->clks_on = 0;
4673 }
4674
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304675 if (host->plat->sdio_lpm_gpio_setup &&
4676 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004677 spin_unlock_irqrestore(&host->lock, flags);
4678 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
4679 spin_lock_irqsave(&host->lock, flags);
4680 host->sdio_gpio_lpm = 1;
4681 }
4682
4683 if (host->sdio_irq_disabled) {
4684 msmsdcc_enable_irq_wake(host);
4685 enable_irq(host->plat->sdiowakeup_irq);
4686 host->sdio_irq_disabled = 0;
4687 }
4688 } else {
4689 if (!host->sdio_irq_disabled) {
4690 disable_irq_nosync(host->plat->sdiowakeup_irq);
4691 host->sdio_irq_disabled = 1;
4692 msmsdcc_disable_irq_wake(host);
4693 }
4694
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304695 if (host->plat->sdio_lpm_gpio_setup &&
4696 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004697 spin_unlock_irqrestore(&host->lock, flags);
4698 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
4699 spin_lock_irqsave(&host->lock, flags);
4700 host->sdio_gpio_lpm = 0;
4701 }
4702
4703 if (!host->clks_on) {
4704 msmsdcc_setup_clocks(host, true);
4705 host->clks_on = 1;
4706 }
4707
4708 if (host->sdcc_irq_disabled) {
4709 writel_relaxed(host->mci_irqenable,
4710 host->base + MMCIMASK0);
4711 mb();
4712 enable_irq(host->core_irqres->start);
4713 host->sdcc_irq_disabled = 0;
4714 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004715 }
4716 spin_unlock_irqrestore(&host->lock, flags);
4717 return 0;
4718}
4719#else
4720int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4721{
4722 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004723}
4724#endif
4725
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004726#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07004727static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004728msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004729{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004730 struct mmc_host *mmc = dev_get_drvdata(dev);
4731 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07004732 int rc = 0;
4733
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004734 if (host->plat->is_sdio_al_client)
4735 return 0;
Sahitya Tummala7661a452011-07-18 13:28:35 +05304736 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004737 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004738 host->sdcc_suspending = 1;
4739 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07004740
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004741 /*
4742 * If the clocks are already turned off by SDIO clients (as
4743 * part of LPM), then clocks should be turned on before
4744 * calling mmc_suspend_host() because mmc_suspend_host might
4745 * send some commands to the card. The clocks will be turned
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304746 * off again after mmc_suspend_host. Thus for SDIO
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004747 * cards, clocks will be turned on before mmc_suspend_host
4748 * and turned off after mmc_suspend_host.
4749 */
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304750 if (mmc->card && mmc_card_sdio(mmc->card)) {
4751 mmc->ios.clock = host->clk_rate;
4752 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4753 }
San Mehat9d2bd732009-09-22 16:44:22 -07004754
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004755 /*
4756 * MMC core thinks that host is disabled by now since
4757 * runtime suspend is scheduled after msmsdcc_disable()
4758 * is called. Thus, MMC core will try to enable the host
4759 * while suspending it. This results in a synchronous
4760 * runtime resume request while in runtime suspending
4761 * context and hence inorder to complete this resume
4762 * requet, it will wait for suspend to be complete,
4763 * but runtime suspend also can not proceed further
4764 * until the host is resumed. Thus, it leads to a hang.
4765 * Hence, increase the pm usage count before suspending
4766 * the host so that any resume requests after this will
4767 * simple become pm usage counter increment operations.
4768 */
4769 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05304770 /* If there is pending detect work abort runtime suspend */
4771 if (unlikely(work_busy(&mmc->detect.work)))
4772 rc = -EAGAIN;
4773 else
4774 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004775 pm_runtime_put_noidle(dev);
4776
4777 if (!rc) {
4778 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
4779 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ)) {
4780 disable_irq(host->core_irqres->start);
4781 host->sdcc_irq_disabled = 1;
4782
4783 /*
4784 * If MMC core level suspend is not supported,
4785 * turn off clocks to allow deep sleep (TCXO
4786 * shutdown).
4787 */
4788 mmc->ios.clock = 0;
4789 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4790 enable_irq(host->core_irqres->start);
4791 host->sdcc_irq_disabled = 0;
4792
4793 if (host->plat->sdiowakeup_irq) {
4794 host->sdio_irq_disabled = 0;
4795 msmsdcc_enable_irq_wake(host);
4796 enable_irq(host->plat->sdiowakeup_irq);
4797 }
4798 }
4799 }
4800 host->sdcc_suspending = 0;
4801 mmc->suspend_task = NULL;
4802 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
4803 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004804 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05304805 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
San Mehat9d2bd732009-09-22 16:44:22 -07004806 return rc;
4807}
4808
4809static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004810msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004811{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004812 struct mmc_host *mmc = dev_get_drvdata(dev);
4813 struct msmsdcc_host *host = mmc_priv(mmc);
4814 unsigned long flags;
4815
4816 if (host->plat->is_sdio_al_client)
4817 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07004818
Sahitya Tummala7661a452011-07-18 13:28:35 +05304819 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004820 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004821 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
4822 if (host->sdcc_irq_disabled) {
4823 enable_irq(host->core_irqres->start);
4824 host->sdcc_irq_disabled = 0;
4825 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304826 mmc->ios.clock = host->clk_rate;
4827 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07004828
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304829 spin_lock_irqsave(&host->lock, flags);
4830 writel_relaxed(host->mci_irqenable,
4831 host->base + MMCIMASK0);
4832 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07004833
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304834 if ((mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) &&
4835 !host->sdio_irq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004836 if (host->plat->sdiowakeup_irq) {
4837 disable_irq_nosync(
4838 host->plat->sdiowakeup_irq);
4839 msmsdcc_disable_irq_wake(host);
4840 host->sdio_irq_disabled = 1;
4841 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304842 }
San Mehat9d2bd732009-09-22 16:44:22 -07004843
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304844 spin_unlock_irqrestore(&host->lock, flags);
4845 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004846
4847 mmc_resume_host(mmc);
4848
4849 /*
4850 * FIXME: Clearing of flags must be handled in clients
4851 * resume handler.
4852 */
4853 spin_lock_irqsave(&host->lock, flags);
4854 mmc->pm_flags = 0;
4855 spin_unlock_irqrestore(&host->lock, flags);
4856
4857 /*
4858 * After resuming the host wait for sometime so that
4859 * the SDIO work will be processed.
4860 */
4861 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO)) {
4862 if ((host->plat->cfg_mpm_sdiowakeup ||
4863 host->plat->sdiowakeup_irq) &&
4864 wake_lock_active(&host->sdio_wlock))
4865 wake_lock_timeout(&host->sdio_wlock, 1);
4866 }
4867
4868 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004869 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304870 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004871 return 0;
4872}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004873
4874static int msmsdcc_runtime_idle(struct device *dev)
4875{
4876 struct mmc_host *mmc = dev_get_drvdata(dev);
4877 struct msmsdcc_host *host = mmc_priv(mmc);
4878
4879 if (host->plat->is_sdio_al_client)
4880 return 0;
4881
4882 /* Idle timeout is not configurable for now */
4883 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
4884
4885 return -EAGAIN;
4886}
4887
4888static int msmsdcc_pm_suspend(struct device *dev)
4889{
4890 struct mmc_host *mmc = dev_get_drvdata(dev);
4891 struct msmsdcc_host *host = mmc_priv(mmc);
4892 int rc = 0;
4893
4894 if (host->plat->is_sdio_al_client)
4895 return 0;
4896
4897
4898 if (host->plat->status_irq)
4899 disable_irq(host->plat->status_irq);
4900
4901 if (!pm_runtime_suspended(dev))
4902 rc = msmsdcc_runtime_suspend(dev);
4903
4904 return rc;
4905}
4906
4907static int msmsdcc_pm_resume(struct device *dev)
4908{
4909 struct mmc_host *mmc = dev_get_drvdata(dev);
4910 struct msmsdcc_host *host = mmc_priv(mmc);
4911 int rc = 0;
4912
4913 if (host->plat->is_sdio_al_client)
4914 return 0;
4915
Sahitya Tummalafb486372011-09-02 19:01:49 +05304916 if (!pm_runtime_suspended(dev))
4917 rc = msmsdcc_runtime_resume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004918 if (host->plat->status_irq) {
4919 msmsdcc_check_status((unsigned long)host);
4920 enable_irq(host->plat->status_irq);
4921 }
4922
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004923 return rc;
4924}
4925
Daniel Walker08ecfde2010-06-23 12:32:20 -07004926#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004927#define msmsdcc_runtime_suspend NULL
4928#define msmsdcc_runtime_resume NULL
4929#define msmsdcc_runtime_idle NULL
4930#define msmsdcc_pm_suspend NULL
4931#define msmsdcc_pm_resume NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07004932#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004933
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004934static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
4935 .runtime_suspend = msmsdcc_runtime_suspend,
4936 .runtime_resume = msmsdcc_runtime_resume,
4937 .runtime_idle = msmsdcc_runtime_idle,
4938 .suspend = msmsdcc_pm_suspend,
4939 .resume = msmsdcc_pm_resume,
4940};
4941
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304942static const struct of_device_id msmsdcc_dt_match[] = {
4943 {.compatible = "qcom,msm-sdcc"},
4944
4945};
4946MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
4947
San Mehat9d2bd732009-09-22 16:44:22 -07004948static struct platform_driver msmsdcc_driver = {
4949 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004950 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07004951 .driver = {
4952 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004953 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304954 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07004955 },
4956};
4957
4958static int __init msmsdcc_init(void)
4959{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004960#if defined(CONFIG_DEBUG_FS)
4961 int ret = 0;
4962 ret = msmsdcc_dbg_init();
4963 if (ret) {
4964 pr_err("Failed to create debug fs dir \n");
4965 return ret;
4966 }
4967#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004968 return platform_driver_register(&msmsdcc_driver);
4969}
4970
4971static void __exit msmsdcc_exit(void)
4972{
4973 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004974
4975#if defined(CONFIG_DEBUG_FS)
4976 debugfs_remove(debugfs_file);
4977 debugfs_remove(debugfs_dir);
4978#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004979}
4980
4981module_init(msmsdcc_init);
4982module_exit(msmsdcc_exit);
4983
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004984MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07004985MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004986
4987#if defined(CONFIG_DEBUG_FS)
4988
4989static int
4990msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
4991{
4992 file->private_data = inode->i_private;
4993 return 0;
4994}
4995
4996static ssize_t
4997msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
4998 size_t count, loff_t *ppos)
4999{
5000 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08005001 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005002 int max, i;
5003
5004 i = 0;
5005 max = sizeof(buf) - 1;
5006
5007 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
5008 host->curr.cmd, host->curr.data);
5009 if (host->curr.cmd) {
5010 struct mmc_command *cmd = host->curr.cmd;
5011
5012 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
5013 cmd->opcode, cmd->arg, cmd->flags);
5014 }
5015 if (host->curr.data) {
5016 struct mmc_data *data = host->curr.data;
5017 i += scnprintf(buf + i, max - i,
5018 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
5019 data->timeout_ns, data->timeout_clks,
5020 data->blksz, data->blocks, data->error,
5021 data->flags);
5022 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
5023 host->curr.xfer_size, host->curr.xfer_remain,
5024 host->curr.data_xfered, host->dma.sg);
5025 }
5026
5027 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
5028}
5029
5030static const struct file_operations msmsdcc_dbg_state_ops = {
5031 .read = msmsdcc_dbg_state_read,
5032 .open = msmsdcc_dbg_state_open,
5033};
5034
5035static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
5036{
5037 if (debugfs_dir) {
5038 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
5039 0644, debugfs_dir, host,
5040 &msmsdcc_dbg_state_ops);
5041 }
5042}
5043
5044static int __init msmsdcc_dbg_init(void)
5045{
5046 int err;
5047
5048 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
5049 if (IS_ERR(debugfs_dir)) {
5050 err = PTR_ERR(debugfs_dir);
5051 debugfs_dir = NULL;
5052 return err;
5053 }
5054
5055 return 0;
5056}
5057#endif