blob: 69921b1d6bbe7eb009de4f71e51171335bb6e0a3 [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);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -0800138static int msmsdcc_vreg_reset(struct msmsdcc_host *host);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530139
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530140static inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
141{
142 unsigned short ret = NR_SG;
143
144 if (host->is_sps_mode) {
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +0530145 ret = SPS_MAX_DESCS;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530146 } else { /* DMA or PIO mode */
147 if (NR_SG > MAX_NR_SG_DMA_PIO)
148 ret = MAX_NR_SG_DMA_PIO;
149 }
150
151 return ret;
152}
153
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530154/* Prevent idle power collapse(pc) while operating in peripheral mode */
155static void msmsdcc_pm_qos_update_latency(struct msmsdcc_host *host, int vote)
156{
157 u32 swfi_latency = 0;
158
159 if (!host->plat->swfi_latency)
160 return;
161
162 swfi_latency = host->plat->swfi_latency + 1;
163
164 if (vote)
165 pm_qos_update_request(&host->pm_qos_req_dma,
166 swfi_latency);
167 else
168 pm_qos_update_request(&host->pm_qos_req_dma,
169 PM_QOS_DEFAULT_VALUE);
170}
171
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700172#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
173static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
174 struct msmsdcc_sps_ep_conn_data *ep);
175static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
176 struct msmsdcc_sps_ep_conn_data *ep);
177#else
178static inline int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
179 struct msmsdcc_sps_ep_conn_data *ep,
180 bool is_producer) { return 0; }
181static inline void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
182 struct msmsdcc_sps_ep_conn_data *ep) { }
183static inline int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
184 struct msmsdcc_sps_ep_conn_data *ep)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530185{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700186 return 0;
187}
188static inline int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
189 struct msmsdcc_sps_ep_conn_data *ep)
190{
191 return 0;
192}
193static inline int msmsdcc_sps_init(struct msmsdcc_host *host) { return 0; }
194static inline void msmsdcc_sps_exit(struct msmsdcc_host *host) {}
195#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530196
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700197/**
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530198 * Apply soft reset to all SDCC BAM pipes
199 *
200 * This function applies soft reset to SDCC BAM pipe.
201 *
202 * This function should be called to recover from error
203 * conditions encountered during CMD/DATA tranfsers with card.
204 *
205 * @host - Pointer to driver's host structure
206 *
207 */
208static void msmsdcc_sps_pipes_reset_and_restore(struct msmsdcc_host *host)
209{
210 int rc;
211
212 /* Reset all SDCC BAM pipes */
213 rc = msmsdcc_sps_reset_ep(host, &host->sps.prod);
214 if (rc)
215 pr_err("%s:msmsdcc_sps_reset_ep(prod) error=%d\n",
216 mmc_hostname(host->mmc), rc);
217 rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
218 if (rc)
219 pr_err("%s:msmsdcc_sps_reset_ep(cons) error=%d\n",
220 mmc_hostname(host->mmc), rc);
221
222 /* Restore all BAM pipes connections */
223 rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
224 if (rc)
225 pr_err("%s:msmsdcc_sps_restore_ep(prod) error=%d\n",
226 mmc_hostname(host->mmc), rc);
227 rc = msmsdcc_sps_restore_ep(host, &host->sps.cons);
228 if (rc)
229 pr_err("%s:msmsdcc_sps_restore_ep(cons) error=%d\n",
230 mmc_hostname(host->mmc), rc);
231}
232
233/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700234 * Apply soft reset
235 *
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530236 * This function applies soft reset to SDCC core and DML core.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700237 *
238 * This function should be called to recover from error
239 * conditions encountered with CMD/DATA tranfsers with card.
240 *
241 * Soft reset should only be used with SDCC controller v4.
242 *
243 * @host - Pointer to driver's host structure
244 *
245 */
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530246static void msmsdcc_soft_reset(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700247{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700248 /*
249 * Reset SDCC controller's DPSM (data path state machine
250 * and CPSM (command path state machine).
251 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700252 writel_relaxed(0, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530253 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700254 writel_relaxed(0, host->base + MMCIDATACTRL);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530255 msmsdcc_delay(host);
256}
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530257
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530258static void msmsdcc_hard_reset(struct msmsdcc_host *host)
259{
260 int ret;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530261
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530262 /* Reset the controller */
263 ret = clk_reset(host->clk, CLK_RESET_ASSERT);
264 if (ret)
265 pr_err("%s: Clock assert failed at %u Hz"
266 " with err %d\n", mmc_hostname(host->mmc),
267 host->clk_rate, ret);
268
269 ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
270 if (ret)
271 pr_err("%s: Clock deassert failed at %u Hz"
272 " with err %d\n", mmc_hostname(host->mmc),
273 host->clk_rate, ret);
274
275 /* Give some delay for clock reset to propogate to controller */
276 msmsdcc_delay(host);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530277}
278
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700279static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
280{
Pratibhasagar V1c11da62011-11-14 12:36:35 +0530281 if (host->sdcc_version) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530282 if (host->is_sps_mode) {
283 /* Reset DML first */
284 msmsdcc_dml_reset(host);
285 /*
286 * delay the SPS pipe reset in thread context as
287 * sps_connect/sps_disconnect APIs can be called
288 * only from non-atomic context.
289 */
290 host->sps.pipe_reset_pending = true;
291 }
292 mb();
293 msmsdcc_soft_reset(host);
294
295 pr_debug("%s: Applied soft reset to Controller\n",
296 mmc_hostname(host->mmc));
297
298 if (host->is_sps_mode)
299 msmsdcc_dml_init(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700300 } else {
301 /* Give Clock reset (hard reset) to controller */
302 u32 mci_clk = 0;
303 u32 mci_mask0 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700304
305 /* Save the controller state */
306 mci_clk = readl_relaxed(host->base + MMCICLOCK);
307 mci_mask0 = readl_relaxed(host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700308 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700309
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530310 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700311 pr_debug("%s: Controller has been reinitialized\n",
312 mmc_hostname(host->mmc));
313
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700314 /* Restore the contoller state */
315 writel_relaxed(host->pwr, host->base + MMCIPOWER);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530316 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700317 writel_relaxed(mci_clk, host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530318 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700319 writel_relaxed(mci_mask0, host->base + MMCIMASK0);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530320 mb(); /* no delay required after writing to MASK0 register */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700321 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530322
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700323 if (host->dummy_52_needed)
324 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700325}
326
327static int
San Mehat9d2bd732009-09-22 16:44:22 -0700328msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
329{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700330 int retval = 0;
331
San Mehat9d2bd732009-09-22 16:44:22 -0700332 BUG_ON(host->curr.data);
333
334 host->curr.mrq = NULL;
335 host->curr.cmd = NULL;
336
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700337 del_timer(&host->req_tout_timer);
338
San Mehat9d2bd732009-09-22 16:44:22 -0700339 if (mrq->data)
340 mrq->data->bytes_xfered = host->curr.data_xfered;
341 if (mrq->cmd->error == -ETIMEDOUT)
342 mdelay(5);
343
344 /*
345 * Need to drop the host lock here; mmc_request_done may call
346 * back into the driver...
347 */
348 spin_unlock(&host->lock);
349 mmc_request_done(host->mmc, mrq);
350 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700351
352 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700353}
354
355static void
356msmsdcc_stop_data(struct msmsdcc_host *host)
357{
San Mehat9d2bd732009-09-22 16:44:22 -0700358 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530359 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530360 host->curr.wait_for_auto_prog_done = 0;
361 host->curr.got_auto_prog_done = 0;
Krishna Konda3f5d48f2011-07-27 10:47:31 -0700362 writel_relaxed(readl_relaxed(host->base + MMCIDATACTRL) &
363 (~(MCI_DPSM_ENABLE)), host->base + MMCIDATACTRL);
Krishna Konda3e5c4d02011-07-11 16:31:45 -0700364 msmsdcc_delay(host); /* Allow the DPSM to be reset */
San Mehat9d2bd732009-09-22 16:44:22 -0700365}
366
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700367static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700368{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700369 return host->core_memres->start + MMCIFIFO;
370}
371
372static inline unsigned int msmsdcc_get_min_sup_clk_rate(
373 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530374
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700375static inline void msmsdcc_delay(struct msmsdcc_host *host)
376{
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530377 ktime_t start, diff;
378
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700379 mb();
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +0530380 udelay(host->reg_write_delay);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530381
Pratibhasagar V1c11da62011-11-14 12:36:35 +0530382 if (host->sdcc_version &&
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530383 (readl_relaxed(host->base + MCI_STATUS2) &
384 MCI_MCLK_REG_WR_ACTIVE)) {
385 start = ktime_get();
386 while (readl_relaxed(host->base + MCI_STATUS2) &
387 MCI_MCLK_REG_WR_ACTIVE) {
388 diff = ktime_sub(ktime_get(), start);
389 /* poll for max. 1 ms */
390 if (ktime_to_us(diff) > 1000) {
391 pr_warning("%s: previous reg. write is"
392 " still active\n",
393 mmc_hostname(host->mmc));
394 break;
395 }
396 }
397 }
San Mehat9d2bd732009-09-22 16:44:22 -0700398}
399
San Mehat56a8b5b2009-11-21 12:29:46 -0800400static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700401msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
402{
403 writel_relaxed(arg, host->base + MMCIARGUMENT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700404 writel_relaxed(c, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530405 /*
406 * As after sending the command, we don't write any of the
407 * controller registers and just wait for the
408 * CMD_RESPOND_END/CMD_SENT/Command failure notication
409 * from Controller.
410 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700411 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800412}
413
414static void
415msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
416{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700417 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800418
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700419 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
420 writel_relaxed((unsigned int)host->curr.xfer_size,
421 host->base + MMCIDATALENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700422 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
423 msmsdcc_delay(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800424
San Mehat6ac9ea62009-12-02 17:24:58 -0800425 if (host->cmd_cmd) {
426 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700427 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800428 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800429}
430
San Mehat9d2bd732009-09-22 16:44:22 -0700431static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530432msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700433{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530434 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700435 unsigned long flags;
436 struct mmc_request *mrq;
437
438 spin_lock_irqsave(&host->lock, flags);
439 mrq = host->curr.mrq;
440 BUG_ON(!mrq);
441
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530442 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700443 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700444 goto out;
445 }
446
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530447 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700448 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700449 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700450 } else {
451 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530452 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700453 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530454 mmc_hostname(host->mmc), host->dma.result);
455 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700456 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530457 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530458 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700459 host->dma.err.flush[0], host->dma.err.flush[1],
460 host->dma.err.flush[2], host->dma.err.flush[3],
461 host->dma.err.flush[4],
462 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530463 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700464 if (!mrq->data->error)
465 mrq->data->error = -EIO;
466 }
San Mehat9d2bd732009-09-22 16:44:22 -0700467 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents,
468 host->dma.dir);
469
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700470 if (host->curr.user_pages) {
471 struct scatterlist *sg = host->dma.sg;
472 int i;
473
474 for (i = 0; i < host->dma.num_ents; i++, sg++)
475 flush_dcache_page(sg_page(sg));
476 }
477
San Mehat9d2bd732009-09-22 16:44:22 -0700478 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800479 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700480
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530481 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
482 (host->curr.wait_for_auto_prog_done &&
483 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700484 /*
485 * If we've already gotten our DATAEND / DATABLKEND
486 * for this request, then complete it through here.
487 */
San Mehat9d2bd732009-09-22 16:44:22 -0700488
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700489 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700490 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700491 host->curr.xfer_remain -= host->curr.xfer_size;
492 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700493 if (host->dummy_52_needed) {
494 mrq->data->bytes_xfered = host->curr.data_xfered;
495 host->dummy_52_sent = 1;
496 msmsdcc_start_command(host, &dummy52cmd,
497 MCI_CPSM_PROGENA);
498 goto out;
499 }
500 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530501 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530502 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700503 host->curr.mrq = NULL;
504 host->curr.cmd = NULL;
505 mrq->data->bytes_xfered = host->curr.data_xfered;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700506 del_timer(&host->req_tout_timer);
San Mehat9d2bd732009-09-22 16:44:22 -0700507 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700508
San Mehat9d2bd732009-09-22 16:44:22 -0700509 mmc_request_done(host->mmc, mrq);
510 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530511 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
512 || !mrq->sbc)) {
513 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530514 }
San Mehat9d2bd732009-09-22 16:44:22 -0700515 }
516
517out:
518 spin_unlock_irqrestore(&host->lock, flags);
519 return;
520}
521
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700522#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
523/**
524 * Callback notification from SPS driver
525 *
526 * This callback function gets triggered called from
527 * SPS driver when requested SPS data transfer is
528 * completed.
529 *
530 * SPS driver invokes this callback in BAM irq context so
531 * SDCC driver schedule a tasklet for further processing
532 * this callback notification at later point of time in
533 * tasklet context and immediately returns control back
534 * to SPS driver.
535 *
536 * @nofity - Pointer to sps event notify sturcture
537 *
538 */
539static void
540msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
541{
542 struct msmsdcc_host *host =
543 (struct msmsdcc_host *)
544 ((struct sps_event_notify *)notify)->user;
545
546 host->sps.notify = *notify;
547 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
548 mmc_hostname(host->mmc), __func__, notify->event_id,
549 notify->data.transfer.iovec.addr,
550 notify->data.transfer.iovec.size,
551 notify->data.transfer.iovec.flags);
552 /* Schedule a tasklet for completing data transfer */
553 tasklet_schedule(&host->sps.tlet);
554}
555
556/**
557 * Tasklet handler for processing SPS callback event
558 *
559 * This function processing SPS event notification and
560 * checks if the SPS transfer is completed or not and
561 * then accordingly notifies status to MMC core layer.
562 *
563 * This function is called in tasklet context.
564 *
565 * @data - Pointer to sdcc driver data
566 *
567 */
568static void msmsdcc_sps_complete_tlet(unsigned long data)
569{
570 unsigned long flags;
571 int i, rc;
572 u32 data_xfered = 0;
573 struct mmc_request *mrq;
574 struct sps_iovec iovec;
575 struct sps_pipe *sps_pipe_handle;
576 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
577 struct sps_event_notify *notify = &host->sps.notify;
578
579 spin_lock_irqsave(&host->lock, flags);
580 if (host->sps.dir == DMA_FROM_DEVICE)
581 sps_pipe_handle = host->sps.prod.pipe_handle;
582 else
583 sps_pipe_handle = host->sps.cons.pipe_handle;
584 mrq = host->curr.mrq;
585
586 if (!mrq) {
587 spin_unlock_irqrestore(&host->lock, flags);
588 return;
589 }
590
591 pr_debug("%s: %s: sps event_id=%d\n",
592 mmc_hostname(host->mmc), __func__,
593 notify->event_id);
594
595 if (msmsdcc_is_dml_busy(host)) {
596 /* oops !!! this should never happen. */
597 pr_err("%s: %s: Received SPS EOT event"
598 " but DML HW is still busy !!!\n",
599 mmc_hostname(host->mmc), __func__);
600 }
601 /*
602 * Got End of transfer event!!! Check if all of the data
603 * has been transferred?
604 */
605 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
606 rc = sps_get_iovec(sps_pipe_handle, &iovec);
607 if (rc) {
608 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
609 mmc_hostname(host->mmc), __func__, rc, i);
610 break;
611 }
612 data_xfered += iovec.size;
613 }
614
615 if (data_xfered == host->curr.xfer_size) {
616 host->curr.data_xfered = host->curr.xfer_size;
617 host->curr.xfer_remain -= host->curr.xfer_size;
618 pr_debug("%s: Data xfer success. data_xfered=0x%x",
619 mmc_hostname(host->mmc),
620 host->curr.xfer_size);
621 } else {
622 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
623 " xfer_size=%d", mmc_hostname(host->mmc),
624 data_xfered, host->curr.xfer_size);
625 msmsdcc_reset_and_restore(host);
626 if (!mrq->data->error)
627 mrq->data->error = -EIO;
628 }
629
630 /* Unmap sg buffers */
631 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
632 host->sps.dir);
633
634 host->sps.sg = NULL;
635 host->sps.busy = 0;
636
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530637 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
638 (host->curr.wait_for_auto_prog_done &&
639 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700640 /*
641 * If we've already gotten our DATAEND / DATABLKEND
642 * for this request, then complete it through here.
643 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700644
645 if (!mrq->data->error) {
646 host->curr.data_xfered = host->curr.xfer_size;
647 host->curr.xfer_remain -= host->curr.xfer_size;
648 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700649 if (host->dummy_52_needed) {
650 mrq->data->bytes_xfered = host->curr.data_xfered;
651 host->dummy_52_sent = 1;
652 msmsdcc_start_command(host, &dummy52cmd,
653 MCI_CPSM_PROGENA);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700654 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700655 return;
656 }
657 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530658 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530659 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700660 host->curr.mrq = NULL;
661 host->curr.cmd = NULL;
662 mrq->data->bytes_xfered = host->curr.data_xfered;
663 del_timer(&host->req_tout_timer);
664 spin_unlock_irqrestore(&host->lock, flags);
665
666 mmc_request_done(host->mmc, mrq);
667 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530668 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
669 || !mrq->sbc)) {
670 msmsdcc_start_command(host, mrq->data->stop, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700671 }
672 }
673 spin_unlock_irqrestore(&host->lock, flags);
674}
675
676/**
677 * Exit from current SPS data transfer
678 *
679 * This function exits from current SPS data transfer.
680 *
681 * This function should be called when error condition
682 * is encountered during data transfer.
683 *
684 * @host - Pointer to sdcc host structure
685 *
686 */
687static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
688{
689 struct mmc_request *mrq;
690
691 mrq = host->curr.mrq;
692 BUG_ON(!mrq);
693
694 msmsdcc_reset_and_restore(host);
695 if (!mrq->data->error)
696 mrq->data->error = -EIO;
697
698 /* Unmap sg buffers */
699 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
700 host->sps.dir);
701
702 host->sps.sg = NULL;
703 host->sps.busy = 0;
704 if (host->curr.data)
705 msmsdcc_stop_data(host);
706
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530707 if (!mrq->data->stop || mrq->cmd->error ||
708 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700709 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530710 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
711 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700712 msmsdcc_start_command(host, mrq->data->stop, 0);
713
714}
715#else
716static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
717static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
718static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
719#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
720
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530721static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700722
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530723static void
724msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
725 unsigned int result,
726 struct msm_dmov_errdata *err)
727{
728 struct msmsdcc_dma_data *dma_data =
729 container_of(cmd, struct msmsdcc_dma_data, hdr);
730 struct msmsdcc_host *host = dma_data->host;
731
732 dma_data->result = result;
733 if (err)
734 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
735
736 tasklet_schedule(&host->dma_tlet);
737}
738
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700739static int msmsdcc_check_dma_op_req(struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700740{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700741 if (((data->blksz * data->blocks) < MCI_FIFOSIZE) ||
742 ((data->blksz * data->blocks) % MCI_FIFOSIZE))
San Mehat9d2bd732009-09-22 16:44:22 -0700743 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700744 else
745 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700746}
747
748static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
749{
750 struct msmsdcc_nc_dmadata *nc;
751 dmov_box *box;
752 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700753 unsigned int n;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530754 int i, err = 0, box_cmd_cnt = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700755 struct scatterlist *sg = data->sg;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530756 unsigned int len, offset;
San Mehat9d2bd732009-09-22 16:44:22 -0700757
Krishna Konda25786ec2011-07-25 16:21:36 -0700758 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700759 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700760
Krishna Konda25786ec2011-07-25 16:21:36 -0700761 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
762
San Mehat9d2bd732009-09-22 16:44:22 -0700763 host->dma.sg = data->sg;
764 host->dma.num_ents = data->sg_len;
765
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530766 /* Prevent memory corruption */
767 BUG_ON(host->dma.num_ents > msmsdcc_get_nr_sg(host));
San Mehat56a8b5b2009-11-21 12:29:46 -0800768
San Mehat9d2bd732009-09-22 16:44:22 -0700769 nc = host->dma.nc;
770
San Mehat9d2bd732009-09-22 16:44:22 -0700771 if (data->flags & MMC_DATA_READ)
772 host->dma.dir = DMA_FROM_DEVICE;
773 else
774 host->dma.dir = DMA_TO_DEVICE;
775
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700776 n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
777 host->dma.num_ents, host->dma.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700778
779 if (n != host->dma.num_ents) {
780 pr_err("%s: Unable to map in all sg elements\n",
781 mmc_hostname(host->mmc));
782 host->dma.sg = NULL;
783 host->dma.num_ents = 0;
784 return -ENOMEM;
San Mehat56a8b5b2009-11-21 12:29:46 -0800785 }
San Mehat9d2bd732009-09-22 16:44:22 -0700786
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530787 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
788 host->curr.user_pages = 0;
789 box = &nc->cmd[0];
790 for (i = 0; i < host->dma.num_ents; i++) {
791 len = sg_dma_len(sg);
792 offset = 0;
793
794 do {
795 /* Check if we can do DMA */
796 if (!len || (box_cmd_cnt >= MMC_MAX_DMA_CMDS)) {
797 err = -ENOTSUPP;
798 goto unmap;
799 }
800
801 box->cmd = CMD_MODE_BOX;
802
803 if (len >= MMC_MAX_DMA_BOX_LENGTH) {
804 len = MMC_MAX_DMA_BOX_LENGTH;
805 len -= len % data->blksz;
806 }
807 rows = (len % MCI_FIFOSIZE) ?
808 (len / MCI_FIFOSIZE) + 1 :
809 (len / MCI_FIFOSIZE);
810
811 if (data->flags & MMC_DATA_READ) {
812 box->src_row_addr = msmsdcc_fifo_addr(host);
813 box->dst_row_addr = sg_dma_address(sg) + offset;
814 box->src_dst_len = (MCI_FIFOSIZE << 16) |
815 (MCI_FIFOSIZE);
816 box->row_offset = MCI_FIFOSIZE;
817 box->num_rows = rows * ((1 << 16) + 1);
818 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
819 } else {
820 box->src_row_addr = sg_dma_address(sg) + offset;
821 box->dst_row_addr = msmsdcc_fifo_addr(host);
822 box->src_dst_len = (MCI_FIFOSIZE << 16) |
823 (MCI_FIFOSIZE);
824 box->row_offset = (MCI_FIFOSIZE << 16);
825 box->num_rows = rows * ((1 << 16) + 1);
826 box->cmd |= CMD_DST_CRCI(host->dma.crci);
827 }
828
829 offset += len;
830 len = sg_dma_len(sg) - offset;
831 box++;
832 box_cmd_cnt++;
833 } while (len);
834 sg++;
835 }
836 /* Mark last command */
837 box--;
838 box->cmd |= CMD_LC;
839
840 /* location of command block must be 64 bit aligned */
841 BUG_ON(host->dma.cmd_busaddr & 0x07);
842
843 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
844 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
845 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
846 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
847
848 /* Flush all data to memory before starting dma */
849 mb();
850
851unmap:
852 if (err) {
853 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
854 host->dma.num_ents, host->dma.dir);
855 pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
856 mmc_hostname(host->mmc), err);
857 }
858
859 return err;
San Mehat9d2bd732009-09-22 16:44:22 -0700860}
861
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700862#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
863/**
864 * Submits data transfer request to SPS driver
865 *
866 * This function make sg (scatter gather) data buffers
867 * DMA ready and then submits them to SPS driver for
868 * transfer.
869 *
870 * @host - Pointer to sdcc host structure
871 * @data - Pointer to mmc_data structure
872 *
873 * @return 0 if success else negative value
874 */
875static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
876 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -0800877{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700878 int rc = 0;
879 u32 flags;
880 int i;
881 u32 addr, len, data_cnt;
882 struct scatterlist *sg = data->sg;
883 struct sps_pipe *sps_pipe_handle;
884
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530885 /* Prevent memory corruption */
886 BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700887
888 host->sps.sg = data->sg;
889 host->sps.num_ents = data->sg_len;
890 host->sps.xfer_req_cnt = 0;
891 if (data->flags & MMC_DATA_READ) {
892 host->sps.dir = DMA_FROM_DEVICE;
893 sps_pipe_handle = host->sps.prod.pipe_handle;
894 } else {
895 host->sps.dir = DMA_TO_DEVICE;
896 sps_pipe_handle = host->sps.cons.pipe_handle;
897 }
898
899 /* Make sg buffers DMA ready */
900 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
901 host->sps.dir);
902
903 if (rc != data->sg_len) {
904 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
905 mmc_hostname(host->mmc), rc);
906 host->sps.sg = NULL;
907 host->sps.num_ents = 0;
908 rc = -ENOMEM;
909 goto dma_map_err;
910 }
911
912 pr_debug("%s: %s: %s: pipe=0x%x, total_xfer=0x%x, sg_len=%d\n",
913 mmc_hostname(host->mmc), __func__,
914 host->sps.dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
915 (u32)sps_pipe_handle, host->curr.xfer_size, data->sg_len);
916
917 for (i = 0; i < data->sg_len; i++) {
918 /*
919 * Check if this is the last buffer to transfer?
920 * If yes then set the INT and EOT flags.
921 */
922 len = sg_dma_len(sg);
923 addr = sg_dma_address(sg);
924 flags = 0;
925 while (len > 0) {
926 if (len > SPS_MAX_DESC_SIZE) {
927 data_cnt = SPS_MAX_DESC_SIZE;
928 } else {
929 data_cnt = len;
930 if (i == data->sg_len - 1)
931 flags = SPS_IOVEC_FLAG_INT |
932 SPS_IOVEC_FLAG_EOT;
933 }
934 rc = sps_transfer_one(sps_pipe_handle, addr,
935 data_cnt, host, flags);
936 if (rc) {
937 pr_err("%s: sps_transfer_one() error! rc=%d,"
938 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
939 mmc_hostname(host->mmc), rc,
940 (u32)sps_pipe_handle, (u32)sg, i);
941 goto dma_map_err;
942 }
943 addr += data_cnt;
944 len -= data_cnt;
945 host->sps.xfer_req_cnt++;
946 }
947 sg++;
948 }
949 goto out;
950
951dma_map_err:
952 /* unmap sg buffers */
953 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
954 host->sps.dir);
955out:
956 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -0700957}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700958#else
959static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
960 struct mmc_data *data) { return 0; }
961#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -0700962
963static void
San Mehat56a8b5b2009-11-21 12:29:46 -0800964msmsdcc_start_command_deferred(struct msmsdcc_host *host,
965 struct mmc_command *cmd, u32 *c)
966{
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530967 DBG(host, "op %02x arg %08x flags %08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700968 cmd->opcode, cmd->arg, cmd->flags);
969
San Mehat56a8b5b2009-11-21 12:29:46 -0800970 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
971
972 if (cmd->flags & MMC_RSP_PRESENT) {
973 if (cmd->flags & MMC_RSP_136)
974 *c |= MCI_CPSM_LONGRSP;
975 *c |= MCI_CPSM_RESPONSE;
976 }
977
978 if (/*interrupt*/0)
979 *c |= MCI_CPSM_INTERRUPT;
980
Subhash Jadavanide0fc772011-11-13 12:27:52 +0530981 if (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
982 cmd->opcode == MMC_READ_MULTIPLE_BLOCK ||
983 cmd->opcode == MMC_WRITE_BLOCK ||
984 cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK ||
985 cmd->opcode == SD_IO_RW_EXTENDED)
San Mehat56a8b5b2009-11-21 12:29:46 -0800986 *c |= MCI_CSPM_DATCMD;
987
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700988 /* Check if AUTO CMD19 is required or not? */
Subhash Jadavani1d6ba602011-09-21 18:10:54 +0530989 if (host->tuning_needed) {
990 /*
991 * For open ended block read operation (without CMD23),
992 * AUTO_CMD19 bit should be set while sending the READ command.
993 * For close ended block read operation (with CMD23),
994 * AUTO_CMD19 bit should be set while sending CMD23.
995 */
Subhash Jadavanide0fc772011-11-13 12:27:52 +0530996 if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
997 host->curr.mrq->cmd->opcode ==
998 MMC_READ_MULTIPLE_BLOCK) ||
Subhash Jadavani1d6ba602011-09-21 18:10:54 +0530999 (!host->curr.mrq->sbc &&
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301000 (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
1001 cmd->opcode == MMC_READ_MULTIPLE_BLOCK))) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301002 msmsdcc_enable_cdr_cm_sdc4_dll(host);
1003 *c |= MCI_CSPM_AUTO_CMD19;
1004 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001005 }
1006
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05301007 /* Clear CDR_EN bit for write operations */
1008 if (host->tuning_needed && cmd->mrq->data &&
1009 (cmd->mrq->data->flags & MMC_DATA_WRITE))
1010 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) &
1011 ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
1012
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301013 if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301014 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001015 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301016 }
1017
San Mehat56a8b5b2009-11-21 12:29:46 -08001018 if (cmd == cmd->mrq->stop)
1019 *c |= MCI_CSPM_MCIABORT;
1020
San Mehat56a8b5b2009-11-21 12:29:46 -08001021 if (host->curr.cmd != NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001022 pr_err("%s: Overlapping command requests\n",
1023 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -08001024 }
1025 host->curr.cmd = cmd;
1026}
1027
1028static void
1029msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1030 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001031{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301032 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001033 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001034 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001035 unsigned int pio_irqmask = 0;
1036
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301037 BUG_ON(!data->sg);
1038 BUG_ON(!data->sg_len);
1039
San Mehat9d2bd732009-09-22 16:44:22 -07001040 host->curr.data = data;
1041 host->curr.xfer_size = data->blksz * data->blocks;
1042 host->curr.xfer_remain = host->curr.xfer_size;
1043 host->curr.data_xfered = 0;
1044 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301045 host->curr.got_auto_prog_done = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001046
San Mehat9d2bd732009-09-22 16:44:22 -07001047 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1048
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301049 if (host->curr.wait_for_auto_prog_done)
1050 datactrl |= MCI_AUTO_PROG_DONE;
1051
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001052 if (!msmsdcc_check_dma_op_req(data)) {
1053 if (host->is_dma_mode && !msmsdcc_config_dma(host, data)) {
1054 datactrl |= MCI_DPSM_DMAENABLE;
1055 } else if (host->is_sps_mode) {
1056 if (!msmsdcc_is_dml_busy(host)) {
1057 if (!msmsdcc_sps_start_xfer(host, data)) {
1058 /* Now kick start DML transfer */
1059 mb();
1060 msmsdcc_dml_start_xfer(host, data);
1061 datactrl |= MCI_DPSM_DMAENABLE;
1062 host->sps.busy = 1;
1063 }
1064 } else {
1065 /*
1066 * Can't proceed with new transfer as
1067 * previous trasnfer is already in progress.
1068 * There is no point of going into PIO mode
1069 * as well. Is this a time to do kernel panic?
1070 */
1071 pr_err("%s: %s: DML HW is busy!!!"
1072 " Can't perform new SPS transfers"
1073 " now\n", mmc_hostname(host->mmc),
1074 __func__);
1075 }
1076 }
1077 }
1078
1079 /* Is data transfer in PIO mode required? */
1080 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001081 if (data->flags & MMC_DATA_READ) {
1082 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1083 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1084 pio_irqmask |= MCI_RXDATAAVLBLMASK;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001085 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001086 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1087 MCI_TXFIFOEMPTYMASK;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001088
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001089 msmsdcc_sg_start(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001090 }
1091
1092 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301093 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
San Mehat9d2bd732009-09-22 16:44:22 -07001094
San Mehat56a8b5b2009-11-21 12:29:46 -08001095 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001096 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001097 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -07001098
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001099 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
1100 /* Use ADM (Application Data Mover) HW for Data transfer */
1101 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001102 host->cmd_timeout = timeout;
1103 host->cmd_pio_irqmask = pio_irqmask;
1104 host->cmd_datactrl = datactrl;
1105 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001106
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001107 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1108 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001109 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001110
1111 if (cmd) {
1112 msmsdcc_start_command_deferred(host, cmd, &c);
1113 host->cmd_c = c;
1114 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001115 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1116 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1117 host->base + MMCIMASK0);
1118 mb();
1119 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001120 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001121 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001122 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001123
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001124 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001125
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001126 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1127 (~(MCI_IRQ_PIO))) | pio_irqmask,
1128 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001129 writel_relaxed(datactrl, base + MMCIDATACTRL);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301130 /*
1131 * We don't need delay after writing to DATA_CTRL register
1132 * if we are not writing to CMD register immediately after
1133 * this. As we already have delay before sending the
1134 * command, we just need mb() here.
1135 */
1136 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001137
1138 if (cmd) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001139 msmsdcc_delay(host); /* Delay between data/command */
San Mehat56a8b5b2009-11-21 12:29:46 -08001140 /* Daisy-chain the command if requested */
1141 msmsdcc_start_command(host, cmd, c);
1142 }
San Mehat9d2bd732009-09-22 16:44:22 -07001143 }
1144}
1145
1146static void
1147msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1148{
San Mehat56a8b5b2009-11-21 12:29:46 -08001149 msmsdcc_start_command_deferred(host, cmd, &c);
1150 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001151}
1152
1153static void
1154msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1155 unsigned int status)
1156{
1157 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001158 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1159 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1160 pr_err("%s: Data CRC error\n",
1161 mmc_hostname(host->mmc));
1162 pr_err("%s: opcode 0x%.8x\n", __func__,
1163 data->mrq->cmd->opcode);
1164 pr_err("%s: blksz %d, blocks %d\n", __func__,
1165 data->blksz, data->blocks);
1166 data->error = -EILSEQ;
1167 }
San Mehat9d2bd732009-09-22 16:44:22 -07001168 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001169 /* CRC is optional for the bus test commands, not all
1170 * cards respond back with CRC. However controller
1171 * waits for the CRC and times out. Hence ignore the
1172 * data timeouts during the Bustest.
1173 */
1174 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1175 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301176 pr_err("%s: CMD%d: Data timeout\n",
1177 mmc_hostname(host->mmc),
1178 data->mrq->cmd->opcode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001179 data->error = -ETIMEDOUT;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301180 msmsdcc_dump_sdcc_state(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001181 }
San Mehat9d2bd732009-09-22 16:44:22 -07001182 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001183 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001184 data->error = -EIO;
1185 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001186 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001187 data->error = -EIO;
1188 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001189 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001190 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001191 data->error = -EIO;
1192 }
San Mehat9d2bd732009-09-22 16:44:22 -07001193
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001194 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001195 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001196 host->dummy_52_needed = 0;
1197}
San Mehat9d2bd732009-09-22 16:44:22 -07001198
1199static int
1200msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1201{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001202 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001203 uint32_t *ptr = (uint32_t *) buffer;
1204 int count = 0;
1205
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301206 if (remain % 4)
1207 remain = ((remain >> 2) + 1) << 2;
1208
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001209 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1210
1211 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001212 ptr++;
1213 count += sizeof(uint32_t);
1214
1215 remain -= sizeof(uint32_t);
1216 if (remain == 0)
1217 break;
1218 }
1219 return count;
1220}
1221
1222static int
1223msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001224 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001225{
1226 void __iomem *base = host->base;
1227 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001228 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001229
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001230 while (readl_relaxed(base + MMCISTATUS) &
1231 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1232 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001233
San Mehat9d2bd732009-09-22 16:44:22 -07001234 count = min(remain, maxcnt);
1235
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301236 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1237 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001238 ptr += count;
1239 remain -= count;
1240
1241 if (remain == 0)
1242 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001243 }
1244 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001245
1246 return ptr - buffer;
1247}
1248
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001249/*
1250 * Copy up to a word (4 bytes) between a scatterlist
1251 * and a temporary bounce buffer when the word lies across
1252 * two pages. The temporary buffer can then be read to/
1253 * written from the FIFO once.
1254 */
1255static void _msmsdcc_sg_consume_word(struct msmsdcc_host *host)
1256{
1257 struct msmsdcc_pio_data *pio = &host->pio;
1258 unsigned int bytes_avail;
1259
1260 if (host->curr.data->flags & MMC_DATA_READ)
1261 memcpy(pio->sg_miter.addr, pio->bounce_buf,
1262 pio->bounce_buf_len);
1263 else
1264 memcpy(pio->bounce_buf, pio->sg_miter.addr,
1265 pio->bounce_buf_len);
1266
1267 while (pio->bounce_buf_len != 4) {
1268 if (!sg_miter_next(&pio->sg_miter))
1269 break;
1270 bytes_avail = min_t(unsigned int, pio->sg_miter.length,
1271 4 - pio->bounce_buf_len);
1272 if (host->curr.data->flags & MMC_DATA_READ)
1273 memcpy(pio->sg_miter.addr,
1274 &pio->bounce_buf[pio->bounce_buf_len],
1275 bytes_avail);
1276 else
1277 memcpy(&pio->bounce_buf[pio->bounce_buf_len],
1278 pio->sg_miter.addr, bytes_avail);
1279
1280 pio->sg_miter.consumed = bytes_avail;
1281 pio->bounce_buf_len += bytes_avail;
1282 }
1283}
1284
1285/*
1286 * Use sg_miter_next to return as many 4-byte aligned
1287 * chunks as possible, using a temporary 4 byte buffer
1288 * for alignment if necessary
1289 */
1290static int msmsdcc_sg_next(struct msmsdcc_host *host, char **buf, int *len)
1291{
1292 struct msmsdcc_pio_data *pio = &host->pio;
1293 unsigned int length, rlength;
1294 char *buffer;
1295
1296 if (!sg_miter_next(&pio->sg_miter))
1297 return 0;
1298
1299 buffer = pio->sg_miter.addr;
1300 length = pio->sg_miter.length;
1301
1302 if (length < host->curr.xfer_remain) {
1303 rlength = round_down(length, 4);
1304 if (rlength) {
1305 /*
1306 * We have a 4-byte aligned chunk.
1307 * The rounding will be reflected by
1308 * a call to msmsdcc_sg_consumed
1309 */
1310 length = rlength;
1311 goto sg_next_end;
1312 }
1313 /*
1314 * We have a length less than 4 bytes. Check to
1315 * see if more buffer is available, and combine
1316 * to make 4 bytes if possible.
1317 */
1318 pio->bounce_buf_len = length;
1319 memset(pio->bounce_buf, 0, 4);
1320
1321 /*
1322 * On a read, get 4 bytes from FIFO, and distribute
1323 * (4-bouce_buf_len) bytes into consecutive
1324 * sgl buffers when msmsdcc_sg_consumed is called
1325 */
1326 if (host->curr.data->flags & MMC_DATA_READ) {
1327 buffer = pio->bounce_buf;
1328 length = 4;
1329 goto sg_next_end;
1330 } else {
1331 _msmsdcc_sg_consume_word(host);
1332 buffer = pio->bounce_buf;
1333 length = pio->bounce_buf_len;
1334 }
1335 }
1336
1337sg_next_end:
1338 *buf = buffer;
1339 *len = length;
1340 return 1;
1341}
1342
1343/*
1344 * Update sg_miter.consumed based on how many bytes were
1345 * consumed. If the bounce buffer was used to read from FIFO,
1346 * redistribute into sgls.
1347 */
1348static void msmsdcc_sg_consumed(struct msmsdcc_host *host,
1349 unsigned int length)
1350{
1351 struct msmsdcc_pio_data *pio = &host->pio;
1352
1353 if (host->curr.data->flags & MMC_DATA_READ) {
1354 if (length > pio->sg_miter.consumed)
1355 /*
1356 * consumed 4 bytes, but sgl
1357 * describes < 4 bytes
1358 */
1359 _msmsdcc_sg_consume_word(host);
1360 else
1361 pio->sg_miter.consumed = length;
1362 } else
1363 if (length < pio->sg_miter.consumed)
1364 pio->sg_miter.consumed = length;
1365}
1366
1367static void msmsdcc_sg_start(struct msmsdcc_host *host)
1368{
1369 unsigned int sg_miter_flags = SG_MITER_ATOMIC;
1370
1371 host->pio.bounce_buf_len = 0;
1372
1373 if (host->curr.data->flags & MMC_DATA_READ)
1374 sg_miter_flags |= SG_MITER_TO_SG;
1375 else
1376 sg_miter_flags |= SG_MITER_FROM_SG;
1377
1378 sg_miter_start(&host->pio.sg_miter, host->curr.data->sg,
1379 host->curr.data->sg_len, sg_miter_flags);
1380}
1381
1382static void msmsdcc_sg_stop(struct msmsdcc_host *host)
1383{
1384 sg_miter_stop(&host->pio.sg_miter);
1385}
1386
San Mehat1cd22962010-02-03 12:59:29 -08001387static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001388msmsdcc_pio_irq(int irq, void *dev_id)
1389{
1390 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001391 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001392 uint32_t status;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001393 unsigned long flags;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001394 unsigned int remain;
1395 char *buffer;
San Mehat9d2bd732009-09-22 16:44:22 -07001396
Murali Palnati36448a42011-09-02 15:06:18 +05301397 spin_lock(&host->lock);
1398
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001399 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001400
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001401 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301402 (MCI_IRQ_PIO)) == 0) {
1403 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001404 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301405 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001406#if IRQ_DEBUG
1407 msmsdcc_print_status(host, "irq1-r", status);
1408#endif
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001409 local_irq_save(flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001410
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001411 do {
1412 unsigned int len;
San Mehat9d2bd732009-09-22 16:44:22 -07001413
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001414 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1415 | MCI_RXDATAAVLBL)))
1416 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001417
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001418 if (!msmsdcc_sg_next(host, &buffer, &remain))
1419 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001420
San Mehat9d2bd732009-09-22 16:44:22 -07001421 len = 0;
1422 if (status & MCI_RXACTIVE)
1423 len = msmsdcc_pio_read(host, buffer, remain);
1424 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001425 len = msmsdcc_pio_write(host, buffer, remain);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001426
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301427 /* len might have aligned to 32bits above */
1428 if (len > remain)
1429 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001430
San Mehat9d2bd732009-09-22 16:44:22 -07001431 host->curr.xfer_remain -= len;
1432 host->curr.data_xfered += len;
1433 remain -= len;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001434 msmsdcc_sg_consumed(host, len);
San Mehat9d2bd732009-09-22 16:44:22 -07001435
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001436 if (remain) /* Done with this page? */
1437 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001438
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001439 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001440 } while (1);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001441
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001442 msmsdcc_sg_stop(host);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001443 local_irq_restore(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001444
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001445 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1446 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1447 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1448 host->base + MMCIMASK0);
1449 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301450 /*
1451 * back to back write to MASK0 register don't need
1452 * synchronization delay.
1453 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001454 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1455 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1456 }
1457 mb();
1458 } else if (!host->curr.xfer_remain) {
1459 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1460 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1461 mb();
1462 }
San Mehat9d2bd732009-09-22 16:44:22 -07001463
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001464 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001465
1466 return IRQ_HANDLED;
1467}
1468
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001469static void
1470msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1471
1472static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1473 struct mmc_data *data)
1474{
1475 u32 loop_cnt = 0;
1476
1477 /*
1478 * For read commands with data less than fifo size, it is possible to
1479 * get DATAEND first and RXDATA_AVAIL might be set later because of
1480 * synchronization delay through the asynchronous RX FIFO. Thus, for
1481 * such cases, even after DATAEND interrupt is received software
1482 * should poll for RXDATA_AVAIL until the requested data is read out
1483 * of FIFO. This change is needed to get around this abnormal but
1484 * sometimes expected behavior of SDCC3 controller.
1485 *
1486 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1487 * after the data is loaded into RX FIFO. This would amount to less
1488 * than a microsecond and thus looping for 1000 times is good enough
1489 * for that delay.
1490 */
1491 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1492 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1493 spin_unlock(&host->lock);
1494 msmsdcc_pio_irq(1, host);
1495 spin_lock(&host->lock);
1496 }
1497 }
1498 if (loop_cnt == 1000) {
1499 pr_info("%s: Timed out while polling for Rx Data\n",
1500 mmc_hostname(host->mmc));
1501 data->error = -ETIMEDOUT;
1502 msmsdcc_reset_and_restore(host);
1503 }
1504}
1505
San Mehat9d2bd732009-09-22 16:44:22 -07001506static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1507{
1508 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001509
1510 host->curr.cmd = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001511 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1512 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1513 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1514 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -07001515
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001516 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301517 pr_debug("%s: CMD%d: Command timeout\n",
1518 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001519 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001520 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
1521 !host->cmd19_tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301522 pr_err("%s: CMD%d: Command CRC error\n",
1523 mmc_hostname(host->mmc), cmd->opcode);
1524 msmsdcc_dump_sdcc_state(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001525 cmd->error = -EILSEQ;
1526 }
1527
1528 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001529 if (host->curr.data && host->dma.sg &&
1530 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001531 msm_dmov_stop_cmd(host->dma.channel,
1532 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001533 else if (host->curr.data && host->sps.sg &&
1534 host->is_sps_mode){
1535 /* Stop current SPS transfer */
1536 msmsdcc_sps_exit_curr_xfer(host);
1537 }
San Mehat9d2bd732009-09-22 16:44:22 -07001538 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301539 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001540 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301541 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301542 } else { /* host->data == NULL */
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301543 if (!cmd->error && host->prog_enable) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301544 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001545 host->prog_enable = 0;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301546 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001547 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301548 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301549 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301550 host->prog_enable = 0;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001551 if (host->dummy_52_needed)
1552 host->dummy_52_needed = 0;
1553 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001554 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301555 msmsdcc_request_end(host, cmd->mrq);
1556 }
1557 }
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301558 } else if ((cmd == host->curr.mrq->sbc) && cmd->data) {
1559 if (cmd->data->flags & MMC_DATA_READ)
1560 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1561 else
1562 msmsdcc_request_start(host, host->curr.mrq);
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301563 } else if (cmd->data) {
1564 if (!(cmd->data->flags & MMC_DATA_READ))
1565 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001566 }
1567}
1568
San Mehat9d2bd732009-09-22 16:44:22 -07001569static irqreturn_t
1570msmsdcc_irq(int irq, void *dev_id)
1571{
1572 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001573 u32 status;
1574 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001575 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001576
1577 spin_lock(&host->lock);
1578
1579 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001580 struct mmc_command *cmd;
1581 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001582
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001583 if (timer) {
1584 timer = 0;
1585 msmsdcc_delay(host);
1586 }
San Mehat865c8062009-11-13 13:42:06 -08001587
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001588 if (!host->clks_on) {
1589 pr_debug("%s: %s: SDIO async irq received\n",
1590 mmc_hostname(host->mmc), __func__);
1591 host->mmc->ios.clock = host->clk_rate;
1592 spin_unlock(&host->lock);
1593 host->mmc->ops->set_ios(host->mmc, &host->mmc->ios);
1594 spin_lock(&host->lock);
1595 if (host->plat->cfg_mpm_sdiowakeup &&
1596 (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
1597 wake_lock(&host->sdio_wlock);
1598 /* only ansyc interrupt can come when clocks are off */
1599 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301600 if (host->clk_rate <=
1601 msmsdcc_get_min_sup_clk_rate(host))
1602 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001603 }
1604
1605 status = readl_relaxed(host->base + MMCISTATUS);
1606
1607 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1608 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001609 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001610
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001611#if IRQ_DEBUG
1612 msmsdcc_print_status(host, "irq0-r", status);
1613#endif
1614 status &= readl_relaxed(host->base + MMCIMASK0);
1615 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301616 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301617 if (host->clk_rate <=
1618 msmsdcc_get_min_sup_clk_rate(host))
1619 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001620#if IRQ_DEBUG
1621 msmsdcc_print_status(host, "irq0-p", status);
1622#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001623
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001624#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
1625 if (status & MCI_SDIOINTROPE) {
1626 if (host->sdcc_suspending)
1627 wake_lock(&host->sdio_suspend_wlock);
1628 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001629 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001630#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001631 data = host->curr.data;
1632
1633 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001634 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1635 MCI_CMDTIMEOUT)) {
1636 if (status & MCI_CMDTIMEOUT)
1637 pr_debug("%s: dummy CMD52 timeout\n",
1638 mmc_hostname(host->mmc));
1639 if (status & MCI_CMDCRCFAIL)
1640 pr_debug("%s: dummy CMD52 CRC failed\n",
1641 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001642 host->dummy_52_sent = 0;
1643 host->dummy_52_needed = 0;
1644 if (data) {
1645 msmsdcc_stop_data(host);
1646 msmsdcc_request_end(host, data->mrq);
1647 }
1648 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001649 spin_unlock(&host->lock);
1650 return IRQ_HANDLED;
1651 }
1652 break;
1653 }
1654
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001655 /*
1656 * Check for proper command response
1657 */
1658 cmd = host->curr.cmd;
1659 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1660 MCI_CMDTIMEOUT | MCI_PROGDONE |
1661 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1662 msmsdcc_do_cmdirq(host, status);
1663 }
1664
Sathish Ambley081d7842011-11-29 11:19:41 -08001665 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001666 /* Check for data errors */
1667 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1668 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1669 msmsdcc_data_err(host, data, status);
1670 host->curr.data_xfered = 0;
1671 if (host->dma.sg && host->is_dma_mode)
1672 msm_dmov_stop_cmd(host->dma.channel,
1673 &host->dma.hdr, 0);
1674 else if (host->sps.sg && host->is_sps_mode) {
1675 /* Stop current SPS transfer */
1676 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301677 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001678 msmsdcc_reset_and_restore(host);
1679 if (host->curr.data)
1680 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301681 if (!data->stop || (host->curr.mrq->sbc
1682 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001683 timer |=
1684 msmsdcc_request_end(host,
1685 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301686 else if ((host->curr.mrq->sbc
1687 && data->error) ||
1688 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001689 msmsdcc_start_command(host,
1690 data->stop,
1691 0);
1692 timer = 1;
1693 }
1694 }
1695 }
1696
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301697 /* Check for prog done */
1698 if (host->curr.wait_for_auto_prog_done &&
1699 (status & MCI_PROGDONE))
1700 host->curr.got_auto_prog_done = 1;
1701
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001702 /* Check for data done */
1703 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1704 host->curr.got_dataend = 1;
1705
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301706 if (host->curr.got_dataend &&
1707 (!host->curr.wait_for_auto_prog_done ||
1708 (host->curr.wait_for_auto_prog_done &&
1709 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001710 /*
1711 * If DMA is still in progress, we complete
1712 * via the completion handler
1713 */
1714 if (!host->dma.busy && !host->sps.busy) {
1715 /*
1716 * There appears to be an issue in the
1717 * controller where if you request a
1718 * small block transfer (< fifo size),
1719 * you may get your DATAEND/DATABLKEND
1720 * irq without the PIO data irq.
1721 *
1722 * Check to see if theres still data
1723 * to be read, and simulate a PIO irq.
1724 */
1725 if (data->flags & MMC_DATA_READ)
1726 msmsdcc_wait_for_rxdata(host,
1727 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001728 if (!data->error) {
1729 host->curr.data_xfered =
1730 host->curr.xfer_size;
1731 host->curr.xfer_remain -=
1732 host->curr.xfer_size;
1733 }
1734
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001735 if (!host->dummy_52_needed) {
1736 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301737 if (!data->stop ||
1738 (host->curr.mrq->sbc
1739 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001740 msmsdcc_request_end(
1741 host,
1742 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301743 else if ((host->curr.mrq->sbc
1744 && data->error) ||
1745 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001746 msmsdcc_start_command(
1747 host,
1748 data->stop, 0);
1749 timer = 1;
1750 }
1751 } else {
1752 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001753 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001754 &dummy52cmd,
1755 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001756 }
1757 }
1758 }
1759 }
1760
San Mehat9d2bd732009-09-22 16:44:22 -07001761 ret = 1;
1762 } while (status);
1763
1764 spin_unlock(&host->lock);
1765
San Mehat9d2bd732009-09-22 16:44:22 -07001766 return IRQ_RETVAL(ret);
1767}
1768
1769static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001770msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1771{
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301772 if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001773 /* Queue/read data, daisy-chain command when data starts */
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301774 if (mrq->sbc)
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301775 msmsdcc_start_data(host, mrq->data, mrq->sbc, 0);
1776 else
1777 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001778 } else {
1779 msmsdcc_start_command(host, mrq->cmd, 0);
1780 }
1781}
1782
1783static void
San Mehat9d2bd732009-09-22 16:44:22 -07001784msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1785{
1786 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001787 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001788
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001789 /*
1790 * Get the SDIO AL client out of LPM.
1791 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001792 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001793 if (host->plat->is_sdio_al_client)
1794 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001795
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301796 /* check if sps pipe reset is pending? */
1797 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1798 msmsdcc_sps_pipes_reset_and_restore(host);
1799 host->sps.pipe_reset_pending = false;
1800 }
1801
San Mehat9d2bd732009-09-22 16:44:22 -07001802 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001803 WARN(host->curr.mrq, "Request in progress\n");
1804 WARN(!host->pwr, "SDCC power is turned off\n");
1805 WARN(!host->clks_on, "SDCC clocks are turned off\n");
1806 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
San Mehat9d2bd732009-09-22 16:44:22 -07001807
1808 if (host->eject) {
1809 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1810 mrq->cmd->error = 0;
1811 mrq->data->bytes_xfered = mrq->data->blksz *
1812 mrq->data->blocks;
1813 } else
1814 mrq->cmd->error = -ENOMEDIUM;
1815
1816 spin_unlock_irqrestore(&host->lock, flags);
1817 mmc_request_done(mmc, mrq);
1818 return;
1819 }
1820
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301821 /*
1822 * Kick the software command timeout timer here.
1823 * Timer expires in 10 secs.
1824 */
1825 mod_timer(&host->req_tout_timer,
1826 (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
San Mehat9d2bd732009-09-22 16:44:22 -07001827
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301828 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301829 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301830 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
1831 mrq->cmd->opcode == 54) {
Pratibhasagar V1c11da62011-11-14 12:36:35 +05301832 if (!host->sdcc_version)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001833 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301834 else
1835 /*
1836 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
1837 * write operations using CMD53 and CMD54.
1838 * Setting this bit with CMD53 would
1839 * automatically triggers PROG_DONE interrupt
1840 * without the need of sending dummy CMD52.
1841 */
1842 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani758cf8c2011-11-13 11:59:55 +05301843 } else if (mrq->cmd->opcode == MMC_WRITE_BLOCK &&
1844 host->sdcc_version) {
1845 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001846 }
San Mehat9d2bd732009-09-22 16:44:22 -07001847 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301848
Pratibhasagar V00b94332011-10-18 14:57:27 +05301849 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301850 mrq->sbc->mrq = mrq;
1851 mrq->sbc->data = mrq->data;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301852 if (mrq->data->flags & MMC_DATA_WRITE) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301853 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301854 msmsdcc_start_command(host, mrq->sbc, 0);
1855 } else {
1856 msmsdcc_request_start(host, mrq);
1857 }
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301858 } else {
1859 msmsdcc_request_start(host, mrq);
1860 }
1861
San Mehat9d2bd732009-09-22 16:44:22 -07001862 spin_unlock_irqrestore(&host->lock, flags);
1863}
1864
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001865static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1866 int min_uV, int max_uV)
1867{
1868 int rc = 0;
1869
1870 if (vreg->set_voltage_sup) {
1871 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1872 if (rc) {
1873 pr_err("%s: regulator_set_voltage(%s) failed."
1874 " min_uV=%d, max_uV=%d, rc=%d\n",
1875 __func__, vreg->name, min_uV, max_uV, rc);
1876 }
1877 }
1878
1879 return rc;
1880}
1881
1882static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1883 int uA_load)
1884{
1885 int rc = 0;
1886
Krishna Kondafea60182011-11-01 16:01:34 -07001887 /* regulators that do not support regulator_set_voltage also
1888 do not support regulator_set_optimum_mode */
1889 if (vreg->set_voltage_sup) {
1890 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1891 if (rc < 0)
1892 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
1893 "uA_load=%d) failed. rc=%d\n", __func__,
1894 vreg->name, uA_load, rc);
1895 else
1896 /* regulator_set_optimum_mode() can return non zero
1897 * value even for success case.
1898 */
1899 rc = 0;
1900 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001901
1902 return rc;
1903}
1904
1905static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1906 struct device *dev)
1907{
1908 int rc = 0;
1909
1910 /* check if regulator is already initialized? */
1911 if (vreg->reg)
1912 goto out;
1913
1914 /* Get the regulator handle */
1915 vreg->reg = regulator_get(dev, vreg->name);
1916 if (IS_ERR(vreg->reg)) {
1917 rc = PTR_ERR(vreg->reg);
1918 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
1919 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001920 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001921 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001922
1923 if (regulator_count_voltages(vreg->reg) > 0)
1924 vreg->set_voltage_sup = 1;
1925
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001926out:
1927 return rc;
1928}
1929
1930static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
1931{
1932 if (vreg->reg)
1933 regulator_put(vreg->reg);
1934}
1935
1936/* This init function should be called only once for each SDCC slot */
1937static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
1938{
1939 int rc = 0;
1940 struct msm_mmc_slot_reg_data *curr_slot;
1941 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1942 struct device *dev = mmc_dev(host->mmc);
1943
1944 curr_slot = host->plat->vreg_data;
1945 if (!curr_slot)
1946 goto out;
1947
1948 curr_vdd_reg = curr_slot->vdd_data;
1949 curr_vccq_reg = curr_slot->vccq_data;
1950 curr_vddp_reg = curr_slot->vddp_data;
1951
1952 if (is_init) {
1953 /*
1954 * Get the regulator handle from voltage regulator framework
1955 * and then try to set the voltage level for the regulator
1956 */
1957 if (curr_vdd_reg) {
1958 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
1959 if (rc)
1960 goto out;
1961 }
1962 if (curr_vccq_reg) {
1963 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
1964 if (rc)
1965 goto vdd_reg_deinit;
1966 }
1967 if (curr_vddp_reg) {
1968 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
1969 if (rc)
1970 goto vccq_reg_deinit;
1971 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08001972 rc = msmsdcc_vreg_reset(host);
1973 if (rc)
1974 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
1975 host->pdev_id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001976 goto out;
1977 } else {
1978 /* Deregister all regulators from regulator framework */
1979 goto vddp_reg_deinit;
1980 }
1981vddp_reg_deinit:
1982 if (curr_vddp_reg)
1983 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
1984vccq_reg_deinit:
1985 if (curr_vccq_reg)
1986 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
1987vdd_reg_deinit:
1988 if (curr_vdd_reg)
1989 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
1990out:
1991 return rc;
1992}
1993
1994static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
1995{
1996 int rc = 0;
1997
Subhash Jadavanicc922692011-08-01 23:05:01 +05301998 /* Put regulator in HPM (high power mode) */
1999 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2000 if (rc < 0)
2001 goto out;
2002
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002003 if (!vreg->is_enabled) {
2004 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302005 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2006 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002007 if (rc)
2008 goto out;
2009
2010 rc = regulator_enable(vreg->reg);
2011 if (rc) {
2012 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2013 __func__, vreg->name, rc);
2014 goto out;
2015 }
2016 vreg->is_enabled = true;
2017 }
2018
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002019out:
2020 return rc;
2021}
2022
2023static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
2024{
2025 int rc = 0;
2026
2027 /* Never disable regulator marked as always_on */
2028 if (vreg->is_enabled && !vreg->always_on) {
2029 rc = regulator_disable(vreg->reg);
2030 if (rc) {
2031 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2032 __func__, vreg->name, rc);
2033 goto out;
2034 }
2035 vreg->is_enabled = false;
2036
2037 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2038 if (rc < 0)
2039 goto out;
2040
2041 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302042 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002043 if (rc)
2044 goto out;
2045 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
2046 /* Put always_on regulator in LPM (low power mode) */
2047 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2048 if (rc < 0)
2049 goto out;
2050 }
2051out:
2052 return rc;
2053}
2054
2055static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
2056{
2057 int rc = 0, i;
2058 struct msm_mmc_slot_reg_data *curr_slot;
2059 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
2060 struct msm_mmc_reg_data *vreg_table[3];
2061
2062 curr_slot = host->plat->vreg_data;
2063 if (!curr_slot)
2064 goto out;
2065
2066 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
2067 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
2068 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
2069
2070 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2071 if (vreg_table[i]) {
2072 if (enable)
2073 rc = msmsdcc_vreg_enable(vreg_table[i]);
2074 else
2075 rc = msmsdcc_vreg_disable(vreg_table[i]);
2076 if (rc)
2077 goto out;
2078 }
2079 }
2080out:
2081 return rc;
2082}
2083
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002084/*
2085 * Reset vreg by ensuring it is off during probe. A call
2086 * to enable vreg is needed to balance disable vreg
2087 */
2088static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2089{
2090 int rc;
2091
2092 rc = msmsdcc_setup_vreg(host, 1);
2093 if (rc)
2094 return rc;
2095 rc = msmsdcc_setup_vreg(host, 0);
2096 return rc;
2097}
2098
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302099static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002100{
2101 int rc = 0;
2102
2103 if (host->plat->vreg_data) {
2104 struct msm_mmc_reg_data *vddp_reg =
2105 host->plat->vreg_data->vddp_data;
2106
2107 if (vddp_reg && vddp_reg->is_enabled)
2108 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
2109 }
2110
2111 return rc;
2112}
2113
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302114static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
2115{
2116 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2117 int rc = 0;
2118
2119 if (curr_slot && curr_slot->vddp_data) {
2120 rc = msmsdcc_set_vddp_level(host,
2121 curr_slot->vddp_data->low_vol_level);
2122
2123 if (rc)
2124 pr_err("%s: %s: failed to change vddp level to %d",
2125 mmc_hostname(host->mmc), __func__,
2126 curr_slot->vddp_data->low_vol_level);
2127 }
2128
2129 return rc;
2130}
2131
2132static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
2133{
2134 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2135 int rc = 0;
2136
2137 if (curr_slot && curr_slot->vddp_data) {
2138 rc = msmsdcc_set_vddp_level(host,
2139 curr_slot->vddp_data->high_vol_level);
2140
2141 if (rc)
2142 pr_err("%s: %s: failed to change vddp level to %d",
2143 mmc_hostname(host->mmc), __func__,
2144 curr_slot->vddp_data->high_vol_level);
2145 }
2146
2147 return rc;
2148}
2149
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002150static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2151{
2152 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2153 return 1;
2154 return 0;
2155}
2156
2157static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
2158{
2159 if (enable) {
2160 if (!IS_ERR_OR_NULL(host->dfab_pclk))
2161 clk_enable(host->dfab_pclk);
2162 if (!IS_ERR(host->pclk))
2163 clk_enable(host->pclk);
2164 clk_enable(host->clk);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302165 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002166 } else {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302167 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002168 clk_disable(host->clk);
2169 if (!IS_ERR(host->pclk))
2170 clk_disable(host->pclk);
2171 if (!IS_ERR_OR_NULL(host->dfab_pclk))
2172 clk_disable(host->dfab_pclk);
2173 }
2174}
2175
2176static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2177 unsigned int req_clk)
2178{
2179 unsigned int sel_clk = -1;
2180
2181 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2182 unsigned char cnt;
2183
2184 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2185 if (host->plat->sup_clk_table[cnt] > req_clk)
2186 break;
2187 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2188 sel_clk = host->plat->sup_clk_table[cnt];
2189 break;
2190 } else
2191 sel_clk = host->plat->sup_clk_table[cnt];
2192 }
2193 } else {
2194 if ((req_clk < host->plat->msmsdcc_fmax) &&
2195 (req_clk > host->plat->msmsdcc_fmid))
2196 sel_clk = host->plat->msmsdcc_fmid;
2197 else
2198 sel_clk = req_clk;
2199 }
2200
2201 return sel_clk;
2202}
2203
2204static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2205 struct msmsdcc_host *host)
2206{
2207 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2208 return host->plat->sup_clk_table[0];
2209 else
2210 return host->plat->msmsdcc_fmin;
2211}
2212
2213static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2214 struct msmsdcc_host *host)
2215{
2216 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2217 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2218 else
2219 return host->plat->msmsdcc_fmax;
2220}
2221
2222static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302223{
2224 struct msm_mmc_gpio_data *curr;
2225 int i, rc = 0;
2226
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002227 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302228 for (i = 0; i < curr->size; i++) {
2229 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002230 if (curr->gpio[i].is_always_on &&
2231 curr->gpio[i].is_enabled)
2232 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302233 rc = gpio_request(curr->gpio[i].no,
2234 curr->gpio[i].name);
2235 if (rc) {
2236 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2237 mmc_hostname(host->mmc),
2238 curr->gpio[i].no,
2239 curr->gpio[i].name, rc);
2240 goto free_gpios;
2241 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002242 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302243 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002244 if (curr->gpio[i].is_always_on)
2245 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302246 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002247 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302248 }
2249 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002250 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302251
2252free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002253 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302254 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002255 curr->gpio[i].is_enabled = false;
2256 }
2257out:
2258 return rc;
2259}
2260
2261static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2262{
2263 struct msm_mmc_pad_data *curr;
2264 int i;
2265
2266 curr = host->plat->pin_data->pad_data;
2267 for (i = 0; i < curr->drv->size; i++) {
2268 if (enable)
2269 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2270 curr->drv->on[i].val);
2271 else
2272 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2273 curr->drv->off[i].val);
2274 }
2275
2276 for (i = 0; i < curr->pull->size; i++) {
2277 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002278 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002279 curr->pull->on[i].val);
2280 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002281 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002282 curr->pull->off[i].val);
2283 }
2284
2285 return 0;
2286}
2287
2288static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2289{
2290 int rc = 0;
2291
2292 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2293 return 0;
2294
2295 if (host->plat->pin_data->is_gpio)
2296 rc = msmsdcc_setup_gpio(host, enable);
2297 else
2298 rc = msmsdcc_setup_pad(host, enable);
2299
2300 if (!rc)
2301 host->plat->pin_data->cfg_sts = enable;
2302
2303 return rc;
2304}
2305
2306static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2307{
2308 unsigned int wakeup_irq;
2309
2310 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2311 host->plat->sdiowakeup_irq :
2312 host->core_irqres->start;
2313
2314 if (!host->irq_wake_enabled) {
2315 enable_irq_wake(wakeup_irq);
2316 host->irq_wake_enabled = true;
2317 }
2318}
2319
2320static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2321{
2322 unsigned int wakeup_irq;
2323
2324 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2325 host->plat->sdiowakeup_irq :
2326 host->core_irqres->start;
2327
2328 if (host->irq_wake_enabled) {
2329 disable_irq_wake(wakeup_irq);
2330 host->irq_wake_enabled = false;
2331 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302332}
2333
San Mehat9d2bd732009-09-22 16:44:22 -07002334static void
2335msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2336{
2337 struct msmsdcc_host *host = mmc_priv(mmc);
2338 u32 clk = 0, pwr = 0;
2339 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002340 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002341 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002342
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002343 DBG(host, "ios->clock = %u\n", ios->clock);
Sahitya Tummala7a892482011-01-18 11:22:49 +05302344
San Mehat9d2bd732009-09-22 16:44:22 -07002345 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002346 spin_lock_irqsave(&host->lock, flags);
2347 if (!host->clks_on) {
2348 msmsdcc_setup_clocks(host, true);
2349 host->clks_on = 1;
2350 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2351 if (!host->plat->sdiowakeup_irq) {
2352 writel_relaxed(host->mci_irqenable,
2353 host->base + MMCIMASK0);
2354 mb();
2355 if (host->plat->cfg_mpm_sdiowakeup &&
2356 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2357 host->plat->cfg_mpm_sdiowakeup(
2358 mmc_dev(mmc), SDC_DAT1_DISWAKE);
2359 msmsdcc_disable_irq_wake(host);
2360 } else if (!(mmc->pm_flags &
2361 MMC_PM_WAKE_SDIO_IRQ)) {
2362 writel_relaxed(host->mci_irqenable,
2363 host->base + MMCIMASK0);
2364 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05302365 } else {
2366 writel_relaxed(host->mci_irqenable,
2367 host->base + MMCIMASK0);
2368 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002369 }
San Mehat9d2bd732009-09-22 16:44:22 -07002370 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002371 spin_unlock_irqrestore(&host->lock, flags);
2372
2373 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2374 /*
2375 * For DDR50 mode, controller needs clock rate to be
2376 * double than what is required on the SD card CLK pin.
2377 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302378 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002379 /*
2380 * Make sure that we don't double the clock if
2381 * doubled clock rate is already set
2382 */
2383 if (!host->ddr_doubled_clk_rate ||
2384 (host->ddr_doubled_clk_rate &&
2385 (host->ddr_doubled_clk_rate != ios->clock))) {
2386 host->ddr_doubled_clk_rate =
2387 msmsdcc_get_sup_clk_rate(
2388 host, (ios->clock * 2));
2389 clock = host->ddr_doubled_clk_rate;
2390 }
2391 } else {
2392 host->ddr_doubled_clk_rate = 0;
2393 }
2394
2395 if (clock != host->clk_rate) {
2396 rc = clk_set_rate(host->clk, clock);
2397 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302398 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002399 mmc_hostname(mmc), clock);
2400 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302401 host->reg_write_delay =
2402 (1 + ((3 * USEC_PER_SEC) /
2403 (host->clk_rate ? host->clk_rate :
2404 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002405 }
2406 /*
2407 * give atleast 2 MCLK cycles delay for clocks
2408 * and SDCC core to stabilize
2409 */
2410 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002411 clk |= MCI_CLK_ENABLE;
2412 }
2413
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002414 if (ios->bus_width == MMC_BUS_WIDTH_8)
2415 clk |= MCI_CLK_WIDEBUS_8;
2416 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2417 clk |= MCI_CLK_WIDEBUS_4;
2418 else
2419 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002420
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002421 if (msmsdcc_is_pwrsave(host))
2422 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002423
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002424 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002425
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002426 host->tuning_needed = 0;
2427 /*
2428 * Select the controller timing mode according
2429 * to current bus speed mode
2430 */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302431 if (ios->timing == MMC_TIMING_UHS_SDR104) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002432 clk |= (4 << 14);
2433 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302434 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002435 clk |= (3 << 14);
2436 } else {
2437 clk |= (2 << 14); /* feedback clock */
2438 }
2439
2440 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2441 clk |= (2 << 23);
2442
Subhash Jadavani00083572012-02-15 16:18:01 +05302443 /* Clear IO_PAD_PWR_SWITCH while powering off the card */
2444 if (!ios->vdd)
2445 host->io_pad_pwr_switch = 0;
2446
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002447 if (host->io_pad_pwr_switch)
2448 clk |= IO_PAD_PWR_SWITCH;
2449
2450 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
San Mehat9d2bd732009-09-22 16:44:22 -07002451 pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002452 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2453 pwr |= msmsdcc_setup_vreg(host, !!ios->vdd);
San Mehat9d2bd732009-09-22 16:44:22 -07002454
2455 switch (ios->power_mode) {
2456 case MMC_POWER_OFF:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002457 htc_pwrsink_set(PWRSINK_SDCARD, 0);
2458 if (!host->sdcc_irq_disabled) {
2459 if (host->plat->cfg_mpm_sdiowakeup)
2460 host->plat->cfg_mpm_sdiowakeup(
2461 mmc_dev(mmc), SDC_DAT1_DISABLE);
2462 disable_irq(host->core_irqres->start);
2463 host->sdcc_irq_disabled = 1;
2464 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302465 /*
2466 * As VDD pad rail is always on, set low voltage for VDD
2467 * pad rail when slot is unused (when card is not present
2468 * or during system suspend).
2469 */
2470 msmsdcc_set_vddp_low_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002471 msmsdcc_setup_pins(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002472 break;
2473 case MMC_POWER_UP:
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302474 /* writing PWR_UP bit is redundant */
San Mehat9d2bd732009-09-22 16:44:22 -07002475 pwr |= MCI_PWR_UP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002476 if (host->sdcc_irq_disabled) {
2477 if (host->plat->cfg_mpm_sdiowakeup)
2478 host->plat->cfg_mpm_sdiowakeup(
2479 mmc_dev(mmc), SDC_DAT1_ENABLE);
2480 enable_irq(host->core_irqres->start);
2481 host->sdcc_irq_disabled = 0;
2482 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302483 msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002484 msmsdcc_setup_pins(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07002485 break;
2486 case MMC_POWER_ON:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002487 htc_pwrsink_set(PWRSINK_SDCARD, 100);
San Mehat9d2bd732009-09-22 16:44:22 -07002488 pwr |= MCI_PWR_ON;
2489 break;
2490 }
2491
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002492 spin_lock_irqsave(&host->lock, flags);
2493 if (!host->clks_on) {
2494 /* force the clocks to be on */
2495 msmsdcc_setup_clocks(host, true);
2496 /*
2497 * give atleast 2 MCLK cycles delay for clocks
2498 * and SDCC core to stabilize
2499 */
2500 msmsdcc_delay(host);
2501 }
2502 writel_relaxed(clk, host->base + MMCICLOCK);
2503 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002504
2505 if (host->pwr != pwr) {
2506 host->pwr = pwr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002507 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302508 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002509 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002510 if (!host->clks_on) {
2511 /* force the clocks to be off */
2512 msmsdcc_setup_clocks(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002513 }
2514
2515 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
2516 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2517 if (!host->plat->sdiowakeup_irq) {
2518 writel_relaxed(MCI_SDIOINTMASK,
2519 host->base + MMCIMASK0);
2520 mb();
2521 if (host->plat->cfg_mpm_sdiowakeup &&
2522 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2523 host->plat->cfg_mpm_sdiowakeup(
2524 mmc_dev(mmc), SDC_DAT1_ENWAKE);
2525 msmsdcc_enable_irq_wake(host);
2526 } else if (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2527 writel_relaxed(0, host->base + MMCIMASK0);
2528 } else {
2529 writel_relaxed(MCI_SDIOINTMASK,
2530 host->base + MMCIMASK0);
2531 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302532 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002533 }
2534 msmsdcc_setup_clocks(host, false);
2535 host->clks_on = 0;
2536 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302537
2538 if (host->cmd19_tuning_in_progress)
2539 WARN(!host->clks_on,
2540 "cmd19_tuning_in_progress but SDCC clocks are OFF\n");
2541
San Mehat4adbbcc2009-11-08 13:00:37 -08002542 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002543}
2544
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002545int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2546{
2547 struct msmsdcc_host *host = mmc_priv(mmc);
2548 u32 clk;
2549
2550 clk = readl_relaxed(host->base + MMCICLOCK);
2551 pr_debug("Changing to pwr_save=%d", pwrsave);
2552 if (pwrsave && msmsdcc_is_pwrsave(host))
2553 clk |= MCI_CLK_PWRSAVE;
2554 else
2555 clk &= ~MCI_CLK_PWRSAVE;
2556 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302557 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002558
2559 return 0;
2560}
2561
2562static int msmsdcc_get_ro(struct mmc_host *mmc)
2563{
2564 int status = -ENOSYS;
2565 struct msmsdcc_host *host = mmc_priv(mmc);
2566
2567 if (host->plat->wpswitch) {
2568 status = host->plat->wpswitch(mmc_dev(mmc));
2569 } else if (host->plat->wpswitch_gpio) {
2570 status = gpio_request(host->plat->wpswitch_gpio,
2571 "SD_WP_Switch");
2572 if (status) {
2573 pr_err("%s: %s: Failed to request GPIO %d\n",
2574 mmc_hostname(mmc), __func__,
2575 host->plat->wpswitch_gpio);
2576 } else {
2577 status = gpio_direction_input(
2578 host->plat->wpswitch_gpio);
2579 if (!status) {
2580 /*
2581 * Wait for atleast 300ms as debounce
2582 * time for GPIO input to stabilize.
2583 */
2584 msleep(300);
2585 status = gpio_get_value_cansleep(
2586 host->plat->wpswitch_gpio);
2587 status ^= !host->plat->wpswitch_polarity;
2588 }
2589 gpio_free(host->plat->wpswitch_gpio);
2590 }
2591 }
2592
2593 if (status < 0)
2594 status = -ENOSYS;
2595 pr_debug("%s: Card read-only status %d\n", __func__, status);
2596
2597 return status;
2598}
2599
2600#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002601static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2602{
2603 struct msmsdcc_host *host = mmc_priv(mmc);
2604 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002605
2606 if (enable) {
2607 spin_lock_irqsave(&host->lock, flags);
2608 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
2609 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
2610 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2611 spin_unlock_irqrestore(&host->lock, flags);
2612 } else {
2613 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
2614 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
2615 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2616 }
2617 mb();
2618}
2619#endif /* CONFIG_MMC_MSM_SDIO_SUPPORT */
2620
2621#ifdef CONFIG_PM_RUNTIME
2622static int msmsdcc_enable(struct mmc_host *mmc)
2623{
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302624 int rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002625 struct device *dev = mmc->parent;
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302626 struct msmsdcc_host *host = mmc_priv(mmc);
2627
2628 msmsdcc_pm_qos_update_latency(host, 1);
2629
2630 if (mmc->card && mmc_card_sdio(mmc->card) && host->is_resumed)
2631 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002632
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302633 if (dev->power.runtime_status == RPM_SUSPENDING) {
2634 if (mmc->suspend_task == current) {
2635 pm_runtime_get_noresume(dev);
2636 goto out;
2637 }
2638 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002639
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302640 rc = pm_runtime_get_sync(dev);
2641
2642 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002643 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2644 __func__, rc);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302645 return rc;
2646 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302647
2648 host->is_resumed = true;
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302649out:
2650 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002651}
2652
2653static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2654{
2655 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302656 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002657
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302658 msmsdcc_pm_qos_update_latency(host, 0);
2659
2660 if (mmc->card && mmc_card_sdio(mmc->card))
2661 return 0;
2662
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302663 if (host->plat->disable_runtime_pm)
2664 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002665
2666 rc = pm_runtime_put_sync(mmc->parent);
2667
2668 if (rc < 0)
2669 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2670 __func__, rc);
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302671 else
2672 host->is_resumed = false;
2673
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002674 return rc;
2675}
2676#else
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302677static int msmsdcc_enable(struct mmc_host *mmc)
2678{
2679 struct msmsdcc_host *host = mmc_priv(mmc);
2680 unsigned long flags;
2681
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302682 msmsdcc_pm_qos_update_latency(host, 1);
2683
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302684 spin_lock_irqsave(&host->lock, flags);
2685 if (!host->clks_on) {
2686 msmsdcc_setup_clocks(host, true);
2687 host->clks_on = 1;
2688 }
2689 spin_unlock_irqrestore(&host->lock, flags);
2690
2691 return 0;
2692}
2693
2694static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2695{
2696 struct msmsdcc_host *host = mmc_priv(mmc);
2697 unsigned long flags;
2698
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302699 msmsdcc_pm_qos_update_latency(host, 0);
2700
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302701 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302702 return 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302703
2704 spin_lock_irqsave(&host->lock, flags);
2705 if (host->clks_on) {
2706 msmsdcc_setup_clocks(host, false);
2707 host->clks_on = 0;
2708 }
2709 spin_unlock_irqrestore(&host->lock, flags);
2710
2711 return 0;
2712}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002713#endif
2714
2715static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2716 struct mmc_ios *ios)
2717{
2718 struct msmsdcc_host *host = mmc_priv(mmc);
2719 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302720 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002721
Subhash Jadavani00083572012-02-15 16:18:01 +05302722 spin_lock_irqsave(&host->lock, flags);
2723 host->io_pad_pwr_switch = 0;
2724 spin_unlock_irqrestore(&host->lock, flags);
2725
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002726 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2727 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302728 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002729 goto out;
2730 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2731 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302732 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002733 goto out;
2734 }
San Mehat9d2bd732009-09-22 16:44:22 -07002735
2736 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002737 /*
2738 * If we are here means voltage switch from high voltage to
2739 * low voltage is required
2740 */
2741
2742 /*
2743 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2744 * register until they become all zeros.
2745 */
2746 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302747 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002748 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2749 mmc_hostname(mmc), __func__);
2750 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002751 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002752
2753 /* Stop SD CLK output. */
2754 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2755 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302756 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002757 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002758
2759 /*
2760 * Switch VDDPX from high voltage to low voltage
2761 * to change the VDD of the SD IO pads.
2762 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302763 rc = msmsdcc_set_vddp_low_vol(host);
2764 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002765 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002766
2767 spin_lock_irqsave(&host->lock, flags);
2768 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2769 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302770 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002771 host->io_pad_pwr_switch = 1;
2772 spin_unlock_irqrestore(&host->lock, flags);
2773
2774 /* Wait 5 ms for the voltage regulater in the card to become stable. */
2775 usleep_range(5000, 5500);
2776
2777 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302778 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002779 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2780 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302781 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002782 spin_unlock_irqrestore(&host->lock, flags);
2783
2784 /*
2785 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
2786 * don't become all ones within 1 ms then a Voltage Switch
2787 * sequence has failed and a power cycle to the card is required.
2788 * Otherwise Voltage Switch sequence is completed successfully.
2789 */
2790 usleep_range(1000, 1500);
2791
2792 spin_lock_irqsave(&host->lock, flags);
2793 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
2794 != (0xF << 1)) {
2795 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
2796 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302797 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002798 goto out_unlock;
2799 }
2800
2801out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302802 /* Enable PWRSAVE */
2803 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2804 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002805 spin_unlock_irqrestore(&host->lock, flags);
2806out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302807 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002808}
2809
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302810static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002811{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002812 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002813
2814 /* Program the MCLK value to MCLK_FREQ bit field */
2815 if (host->clk_rate <= 112000000)
2816 mclk_freq = 0;
2817 else if (host->clk_rate <= 125000000)
2818 mclk_freq = 1;
2819 else if (host->clk_rate <= 137000000)
2820 mclk_freq = 2;
2821 else if (host->clk_rate <= 150000000)
2822 mclk_freq = 3;
2823 else if (host->clk_rate <= 162000000)
2824 mclk_freq = 4;
2825 else if (host->clk_rate <= 175000000)
2826 mclk_freq = 5;
2827 else if (host->clk_rate <= 187000000)
2828 mclk_freq = 6;
2829 else if (host->clk_rate <= 200000000)
2830 mclk_freq = 7;
2831
2832 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2833 & ~(7 << 24)) | (mclk_freq << 24)),
2834 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002835}
2836
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302837/* Initialize the DLL (Programmable Delay Line ) */
2838static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002839{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002840 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302841 unsigned long flags;
2842 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002843
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302844 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002845 /*
2846 * Make sure that clock is always enabled when DLL
2847 * tuning is in progress. Keeping PWRSAVE ON may
2848 * turn off the clock. So let's disable the PWRSAVE
2849 * here and re-enable it once tuning is completed.
2850 */
2851 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2852 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302853
2854 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
2855 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2856 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2857
2858 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
2859 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2860 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2861
2862 msmsdcc_cm_sdc4_dll_set_freq(host);
2863
2864 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
2865 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2866 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2867
2868 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
2869 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2870 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2871
2872 /* Set DLL_EN bit to 1. */
2873 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2874 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
2875
2876 /* Set CK_OUT_EN bit to 1. */
2877 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2878 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2879
2880 wait_cnt = 50;
2881 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
2882 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
2883 /* max. wait for 50us sec for LOCK bit to be set */
2884 if (--wait_cnt == 0) {
2885 pr_err("%s: %s: DLL failed to LOCK\n",
2886 mmc_hostname(host->mmc), __func__);
2887 rc = -ETIMEDOUT;
2888 goto out;
2889 }
2890 /* wait for 1us before polling again */
2891 udelay(1);
2892 }
2893
2894out:
2895 /* re-enable PWRSAVE */
2896 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2897 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2898 spin_unlock_irqrestore(&host->lock, flags);
2899
2900 return rc;
2901}
2902
2903static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
2904 u8 poll)
2905{
2906 int rc = 0;
2907 u32 wait_cnt = 50;
2908 u8 ck_out_en = 0;
2909
2910 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
2911 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
2912 MCI_CK_OUT_EN);
2913
2914 while (ck_out_en != poll) {
2915 if (--wait_cnt == 0) {
2916 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
2917 mmc_hostname(host->mmc), __func__, poll);
2918 rc = -ETIMEDOUT;
2919 goto out;
2920 }
2921 udelay(1);
2922
2923 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
2924 MCI_CK_OUT_EN);
2925 }
2926out:
2927 return rc;
2928}
2929
2930/*
2931 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
2932 * calibration sequence. This function should be called before
2933 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
2934 * commands (CMD17/CMD18).
2935 *
2936 * This function gets called when host spinlock acquired.
2937 */
2938static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
2939{
2940 int rc = 0;
2941 u32 config;
2942
2943 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
2944 config |= MCI_CDR_EN;
2945 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
2946 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
2947
2948 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2949 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
2950 if (rc)
2951 goto err_out;
2952
2953 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2954 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2955 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2956
2957 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
2958 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
2959 if (rc)
2960 goto err_out;
2961
2962 goto out;
2963
2964err_out:
2965 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
2966out:
2967 return rc;
2968}
2969
2970static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2971 u8 phase)
2972{
2973 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05302974 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
2975 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
2976 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302977 unsigned long flags;
2978 u32 config;
2979
2980 spin_lock_irqsave(&host->lock, flags);
2981
2982 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
2983 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
2984 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
2985 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
2986
2987 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2988 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
2989 if (rc)
2990 goto err_out;
2991
2992 /*
2993 * Write the selected DLL clock output phase (0 ... 15)
2994 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
2995 */
2996 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2997 & ~(0xF << 20))
2998 | (grey_coded_phase_table[phase] << 20)),
2999 host->base + MCI_DLL_CONFIG);
3000
3001 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3002 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3003 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3004
3005 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3006 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3007 if (rc)
3008 goto err_out;
3009
3010 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3011 config |= MCI_CDR_EN;
3012 config &= ~MCI_CDR_EXT_EN;
3013 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3014 goto out;
3015
3016err_out:
3017 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3018 mmc_hostname(host->mmc), __func__, phase);
3019out:
3020 spin_unlock_irqrestore(&host->lock, flags);
3021 return rc;
3022}
3023
3024/*
3025 * Find out the greatest range of consecuitive selected
3026 * DLL clock output phases that can be used as sampling
3027 * setting for SD3.0 UHS-I card read operation (in SDR104
3028 * timing mode) or for eMMC4.5 card read operation (in HS200
3029 * timing mode).
3030 * Select the 3/4 of the range and configure the DLL with the
3031 * selected DLL clock output phase.
3032*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303033static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303034 u8 *phase_table, u8 total_phases)
3035{
Subhash Jadavani34187042012-03-02 10:59:49 +05303036 int ret;
3037 u8 ranges[16][16] = { {0}, {0} };
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303038 u8 phases_per_row[16] = {0};
3039 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303040 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3041 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303042
Subhash Jadavani34187042012-03-02 10:59:49 +05303043 if (total_phases > 16) {
3044 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3045 mmc_hostname(host->mmc), __func__, total_phases);
3046 return -EINVAL;
3047 }
3048
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303049 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303050 ranges[row_index][col_index] = phase_table[cnt];
3051 phases_per_row[row_index] += 1;
3052 col_index++;
3053
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303054 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303055 continue;
3056 /* check if next phase in phase_table is consecutive or not */
3057 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3058 row_index++;
3059 col_index = 0;
3060 }
3061 }
3062
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303063 /* Check if phase-0 is present in first valid window? */
3064 if (!ranges[0][0]) {
3065 phase_0_found = true;
3066 phase_0_raw_index = 0;
3067 /* Check if cycle exist between 2 valid windows */
3068 for (cnt = 1; cnt <= row_index; cnt++) {
3069 if (phases_per_row[cnt]) {
3070 for (i = 0; i <= phases_per_row[cnt]; i++) {
3071 if (ranges[cnt][i] == 15) {
3072 phase_15_found = true;
3073 phase_15_raw_index = cnt;
3074 break;
3075 }
3076 }
3077 }
3078 }
3079 }
3080
3081 /* If 2 valid windows form cycle then merge them as single window */
3082 if (phase_0_found && phase_15_found) {
3083 /* number of phases in raw where phase 0 is present */
3084 u8 phases_0 = phases_per_row[phase_0_raw_index];
3085 /* number of phases in raw where phase 15 is present */
3086 u8 phases_15 = phases_per_row[phase_15_raw_index];
3087
3088 cnt = 0;
3089 for (i = phases_15; i < (phases_15 + phases_0); i++) {
3090 ranges[phase_15_raw_index][i] =
3091 ranges[phase_0_raw_index][cnt];
3092 cnt++;
3093 }
3094 phases_per_row[phase_0_raw_index] = 0;
3095 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
3096 }
3097
3098 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303099 if (phases_per_row[cnt] > curr_max) {
3100 curr_max = phases_per_row[cnt];
3101 selected_row_index = cnt;
3102 }
3103 }
3104
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303105 i = ((curr_max * 3) / 4) - 1;
Subhash Jadavani34187042012-03-02 10:59:49 +05303106 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303107
3108 return ret;
3109}
3110
Girish K Sa3f41692012-02-29 12:00:09 +05303111static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303112{
3113 int rc = 0;
3114 struct msmsdcc_host *host = mmc_priv(mmc);
3115 unsigned long flags;
3116 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
3117
3118 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
3119
3120 /* Tuning is only required for SDR104 modes */
3121 if (!host->tuning_needed) {
3122 rc = 0;
3123 goto exit;
3124 }
3125
3126 spin_lock_irqsave(&host->lock, flags);
3127 WARN(!host->pwr, "SDCC power is turned off\n");
3128 WARN(!host->clks_on, "SDCC clocks are turned off\n");
3129 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
3130
3131 host->cmd19_tuning_in_progress = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05303132 msmsdcc_delay(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303133 spin_unlock_irqrestore(&host->lock, flags);
3134
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003135 /* first of all reset the tuning block */
3136 rc = msmsdcc_init_cm_sdc4_dll(host);
3137 if (rc)
3138 goto out;
3139
3140 data_buf = kmalloc(64, GFP_KERNEL);
3141 if (!data_buf) {
3142 rc = -ENOMEM;
3143 goto out;
3144 }
3145
3146 phase = 0;
3147 do {
3148 struct mmc_command cmd = {0};
3149 struct mmc_data data = {0};
3150 struct mmc_request mrq = {
3151 .cmd = &cmd,
3152 .data = &data
3153 };
3154 struct scatterlist sg;
3155
3156 /* set the phase in delay line hw block */
3157 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3158 if (rc)
3159 goto kfree;
3160
3161 cmd.opcode = MMC_SEND_TUNING_BLOCK;
3162 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
3163
3164 data.blksz = 64;
3165 data.blocks = 1;
3166 data.flags = MMC_DATA_READ;
3167 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
3168
3169 data.sg = &sg;
3170 data.sg_len = 1;
3171 sg_init_one(&sg, data_buf, 64);
3172 memset(data_buf, 0, 64);
3173 mmc_wait_for_req(mmc, &mrq);
3174
3175 if (!cmd.error && !data.error &&
3176 !memcmp(data_buf, cmd19_tuning_block, 64)) {
3177 /* tuning is successful with this tuning point */
3178 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303179 pr_debug("%s: %s: found good phase = %d\n",
3180 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003181 }
3182 } while (++phase < 16);
3183
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003184 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303185 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303186 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05303187 if (rc < 0)
3188 goto kfree;
3189 else
3190 phase = (u8)rc;
3191
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003192 /*
3193 * Finally set the selected phase in delay
3194 * line hw block.
3195 */
3196 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3197 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303198 goto kfree;
3199 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
3200 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003201 } else {
3202 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303203 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003204 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303205 msmsdcc_dump_sdcc_state(host);
3206 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003207 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003208
3209kfree:
3210 kfree(data_buf);
3211out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303212 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05303213 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003214 host->cmd19_tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303215 spin_unlock_irqrestore(&host->lock, flags);
3216exit:
3217 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003218 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07003219}
3220
3221static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003222 .enable = msmsdcc_enable,
3223 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07003224 .request = msmsdcc_request,
3225 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003226 .get_ro = msmsdcc_get_ro,
3227#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07003228 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003229#endif
3230 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
3231 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07003232};
3233
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003234static unsigned int
3235msmsdcc_slot_status(struct msmsdcc_host *host)
3236{
3237 int status;
3238 unsigned int gpio_no = host->plat->status_gpio;
3239
3240 status = gpio_request(gpio_no, "SD_HW_Detect");
3241 if (status) {
3242 pr_err("%s: %s: Failed to request GPIO %d\n",
3243 mmc_hostname(host->mmc), __func__, gpio_no);
3244 } else {
3245 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003246 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08003247 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003248 if (host->plat->is_status_gpio_active_low)
3249 status = !status;
3250 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003251 gpio_free(gpio_no);
3252 }
3253 return status;
3254}
3255
San Mehat9d2bd732009-09-22 16:44:22 -07003256static void
3257msmsdcc_check_status(unsigned long data)
3258{
3259 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3260 unsigned int status;
3261
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003262 if (host->plat->status || host->plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08003263 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003264 status = host->plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08003265 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003266 status = msmsdcc_slot_status(host);
3267
Krishna Konda941604a2012-01-10 17:46:34 -08003268 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08003269
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003270 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08003271 if (host->plat->status)
3272 pr_info("%s: Slot status change detected "
3273 "(%d -> %d)\n",
3274 mmc_hostname(host->mmc),
3275 host->oldstat, status);
3276 else if (host->plat->is_status_gpio_active_low)
3277 pr_info("%s: Slot status change detected "
3278 "(%d -> %d) and the card detect GPIO"
3279 " is ACTIVE_LOW\n",
3280 mmc_hostname(host->mmc),
3281 host->oldstat, status);
3282 else
3283 pr_info("%s: Slot status change detected "
3284 "(%d -> %d) and the card detect GPIO"
3285 " is ACTIVE_HIGH\n",
3286 mmc_hostname(host->mmc),
3287 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07003288 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003289 }
3290 host->oldstat = status;
3291 } else {
3292 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07003293 }
San Mehat9d2bd732009-09-22 16:44:22 -07003294}
3295
3296static irqreturn_t
3297msmsdcc_platform_status_irq(int irq, void *dev_id)
3298{
3299 struct msmsdcc_host *host = dev_id;
3300
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003301 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07003302 msmsdcc_check_status((unsigned long) host);
3303 return IRQ_HANDLED;
3304}
3305
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003306static irqreturn_t
3307msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
3308{
3309 struct msmsdcc_host *host = dev_id;
3310
3311 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
3312 spin_lock(&host->lock);
3313 if (!host->sdio_irq_disabled) {
3314 disable_irq_nosync(irq);
3315 if (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
3316 wake_lock(&host->sdio_wlock);
3317 msmsdcc_disable_irq_wake(host);
3318 }
3319 host->sdio_irq_disabled = 1;
3320 }
3321 if (host->plat->is_sdio_al_client) {
3322 if (!host->clks_on) {
3323 msmsdcc_setup_clocks(host, true);
3324 host->clks_on = 1;
3325 }
3326 if (host->sdcc_irq_disabled) {
3327 writel_relaxed(host->mci_irqenable,
3328 host->base + MMCIMASK0);
3329 mb();
3330 enable_irq(host->core_irqres->start);
3331 host->sdcc_irq_disabled = 0;
3332 }
3333 wake_lock(&host->sdio_wlock);
3334 }
3335 spin_unlock(&host->lock);
3336
3337 return IRQ_HANDLED;
3338}
3339
San Mehat9d2bd732009-09-22 16:44:22 -07003340static void
3341msmsdcc_status_notify_cb(int card_present, void *dev_id)
3342{
3343 struct msmsdcc_host *host = dev_id;
3344
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003345 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07003346 card_present);
3347 msmsdcc_check_status((unsigned long) host);
3348}
3349
San Mehat9d2bd732009-09-22 16:44:22 -07003350static int
3351msmsdcc_init_dma(struct msmsdcc_host *host)
3352{
3353 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
3354 host->dma.host = host;
3355 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003356 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003357
3358 if (!host->dmares)
3359 return -ENODEV;
3360
3361 host->dma.nc = dma_alloc_coherent(NULL,
3362 sizeof(struct msmsdcc_nc_dmadata),
3363 &host->dma.nc_busaddr,
3364 GFP_KERNEL);
3365 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003366 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07003367 return -ENOMEM;
3368 }
3369 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
3370 host->dma.cmd_busaddr = host->dma.nc_busaddr;
3371 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
3372 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
3373 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07003374 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07003375
3376 return 0;
3377}
3378
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003379#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
3380/**
3381 * Allocate and Connect a SDCC peripheral's SPS endpoint
3382 *
3383 * This function allocates endpoint context and
3384 * connect it with memory endpoint by calling
3385 * appropriate SPS driver APIs.
3386 *
3387 * Also registers a SPS callback function with
3388 * SPS driver
3389 *
3390 * This function should only be called once typically
3391 * during driver probe.
3392 *
3393 * @host - Pointer to sdcc host structure
3394 * @ep - Pointer to sps endpoint data structure
3395 * @is_produce - 1 means Producer endpoint
3396 * 0 means Consumer endpoint
3397 *
3398 * @return - 0 if successful else negative value.
3399 *
3400 */
3401static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
3402 struct msmsdcc_sps_ep_conn_data *ep,
3403 bool is_producer)
3404{
3405 int rc = 0;
3406 struct sps_pipe *sps_pipe_handle;
3407 struct sps_connect *sps_config = &ep->config;
3408 struct sps_register_event *sps_event = &ep->event;
3409
3410 /* Allocate endpoint context */
3411 sps_pipe_handle = sps_alloc_endpoint();
3412 if (!sps_pipe_handle) {
3413 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
3414 mmc_hostname(host->mmc), is_producer);
3415 rc = -ENOMEM;
3416 goto out;
3417 }
3418
3419 /* Get default connection configuration for an endpoint */
3420 rc = sps_get_config(sps_pipe_handle, sps_config);
3421 if (rc) {
3422 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
3423 " rc=%d", mmc_hostname(host->mmc),
3424 (u32)sps_pipe_handle, rc);
3425 goto get_config_err;
3426 }
3427
3428 /* Modify the default connection configuration */
3429 if (is_producer) {
3430 /*
3431 * For SDCC producer transfer, source should be
3432 * SDCC peripheral where as destination should
3433 * be system memory.
3434 */
3435 sps_config->source = host->sps.bam_handle;
3436 sps_config->destination = SPS_DEV_HANDLE_MEM;
3437 /* Producer pipe will handle this connection */
3438 sps_config->mode = SPS_MODE_SRC;
3439 sps_config->options =
3440 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3441 } else {
3442 /*
3443 * For SDCC consumer transfer, source should be
3444 * system memory where as destination should
3445 * SDCC peripheral
3446 */
3447 sps_config->source = SPS_DEV_HANDLE_MEM;
3448 sps_config->destination = host->sps.bam_handle;
3449 sps_config->mode = SPS_MODE_DEST;
3450 sps_config->options =
3451 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3452 }
3453
3454 /* Producer pipe index */
3455 sps_config->src_pipe_index = host->sps.src_pipe_index;
3456 /* Consumer pipe index */
3457 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
3458 /*
3459 * This event thresold value is only significant for BAM-to-BAM
3460 * transfer. It's ignored for BAM-to-System mode transfer.
3461 */
3462 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05303463
3464 /* Allocate maximum descriptor fifo size */
3465 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
3466 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003467 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
3468 sps_config->desc.size,
3469 &sps_config->desc.phys_base,
3470 GFP_KERNEL);
3471
Pratibhasagar V00b94332011-10-18 14:57:27 +05303472 if (!sps_config->desc.base) {
3473 rc = -ENOMEM;
3474 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3475 , mmc_hostname(host->mmc));
3476 goto get_config_err;
3477 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003478 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3479
3480 /* Establish connection between peripheral and memory endpoint */
3481 rc = sps_connect(sps_pipe_handle, sps_config);
3482 if (rc) {
3483 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3484 " rc=%d", mmc_hostname(host->mmc),
3485 (u32)sps_pipe_handle, rc);
3486 goto sps_connect_err;
3487 }
3488
3489 sps_event->mode = SPS_TRIGGER_CALLBACK;
3490 sps_event->options = SPS_O_EOT;
3491 sps_event->callback = msmsdcc_sps_complete_cb;
3492 sps_event->xfer_done = NULL;
3493 sps_event->user = (void *)host;
3494
3495 /* Register callback event for EOT (End of transfer) event. */
3496 rc = sps_register_event(sps_pipe_handle, sps_event);
3497 if (rc) {
3498 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3499 " rc=%d", mmc_hostname(host->mmc),
3500 (u32)sps_pipe_handle, rc);
3501 goto reg_event_err;
3502 }
3503 /* Now save the sps pipe handle */
3504 ep->pipe_handle = sps_pipe_handle;
3505 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3506 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3507 __func__, is_producer ? "READ" : "WRITE",
3508 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3509 goto out;
3510
3511reg_event_err:
3512 sps_disconnect(sps_pipe_handle);
3513sps_connect_err:
3514 dma_free_coherent(mmc_dev(host->mmc),
3515 sps_config->desc.size,
3516 sps_config->desc.base,
3517 sps_config->desc.phys_base);
3518get_config_err:
3519 sps_free_endpoint(sps_pipe_handle);
3520out:
3521 return rc;
3522}
3523
3524/**
3525 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3526 *
3527 * This function disconnect endpoint and deallocates
3528 * endpoint context.
3529 *
3530 * This function should only be called once typically
3531 * during driver remove.
3532 *
3533 * @host - Pointer to sdcc host structure
3534 * @ep - Pointer to sps endpoint data structure
3535 *
3536 */
3537static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3538 struct msmsdcc_sps_ep_conn_data *ep)
3539{
3540 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3541 struct sps_connect *sps_config = &ep->config;
3542 struct sps_register_event *sps_event = &ep->event;
3543
3544 sps_event->xfer_done = NULL;
3545 sps_event->callback = NULL;
3546 sps_register_event(sps_pipe_handle, sps_event);
3547 sps_disconnect(sps_pipe_handle);
3548 dma_free_coherent(mmc_dev(host->mmc),
3549 sps_config->desc.size,
3550 sps_config->desc.base,
3551 sps_config->desc.phys_base);
3552 sps_free_endpoint(sps_pipe_handle);
3553}
3554
3555/**
3556 * Reset SDCC peripheral's SPS endpoint
3557 *
3558 * This function disconnects an endpoint.
3559 *
3560 * This function should be called for reseting
3561 * SPS endpoint when data transfer error is
3562 * encountered during data transfer. This
3563 * can be considered as soft reset to endpoint.
3564 *
3565 * This function should only be called if
3566 * msmsdcc_sps_init() is already called.
3567 *
3568 * @host - Pointer to sdcc host structure
3569 * @ep - Pointer to sps endpoint data structure
3570 *
3571 * @return - 0 if successful else negative value.
3572 */
3573static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3574 struct msmsdcc_sps_ep_conn_data *ep)
3575{
3576 int rc = 0;
3577 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3578
3579 rc = sps_disconnect(sps_pipe_handle);
3580 if (rc) {
3581 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3582 " rc=%d", mmc_hostname(host->mmc), __func__,
3583 (u32)sps_pipe_handle, rc);
3584 goto out;
3585 }
3586 out:
3587 return rc;
3588}
3589
3590/**
3591 * Restore SDCC peripheral's SPS endpoint
3592 *
3593 * This function connects an endpoint.
3594 *
3595 * This function should be called for restoring
3596 * SPS endpoint after data transfer error is
3597 * encountered during data transfer. This
3598 * can be considered as soft reset to endpoint.
3599 *
3600 * This function should only be called if
3601 * msmsdcc_sps_reset_ep() is called before.
3602 *
3603 * @host - Pointer to sdcc host structure
3604 * @ep - Pointer to sps endpoint data structure
3605 *
3606 * @return - 0 if successful else negative value.
3607 */
3608static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3609 struct msmsdcc_sps_ep_conn_data *ep)
3610{
3611 int rc = 0;
3612 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3613 struct sps_connect *sps_config = &ep->config;
3614 struct sps_register_event *sps_event = &ep->event;
3615
3616 /* Establish connection between peripheral and memory endpoint */
3617 rc = sps_connect(sps_pipe_handle, sps_config);
3618 if (rc) {
3619 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3620 " rc=%d", mmc_hostname(host->mmc), __func__,
3621 (u32)sps_pipe_handle, rc);
3622 goto out;
3623 }
3624
3625 /* Register callback event for EOT (End of transfer) event. */
3626 rc = sps_register_event(sps_pipe_handle, sps_event);
3627 if (rc) {
3628 pr_err("%s: %s: sps_register_event() failed!!!"
3629 " pipe_handle=0x%x, rc=%d",
3630 mmc_hostname(host->mmc), __func__,
3631 (u32)sps_pipe_handle, rc);
3632 goto reg_event_err;
3633 }
3634 goto out;
3635
3636reg_event_err:
3637 sps_disconnect(sps_pipe_handle);
3638out:
3639 return rc;
3640}
3641
3642/**
3643 * Initialize SPS HW connected with SDCC core
3644 *
3645 * This function register BAM HW resources with
3646 * SPS driver and then initialize 2 SPS endpoints
3647 *
3648 * This function should only be called once typically
3649 * during driver probe.
3650 *
3651 * @host - Pointer to sdcc host structure
3652 *
3653 * @return - 0 if successful else negative value.
3654 *
3655 */
3656static int msmsdcc_sps_init(struct msmsdcc_host *host)
3657{
3658 int rc = 0;
3659 struct sps_bam_props bam = {0};
3660
3661 host->bam_base = ioremap(host->bam_memres->start,
3662 resource_size(host->bam_memres));
3663 if (!host->bam_base) {
3664 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3665 " size=0x%x", mmc_hostname(host->mmc),
3666 host->bam_memres->start,
3667 (host->bam_memres->end -
3668 host->bam_memres->start));
3669 rc = -ENOMEM;
3670 goto out;
3671 }
3672
3673 bam.phys_addr = host->bam_memres->start;
3674 bam.virt_addr = host->bam_base;
3675 /*
3676 * This event thresold value is only significant for BAM-to-BAM
3677 * transfer. It's ignored for BAM-to-System mode transfer.
3678 */
3679 bam.event_threshold = 0x10; /* Pipe event threshold */
3680 /*
3681 * This threshold controls when the BAM publish
3682 * the descriptor size on the sideband interface.
3683 * SPS HW will only be used when
3684 * data transfer size > MCI_FIFOSIZE (64 bytes).
3685 * PIO mode will be used when
3686 * data transfer size < MCI_FIFOSIZE (64 bytes).
3687 * So set this thresold value to 64 bytes.
3688 */
3689 bam.summing_threshold = 64;
3690 /* SPS driver wll handle the SDCC BAM IRQ */
3691 bam.irq = (u32)host->bam_irqres->start;
3692 bam.manage = SPS_BAM_MGR_LOCAL;
3693
3694 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3695 (u32)bam.phys_addr);
3696 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3697 (u32)bam.virt_addr);
3698
3699 /* Register SDCC Peripheral BAM device to SPS driver */
3700 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3701 if (rc) {
3702 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3703 mmc_hostname(host->mmc), rc);
3704 goto reg_bam_err;
3705 }
3706 pr_info("%s: BAM device registered. bam_handle=0x%x",
3707 mmc_hostname(host->mmc), host->sps.bam_handle);
3708
3709 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3710 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3711
3712 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3713 SPS_PROD_PERIPHERAL);
3714 if (rc)
3715 goto sps_reset_err;
3716 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3717 SPS_CONS_PERIPHERAL);
3718 if (rc)
3719 goto cons_conn_err;
3720
3721 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3722 mmc_hostname(host->mmc),
3723 (unsigned long long)host->bam_memres->start,
3724 (unsigned int)host->bam_irqres->start);
3725 goto out;
3726
3727cons_conn_err:
3728 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3729sps_reset_err:
3730 sps_deregister_bam_device(host->sps.bam_handle);
3731reg_bam_err:
3732 iounmap(host->bam_base);
3733out:
3734 return rc;
3735}
3736
3737/**
3738 * De-initialize SPS HW connected with SDCC core
3739 *
3740 * This function deinitialize SPS endpoints and then
3741 * deregisters BAM resources from SPS driver.
3742 *
3743 * This function should only be called once typically
3744 * during driver remove.
3745 *
3746 * @host - Pointer to sdcc host structure
3747 *
3748 */
3749static void msmsdcc_sps_exit(struct msmsdcc_host *host)
3750{
3751 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
3752 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3753 sps_deregister_bam_device(host->sps.bam_handle);
3754 iounmap(host->bam_base);
3755}
3756#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
3757
3758static ssize_t
3759show_polling(struct device *dev, struct device_attribute *attr, char *buf)
3760{
3761 struct mmc_host *mmc = dev_get_drvdata(dev);
3762 struct msmsdcc_host *host = mmc_priv(mmc);
3763 int poll;
3764 unsigned long flags;
3765
3766 spin_lock_irqsave(&host->lock, flags);
3767 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
3768 spin_unlock_irqrestore(&host->lock, flags);
3769
3770 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
3771}
3772
3773static ssize_t
3774set_polling(struct device *dev, struct device_attribute *attr,
3775 const char *buf, size_t count)
3776{
3777 struct mmc_host *mmc = dev_get_drvdata(dev);
3778 struct msmsdcc_host *host = mmc_priv(mmc);
3779 int value;
3780 unsigned long flags;
3781
3782 sscanf(buf, "%d", &value);
3783
3784 spin_lock_irqsave(&host->lock, flags);
3785 if (value) {
3786 mmc->caps |= MMC_CAP_NEEDS_POLL;
3787 mmc_detect_change(host->mmc, 0);
3788 } else {
3789 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3790 }
3791#ifdef CONFIG_HAS_EARLYSUSPEND
3792 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
3793#endif
3794 spin_unlock_irqrestore(&host->lock, flags);
3795 return count;
3796}
3797
3798static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
3799 show_polling, set_polling);
3800static struct attribute *dev_attrs[] = {
3801 &dev_attr_polling.attr,
3802 NULL,
3803};
3804static struct attribute_group dev_attr_grp = {
3805 .attrs = dev_attrs,
3806};
3807
3808#ifdef CONFIG_HAS_EARLYSUSPEND
3809static void msmsdcc_early_suspend(struct early_suspend *h)
3810{
3811 struct msmsdcc_host *host =
3812 container_of(h, struct msmsdcc_host, early_suspend);
3813 unsigned long flags;
3814
3815 spin_lock_irqsave(&host->lock, flags);
3816 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
3817 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3818 spin_unlock_irqrestore(&host->lock, flags);
3819};
3820static void msmsdcc_late_resume(struct early_suspend *h)
3821{
3822 struct msmsdcc_host *host =
3823 container_of(h, struct msmsdcc_host, early_suspend);
3824 unsigned long flags;
3825
3826 if (host->polling_enabled) {
3827 spin_lock_irqsave(&host->lock, flags);
3828 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
3829 mmc_detect_change(host->mmc, 0);
3830 spin_unlock_irqrestore(&host->lock, flags);
3831 }
3832};
3833#endif
3834
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303835void msmsdcc_print_regs(const char *name, void __iomem *base,
3836 unsigned int no_of_regs)
3837{
3838 unsigned int i;
3839
3840 if (!base)
3841 return;
3842 pr_info("===== %s: Register Dumps @base=0x%x =====\n",
3843 name, (u32)base);
3844 for (i = 0; i < no_of_regs; i = i + 4) {
3845 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x.\n", i*4,
3846 (u32)readl_relaxed(base + i*4),
3847 (u32)readl_relaxed(base + ((i+1)*4)),
3848 (u32)readl_relaxed(base + ((i+2)*4)),
3849 (u32)readl_relaxed(base + ((i+3)*4)));
3850 }
3851}
3852
3853static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
3854{
3855 /* Dump current state of SDCC clocks, power and irq */
3856 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
3857 (host->pwr ? "ON" : "OFF"));
3858 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
3859 mmc_hostname(host->mmc),
3860 (host->clks_on ? "ON" : "OFF"),
3861 (u32)clk_get_rate(host->clk));
3862 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
3863 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
3864
3865 /* Now dump SDCC registers. Don't print FIFO registers */
3866 if (host->clks_on)
3867 msmsdcc_print_regs("SDCC-CORE", host->base, 28);
3868
3869 if (host->curr.data) {
3870 if (msmsdcc_check_dma_op_req(host->curr.data))
3871 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
3872 else if (host->is_dma_mode)
3873 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
3874 mmc_hostname(host->mmc), host->dma.busy,
3875 host->dma.channel, host->dma.crci);
3876 else if (host->is_sps_mode)
3877 pr_info("%s: SPS mode: busy=%d\n",
3878 mmc_hostname(host->mmc), host->sps.busy);
3879
3880 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
3881 mmc_hostname(host->mmc), host->curr.xfer_size,
3882 host->curr.data_xfered, host->curr.xfer_remain);
3883 pr_info("%s: got_dataend=%d, prog_enable=%d,"
3884 " wait_for_auto_prog_done=%d,"
3885 " got_auto_prog_done=%d\n",
3886 mmc_hostname(host->mmc), host->curr.got_dataend,
3887 host->prog_enable, host->curr.wait_for_auto_prog_done,
3888 host->curr.got_auto_prog_done);
3889 }
3890
3891}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003892static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
3893{
3894 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3895 struct mmc_request *mrq;
3896 unsigned long flags;
3897
3898 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003899 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003900 pr_info("%s: %s: dummy CMD52 timeout\n",
3901 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003902 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003903 }
3904
3905 mrq = host->curr.mrq;
3906
3907 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303908 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
3909 mrq->cmd->opcode);
3910 msmsdcc_dump_sdcc_state(host);
3911
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003912 if (!mrq->cmd->error)
3913 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303914 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003915 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003916 if (mrq->data && !mrq->data->error)
3917 mrq->data->error = -ETIMEDOUT;
3918 host->curr.data_xfered = 0;
3919 if (host->dma.sg && host->is_dma_mode) {
3920 msm_dmov_stop_cmd(host->dma.channel,
3921 &host->dma.hdr, 0);
3922 } else if (host->sps.sg && host->is_sps_mode) {
3923 /* Stop current SPS transfer */
3924 msmsdcc_sps_exit_curr_xfer(host);
3925 } else {
3926 msmsdcc_reset_and_restore(host);
3927 msmsdcc_stop_data(host);
3928 if (mrq->data && mrq->data->stop)
3929 msmsdcc_start_command(host,
3930 mrq->data->stop, 0);
3931 else
3932 msmsdcc_request_end(host, mrq);
3933 }
3934 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05303935 host->prog_enable = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003936 msmsdcc_reset_and_restore(host);
3937 msmsdcc_request_end(host, mrq);
3938 }
3939 }
3940 spin_unlock_irqrestore(&host->lock, flags);
3941}
3942
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303943static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
3944{
3945 int i, ret;
3946 struct mmc_platform_data *pdata;
3947 struct device_node *np = dev->of_node;
3948 u32 bus_width = 0;
3949 u32 *clk_table;
3950 int clk_table_len;
3951 u32 *sup_voltages;
3952 int sup_volt_len;
3953
3954 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
3955 if (!pdata) {
3956 dev_err(dev, "could not allocate memory for platform data\n");
3957 goto err;
3958 }
3959
3960 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
3961 if (bus_width == 8) {
3962 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
3963 } else if (bus_width == 4) {
3964 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
3965 } else {
3966 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
3967 pdata->mmc_bus_width = 0;
3968 }
3969
3970 if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
3971 size_t sz;
3972 sz = sup_volt_len / sizeof(*sup_voltages);
3973 if (sz > 0) {
3974 sup_voltages = devm_kzalloc(dev,
3975 sz * sizeof(*sup_voltages), GFP_KERNEL);
3976 if (!sup_voltages) {
3977 dev_err(dev, "No memory for supported voltage\n");
3978 goto err;
3979 }
3980
3981 ret = of_property_read_u32_array(np,
3982 "qcom,sdcc-sup-voltages", sup_voltages, sz);
3983 if (ret < 0) {
3984 dev_err(dev, "error while reading voltage"
3985 "ranges %d\n", ret);
3986 goto err;
3987 }
3988 } else {
3989 dev_err(dev, "No supported voltages\n");
3990 goto err;
3991 }
3992 for (i = 0; i < sz; i += 2) {
3993 u32 mask;
3994
3995 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
3996 sup_voltages[i + 1]);
3997 if (!mask)
3998 dev_err(dev, "Invalide voltage range %d\n", i);
3999 pdata->ocr_mask |= mask;
4000 }
4001 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
4002 } else {
4003 dev_err(dev, "Supported voltage range not specified\n");
4004 }
4005
4006 if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
4007 size_t sz;
4008 sz = clk_table_len / sizeof(*clk_table);
4009
4010 if (sz > 0) {
4011 clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
4012 GFP_KERNEL);
4013 if (!clk_table) {
4014 dev_err(dev, "No memory for clock table\n");
4015 goto err;
4016 }
4017
4018 ret = of_property_read_u32_array(np,
4019 "qcom,sdcc-clk-rates", clk_table, sz);
4020 if (ret < 0) {
4021 dev_err(dev, "error while reading clk"
4022 "table %d\n", ret);
4023 goto err;
4024 }
4025 } else {
4026 dev_err(dev, "clk_table not specified\n");
4027 goto err;
4028 }
4029 pdata->sup_clk_table = clk_table;
4030 pdata->sup_clk_cnt = sz;
4031 } else {
4032 dev_err(dev, "Supported clock rates not specified\n");
4033 }
4034
4035 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
4036 pdata->nonremovable = true;
4037 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
4038 pdata->disable_cmd23 = true;
4039
4040 return pdata;
4041err:
4042 return NULL;
4043}
4044
San Mehat9d2bd732009-09-22 16:44:22 -07004045static int
4046msmsdcc_probe(struct platform_device *pdev)
4047{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304048 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07004049 struct msmsdcc_host *host;
4050 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004051 unsigned long flags;
4052 struct resource *core_irqres = NULL;
4053 struct resource *bam_irqres = NULL;
4054 struct resource *core_memres = NULL;
4055 struct resource *dml_memres = NULL;
4056 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07004057 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07004058 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05304059 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004060 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07004061
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304062 if (pdev->dev.of_node) {
4063 plat = msmsdcc_populate_pdata(&pdev->dev);
4064 of_property_read_u32((&pdev->dev)->of_node,
4065 "cell-index", &pdev->id);
4066 } else {
4067 plat = pdev->dev.platform_data;
4068 }
4069
San Mehat9d2bd732009-09-22 16:44:22 -07004070 /* must have platform data */
4071 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004072 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004073 ret = -EINVAL;
4074 goto out;
4075 }
4076
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004077 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07004078 return -EINVAL;
4079
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304080 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
4081 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
4082 return -EINVAL;
4083 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004084
San Mehat9d2bd732009-09-22 16:44:22 -07004085 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004086 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004087 return -ENXIO;
4088 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304089 if (pdev->dev.of_node) {
4090 /*
4091 * Device tree iomem resources are only accessible by index.
4092 * index = 0 -> SDCC register interface
4093 * index = 1 -> DML register interface
4094 * index = 2 -> BAM register interface
4095 * IRQ resources:
4096 * index = 0 -> SDCC IRQ
4097 * index = 1 -> BAM IRQ
4098 */
4099 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
4100 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
4101 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
4102 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
4103 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
4104 } else {
4105 for (i = 0; i < pdev->num_resources; i++) {
4106 if (pdev->resource[i].flags & IORESOURCE_MEM) {
4107 if (!strncmp(pdev->resource[i].name,
4108 "sdcc_dml_addr",
4109 sizeof("sdcc_dml_addr")))
4110 dml_memres = &pdev->resource[i];
4111 else if (!strncmp(pdev->resource[i].name,
4112 "sdcc_bam_addr",
4113 sizeof("sdcc_bam_addr")))
4114 bam_memres = &pdev->resource[i];
4115 else
4116 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07004117
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304118 }
4119 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
4120 if (!strncmp(pdev->resource[i].name,
4121 "sdcc_bam_irq",
4122 sizeof("sdcc_bam_irq")))
4123 bam_irqres = &pdev->resource[i];
4124 else
4125 core_irqres = &pdev->resource[i];
4126 }
4127 if (pdev->resource[i].flags & IORESOURCE_DMA) {
4128 if (!strncmp(pdev->resource[i].name,
4129 "sdcc_dma_chnl",
4130 sizeof("sdcc_dma_chnl")))
4131 dmares = &pdev->resource[i];
4132 else if (!strncmp(pdev->resource[i].name,
4133 "sdcc_dma_crci",
4134 sizeof("sdcc_dma_crci")))
4135 dma_crci_res = &pdev->resource[i];
4136 }
Krishna Konda25786ec2011-07-25 16:21:36 -07004137 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004138 }
4139
4140 if (!core_irqres || !core_memres) {
4141 pr_err("%s: Invalid sdcc core resource\n", __func__);
4142 return -ENXIO;
4143 }
4144
4145 /*
4146 * Both BAM and DML memory resource should be preset.
4147 * BAM IRQ resource should also be present.
4148 */
4149 if ((bam_memres && !dml_memres) ||
4150 (!bam_memres && dml_memres) ||
4151 ((bam_memres && dml_memres) && !bam_irqres)) {
4152 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004153 return -ENXIO;
4154 }
4155
4156 /*
4157 * Setup our host structure
4158 */
San Mehat9d2bd732009-09-22 16:44:22 -07004159 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
4160 if (!mmc) {
4161 ret = -ENOMEM;
4162 goto out;
4163 }
4164
4165 host = mmc_priv(mmc);
4166 host->pdev_id = pdev->id;
4167 host->plat = plat;
4168 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08004169 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05304170
4171 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004172 host->is_sps_mode = 1;
4173 else if (dmares)
4174 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07004175
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004176 host->base = ioremap(core_memres->start,
4177 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07004178 if (!host->base) {
4179 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004180 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004181 }
4182
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004183 host->core_irqres = core_irqres;
4184 host->bam_irqres = bam_irqres;
4185 host->core_memres = core_memres;
4186 host->dml_memres = dml_memres;
4187 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07004188 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07004189 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07004190 spin_lock_init(&host->lock);
4191
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004192#ifdef CONFIG_MMC_EMBEDDED_SDIO
4193 if (plat->embedded_sdio)
4194 mmc_set_embedded_sdio_data(mmc,
4195 &plat->embedded_sdio->cis,
4196 &plat->embedded_sdio->cccr,
4197 plat->embedded_sdio->funcs,
4198 plat->embedded_sdio->num_funcs);
4199#endif
4200
Sahitya Tummala62612cf2010-12-08 15:03:03 +05304201 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
4202 (unsigned long)host);
4203
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004204 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
4205 (unsigned long)host);
4206 if (host->is_dma_mode) {
4207 /* Setup DMA */
4208 ret = msmsdcc_init_dma(host);
4209 if (ret)
4210 goto ioremap_free;
4211 } else {
4212 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004213 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004214 }
4215
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004216 /*
4217 * Setup SDCC clock if derived from Dayatona
4218 * fabric core clock.
4219 */
4220 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07004221 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004222 if (!IS_ERR(host->dfab_pclk)) {
4223 /* Set the clock rate to 64MHz for max. performance */
4224 ret = clk_set_rate(host->dfab_pclk, 64000000);
4225 if (ret)
4226 goto dfab_pclk_put;
4227 ret = clk_enable(host->dfab_pclk);
4228 if (ret)
4229 goto dfab_pclk_put;
4230 } else
4231 goto dma_free;
4232 }
4233
4234 /*
4235 * Setup main peripheral bus clock
4236 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004237 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004238 if (!IS_ERR(host->pclk)) {
4239 ret = clk_enable(host->pclk);
4240 if (ret)
4241 goto pclk_put;
4242
4243 host->pclk_rate = clk_get_rate(host->pclk);
4244 }
4245
4246 /*
4247 * Setup SDC MMC clock
4248 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004249 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07004250 if (IS_ERR(host->clk)) {
4251 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004252 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07004253 }
4254
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004255 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
4256 if (ret) {
4257 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
4258 goto clk_put;
4259 }
4260
4261 ret = clk_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004262 if (ret)
4263 goto clk_put;
4264
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004265 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304266 if (!host->clk_rate)
4267 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304268
4269 /*
4270 * Lookup the Controller Version, to identify the supported features
4271 * Version number read as 0 would indicate SDCC3 or earlier versions
4272 */
4273 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
4274 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
4275 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304276 /*
4277 * Set the register write delay according to min. clock frequency
4278 * supported and update later when the host->clk_rate changes.
4279 */
4280 host->reg_write_delay =
4281 (1 + ((3 * USEC_PER_SEC) /
4282 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004283
4284 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05304285 /* Apply Hard reset to SDCC to put it in power on default state */
4286 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004287
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304288 /* pm qos request to prevent apps idle power collapse */
4289 if (host->plat->swfi_latency)
4290 pm_qos_add_request(&host->pm_qos_req_dma,
4291 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
4292
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004293 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07004294 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004295 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07004296 goto clk_disable;
4297 }
4298
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004299
4300 /* Clocks has to be running before accessing SPS/DML HW blocks */
4301 if (host->is_sps_mode) {
4302 /* Initialize SPS */
4303 ret = msmsdcc_sps_init(host);
4304 if (ret)
4305 goto vreg_deinit;
4306 /* Initialize DML */
4307 ret = msmsdcc_dml_init(host);
4308 if (ret)
4309 goto sps_exit;
4310 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05304311 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07004312
San Mehat9d2bd732009-09-22 16:44:22 -07004313 /*
4314 * Setup MMC host structure
4315 */
4316 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004317 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
4318 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004319 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004320 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
4321 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07004322
San Mehat9d2bd732009-09-22 16:44:22 -07004323 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304324 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304325
4326 /*
4327 * If we send the CMD23 before multi block write/read command
4328 * then we need not to send CMD12 at the end of the transfer.
4329 * If we don't send the CMD12 then only way to detect the PROG_DONE
4330 * status is to use the AUTO_PROG_DONE status provided by SDCC4
4331 * controller. So let's enable the CMD23 for SDCC4 only.
4332 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304333 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304334 mmc->caps |= MMC_CAP_CMD23;
4335
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004336 mmc->caps |= plat->uhs_caps;
4337 /*
4338 * XPC controls the maximum current in the default speed mode of SDXC
4339 * card. XPC=0 means 100mA (max.) but speed class is not supported.
4340 * XPC=1 means 150mA (max.) and speed class is supported.
4341 */
4342 if (plat->xpc_cap)
4343 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
4344 MMC_CAP_SET_XPC_180);
4345
4346 if (plat->nonremovable)
4347 mmc->caps |= MMC_CAP_NONREMOVABLE;
4348#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
4349 mmc->caps |= MMC_CAP_SDIO_IRQ;
4350#endif
4351
4352 if (plat->is_sdio_al_client)
4353 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07004354
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304355 mmc->max_segs = msmsdcc_get_nr_sg(host);
4356 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
4357 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07004358
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304359 mmc->max_req_size = MMC_MAX_REQ_SIZE;
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +05304360 mmc->max_seg_size = mmc->max_req_size;
San Mehat9d2bd732009-09-22 16:44:22 -07004361
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004362 writel_relaxed(0, host->base + MMCIMASK0);
4363 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -07004364
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004365 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
4366 mb();
4367 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07004368
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004369 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
4370 DRIVER_NAME " (cmd)", host);
4371 if (ret)
4372 goto dml_exit;
4373
4374 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
4375 DRIVER_NAME " (pio)", host);
4376 if (ret)
4377 goto irq_free;
4378
4379 /*
4380 * Enable SDCC IRQ only when host is powered on. Otherwise, this
4381 * IRQ is un-necessarily being monitored by MPM (Modem power
4382 * management block) during idle-power collapse. The MPM will be
4383 * configured to monitor the DATA1 GPIO line with level-low trigger
4384 * and thus depending on the GPIO status, it prevents TCXO shutdown
4385 * during idle-power collapse.
4386 */
4387 disable_irq(core_irqres->start);
4388 host->sdcc_irq_disabled = 1;
4389
4390 if (plat->sdiowakeup_irq) {
4391 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4392 mmc_hostname(mmc));
4393 ret = request_irq(plat->sdiowakeup_irq,
4394 msmsdcc_platform_sdiowakeup_irq,
4395 IRQF_SHARED | IRQF_TRIGGER_LOW,
4396 DRIVER_NAME "sdiowakeup", host);
4397 if (ret) {
4398 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
4399 plat->sdiowakeup_irq, ret);
4400 goto pio_irq_free;
4401 } else {
4402 spin_lock_irqsave(&host->lock, flags);
4403 if (!host->sdio_irq_disabled) {
4404 disable_irq_nosync(plat->sdiowakeup_irq);
4405 host->sdio_irq_disabled = 1;
4406 }
4407 spin_unlock_irqrestore(&host->lock, flags);
4408 }
4409 }
4410
4411 if (plat->cfg_mpm_sdiowakeup) {
4412 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4413 mmc_hostname(mmc));
4414 }
4415
4416 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
4417 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004418 /*
4419 * Setup card detect change
4420 */
4421
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004422 if (plat->status || plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08004423 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004424 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08004425 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004426 host->oldstat = msmsdcc_slot_status(host);
Krishna Konda360aa422011-12-06 18:27:41 -08004427
Krishna Konda941604a2012-01-10 17:46:34 -08004428 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004429 }
San Mehat9d2bd732009-09-22 16:44:22 -07004430
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004431 if (plat->status_irq) {
4432 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07004433 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004434 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07004435 DRIVER_NAME " (slot)",
4436 host);
4437 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004438 pr_err("Unable to get slot IRQ %d (%d)\n",
4439 plat->status_irq, ret);
4440 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004441 }
4442 } else if (plat->register_status_notify) {
4443 plat->register_status_notify(msmsdcc_status_notify_cb, host);
4444 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004445 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07004446 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004447
4448 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004449
4450 ret = pm_runtime_set_active(&(pdev)->dev);
4451 if (ret < 0)
4452 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
4453 __func__, ret);
4454 /*
4455 * There is no notion of suspend/resume for SD/MMC/SDIO
4456 * cards. So host can be suspended/resumed with out
4457 * worrying about its children.
4458 */
4459 pm_suspend_ignore_children(&(pdev)->dev, true);
4460
4461 /*
4462 * MMC/SD/SDIO bus suspend/resume operations are defined
4463 * only for the slots that will be used for non-removable
4464 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
4465 * defined. Otherwise, they simply become card removal and
4466 * insertion events during suspend and resume respectively.
4467 * Hence, enable run-time PM only for slots for which bus
4468 * suspend/resume operations are defined.
4469 */
4470#ifdef CONFIG_MMC_UNSAFE_RESUME
4471 /*
4472 * If this capability is set, MMC core will enable/disable host
4473 * for every claim/release operation on a host. We use this
4474 * notification to increment/decrement runtime pm usage count.
4475 */
4476 mmc->caps |= MMC_CAP_DISABLE;
4477 pm_runtime_enable(&(pdev)->dev);
4478#else
4479 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
4480 mmc->caps |= MMC_CAP_DISABLE;
4481 pm_runtime_enable(&(pdev)->dev);
4482 }
4483#endif
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05304484#ifndef CONFIG_PM_RUNTIME
4485 mmc_set_disable_delay(mmc, MSM_MMC_DISABLE_TIMEOUT);
4486#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004487 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
4488 (unsigned long)host);
4489
San Mehat9d2bd732009-09-22 16:44:22 -07004490 mmc_add_host(mmc);
4491
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004492#ifdef CONFIG_HAS_EARLYSUSPEND
4493 host->early_suspend.suspend = msmsdcc_early_suspend;
4494 host->early_suspend.resume = msmsdcc_late_resume;
4495 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
4496 register_early_suspend(&host->early_suspend);
4497#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004498
Krishna Konda25786ec2011-07-25 16:21:36 -07004499 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
4500 " dmacrcri %d\n", mmc_hostname(mmc),
4501 (unsigned long long)core_memres->start,
4502 (unsigned int) core_irqres->start,
4503 (unsigned int) plat->status_irq, host->dma.channel,
4504 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004505
4506 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
4507 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
4508 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
4509 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
4510 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
4511 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
4512 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
4513 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
4514 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
4515 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
4516 host->eject);
4517 pr_info("%s: Power save feature enable = %d\n",
4518 mmc_hostname(mmc), msmsdcc_pwrsave);
4519
Krishna Konda25786ec2011-07-25 16:21:36 -07004520 if (host->is_dma_mode && host->dma.channel != -1
4521 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004522 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004523 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004524 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004525 mmc_hostname(mmc), host->dma.cmd_busaddr,
4526 host->dma.cmdptr_busaddr);
4527 } else if (host->is_sps_mode) {
4528 pr_info("%s: SPS-BAM data transfer mode available\n",
4529 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004530 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004531 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004532
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004533#if defined(CONFIG_DEBUG_FS)
4534 msmsdcc_dbg_createhost(host);
4535#endif
4536 if (!plat->status_irq) {
4537 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
4538 if (ret)
4539 goto platform_irq_free;
4540 }
San Mehat9d2bd732009-09-22 16:44:22 -07004541 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004542
4543 platform_irq_free:
4544 del_timer_sync(&host->req_tout_timer);
4545 pm_runtime_disable(&(pdev)->dev);
4546 pm_runtime_set_suspended(&(pdev)->dev);
4547
4548 if (plat->status_irq)
4549 free_irq(plat->status_irq, host);
4550 sdiowakeup_irq_free:
4551 wake_lock_destroy(&host->sdio_suspend_wlock);
4552 if (plat->sdiowakeup_irq)
4553 free_irq(plat->sdiowakeup_irq, host);
4554 pio_irq_free:
4555 if (plat->sdiowakeup_irq)
4556 wake_lock_destroy(&host->sdio_wlock);
4557 free_irq(core_irqres->start, host);
4558 irq_free:
4559 free_irq(core_irqres->start, host);
4560 dml_exit:
4561 if (host->is_sps_mode)
4562 msmsdcc_dml_exit(host);
4563 sps_exit:
4564 if (host->is_sps_mode)
4565 msmsdcc_sps_exit(host);
4566 vreg_deinit:
4567 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07004568 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004569 clk_disable(host->clk);
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304570 if (host->plat->swfi_latency)
4571 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07004572 clk_put:
4573 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004574 pclk_disable:
4575 if (!IS_ERR(host->pclk))
4576 clk_disable(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07004577 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004578 if (!IS_ERR(host->pclk))
4579 clk_put(host->pclk);
4580 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4581 clk_disable(host->dfab_pclk);
4582 dfab_pclk_put:
4583 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4584 clk_put(host->dfab_pclk);
4585 dma_free:
4586 if (host->is_dma_mode) {
4587 if (host->dmares)
4588 dma_free_coherent(NULL,
4589 sizeof(struct msmsdcc_nc_dmadata),
4590 host->dma.nc, host->dma.nc_busaddr);
4591 }
4592 ioremap_free:
4593 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07004594 host_free:
4595 mmc_free_host(mmc);
4596 out:
4597 return ret;
4598}
4599
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004600static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07004601{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004602 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4603 struct mmc_platform_data *plat;
4604 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004605
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004606 if (!mmc)
4607 return -ENXIO;
4608
4609 if (pm_runtime_suspended(&(pdev)->dev))
4610 pm_runtime_resume(&(pdev)->dev);
4611
4612 host = mmc_priv(mmc);
4613
4614 DBG(host, "Removing SDCC device = %d\n", pdev->id);
4615 plat = host->plat;
4616
4617 if (!plat->status_irq)
4618 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
4619
4620 del_timer_sync(&host->req_tout_timer);
4621 tasklet_kill(&host->dma_tlet);
4622 tasklet_kill(&host->sps.tlet);
4623 mmc_remove_host(mmc);
4624
4625 if (plat->status_irq)
4626 free_irq(plat->status_irq, host);
4627
4628 wake_lock_destroy(&host->sdio_suspend_wlock);
4629 if (plat->sdiowakeup_irq) {
4630 wake_lock_destroy(&host->sdio_wlock);
4631 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
4632 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07004633 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004634
4635 free_irq(host->core_irqres->start, host);
4636 free_irq(host->core_irqres->start, host);
4637
4638 clk_put(host->clk);
4639 if (!IS_ERR(host->pclk))
4640 clk_put(host->pclk);
4641 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4642 clk_put(host->dfab_pclk);
4643
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304644 if (host->plat->swfi_latency)
4645 pm_qos_remove_request(&host->pm_qos_req_dma);
4646
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004647 msmsdcc_vreg_init(host, false);
4648
4649 if (host->is_dma_mode) {
4650 if (host->dmares)
4651 dma_free_coherent(NULL,
4652 sizeof(struct msmsdcc_nc_dmadata),
4653 host->dma.nc, host->dma.nc_busaddr);
4654 }
4655
4656 if (host->is_sps_mode) {
4657 msmsdcc_dml_exit(host);
4658 msmsdcc_sps_exit(host);
4659 }
4660
4661 iounmap(host->base);
4662 mmc_free_host(mmc);
4663
4664#ifdef CONFIG_HAS_EARLYSUSPEND
4665 unregister_early_suspend(&host->early_suspend);
4666#endif
4667 pm_runtime_disable(&(pdev)->dev);
4668 pm_runtime_set_suspended(&(pdev)->dev);
4669
4670 return 0;
4671}
4672
4673#ifdef CONFIG_MSM_SDIO_AL
4674int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4675{
4676 struct msmsdcc_host *host = mmc_priv(mmc);
4677 unsigned long flags;
4678
4679 spin_lock_irqsave(&host->lock, flags);
4680 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
4681 enable ? "En" : "Dis");
4682
4683 if (enable) {
4684 if (!host->sdcc_irq_disabled) {
4685 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05304686 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004687 host->sdcc_irq_disabled = 1;
4688 }
4689
4690 if (host->clks_on) {
4691 msmsdcc_setup_clocks(host, false);
4692 host->clks_on = 0;
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), 0);
4699 spin_lock_irqsave(&host->lock, flags);
4700 host->sdio_gpio_lpm = 1;
4701 }
4702
4703 if (host->sdio_irq_disabled) {
4704 msmsdcc_enable_irq_wake(host);
4705 enable_irq(host->plat->sdiowakeup_irq);
4706 host->sdio_irq_disabled = 0;
4707 }
4708 } else {
4709 if (!host->sdio_irq_disabled) {
4710 disable_irq_nosync(host->plat->sdiowakeup_irq);
4711 host->sdio_irq_disabled = 1;
4712 msmsdcc_disable_irq_wake(host);
4713 }
4714
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304715 if (host->plat->sdio_lpm_gpio_setup &&
4716 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004717 spin_unlock_irqrestore(&host->lock, flags);
4718 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
4719 spin_lock_irqsave(&host->lock, flags);
4720 host->sdio_gpio_lpm = 0;
4721 }
4722
4723 if (!host->clks_on) {
4724 msmsdcc_setup_clocks(host, true);
4725 host->clks_on = 1;
4726 }
4727
4728 if (host->sdcc_irq_disabled) {
4729 writel_relaxed(host->mci_irqenable,
4730 host->base + MMCIMASK0);
4731 mb();
4732 enable_irq(host->core_irqres->start);
4733 host->sdcc_irq_disabled = 0;
4734 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004735 }
4736 spin_unlock_irqrestore(&host->lock, flags);
4737 return 0;
4738}
4739#else
4740int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4741{
4742 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004743}
4744#endif
4745
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004746#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07004747static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004748msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004749{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004750 struct mmc_host *mmc = dev_get_drvdata(dev);
4751 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07004752 int rc = 0;
4753
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004754 if (host->plat->is_sdio_al_client)
4755 return 0;
Sahitya Tummala7661a452011-07-18 13:28:35 +05304756 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004757 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004758 host->sdcc_suspending = 1;
4759 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07004760
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004761 /*
4762 * If the clocks are already turned off by SDIO clients (as
4763 * part of LPM), then clocks should be turned on before
4764 * calling mmc_suspend_host() because mmc_suspend_host might
4765 * send some commands to the card. The clocks will be turned
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304766 * off again after mmc_suspend_host. Thus for SDIO
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004767 * cards, clocks will be turned on before mmc_suspend_host
4768 * and turned off after mmc_suspend_host.
4769 */
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304770 if (mmc->card && mmc_card_sdio(mmc->card)) {
4771 mmc->ios.clock = host->clk_rate;
4772 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4773 }
San Mehat9d2bd732009-09-22 16:44:22 -07004774
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004775 /*
4776 * MMC core thinks that host is disabled by now since
4777 * runtime suspend is scheduled after msmsdcc_disable()
4778 * is called. Thus, MMC core will try to enable the host
4779 * while suspending it. This results in a synchronous
4780 * runtime resume request while in runtime suspending
4781 * context and hence inorder to complete this resume
4782 * requet, it will wait for suspend to be complete,
4783 * but runtime suspend also can not proceed further
4784 * until the host is resumed. Thus, it leads to a hang.
4785 * Hence, increase the pm usage count before suspending
4786 * the host so that any resume requests after this will
4787 * simple become pm usage counter increment operations.
4788 */
4789 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05304790 /* If there is pending detect work abort runtime suspend */
4791 if (unlikely(work_busy(&mmc->detect.work)))
4792 rc = -EAGAIN;
4793 else
4794 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004795 pm_runtime_put_noidle(dev);
4796
4797 if (!rc) {
4798 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
4799 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ)) {
4800 disable_irq(host->core_irqres->start);
4801 host->sdcc_irq_disabled = 1;
4802
4803 /*
4804 * If MMC core level suspend is not supported,
4805 * turn off clocks to allow deep sleep (TCXO
4806 * shutdown).
4807 */
4808 mmc->ios.clock = 0;
4809 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4810 enable_irq(host->core_irqres->start);
4811 host->sdcc_irq_disabled = 0;
4812
4813 if (host->plat->sdiowakeup_irq) {
4814 host->sdio_irq_disabled = 0;
4815 msmsdcc_enable_irq_wake(host);
4816 enable_irq(host->plat->sdiowakeup_irq);
4817 }
4818 }
4819 }
4820 host->sdcc_suspending = 0;
4821 mmc->suspend_task = NULL;
4822 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
4823 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004824 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05304825 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
San Mehat9d2bd732009-09-22 16:44:22 -07004826 return rc;
4827}
4828
4829static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004830msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004831{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004832 struct mmc_host *mmc = dev_get_drvdata(dev);
4833 struct msmsdcc_host *host = mmc_priv(mmc);
4834 unsigned long flags;
4835
4836 if (host->plat->is_sdio_al_client)
4837 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07004838
Sahitya Tummala7661a452011-07-18 13:28:35 +05304839 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004840 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004841 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
4842 if (host->sdcc_irq_disabled) {
4843 enable_irq(host->core_irqres->start);
4844 host->sdcc_irq_disabled = 0;
4845 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304846 mmc->ios.clock = host->clk_rate;
4847 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07004848
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304849 spin_lock_irqsave(&host->lock, flags);
4850 writel_relaxed(host->mci_irqenable,
4851 host->base + MMCIMASK0);
4852 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07004853
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304854 if ((mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) &&
4855 !host->sdio_irq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004856 if (host->plat->sdiowakeup_irq) {
4857 disable_irq_nosync(
4858 host->plat->sdiowakeup_irq);
4859 msmsdcc_disable_irq_wake(host);
4860 host->sdio_irq_disabled = 1;
4861 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304862 }
San Mehat9d2bd732009-09-22 16:44:22 -07004863
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304864 spin_unlock_irqrestore(&host->lock, flags);
4865 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004866
4867 mmc_resume_host(mmc);
4868
4869 /*
4870 * FIXME: Clearing of flags must be handled in clients
4871 * resume handler.
4872 */
4873 spin_lock_irqsave(&host->lock, flags);
4874 mmc->pm_flags = 0;
4875 spin_unlock_irqrestore(&host->lock, flags);
4876
4877 /*
4878 * After resuming the host wait for sometime so that
4879 * the SDIO work will be processed.
4880 */
4881 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO)) {
4882 if ((host->plat->cfg_mpm_sdiowakeup ||
4883 host->plat->sdiowakeup_irq) &&
4884 wake_lock_active(&host->sdio_wlock))
4885 wake_lock_timeout(&host->sdio_wlock, 1);
4886 }
4887
4888 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004889 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304890 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004891 return 0;
4892}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004893
4894static int msmsdcc_runtime_idle(struct device *dev)
4895{
4896 struct mmc_host *mmc = dev_get_drvdata(dev);
4897 struct msmsdcc_host *host = mmc_priv(mmc);
4898
4899 if (host->plat->is_sdio_al_client)
4900 return 0;
4901
4902 /* Idle timeout is not configurable for now */
4903 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
4904
4905 return -EAGAIN;
4906}
4907
4908static int msmsdcc_pm_suspend(struct device *dev)
4909{
4910 struct mmc_host *mmc = dev_get_drvdata(dev);
4911 struct msmsdcc_host *host = mmc_priv(mmc);
4912 int rc = 0;
4913
4914 if (host->plat->is_sdio_al_client)
4915 return 0;
4916
4917
4918 if (host->plat->status_irq)
4919 disable_irq(host->plat->status_irq);
4920
4921 if (!pm_runtime_suspended(dev))
4922 rc = msmsdcc_runtime_suspend(dev);
4923
4924 return rc;
4925}
4926
4927static int msmsdcc_pm_resume(struct device *dev)
4928{
4929 struct mmc_host *mmc = dev_get_drvdata(dev);
4930 struct msmsdcc_host *host = mmc_priv(mmc);
4931 int rc = 0;
4932
4933 if (host->plat->is_sdio_al_client)
4934 return 0;
4935
Sahitya Tummalafb486372011-09-02 19:01:49 +05304936 if (!pm_runtime_suspended(dev))
4937 rc = msmsdcc_runtime_resume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004938 if (host->plat->status_irq) {
4939 msmsdcc_check_status((unsigned long)host);
4940 enable_irq(host->plat->status_irq);
4941 }
4942
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004943 return rc;
4944}
4945
Daniel Walker08ecfde2010-06-23 12:32:20 -07004946#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004947#define msmsdcc_runtime_suspend NULL
4948#define msmsdcc_runtime_resume NULL
4949#define msmsdcc_runtime_idle NULL
4950#define msmsdcc_pm_suspend NULL
4951#define msmsdcc_pm_resume NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07004952#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004953
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004954static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
4955 .runtime_suspend = msmsdcc_runtime_suspend,
4956 .runtime_resume = msmsdcc_runtime_resume,
4957 .runtime_idle = msmsdcc_runtime_idle,
4958 .suspend = msmsdcc_pm_suspend,
4959 .resume = msmsdcc_pm_resume,
4960};
4961
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304962static const struct of_device_id msmsdcc_dt_match[] = {
4963 {.compatible = "qcom,msm-sdcc"},
4964
4965};
4966MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
4967
San Mehat9d2bd732009-09-22 16:44:22 -07004968static struct platform_driver msmsdcc_driver = {
4969 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004970 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07004971 .driver = {
4972 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004973 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304974 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07004975 },
4976};
4977
4978static int __init msmsdcc_init(void)
4979{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004980#if defined(CONFIG_DEBUG_FS)
4981 int ret = 0;
4982 ret = msmsdcc_dbg_init();
4983 if (ret) {
4984 pr_err("Failed to create debug fs dir \n");
4985 return ret;
4986 }
4987#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004988 return platform_driver_register(&msmsdcc_driver);
4989}
4990
4991static void __exit msmsdcc_exit(void)
4992{
4993 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004994
4995#if defined(CONFIG_DEBUG_FS)
4996 debugfs_remove(debugfs_file);
4997 debugfs_remove(debugfs_dir);
4998#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004999}
5000
5001module_init(msmsdcc_init);
5002module_exit(msmsdcc_exit);
5003
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005004MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07005005MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005006
5007#if defined(CONFIG_DEBUG_FS)
5008
5009static int
5010msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
5011{
5012 file->private_data = inode->i_private;
5013 return 0;
5014}
5015
5016static ssize_t
5017msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
5018 size_t count, loff_t *ppos)
5019{
5020 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08005021 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005022 int max, i;
5023
5024 i = 0;
5025 max = sizeof(buf) - 1;
5026
5027 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
5028 host->curr.cmd, host->curr.data);
5029 if (host->curr.cmd) {
5030 struct mmc_command *cmd = host->curr.cmd;
5031
5032 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
5033 cmd->opcode, cmd->arg, cmd->flags);
5034 }
5035 if (host->curr.data) {
5036 struct mmc_data *data = host->curr.data;
5037 i += scnprintf(buf + i, max - i,
5038 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
5039 data->timeout_ns, data->timeout_clks,
5040 data->blksz, data->blocks, data->error,
5041 data->flags);
5042 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
5043 host->curr.xfer_size, host->curr.xfer_remain,
5044 host->curr.data_xfered, host->dma.sg);
5045 }
5046
5047 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
5048}
5049
5050static const struct file_operations msmsdcc_dbg_state_ops = {
5051 .read = msmsdcc_dbg_state_read,
5052 .open = msmsdcc_dbg_state_open,
5053};
5054
5055static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
5056{
5057 if (debugfs_dir) {
5058 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
5059 0644, debugfs_dir, host,
5060 &msmsdcc_dbg_state_ops);
5061 }
5062}
5063
5064static int __init msmsdcc_dbg_init(void)
5065{
5066 int err;
5067
5068 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
5069 if (IS_ERR(debugfs_dir)) {
5070 err = PTR_ERR(debugfs_dir);
5071 debugfs_dir = NULL;
5072 return err;
5073 }
5074
5075 return 0;
5076}
5077#endif