blob: 318c319f5c4cc870d2a8f24b6537375d1683261c [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>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070056#include <mach/sdio_al.h>
Subhash Jadavanic9b85752012-04-13 11:16:49 +053057#include <mach/mpm.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
Subhash Jadavanie6e1b822012-03-12 18:17:58 +053072/* Use SPS only if transfer size is more than this macro */
73#define SPS_MIN_XFER_SIZE MCI_FIFOSIZE
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070074
75#if defined(CONFIG_DEBUG_FS)
76static void msmsdcc_dbg_createhost(struct msmsdcc_host *);
77static struct dentry *debugfs_dir;
78static struct dentry *debugfs_file;
79static int msmsdcc_dbg_init(void);
80#endif
81
Subhash Jadavani8766e352011-11-30 11:30:32 +053082static u64 dma_mask = DMA_BIT_MASK(32);
San Mehat9d2bd732009-09-22 16:44:22 -070083static unsigned int msmsdcc_pwrsave = 1;
San Mehat9d2bd732009-09-22 16:44:22 -070084
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070085static struct mmc_command dummy52cmd;
86static struct mmc_request dummy52mrq = {
87 .cmd = &dummy52cmd,
88 .data = NULL,
89 .stop = NULL,
90};
91static struct mmc_command dummy52cmd = {
92 .opcode = SD_IO_RW_DIRECT,
93 .flags = MMC_RSP_PRESENT,
94 .data = NULL,
95 .mrq = &dummy52mrq,
96};
97/*
98 * An array holding the Tuning pattern to compare with when
99 * executing a tuning cycle.
100 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +0530101static const u32 tuning_block_64[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700102 0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
103 0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
104 0xF0FFF0FF, 0x3CCCFC0F, 0xCFCC33CC, 0xEEFFEFFF,
105 0xFDFFFDFF, 0xFFBFFFDF, 0xFFF7FFBB, 0xDE7B7FF7
106};
San Mehat865c8062009-11-13 13:42:06 -0800107
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +0530108static const u32 tuning_block_128[] = {
109 0xFF00FFFF, 0x0000FFFF, 0xCCCCFFFF, 0xCCCC33CC,
110 0xCC3333CC, 0xFFFFCCCC, 0xFFFFEEFF, 0xFFEEEEFF,
111 0xFFDDFFFF, 0xDDDDFFFF, 0xBBFFFFFF, 0xBBFFFFFF,
112 0xFFFFFFBB, 0xFFFFFF77, 0x77FF7777, 0xFFEEDDBB,
113 0x00FFFFFF, 0x00FFFFFF, 0xCCFFFF00, 0xCC33CCCC,
114 0x3333CCCC, 0xFFCCCCCC, 0xFFEEFFFF, 0xEEEEFFFF,
115 0xDDFFFFFF, 0xDDFFFFFF, 0xFFFFFFDD, 0xFFFFFFBB,
116 0xFFFFBBBB, 0xFFFF77FF, 0xFF7777FF, 0xEEDDBB77
117};
118
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700119#if IRQ_DEBUG == 1
120static char *irq_status_bits[] = { "cmdcrcfail", "datcrcfail", "cmdtimeout",
121 "dattimeout", "txunderrun", "rxoverrun",
122 "cmdrespend", "cmdsent", "dataend", NULL,
123 "datablkend", "cmdactive", "txactive",
124 "rxactive", "txhalfempty", "rxhalffull",
125 "txfifofull", "rxfifofull", "txfifoempty",
126 "rxfifoempty", "txdataavlbl", "rxdataavlbl",
127 "sdiointr", "progdone", "atacmdcompl",
128 "sdiointrope", "ccstimeout", NULL, NULL,
129 NULL, NULL, NULL };
130
131static void
132msmsdcc_print_status(struct msmsdcc_host *host, char *hdr, uint32_t status)
San Mehat865c8062009-11-13 13:42:06 -0800133{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700134 int i;
San Mehat8b1c2ba2009-11-16 10:17:30 -0800135
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700136 pr_debug("%s-%s ", mmc_hostname(host->mmc), hdr);
137 for (i = 0; i < 32; i++) {
138 if (status & (1 << i))
139 pr_debug("%s ", irq_status_bits[i]);
San Mehat865c8062009-11-13 13:42:06 -0800140 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700141 pr_debug("\n");
San Mehatc7fc9372009-11-22 17:19:07 -0800142}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700143#endif
San Mehat865c8062009-11-13 13:42:06 -0800144
San Mehat9d2bd732009-09-22 16:44:22 -0700145static void
146msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
147 u32 c);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530148static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530149static inline void msmsdcc_delay(struct msmsdcc_host *host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530150static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -0800151static void msmsdcc_sg_start(struct msmsdcc_host *host);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -0800152static int msmsdcc_vreg_reset(struct msmsdcc_host *host);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530153
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530154static inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
155{
156 unsigned short ret = NR_SG;
157
158 if (host->is_sps_mode) {
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +0530159 ret = SPS_MAX_DESCS;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530160 } else { /* DMA or PIO mode */
161 if (NR_SG > MAX_NR_SG_DMA_PIO)
162 ret = MAX_NR_SG_DMA_PIO;
163 }
164
165 return ret;
166}
167
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530168/* Prevent idle power collapse(pc) while operating in peripheral mode */
169static void msmsdcc_pm_qos_update_latency(struct msmsdcc_host *host, int vote)
170{
171 u32 swfi_latency = 0;
172
173 if (!host->plat->swfi_latency)
174 return;
175
176 swfi_latency = host->plat->swfi_latency + 1;
177
178 if (vote)
179 pm_qos_update_request(&host->pm_qos_req_dma,
180 swfi_latency);
181 else
182 pm_qos_update_request(&host->pm_qos_req_dma,
183 PM_QOS_DEFAULT_VALUE);
184}
185
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700186#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
187static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
188 struct msmsdcc_sps_ep_conn_data *ep);
189static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
190 struct msmsdcc_sps_ep_conn_data *ep);
191#else
192static inline int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
193 struct msmsdcc_sps_ep_conn_data *ep,
194 bool is_producer) { return 0; }
195static inline void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
196 struct msmsdcc_sps_ep_conn_data *ep) { }
197static inline int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
198 struct msmsdcc_sps_ep_conn_data *ep)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530199{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700200 return 0;
201}
202static inline int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
203 struct msmsdcc_sps_ep_conn_data *ep)
204{
205 return 0;
206}
207static inline int msmsdcc_sps_init(struct msmsdcc_host *host) { return 0; }
208static inline void msmsdcc_sps_exit(struct msmsdcc_host *host) {}
209#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530210
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700211/**
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530212 * Apply soft reset to all SDCC BAM pipes
213 *
214 * This function applies soft reset to SDCC BAM pipe.
215 *
216 * This function should be called to recover from error
217 * conditions encountered during CMD/DATA tranfsers with card.
218 *
219 * @host - Pointer to driver's host structure
220 *
221 */
222static void msmsdcc_sps_pipes_reset_and_restore(struct msmsdcc_host *host)
223{
224 int rc;
225
226 /* Reset all SDCC BAM pipes */
227 rc = msmsdcc_sps_reset_ep(host, &host->sps.prod);
228 if (rc)
229 pr_err("%s:msmsdcc_sps_reset_ep(prod) error=%d\n",
230 mmc_hostname(host->mmc), rc);
231 rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
232 if (rc)
233 pr_err("%s:msmsdcc_sps_reset_ep(cons) error=%d\n",
234 mmc_hostname(host->mmc), rc);
235
236 /* Restore all BAM pipes connections */
237 rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
238 if (rc)
239 pr_err("%s:msmsdcc_sps_restore_ep(prod) error=%d\n",
240 mmc_hostname(host->mmc), rc);
241 rc = msmsdcc_sps_restore_ep(host, &host->sps.cons);
242 if (rc)
243 pr_err("%s:msmsdcc_sps_restore_ep(cons) error=%d\n",
244 mmc_hostname(host->mmc), rc);
245}
246
247/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700248 * Apply soft reset
249 *
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530250 * This function applies soft reset to SDCC core and DML core.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700251 *
252 * This function should be called to recover from error
253 * conditions encountered with CMD/DATA tranfsers with card.
254 *
255 * Soft reset should only be used with SDCC controller v4.
256 *
257 * @host - Pointer to driver's host structure
258 *
259 */
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530260static void msmsdcc_soft_reset(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700261{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700262 /*
263 * Reset SDCC controller's DPSM (data path state machine
264 * and CPSM (command path state machine).
265 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700266 writel_relaxed(0, host->base + MMCICOMMAND);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530267 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700268 writel_relaxed(0, host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530269 msmsdcc_sync_reg_wr(host);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530270}
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530271
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530272static void msmsdcc_hard_reset(struct msmsdcc_host *host)
273{
274 int ret;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530275
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530276 /* Reset the controller */
277 ret = clk_reset(host->clk, CLK_RESET_ASSERT);
278 if (ret)
279 pr_err("%s: Clock assert failed at %u Hz"
280 " with err %d\n", mmc_hostname(host->mmc),
281 host->clk_rate, ret);
282
283 ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
284 if (ret)
285 pr_err("%s: Clock deassert failed at %u Hz"
286 " with err %d\n", mmc_hostname(host->mmc),
287 host->clk_rate, ret);
288
Subhash Jadavanidd432952012-03-28 11:25:56 +0530289 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530290 /* Give some delay for clock reset to propogate to controller */
291 msmsdcc_delay(host);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530292}
293
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700294static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
295{
Pratibhasagar V1c11da62011-11-14 12:36:35 +0530296 if (host->sdcc_version) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530297 if (host->is_sps_mode) {
298 /* Reset DML first */
299 msmsdcc_dml_reset(host);
300 /*
301 * delay the SPS pipe reset in thread context as
302 * sps_connect/sps_disconnect APIs can be called
303 * only from non-atomic context.
304 */
305 host->sps.pipe_reset_pending = true;
306 }
307 mb();
308 msmsdcc_soft_reset(host);
309
310 pr_debug("%s: Applied soft reset to Controller\n",
311 mmc_hostname(host->mmc));
312
313 if (host->is_sps_mode)
314 msmsdcc_dml_init(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700315 } else {
316 /* Give Clock reset (hard reset) to controller */
317 u32 mci_clk = 0;
318 u32 mci_mask0 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700319
320 /* Save the controller state */
321 mci_clk = readl_relaxed(host->base + MMCICLOCK);
322 mci_mask0 = readl_relaxed(host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +0530323 host->pwr = readl_relaxed(host->base + MMCIPOWER);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700324 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700325
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530326 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700327 pr_debug("%s: Controller has been reinitialized\n",
328 mmc_hostname(host->mmc));
329
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700330 /* Restore the contoller state */
331 writel_relaxed(host->pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530332 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700333 writel_relaxed(mci_clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530334 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700335 writel_relaxed(mci_mask0, host->base + MMCIMASK0);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530336 mb(); /* no delay required after writing to MASK0 register */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700337 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530338
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700339 if (host->dummy_52_needed)
340 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700341}
342
343static int
San Mehat9d2bd732009-09-22 16:44:22 -0700344msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
345{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700346 int retval = 0;
347
San Mehat9d2bd732009-09-22 16:44:22 -0700348 BUG_ON(host->curr.data);
349
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700350 del_timer(&host->req_tout_timer);
351
San Mehat9d2bd732009-09-22 16:44:22 -0700352 if (mrq->data)
353 mrq->data->bytes_xfered = host->curr.data_xfered;
354 if (mrq->cmd->error == -ETIMEDOUT)
355 mdelay(5);
356
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530357 /* Clear current request information as current request has ended */
358 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
359
San Mehat9d2bd732009-09-22 16:44:22 -0700360 /*
361 * Need to drop the host lock here; mmc_request_done may call
362 * back into the driver...
363 */
364 spin_unlock(&host->lock);
365 mmc_request_done(host->mmc, mrq);
366 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700367
368 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700369}
370
371static void
372msmsdcc_stop_data(struct msmsdcc_host *host)
373{
San Mehat9d2bd732009-09-22 16:44:22 -0700374 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530375 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530376 host->curr.wait_for_auto_prog_done = 0;
377 host->curr.got_auto_prog_done = 0;
Krishna Konda3f5d48f2011-07-27 10:47:31 -0700378 writel_relaxed(readl_relaxed(host->base + MMCIDATACTRL) &
379 (~(MCI_DPSM_ENABLE)), host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530380 msmsdcc_sync_reg_wr(host); /* Allow the DPSM to be reset */
San Mehat9d2bd732009-09-22 16:44:22 -0700381}
382
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700383static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700384{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700385 return host->core_memres->start + MMCIFIFO;
386}
387
388static inline unsigned int msmsdcc_get_min_sup_clk_rate(
389 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530390
Subhash Jadavanidd432952012-03-28 11:25:56 +0530391static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700392{
393 mb();
Subhash Jadavanidd432952012-03-28 11:25:56 +0530394 if (!host->sdcc_version)
395 udelay(host->reg_write_delay);
396 else if (readl_relaxed(host->base + MCI_STATUS2) &
397 MCI_MCLK_REG_WR_ACTIVE) {
398 ktime_t start, diff;
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530399
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530400 start = ktime_get();
401 while (readl_relaxed(host->base + MCI_STATUS2) &
402 MCI_MCLK_REG_WR_ACTIVE) {
403 diff = ktime_sub(ktime_get(), start);
404 /* poll for max. 1 ms */
405 if (ktime_to_us(diff) > 1000) {
406 pr_warning("%s: previous reg. write is"
407 " still active\n",
408 mmc_hostname(host->mmc));
409 break;
410 }
411 }
412 }
San Mehat9d2bd732009-09-22 16:44:22 -0700413}
414
Subhash Jadavanidd432952012-03-28 11:25:56 +0530415static inline void msmsdcc_delay(struct msmsdcc_host *host)
416{
417 udelay(host->reg_write_delay);
418
419}
420
San Mehat56a8b5b2009-11-21 12:29:46 -0800421static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700422msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
423{
424 writel_relaxed(arg, host->base + MMCIARGUMENT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700425 writel_relaxed(c, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530426 /*
427 * As after sending the command, we don't write any of the
428 * controller registers and just wait for the
429 * CMD_RESPOND_END/CMD_SENT/Command failure notication
430 * from Controller.
431 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700432 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800433}
434
435static void
436msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
437{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700438 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800439
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700440 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
441 writel_relaxed((unsigned int)host->curr.xfer_size,
442 host->base + MMCIDATALENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700443 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530444 msmsdcc_sync_reg_wr(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800445
San Mehat6ac9ea62009-12-02 17:24:58 -0800446 if (host->cmd_cmd) {
447 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700448 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800449 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800450}
451
San Mehat9d2bd732009-09-22 16:44:22 -0700452static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530453msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700454{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530455 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700456 unsigned long flags;
457 struct mmc_request *mrq;
458
459 spin_lock_irqsave(&host->lock, flags);
460 mrq = host->curr.mrq;
461 BUG_ON(!mrq);
462
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530463 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700464 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700465 goto out;
466 }
467
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530468 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700469 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700470 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700471 } else {
472 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530473 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700474 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530475 mmc_hostname(host->mmc), host->dma.result);
476 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700477 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530478 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530479 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700480 host->dma.err.flush[0], host->dma.err.flush[1],
481 host->dma.err.flush[2], host->dma.err.flush[3],
482 host->dma.err.flush[4],
483 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530484 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700485 if (!mrq->data->error)
486 mrq->data->error = -EIO;
487 }
San Mehat9d2bd732009-09-22 16:44:22 -0700488 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents,
489 host->dma.dir);
490
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700491 if (host->curr.user_pages) {
492 struct scatterlist *sg = host->dma.sg;
493 int i;
494
495 for (i = 0; i < host->dma.num_ents; i++, sg++)
496 flush_dcache_page(sg_page(sg));
497 }
498
San Mehat9d2bd732009-09-22 16:44:22 -0700499 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800500 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700501
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530502 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
503 (host->curr.wait_for_auto_prog_done &&
504 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700505 /*
506 * If we've already gotten our DATAEND / DATABLKEND
507 * for this request, then complete it through here.
508 */
San Mehat9d2bd732009-09-22 16:44:22 -0700509
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700510 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700511 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700512 host->curr.xfer_remain -= host->curr.xfer_size;
513 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700514 if (host->dummy_52_needed) {
515 mrq->data->bytes_xfered = host->curr.data_xfered;
516 host->dummy_52_sent = 1;
517 msmsdcc_start_command(host, &dummy52cmd,
518 MCI_CPSM_PROGENA);
519 goto out;
520 }
521 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530522 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530523 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700524 mrq->data->bytes_xfered = host->curr.data_xfered;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700525 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530526 /*
527 * Clear current request information as current
528 * request has ended
529 */
530 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
San Mehat9d2bd732009-09-22 16:44:22 -0700531 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700532
San Mehat9d2bd732009-09-22 16:44:22 -0700533 mmc_request_done(host->mmc, mrq);
534 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530535 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
536 || !mrq->sbc)) {
537 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530538 }
San Mehat9d2bd732009-09-22 16:44:22 -0700539 }
540
541out:
542 spin_unlock_irqrestore(&host->lock, flags);
543 return;
544}
545
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700546#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
547/**
548 * Callback notification from SPS driver
549 *
550 * This callback function gets triggered called from
551 * SPS driver when requested SPS data transfer is
552 * completed.
553 *
554 * SPS driver invokes this callback in BAM irq context so
555 * SDCC driver schedule a tasklet for further processing
556 * this callback notification at later point of time in
557 * tasklet context and immediately returns control back
558 * to SPS driver.
559 *
560 * @nofity - Pointer to sps event notify sturcture
561 *
562 */
563static void
564msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
565{
566 struct msmsdcc_host *host =
567 (struct msmsdcc_host *)
568 ((struct sps_event_notify *)notify)->user;
569
570 host->sps.notify = *notify;
571 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
572 mmc_hostname(host->mmc), __func__, notify->event_id,
573 notify->data.transfer.iovec.addr,
574 notify->data.transfer.iovec.size,
575 notify->data.transfer.iovec.flags);
576 /* Schedule a tasklet for completing data transfer */
577 tasklet_schedule(&host->sps.tlet);
578}
579
580/**
581 * Tasklet handler for processing SPS callback event
582 *
583 * This function processing SPS event notification and
584 * checks if the SPS transfer is completed or not and
585 * then accordingly notifies status to MMC core layer.
586 *
587 * This function is called in tasklet context.
588 *
589 * @data - Pointer to sdcc driver data
590 *
591 */
592static void msmsdcc_sps_complete_tlet(unsigned long data)
593{
594 unsigned long flags;
595 int i, rc;
596 u32 data_xfered = 0;
597 struct mmc_request *mrq;
598 struct sps_iovec iovec;
599 struct sps_pipe *sps_pipe_handle;
600 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
601 struct sps_event_notify *notify = &host->sps.notify;
602
603 spin_lock_irqsave(&host->lock, flags);
604 if (host->sps.dir == DMA_FROM_DEVICE)
605 sps_pipe_handle = host->sps.prod.pipe_handle;
606 else
607 sps_pipe_handle = host->sps.cons.pipe_handle;
608 mrq = host->curr.mrq;
609
610 if (!mrq) {
611 spin_unlock_irqrestore(&host->lock, flags);
612 return;
613 }
614
615 pr_debug("%s: %s: sps event_id=%d\n",
616 mmc_hostname(host->mmc), __func__,
617 notify->event_id);
618
619 if (msmsdcc_is_dml_busy(host)) {
620 /* oops !!! this should never happen. */
621 pr_err("%s: %s: Received SPS EOT event"
622 " but DML HW is still busy !!!\n",
623 mmc_hostname(host->mmc), __func__);
624 }
625 /*
626 * Got End of transfer event!!! Check if all of the data
627 * has been transferred?
628 */
629 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
630 rc = sps_get_iovec(sps_pipe_handle, &iovec);
631 if (rc) {
632 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
633 mmc_hostname(host->mmc), __func__, rc, i);
634 break;
635 }
636 data_xfered += iovec.size;
637 }
638
639 if (data_xfered == host->curr.xfer_size) {
640 host->curr.data_xfered = host->curr.xfer_size;
641 host->curr.xfer_remain -= host->curr.xfer_size;
642 pr_debug("%s: Data xfer success. data_xfered=0x%x",
643 mmc_hostname(host->mmc),
644 host->curr.xfer_size);
645 } else {
646 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
647 " xfer_size=%d", mmc_hostname(host->mmc),
648 data_xfered, host->curr.xfer_size);
649 msmsdcc_reset_and_restore(host);
650 if (!mrq->data->error)
651 mrq->data->error = -EIO;
652 }
653
654 /* Unmap sg buffers */
655 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
656 host->sps.dir);
657
658 host->sps.sg = NULL;
659 host->sps.busy = 0;
660
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530661 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
662 (host->curr.wait_for_auto_prog_done &&
663 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700664 /*
665 * If we've already gotten our DATAEND / DATABLKEND
666 * for this request, then complete it through here.
667 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700668
669 if (!mrq->data->error) {
670 host->curr.data_xfered = host->curr.xfer_size;
671 host->curr.xfer_remain -= host->curr.xfer_size;
672 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700673 if (host->dummy_52_needed) {
674 mrq->data->bytes_xfered = host->curr.data_xfered;
675 host->dummy_52_sent = 1;
676 msmsdcc_start_command(host, &dummy52cmd,
677 MCI_CPSM_PROGENA);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700678 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700679 return;
680 }
681 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530682 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530683 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700684 mrq->data->bytes_xfered = host->curr.data_xfered;
685 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530686 /*
687 * Clear current request information as current
688 * request has ended
689 */
690 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700691 spin_unlock_irqrestore(&host->lock, flags);
692
693 mmc_request_done(host->mmc, mrq);
694 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530695 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
696 || !mrq->sbc)) {
697 msmsdcc_start_command(host, mrq->data->stop, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700698 }
699 }
700 spin_unlock_irqrestore(&host->lock, flags);
701}
702
703/**
704 * Exit from current SPS data transfer
705 *
706 * This function exits from current SPS data transfer.
707 *
708 * This function should be called when error condition
709 * is encountered during data transfer.
710 *
711 * @host - Pointer to sdcc host structure
712 *
713 */
714static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
715{
716 struct mmc_request *mrq;
717
718 mrq = host->curr.mrq;
719 BUG_ON(!mrq);
720
721 msmsdcc_reset_and_restore(host);
722 if (!mrq->data->error)
723 mrq->data->error = -EIO;
724
725 /* Unmap sg buffers */
726 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
727 host->sps.dir);
728
729 host->sps.sg = NULL;
730 host->sps.busy = 0;
731 if (host->curr.data)
732 msmsdcc_stop_data(host);
733
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530734 if (!mrq->data->stop || mrq->cmd->error ||
735 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700736 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530737 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
738 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700739 msmsdcc_start_command(host, mrq->data->stop, 0);
740
741}
742#else
743static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
744static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
745static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
746#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
747
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530748static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700749
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530750static void
751msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
752 unsigned int result,
753 struct msm_dmov_errdata *err)
754{
755 struct msmsdcc_dma_data *dma_data =
756 container_of(cmd, struct msmsdcc_dma_data, hdr);
757 struct msmsdcc_host *host = dma_data->host;
758
759 dma_data->result = result;
760 if (err)
761 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
762
763 tasklet_schedule(&host->dma_tlet);
764}
765
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530766static bool msmsdcc_is_dma_possible(struct msmsdcc_host *host,
767 struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700768{
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530769 bool ret = true;
770 u32 xfer_size = data->blksz * data->blocks;
771
772 if (host->is_sps_mode) {
773 /*
774 * BAM Mode: Fall back on PIO if size is less
775 * than or equal to SPS_MIN_XFER_SIZE bytes.
776 */
777 if (xfer_size <= SPS_MIN_XFER_SIZE)
778 ret = false;
779 } else if (host->is_dma_mode) {
780 /*
781 * ADM Mode: Fall back on PIO if size is less than FIFO size
782 * or not integer multiple of FIFO size
783 */
784 if (xfer_size % MCI_FIFOSIZE)
785 ret = false;
786 } else {
787 /* PIO Mode */
788 ret = false;
789 }
790
791 return ret;
San Mehat9d2bd732009-09-22 16:44:22 -0700792}
793
794static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
795{
796 struct msmsdcc_nc_dmadata *nc;
797 dmov_box *box;
798 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700799 unsigned int n;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530800 int i, err = 0, box_cmd_cnt = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700801 struct scatterlist *sg = data->sg;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530802 unsigned int len, offset;
San Mehat9d2bd732009-09-22 16:44:22 -0700803
Krishna Konda25786ec2011-07-25 16:21:36 -0700804 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700805 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700806
Krishna Konda25786ec2011-07-25 16:21:36 -0700807 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
808
San Mehat9d2bd732009-09-22 16:44:22 -0700809 host->dma.sg = data->sg;
810 host->dma.num_ents = data->sg_len;
811
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530812 /* Prevent memory corruption */
813 BUG_ON(host->dma.num_ents > msmsdcc_get_nr_sg(host));
San Mehat56a8b5b2009-11-21 12:29:46 -0800814
San Mehat9d2bd732009-09-22 16:44:22 -0700815 nc = host->dma.nc;
816
San Mehat9d2bd732009-09-22 16:44:22 -0700817 if (data->flags & MMC_DATA_READ)
818 host->dma.dir = DMA_FROM_DEVICE;
819 else
820 host->dma.dir = DMA_TO_DEVICE;
821
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700822 n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
823 host->dma.num_ents, host->dma.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700824
825 if (n != host->dma.num_ents) {
826 pr_err("%s: Unable to map in all sg elements\n",
827 mmc_hostname(host->mmc));
828 host->dma.sg = NULL;
829 host->dma.num_ents = 0;
830 return -ENOMEM;
San Mehat56a8b5b2009-11-21 12:29:46 -0800831 }
San Mehat9d2bd732009-09-22 16:44:22 -0700832
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530833 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
834 host->curr.user_pages = 0;
835 box = &nc->cmd[0];
836 for (i = 0; i < host->dma.num_ents; i++) {
837 len = sg_dma_len(sg);
838 offset = 0;
839
840 do {
841 /* Check if we can do DMA */
842 if (!len || (box_cmd_cnt >= MMC_MAX_DMA_CMDS)) {
843 err = -ENOTSUPP;
844 goto unmap;
845 }
846
847 box->cmd = CMD_MODE_BOX;
848
849 if (len >= MMC_MAX_DMA_BOX_LENGTH) {
850 len = MMC_MAX_DMA_BOX_LENGTH;
851 len -= len % data->blksz;
852 }
853 rows = (len % MCI_FIFOSIZE) ?
854 (len / MCI_FIFOSIZE) + 1 :
855 (len / MCI_FIFOSIZE);
856
857 if (data->flags & MMC_DATA_READ) {
858 box->src_row_addr = msmsdcc_fifo_addr(host);
859 box->dst_row_addr = sg_dma_address(sg) + offset;
860 box->src_dst_len = (MCI_FIFOSIZE << 16) |
861 (MCI_FIFOSIZE);
862 box->row_offset = MCI_FIFOSIZE;
863 box->num_rows = rows * ((1 << 16) + 1);
864 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
865 } else {
866 box->src_row_addr = sg_dma_address(sg) + offset;
867 box->dst_row_addr = msmsdcc_fifo_addr(host);
868 box->src_dst_len = (MCI_FIFOSIZE << 16) |
869 (MCI_FIFOSIZE);
870 box->row_offset = (MCI_FIFOSIZE << 16);
871 box->num_rows = rows * ((1 << 16) + 1);
872 box->cmd |= CMD_DST_CRCI(host->dma.crci);
873 }
874
875 offset += len;
876 len = sg_dma_len(sg) - offset;
877 box++;
878 box_cmd_cnt++;
879 } while (len);
880 sg++;
881 }
882 /* Mark last command */
883 box--;
884 box->cmd |= CMD_LC;
885
886 /* location of command block must be 64 bit aligned */
887 BUG_ON(host->dma.cmd_busaddr & 0x07);
888
889 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
890 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
891 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
892 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
893
894 /* Flush all data to memory before starting dma */
895 mb();
896
897unmap:
898 if (err) {
899 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
900 host->dma.num_ents, host->dma.dir);
901 pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
902 mmc_hostname(host->mmc), err);
903 }
904
905 return err;
San Mehat9d2bd732009-09-22 16:44:22 -0700906}
907
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700908#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
909/**
910 * Submits data transfer request to SPS driver
911 *
912 * This function make sg (scatter gather) data buffers
913 * DMA ready and then submits them to SPS driver for
914 * transfer.
915 *
916 * @host - Pointer to sdcc host structure
917 * @data - Pointer to mmc_data structure
918 *
919 * @return 0 if success else negative value
920 */
921static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
922 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -0800923{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700924 int rc = 0;
925 u32 flags;
926 int i;
927 u32 addr, len, data_cnt;
928 struct scatterlist *sg = data->sg;
929 struct sps_pipe *sps_pipe_handle;
930
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530931 /* Prevent memory corruption */
932 BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700933
934 host->sps.sg = data->sg;
935 host->sps.num_ents = data->sg_len;
936 host->sps.xfer_req_cnt = 0;
937 if (data->flags & MMC_DATA_READ) {
938 host->sps.dir = DMA_FROM_DEVICE;
939 sps_pipe_handle = host->sps.prod.pipe_handle;
940 } else {
941 host->sps.dir = DMA_TO_DEVICE;
942 sps_pipe_handle = host->sps.cons.pipe_handle;
943 }
944
945 /* Make sg buffers DMA ready */
946 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
947 host->sps.dir);
948
949 if (rc != data->sg_len) {
950 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
951 mmc_hostname(host->mmc), rc);
952 host->sps.sg = NULL;
953 host->sps.num_ents = 0;
954 rc = -ENOMEM;
955 goto dma_map_err;
956 }
957
958 pr_debug("%s: %s: %s: pipe=0x%x, total_xfer=0x%x, sg_len=%d\n",
959 mmc_hostname(host->mmc), __func__,
960 host->sps.dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
961 (u32)sps_pipe_handle, host->curr.xfer_size, data->sg_len);
962
963 for (i = 0; i < data->sg_len; i++) {
964 /*
965 * Check if this is the last buffer to transfer?
966 * If yes then set the INT and EOT flags.
967 */
968 len = sg_dma_len(sg);
969 addr = sg_dma_address(sg);
970 flags = 0;
971 while (len > 0) {
972 if (len > SPS_MAX_DESC_SIZE) {
973 data_cnt = SPS_MAX_DESC_SIZE;
974 } else {
975 data_cnt = len;
976 if (i == data->sg_len - 1)
977 flags = SPS_IOVEC_FLAG_INT |
978 SPS_IOVEC_FLAG_EOT;
979 }
980 rc = sps_transfer_one(sps_pipe_handle, addr,
981 data_cnt, host, flags);
982 if (rc) {
983 pr_err("%s: sps_transfer_one() error! rc=%d,"
984 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
985 mmc_hostname(host->mmc), rc,
986 (u32)sps_pipe_handle, (u32)sg, i);
987 goto dma_map_err;
988 }
989 addr += data_cnt;
990 len -= data_cnt;
991 host->sps.xfer_req_cnt++;
992 }
993 sg++;
994 }
995 goto out;
996
997dma_map_err:
998 /* unmap sg buffers */
999 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
1000 host->sps.dir);
1001out:
1002 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07001003}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001004#else
1005static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
1006 struct mmc_data *data) { return 0; }
1007#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -07001008
1009static void
San Mehat56a8b5b2009-11-21 12:29:46 -08001010msmsdcc_start_command_deferred(struct msmsdcc_host *host,
1011 struct mmc_command *cmd, u32 *c)
1012{
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301013 DBG(host, "op %02x arg %08x flags %08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001014 cmd->opcode, cmd->arg, cmd->flags);
1015
San Mehat56a8b5b2009-11-21 12:29:46 -08001016 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
1017
1018 if (cmd->flags & MMC_RSP_PRESENT) {
1019 if (cmd->flags & MMC_RSP_136)
1020 *c |= MCI_CPSM_LONGRSP;
1021 *c |= MCI_CPSM_RESPONSE;
1022 }
1023
1024 if (/*interrupt*/0)
1025 *c |= MCI_CPSM_INTERRUPT;
1026
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301027 if (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
1028 cmd->opcode == MMC_READ_MULTIPLE_BLOCK ||
1029 cmd->opcode == MMC_WRITE_BLOCK ||
1030 cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK ||
1031 cmd->opcode == SD_IO_RW_EXTENDED)
San Mehat56a8b5b2009-11-21 12:29:46 -08001032 *c |= MCI_CSPM_DATCMD;
1033
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001034 /* Check if AUTO CMD19 is required or not? */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301035 if (host->tuning_needed &&
1036 !(host->mmc->ios.timing == MMC_TIMING_MMC_HS200)) {
1037
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301038 /*
1039 * For open ended block read operation (without CMD23),
1040 * AUTO_CMD19 bit should be set while sending the READ command.
1041 * For close ended block read operation (with CMD23),
1042 * AUTO_CMD19 bit should be set while sending CMD23.
1043 */
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301044 if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
1045 host->curr.mrq->cmd->opcode ==
1046 MMC_READ_MULTIPLE_BLOCK) ||
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301047 (!host->curr.mrq->sbc &&
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301048 (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
1049 cmd->opcode == MMC_READ_MULTIPLE_BLOCK))) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301050 msmsdcc_enable_cdr_cm_sdc4_dll(host);
1051 *c |= MCI_CSPM_AUTO_CMD19;
1052 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001053 }
1054
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05301055 /* Clear CDR_EN bit for write operations */
1056 if (host->tuning_needed && cmd->mrq->data &&
1057 (cmd->mrq->data->flags & MMC_DATA_WRITE))
1058 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) &
1059 ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
1060
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301061 if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301062 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001063 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301064 }
1065
San Mehat56a8b5b2009-11-21 12:29:46 -08001066 if (cmd == cmd->mrq->stop)
1067 *c |= MCI_CSPM_MCIABORT;
1068
San Mehat56a8b5b2009-11-21 12:29:46 -08001069 if (host->curr.cmd != NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001070 pr_err("%s: Overlapping command requests\n",
1071 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -08001072 }
1073 host->curr.cmd = cmd;
1074}
1075
1076static void
1077msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1078 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001079{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301080 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001081 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001082 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001083 unsigned int pio_irqmask = 0;
1084
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301085 BUG_ON(!data->sg);
1086 BUG_ON(!data->sg_len);
1087
San Mehat9d2bd732009-09-22 16:44:22 -07001088 host->curr.data = data;
1089 host->curr.xfer_size = data->blksz * data->blocks;
1090 host->curr.xfer_remain = host->curr.xfer_size;
1091 host->curr.data_xfered = 0;
1092 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301093 host->curr.got_auto_prog_done = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001094
San Mehat9d2bd732009-09-22 16:44:22 -07001095 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1096
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301097 if (host->curr.wait_for_auto_prog_done)
1098 datactrl |= MCI_AUTO_PROG_DONE;
1099
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05301100 if (msmsdcc_is_dma_possible(host, data)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001101 if (host->is_dma_mode && !msmsdcc_config_dma(host, data)) {
1102 datactrl |= MCI_DPSM_DMAENABLE;
1103 } else if (host->is_sps_mode) {
1104 if (!msmsdcc_is_dml_busy(host)) {
1105 if (!msmsdcc_sps_start_xfer(host, data)) {
1106 /* Now kick start DML transfer */
1107 mb();
1108 msmsdcc_dml_start_xfer(host, data);
1109 datactrl |= MCI_DPSM_DMAENABLE;
1110 host->sps.busy = 1;
1111 }
1112 } else {
1113 /*
1114 * Can't proceed with new transfer as
1115 * previous trasnfer is already in progress.
1116 * There is no point of going into PIO mode
1117 * as well. Is this a time to do kernel panic?
1118 */
1119 pr_err("%s: %s: DML HW is busy!!!"
1120 " Can't perform new SPS transfers"
1121 " now\n", mmc_hostname(host->mmc),
1122 __func__);
1123 }
1124 }
1125 }
1126
1127 /* Is data transfer in PIO mode required? */
1128 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001129 if (data->flags & MMC_DATA_READ) {
1130 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1131 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1132 pio_irqmask |= MCI_RXDATAAVLBLMASK;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001133 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001134 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1135 MCI_TXFIFOEMPTYMASK;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001136
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001137 msmsdcc_sg_start(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001138 }
1139
1140 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301141 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
San Mehat9d2bd732009-09-22 16:44:22 -07001142
San Mehat56a8b5b2009-11-21 12:29:46 -08001143 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001144 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001145 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -07001146
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001147 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
1148 /* Use ADM (Application Data Mover) HW for Data transfer */
1149 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001150 host->cmd_timeout = timeout;
1151 host->cmd_pio_irqmask = pio_irqmask;
1152 host->cmd_datactrl = datactrl;
1153 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001154
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001155 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1156 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001157 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001158
1159 if (cmd) {
1160 msmsdcc_start_command_deferred(host, cmd, &c);
1161 host->cmd_c = c;
1162 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001163 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1164 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1165 host->base + MMCIMASK0);
1166 mb();
1167 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001168 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001169 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001170 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001171
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001172 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001173
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001174 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1175 (~(MCI_IRQ_PIO))) | pio_irqmask,
1176 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001177 writel_relaxed(datactrl, base + MMCIDATACTRL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001178
1179 if (cmd) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05301180 /* Delay between data/command */
1181 msmsdcc_sync_reg_wr(host);
San Mehat56a8b5b2009-11-21 12:29:46 -08001182 /* Daisy-chain the command if requested */
1183 msmsdcc_start_command(host, cmd, c);
Subhash Jadavanidd432952012-03-28 11:25:56 +05301184 } else {
1185 /*
1186 * We don't need delay after writing to DATA_CTRL
1187 * register if we are not writing to CMD register
1188 * immediately after this. As we already have delay
1189 * before sending the command, we just need mb() here.
1190 */
1191 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001192 }
San Mehat9d2bd732009-09-22 16:44:22 -07001193 }
1194}
1195
1196static void
1197msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1198{
San Mehat56a8b5b2009-11-21 12:29:46 -08001199 msmsdcc_start_command_deferred(host, cmd, &c);
1200 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001201}
1202
1203static void
1204msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1205 unsigned int status)
1206{
1207 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001208 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
Subhash Jadavanib30c9822012-03-27 18:03:16 +05301209 || data->mrq->cmd->opcode == MMC_BUS_TEST_R
1210 || data->mrq->cmd->opcode ==
1211 MMC_SEND_TUNING_BLOCK_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001212 pr_err("%s: Data CRC error\n",
1213 mmc_hostname(host->mmc));
1214 pr_err("%s: opcode 0x%.8x\n", __func__,
1215 data->mrq->cmd->opcode);
1216 pr_err("%s: blksz %d, blocks %d\n", __func__,
1217 data->blksz, data->blocks);
1218 data->error = -EILSEQ;
1219 }
San Mehat9d2bd732009-09-22 16:44:22 -07001220 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001221 /* CRC is optional for the bus test commands, not all
1222 * cards respond back with CRC. However controller
1223 * waits for the CRC and times out. Hence ignore the
1224 * data timeouts during the Bustest.
1225 */
1226 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1227 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301228 pr_err("%s: CMD%d: Data timeout\n",
1229 mmc_hostname(host->mmc),
1230 data->mrq->cmd->opcode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001231 data->error = -ETIMEDOUT;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301232 msmsdcc_dump_sdcc_state(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001233 }
San Mehat9d2bd732009-09-22 16:44:22 -07001234 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001235 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001236 data->error = -EIO;
1237 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001238 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001239 data->error = -EIO;
1240 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001241 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001242 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001243 data->error = -EIO;
1244 }
San Mehat9d2bd732009-09-22 16:44:22 -07001245
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001246 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001247 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001248 host->dummy_52_needed = 0;
1249}
San Mehat9d2bd732009-09-22 16:44:22 -07001250
1251static int
1252msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1253{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001254 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001255 uint32_t *ptr = (uint32_t *) buffer;
1256 int count = 0;
1257
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301258 if (remain % 4)
1259 remain = ((remain >> 2) + 1) << 2;
1260
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001261 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1262
1263 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001264 ptr++;
1265 count += sizeof(uint32_t);
1266
1267 remain -= sizeof(uint32_t);
1268 if (remain == 0)
1269 break;
1270 }
1271 return count;
1272}
1273
1274static int
1275msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001276 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001277{
1278 void __iomem *base = host->base;
1279 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001280 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001281
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001282 while (readl_relaxed(base + MMCISTATUS) &
1283 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1284 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001285
San Mehat9d2bd732009-09-22 16:44:22 -07001286 count = min(remain, maxcnt);
1287
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301288 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1289 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001290 ptr += count;
1291 remain -= count;
1292
1293 if (remain == 0)
1294 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001295 }
1296 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001297
1298 return ptr - buffer;
1299}
1300
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001301/*
1302 * Copy up to a word (4 bytes) between a scatterlist
1303 * and a temporary bounce buffer when the word lies across
1304 * two pages. The temporary buffer can then be read to/
1305 * written from the FIFO once.
1306 */
1307static void _msmsdcc_sg_consume_word(struct msmsdcc_host *host)
1308{
1309 struct msmsdcc_pio_data *pio = &host->pio;
1310 unsigned int bytes_avail;
1311
1312 if (host->curr.data->flags & MMC_DATA_READ)
1313 memcpy(pio->sg_miter.addr, pio->bounce_buf,
1314 pio->bounce_buf_len);
1315 else
1316 memcpy(pio->bounce_buf, pio->sg_miter.addr,
1317 pio->bounce_buf_len);
1318
1319 while (pio->bounce_buf_len != 4) {
1320 if (!sg_miter_next(&pio->sg_miter))
1321 break;
1322 bytes_avail = min_t(unsigned int, pio->sg_miter.length,
1323 4 - pio->bounce_buf_len);
1324 if (host->curr.data->flags & MMC_DATA_READ)
1325 memcpy(pio->sg_miter.addr,
1326 &pio->bounce_buf[pio->bounce_buf_len],
1327 bytes_avail);
1328 else
1329 memcpy(&pio->bounce_buf[pio->bounce_buf_len],
1330 pio->sg_miter.addr, bytes_avail);
1331
1332 pio->sg_miter.consumed = bytes_avail;
1333 pio->bounce_buf_len += bytes_avail;
1334 }
1335}
1336
1337/*
1338 * Use sg_miter_next to return as many 4-byte aligned
1339 * chunks as possible, using a temporary 4 byte buffer
1340 * for alignment if necessary
1341 */
1342static int msmsdcc_sg_next(struct msmsdcc_host *host, char **buf, int *len)
1343{
1344 struct msmsdcc_pio_data *pio = &host->pio;
1345 unsigned int length, rlength;
1346 char *buffer;
1347
1348 if (!sg_miter_next(&pio->sg_miter))
1349 return 0;
1350
1351 buffer = pio->sg_miter.addr;
1352 length = pio->sg_miter.length;
1353
1354 if (length < host->curr.xfer_remain) {
1355 rlength = round_down(length, 4);
1356 if (rlength) {
1357 /*
1358 * We have a 4-byte aligned chunk.
1359 * The rounding will be reflected by
1360 * a call to msmsdcc_sg_consumed
1361 */
1362 length = rlength;
1363 goto sg_next_end;
1364 }
1365 /*
1366 * We have a length less than 4 bytes. Check to
1367 * see if more buffer is available, and combine
1368 * to make 4 bytes if possible.
1369 */
1370 pio->bounce_buf_len = length;
1371 memset(pio->bounce_buf, 0, 4);
1372
1373 /*
1374 * On a read, get 4 bytes from FIFO, and distribute
1375 * (4-bouce_buf_len) bytes into consecutive
1376 * sgl buffers when msmsdcc_sg_consumed is called
1377 */
1378 if (host->curr.data->flags & MMC_DATA_READ) {
1379 buffer = pio->bounce_buf;
1380 length = 4;
1381 goto sg_next_end;
1382 } else {
1383 _msmsdcc_sg_consume_word(host);
1384 buffer = pio->bounce_buf;
1385 length = pio->bounce_buf_len;
1386 }
1387 }
1388
1389sg_next_end:
1390 *buf = buffer;
1391 *len = length;
1392 return 1;
1393}
1394
1395/*
1396 * Update sg_miter.consumed based on how many bytes were
1397 * consumed. If the bounce buffer was used to read from FIFO,
1398 * redistribute into sgls.
1399 */
1400static void msmsdcc_sg_consumed(struct msmsdcc_host *host,
1401 unsigned int length)
1402{
1403 struct msmsdcc_pio_data *pio = &host->pio;
1404
1405 if (host->curr.data->flags & MMC_DATA_READ) {
1406 if (length > pio->sg_miter.consumed)
1407 /*
1408 * consumed 4 bytes, but sgl
1409 * describes < 4 bytes
1410 */
1411 _msmsdcc_sg_consume_word(host);
1412 else
1413 pio->sg_miter.consumed = length;
1414 } else
1415 if (length < pio->sg_miter.consumed)
1416 pio->sg_miter.consumed = length;
1417}
1418
1419static void msmsdcc_sg_start(struct msmsdcc_host *host)
1420{
1421 unsigned int sg_miter_flags = SG_MITER_ATOMIC;
1422
1423 host->pio.bounce_buf_len = 0;
1424
1425 if (host->curr.data->flags & MMC_DATA_READ)
1426 sg_miter_flags |= SG_MITER_TO_SG;
1427 else
1428 sg_miter_flags |= SG_MITER_FROM_SG;
1429
1430 sg_miter_start(&host->pio.sg_miter, host->curr.data->sg,
1431 host->curr.data->sg_len, sg_miter_flags);
1432}
1433
1434static void msmsdcc_sg_stop(struct msmsdcc_host *host)
1435{
1436 sg_miter_stop(&host->pio.sg_miter);
1437}
1438
San Mehat1cd22962010-02-03 12:59:29 -08001439static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001440msmsdcc_pio_irq(int irq, void *dev_id)
1441{
1442 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001443 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001444 uint32_t status;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001445 unsigned long flags;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001446 unsigned int remain;
1447 char *buffer;
San Mehat9d2bd732009-09-22 16:44:22 -07001448
Murali Palnati36448a42011-09-02 15:06:18 +05301449 spin_lock(&host->lock);
1450
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001451 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001452
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001453 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301454 (MCI_IRQ_PIO)) == 0) {
1455 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001456 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301457 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001458#if IRQ_DEBUG
1459 msmsdcc_print_status(host, "irq1-r", status);
1460#endif
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001461 local_irq_save(flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001462
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001463 do {
1464 unsigned int len;
San Mehat9d2bd732009-09-22 16:44:22 -07001465
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001466 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1467 | MCI_RXDATAAVLBL)))
1468 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001469
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001470 if (!msmsdcc_sg_next(host, &buffer, &remain))
1471 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001472
San Mehat9d2bd732009-09-22 16:44:22 -07001473 len = 0;
1474 if (status & MCI_RXACTIVE)
1475 len = msmsdcc_pio_read(host, buffer, remain);
1476 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001477 len = msmsdcc_pio_write(host, buffer, remain);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001478
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301479 /* len might have aligned to 32bits above */
1480 if (len > remain)
1481 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001482
San Mehat9d2bd732009-09-22 16:44:22 -07001483 host->curr.xfer_remain -= len;
1484 host->curr.data_xfered += len;
1485 remain -= len;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001486 msmsdcc_sg_consumed(host, len);
San Mehat9d2bd732009-09-22 16:44:22 -07001487
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001488 if (remain) /* Done with this page? */
1489 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001490
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001491 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001492 } while (1);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001493
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001494 msmsdcc_sg_stop(host);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001495 local_irq_restore(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001496
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001497 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1498 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1499 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1500 host->base + MMCIMASK0);
1501 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301502 /*
1503 * back to back write to MASK0 register don't need
1504 * synchronization delay.
1505 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001506 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1507 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1508 }
1509 mb();
1510 } else if (!host->curr.xfer_remain) {
1511 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1512 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1513 mb();
1514 }
San Mehat9d2bd732009-09-22 16:44:22 -07001515
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001516 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001517
1518 return IRQ_HANDLED;
1519}
1520
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001521static void
1522msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1523
1524static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1525 struct mmc_data *data)
1526{
1527 u32 loop_cnt = 0;
1528
1529 /*
1530 * For read commands with data less than fifo size, it is possible to
1531 * get DATAEND first and RXDATA_AVAIL might be set later because of
1532 * synchronization delay through the asynchronous RX FIFO. Thus, for
1533 * such cases, even after DATAEND interrupt is received software
1534 * should poll for RXDATA_AVAIL until the requested data is read out
1535 * of FIFO. This change is needed to get around this abnormal but
1536 * sometimes expected behavior of SDCC3 controller.
1537 *
1538 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1539 * after the data is loaded into RX FIFO. This would amount to less
1540 * than a microsecond and thus looping for 1000 times is good enough
1541 * for that delay.
1542 */
1543 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1544 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1545 spin_unlock(&host->lock);
1546 msmsdcc_pio_irq(1, host);
1547 spin_lock(&host->lock);
1548 }
1549 }
1550 if (loop_cnt == 1000) {
1551 pr_info("%s: Timed out while polling for Rx Data\n",
1552 mmc_hostname(host->mmc));
1553 data->error = -ETIMEDOUT;
1554 msmsdcc_reset_and_restore(host);
1555 }
1556}
1557
San Mehat9d2bd732009-09-22 16:44:22 -07001558static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1559{
1560 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001561
1562 host->curr.cmd = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001563 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1564 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1565 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1566 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -07001567
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001568 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301569 pr_debug("%s: CMD%d: Command timeout\n",
1570 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001571 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001572 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301573 !host->tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301574 pr_err("%s: CMD%d: Command CRC error\n",
1575 mmc_hostname(host->mmc), cmd->opcode);
1576 msmsdcc_dump_sdcc_state(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001577 cmd->error = -EILSEQ;
1578 }
1579
1580 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001581 if (host->curr.data && host->dma.sg &&
1582 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001583 msm_dmov_stop_cmd(host->dma.channel,
1584 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001585 else if (host->curr.data && host->sps.sg &&
1586 host->is_sps_mode){
1587 /* Stop current SPS transfer */
1588 msmsdcc_sps_exit_curr_xfer(host);
1589 }
San Mehat9d2bd732009-09-22 16:44:22 -07001590 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301591 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001592 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301593 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301594 } else { /* host->data == NULL */
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301595 if (!cmd->error && host->prog_enable) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301596 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001597 host->prog_enable = 0;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301598 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001599 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301600 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301601 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301602 host->prog_enable = 0;
Subhash Jadavanied6b0e42012-03-07 16:36:27 +05301603 host->curr.wait_for_auto_prog_done = 0;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001604 if (host->dummy_52_needed)
1605 host->dummy_52_needed = 0;
1606 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001607 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301608 msmsdcc_request_end(host, cmd->mrq);
1609 }
1610 }
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301611 } else if ((cmd == host->curr.mrq->sbc) && cmd->data) {
1612 if (cmd->data->flags & MMC_DATA_READ)
1613 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1614 else
1615 msmsdcc_request_start(host, host->curr.mrq);
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301616 } else if (cmd->data) {
1617 if (!(cmd->data->flags & MMC_DATA_READ))
1618 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001619 }
1620}
1621
San Mehat9d2bd732009-09-22 16:44:22 -07001622static irqreturn_t
1623msmsdcc_irq(int irq, void *dev_id)
1624{
1625 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001626 u32 status;
1627 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001628 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001629
1630 spin_lock(&host->lock);
1631
1632 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001633 struct mmc_command *cmd;
1634 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001635
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001636 if (timer) {
1637 timer = 0;
1638 msmsdcc_delay(host);
1639 }
San Mehat865c8062009-11-13 13:42:06 -08001640
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001641 if (!host->clks_on) {
1642 pr_debug("%s: %s: SDIO async irq received\n",
1643 mmc_hostname(host->mmc), __func__);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301644
1645 /*
1646 * Only async interrupt can come when clocks are off,
1647 * disable further interrupts and enable them when
1648 * clocks are on.
1649 */
1650 if (!host->sdcc_irq_disabled) {
1651 disable_irq_nosync(irq);
1652 host->sdcc_irq_disabled = 1;
1653 }
1654
1655 /*
1656 * If mmc_card_wake_sdio_irq() is set, mmc core layer
1657 * will take care of signaling sdio irq during
1658 * mmc_sdio_resume().
1659 */
1660 if (host->sdcc_suspended)
1661 /*
1662 * This is a wakeup interrupt so hold wakelock
1663 * until SDCC resume is handled.
1664 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001665 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301666 else
1667 mmc_signal_sdio_irq(host->mmc);
1668 ret = 1;
1669 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001670 }
1671
1672 status = readl_relaxed(host->base + MMCISTATUS);
1673
1674 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1675 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001676 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001677
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001678#if IRQ_DEBUG
1679 msmsdcc_print_status(host, "irq0-r", status);
1680#endif
1681 status &= readl_relaxed(host->base + MMCIMASK0);
1682 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301683 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301684 if (host->clk_rate <=
1685 msmsdcc_get_min_sup_clk_rate(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +05301686 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001687#if IRQ_DEBUG
1688 msmsdcc_print_status(host, "irq0-p", status);
1689#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001690
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001691 if (status & MCI_SDIOINTROPE) {
1692 if (host->sdcc_suspending)
1693 wake_lock(&host->sdio_suspend_wlock);
1694 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001695 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001696 data = host->curr.data;
1697
1698 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001699 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1700 MCI_CMDTIMEOUT)) {
1701 if (status & MCI_CMDTIMEOUT)
1702 pr_debug("%s: dummy CMD52 timeout\n",
1703 mmc_hostname(host->mmc));
1704 if (status & MCI_CMDCRCFAIL)
1705 pr_debug("%s: dummy CMD52 CRC failed\n",
1706 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001707 host->dummy_52_sent = 0;
1708 host->dummy_52_needed = 0;
1709 if (data) {
1710 msmsdcc_stop_data(host);
1711 msmsdcc_request_end(host, data->mrq);
1712 }
1713 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001714 spin_unlock(&host->lock);
1715 return IRQ_HANDLED;
1716 }
1717 break;
1718 }
1719
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001720 /*
1721 * Check for proper command response
1722 */
1723 cmd = host->curr.cmd;
1724 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1725 MCI_CMDTIMEOUT | MCI_PROGDONE |
1726 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1727 msmsdcc_do_cmdirq(host, status);
1728 }
1729
Sathish Ambley081d7842011-11-29 11:19:41 -08001730 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001731 /* Check for data errors */
1732 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1733 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1734 msmsdcc_data_err(host, data, status);
1735 host->curr.data_xfered = 0;
1736 if (host->dma.sg && host->is_dma_mode)
1737 msm_dmov_stop_cmd(host->dma.channel,
1738 &host->dma.hdr, 0);
1739 else if (host->sps.sg && host->is_sps_mode) {
1740 /* Stop current SPS transfer */
1741 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301742 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001743 msmsdcc_reset_and_restore(host);
1744 if (host->curr.data)
1745 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301746 if (!data->stop || (host->curr.mrq->sbc
1747 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001748 timer |=
1749 msmsdcc_request_end(host,
1750 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301751 else if ((host->curr.mrq->sbc
1752 && data->error) ||
1753 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001754 msmsdcc_start_command(host,
1755 data->stop,
1756 0);
1757 timer = 1;
1758 }
1759 }
1760 }
1761
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301762 /* Check for prog done */
1763 if (host->curr.wait_for_auto_prog_done &&
1764 (status & MCI_PROGDONE))
1765 host->curr.got_auto_prog_done = 1;
1766
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001767 /* Check for data done */
1768 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1769 host->curr.got_dataend = 1;
1770
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301771 if (host->curr.got_dataend &&
1772 (!host->curr.wait_for_auto_prog_done ||
1773 (host->curr.wait_for_auto_prog_done &&
1774 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001775 /*
1776 * If DMA is still in progress, we complete
1777 * via the completion handler
1778 */
1779 if (!host->dma.busy && !host->sps.busy) {
1780 /*
1781 * There appears to be an issue in the
1782 * controller where if you request a
1783 * small block transfer (< fifo size),
1784 * you may get your DATAEND/DATABLKEND
1785 * irq without the PIO data irq.
1786 *
1787 * Check to see if theres still data
1788 * to be read, and simulate a PIO irq.
1789 */
1790 if (data->flags & MMC_DATA_READ)
1791 msmsdcc_wait_for_rxdata(host,
1792 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001793 if (!data->error) {
1794 host->curr.data_xfered =
1795 host->curr.xfer_size;
1796 host->curr.xfer_remain -=
1797 host->curr.xfer_size;
1798 }
1799
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001800 if (!host->dummy_52_needed) {
1801 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301802 if (!data->stop ||
1803 (host->curr.mrq->sbc
1804 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001805 msmsdcc_request_end(
1806 host,
1807 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301808 else if ((host->curr.mrq->sbc
1809 && data->error) ||
1810 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001811 msmsdcc_start_command(
1812 host,
1813 data->stop, 0);
1814 timer = 1;
1815 }
1816 } else {
1817 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001818 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001819 &dummy52cmd,
1820 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001821 }
1822 }
1823 }
1824 }
1825
San Mehat9d2bd732009-09-22 16:44:22 -07001826 ret = 1;
1827 } while (status);
1828
1829 spin_unlock(&host->lock);
1830
San Mehat9d2bd732009-09-22 16:44:22 -07001831 return IRQ_RETVAL(ret);
1832}
1833
1834static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001835msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1836{
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301837 if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001838 /* Queue/read data, daisy-chain command when data starts */
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301839 if (mrq->sbc)
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301840 msmsdcc_start_data(host, mrq->data, mrq->sbc, 0);
1841 else
1842 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001843 } else {
1844 msmsdcc_start_command(host, mrq->cmd, 0);
1845 }
1846}
1847
1848static void
San Mehat9d2bd732009-09-22 16:44:22 -07001849msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1850{
1851 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001852 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001853
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001854 /*
1855 * Get the SDIO AL client out of LPM.
1856 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001857 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001858 if (host->plat->is_sdio_al_client)
1859 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001860
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301861 /* check if sps pipe reset is pending? */
1862 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1863 msmsdcc_sps_pipes_reset_and_restore(host);
1864 host->sps.pipe_reset_pending = false;
1865 }
1866
San Mehat9d2bd732009-09-22 16:44:22 -07001867 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001868 WARN(host->curr.mrq, "Request in progress\n");
1869 WARN(!host->pwr, "SDCC power is turned off\n");
1870 WARN(!host->clks_on, "SDCC clocks are turned off\n");
1871 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
San Mehat9d2bd732009-09-22 16:44:22 -07001872
1873 if (host->eject) {
1874 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1875 mrq->cmd->error = 0;
1876 mrq->data->bytes_xfered = mrq->data->blksz *
1877 mrq->data->blocks;
1878 } else
1879 mrq->cmd->error = -ENOMEDIUM;
1880
1881 spin_unlock_irqrestore(&host->lock, flags);
1882 mmc_request_done(mmc, mrq);
1883 return;
1884 }
1885
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301886 /*
1887 * Kick the software command timeout timer here.
1888 * Timer expires in 10 secs.
1889 */
1890 mod_timer(&host->req_tout_timer,
1891 (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
San Mehat9d2bd732009-09-22 16:44:22 -07001892
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301893 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301894 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301895 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
1896 mrq->cmd->opcode == 54) {
Pratibhasagar V1c11da62011-11-14 12:36:35 +05301897 if (!host->sdcc_version)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001898 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301899 else
1900 /*
1901 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
1902 * write operations using CMD53 and CMD54.
1903 * Setting this bit with CMD53 would
1904 * automatically triggers PROG_DONE interrupt
1905 * without the need of sending dummy CMD52.
1906 */
1907 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani758cf8c2011-11-13 11:59:55 +05301908 } else if (mrq->cmd->opcode == MMC_WRITE_BLOCK &&
1909 host->sdcc_version) {
1910 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001911 }
San Mehat9d2bd732009-09-22 16:44:22 -07001912 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301913
Pratibhasagar V00b94332011-10-18 14:57:27 +05301914 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301915 mrq->sbc->mrq = mrq;
1916 mrq->sbc->data = mrq->data;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301917 if (mrq->data->flags & MMC_DATA_WRITE) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301918 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301919 msmsdcc_start_command(host, mrq->sbc, 0);
1920 } else {
1921 msmsdcc_request_start(host, mrq);
1922 }
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301923 } else {
1924 msmsdcc_request_start(host, mrq);
1925 }
1926
San Mehat9d2bd732009-09-22 16:44:22 -07001927 spin_unlock_irqrestore(&host->lock, flags);
1928}
1929
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001930static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1931 int min_uV, int max_uV)
1932{
1933 int rc = 0;
1934
1935 if (vreg->set_voltage_sup) {
1936 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1937 if (rc) {
1938 pr_err("%s: regulator_set_voltage(%s) failed."
1939 " min_uV=%d, max_uV=%d, rc=%d\n",
1940 __func__, vreg->name, min_uV, max_uV, rc);
1941 }
1942 }
1943
1944 return rc;
1945}
1946
1947static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1948 int uA_load)
1949{
1950 int rc = 0;
1951
Krishna Kondafea60182011-11-01 16:01:34 -07001952 /* regulators that do not support regulator_set_voltage also
1953 do not support regulator_set_optimum_mode */
1954 if (vreg->set_voltage_sup) {
1955 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1956 if (rc < 0)
1957 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
1958 "uA_load=%d) failed. rc=%d\n", __func__,
1959 vreg->name, uA_load, rc);
1960 else
1961 /* regulator_set_optimum_mode() can return non zero
1962 * value even for success case.
1963 */
1964 rc = 0;
1965 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001966
1967 return rc;
1968}
1969
1970static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1971 struct device *dev)
1972{
1973 int rc = 0;
1974
1975 /* check if regulator is already initialized? */
1976 if (vreg->reg)
1977 goto out;
1978
1979 /* Get the regulator handle */
1980 vreg->reg = regulator_get(dev, vreg->name);
1981 if (IS_ERR(vreg->reg)) {
1982 rc = PTR_ERR(vreg->reg);
1983 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
1984 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001985 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001986 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001987
1988 if (regulator_count_voltages(vreg->reg) > 0)
1989 vreg->set_voltage_sup = 1;
1990
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001991out:
1992 return rc;
1993}
1994
1995static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
1996{
1997 if (vreg->reg)
1998 regulator_put(vreg->reg);
1999}
2000
2001/* This init function should be called only once for each SDCC slot */
2002static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
2003{
2004 int rc = 0;
2005 struct msm_mmc_slot_reg_data *curr_slot;
2006 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
2007 struct device *dev = mmc_dev(host->mmc);
2008
2009 curr_slot = host->plat->vreg_data;
2010 if (!curr_slot)
2011 goto out;
2012
2013 curr_vdd_reg = curr_slot->vdd_data;
2014 curr_vccq_reg = curr_slot->vccq_data;
2015 curr_vddp_reg = curr_slot->vddp_data;
2016
2017 if (is_init) {
2018 /*
2019 * Get the regulator handle from voltage regulator framework
2020 * and then try to set the voltage level for the regulator
2021 */
2022 if (curr_vdd_reg) {
2023 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
2024 if (rc)
2025 goto out;
2026 }
2027 if (curr_vccq_reg) {
2028 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
2029 if (rc)
2030 goto vdd_reg_deinit;
2031 }
2032 if (curr_vddp_reg) {
2033 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
2034 if (rc)
2035 goto vccq_reg_deinit;
2036 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002037 rc = msmsdcc_vreg_reset(host);
2038 if (rc)
2039 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
2040 host->pdev_id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002041 goto out;
2042 } else {
2043 /* Deregister all regulators from regulator framework */
2044 goto vddp_reg_deinit;
2045 }
2046vddp_reg_deinit:
2047 if (curr_vddp_reg)
2048 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
2049vccq_reg_deinit:
2050 if (curr_vccq_reg)
2051 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
2052vdd_reg_deinit:
2053 if (curr_vdd_reg)
2054 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2055out:
2056 return rc;
2057}
2058
2059static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2060{
2061 int rc = 0;
2062
Subhash Jadavanicc922692011-08-01 23:05:01 +05302063 /* Put regulator in HPM (high power mode) */
2064 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2065 if (rc < 0)
2066 goto out;
2067
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002068 if (!vreg->is_enabled) {
2069 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302070 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2071 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002072 if (rc)
2073 goto out;
2074
2075 rc = regulator_enable(vreg->reg);
2076 if (rc) {
2077 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2078 __func__, vreg->name, rc);
2079 goto out;
2080 }
2081 vreg->is_enabled = true;
2082 }
2083
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002084out:
2085 return rc;
2086}
2087
2088static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
2089{
2090 int rc = 0;
2091
2092 /* Never disable regulator marked as always_on */
2093 if (vreg->is_enabled && !vreg->always_on) {
2094 rc = regulator_disable(vreg->reg);
2095 if (rc) {
2096 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2097 __func__, vreg->name, rc);
2098 goto out;
2099 }
2100 vreg->is_enabled = false;
2101
2102 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2103 if (rc < 0)
2104 goto out;
2105
2106 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302107 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002108 if (rc)
2109 goto out;
2110 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
2111 /* Put always_on regulator in LPM (low power mode) */
2112 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2113 if (rc < 0)
2114 goto out;
2115 }
2116out:
2117 return rc;
2118}
2119
2120static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
2121{
2122 int rc = 0, i;
2123 struct msm_mmc_slot_reg_data *curr_slot;
2124 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
2125 struct msm_mmc_reg_data *vreg_table[3];
2126
2127 curr_slot = host->plat->vreg_data;
2128 if (!curr_slot)
2129 goto out;
2130
2131 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
2132 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
2133 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
2134
2135 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2136 if (vreg_table[i]) {
2137 if (enable)
2138 rc = msmsdcc_vreg_enable(vreg_table[i]);
2139 else
2140 rc = msmsdcc_vreg_disable(vreg_table[i]);
2141 if (rc)
2142 goto out;
2143 }
2144 }
2145out:
2146 return rc;
2147}
2148
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002149/*
2150 * Reset vreg by ensuring it is off during probe. A call
2151 * to enable vreg is needed to balance disable vreg
2152 */
2153static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2154{
2155 int rc;
2156
2157 rc = msmsdcc_setup_vreg(host, 1);
2158 if (rc)
2159 return rc;
2160 rc = msmsdcc_setup_vreg(host, 0);
2161 return rc;
2162}
2163
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302164static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002165{
2166 int rc = 0;
2167
2168 if (host->plat->vreg_data) {
2169 struct msm_mmc_reg_data *vddp_reg =
2170 host->plat->vreg_data->vddp_data;
2171
2172 if (vddp_reg && vddp_reg->is_enabled)
2173 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
2174 }
2175
2176 return rc;
2177}
2178
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302179static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
2180{
2181 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2182 int rc = 0;
2183
2184 if (curr_slot && curr_slot->vddp_data) {
2185 rc = msmsdcc_set_vddp_level(host,
2186 curr_slot->vddp_data->low_vol_level);
2187
2188 if (rc)
2189 pr_err("%s: %s: failed to change vddp level to %d",
2190 mmc_hostname(host->mmc), __func__,
2191 curr_slot->vddp_data->low_vol_level);
2192 }
2193
2194 return rc;
2195}
2196
2197static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
2198{
2199 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2200 int rc = 0;
2201
2202 if (curr_slot && curr_slot->vddp_data) {
2203 rc = msmsdcc_set_vddp_level(host,
2204 curr_slot->vddp_data->high_vol_level);
2205
2206 if (rc)
2207 pr_err("%s: %s: failed to change vddp level to %d",
2208 mmc_hostname(host->mmc), __func__,
2209 curr_slot->vddp_data->high_vol_level);
2210 }
2211
2212 return rc;
2213}
2214
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302215static inline int msmsdcc_set_vccq_vol(struct msmsdcc_host *host, int level)
2216{
2217 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2218 int rc = 0;
2219
2220 if (curr_slot && curr_slot->vccq_data) {
2221 rc = msmsdcc_vreg_set_voltage(curr_slot->vccq_data,
2222 level, level);
2223 if (rc)
2224 pr_err("%s: %s: failed to change vccq level to %d",
2225 mmc_hostname(host->mmc), __func__, level);
2226 }
2227
2228 return rc;
2229}
2230
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002231static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2232{
2233 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2234 return 1;
2235 return 0;
2236}
2237
Asutosh Dasf5298c32012-04-03 14:51:47 +05302238/*
2239 * Any function calling msmsdcc_setup_clocks must
2240 * acquire clk_mutex. May sleep.
2241 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002242static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
2243{
2244 if (enable) {
2245 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302246 clk_prepare_enable(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002247 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302248 clk_prepare_enable(host->pclk);
2249 clk_prepare_enable(host->clk);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302250 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302251 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002252 } else {
Subhash Jadavanidd432952012-03-28 11:25:56 +05302253 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302254 msmsdcc_delay(host);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302255 clk_disable_unprepare(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002256 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302257 clk_disable_unprepare(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002258 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302259 clk_disable_unprepare(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002260 }
2261}
2262
2263static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2264 unsigned int req_clk)
2265{
2266 unsigned int sel_clk = -1;
2267
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302268 if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
2269 sel_clk = msmsdcc_get_min_sup_clk_rate(host);
2270 goto out;
2271 }
2272
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002273 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2274 unsigned char cnt;
2275
2276 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2277 if (host->plat->sup_clk_table[cnt] > req_clk)
2278 break;
2279 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2280 sel_clk = host->plat->sup_clk_table[cnt];
2281 break;
2282 } else
2283 sel_clk = host->plat->sup_clk_table[cnt];
2284 }
2285 } else {
2286 if ((req_clk < host->plat->msmsdcc_fmax) &&
2287 (req_clk > host->plat->msmsdcc_fmid))
2288 sel_clk = host->plat->msmsdcc_fmid;
2289 else
2290 sel_clk = req_clk;
2291 }
2292
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302293out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002294 return sel_clk;
2295}
2296
2297static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2298 struct msmsdcc_host *host)
2299{
2300 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2301 return host->plat->sup_clk_table[0];
2302 else
2303 return host->plat->msmsdcc_fmin;
2304}
2305
2306static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2307 struct msmsdcc_host *host)
2308{
2309 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2310 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2311 else
2312 return host->plat->msmsdcc_fmax;
2313}
2314
2315static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302316{
2317 struct msm_mmc_gpio_data *curr;
2318 int i, rc = 0;
2319
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002320 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302321 for (i = 0; i < curr->size; i++) {
2322 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002323 if (curr->gpio[i].is_always_on &&
2324 curr->gpio[i].is_enabled)
2325 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302326 rc = gpio_request(curr->gpio[i].no,
2327 curr->gpio[i].name);
2328 if (rc) {
2329 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2330 mmc_hostname(host->mmc),
2331 curr->gpio[i].no,
2332 curr->gpio[i].name, rc);
2333 goto free_gpios;
2334 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002335 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302336 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002337 if (curr->gpio[i].is_always_on)
2338 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302339 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002340 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302341 }
2342 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002343 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302344
2345free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002346 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302347 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002348 curr->gpio[i].is_enabled = false;
2349 }
2350out:
2351 return rc;
2352}
2353
2354static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2355{
2356 struct msm_mmc_pad_data *curr;
2357 int i;
2358
2359 curr = host->plat->pin_data->pad_data;
2360 for (i = 0; i < curr->drv->size; i++) {
2361 if (enable)
2362 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2363 curr->drv->on[i].val);
2364 else
2365 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2366 curr->drv->off[i].val);
2367 }
2368
2369 for (i = 0; i < curr->pull->size; i++) {
2370 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002371 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002372 curr->pull->on[i].val);
2373 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002374 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002375 curr->pull->off[i].val);
2376 }
2377
2378 return 0;
2379}
2380
2381static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2382{
2383 int rc = 0;
2384
2385 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2386 return 0;
2387
2388 if (host->plat->pin_data->is_gpio)
2389 rc = msmsdcc_setup_gpio(host, enable);
2390 else
2391 rc = msmsdcc_setup_pad(host, enable);
2392
2393 if (!rc)
2394 host->plat->pin_data->cfg_sts = enable;
2395
2396 return rc;
2397}
2398
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302399static int msmsdcc_cfg_mpm_sdiowakeup(struct msmsdcc_host *host,
2400 unsigned mode)
2401{
2402 int ret = 0;
2403 unsigned int pin = host->plat->mpm_sdiowakeup_int;
2404
2405 if (!pin)
2406 return 0;
2407
2408 switch (mode) {
2409 case SDC_DAT1_DISABLE:
2410 ret = msm_mpm_enable_pin(pin, 0);
2411 break;
2412 case SDC_DAT1_ENABLE:
2413 ret = msm_mpm_set_pin_type(pin, IRQ_TYPE_LEVEL_LOW);
2414 ret = msm_mpm_enable_pin(pin, 1);
2415 break;
2416 case SDC_DAT1_ENWAKE:
2417 ret = msm_mpm_set_pin_wake(pin, 1);
2418 break;
2419 case SDC_DAT1_DISWAKE:
2420 ret = msm_mpm_set_pin_wake(pin, 0);
2421 break;
2422 default:
2423 ret = -EINVAL;
2424 break;
2425 }
2426
2427 return ret;
2428}
2429
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302430static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2431{
2432 u32 pwr = 0;
2433 int ret = 0;
2434 struct mmc_host *mmc = host->mmc;
2435
2436 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2437 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2438 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2439 ret = msmsdcc_setup_vreg(host, !!ios->vdd);
2440
2441 if (ret) {
2442 pr_err("%s: Failed to setup voltage regulators\n",
2443 mmc_hostname(host->mmc));
2444 goto out;
2445 }
2446
2447 switch (ios->power_mode) {
2448 case MMC_POWER_OFF:
2449 pwr = MCI_PWR_OFF;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302450 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302451 /*
2452 * As VDD pad rail is always on, set low voltage for VDD
2453 * pad rail when slot is unused (when card is not present
2454 * or during system suspend).
2455 */
2456 msmsdcc_set_vddp_low_vol(host);
2457 msmsdcc_setup_pins(host, false);
2458 break;
2459 case MMC_POWER_UP:
2460 /* writing PWR_UP bit is redundant */
2461 pwr = MCI_PWR_UP;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302462 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302463
2464 msmsdcc_set_vddp_high_vol(host);
2465 msmsdcc_setup_pins(host, true);
2466 break;
2467 case MMC_POWER_ON:
2468 pwr = MCI_PWR_ON;
2469 break;
2470 }
2471
2472out:
2473 return pwr;
2474}
2475
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002476static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2477{
2478 unsigned int wakeup_irq;
2479
2480 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2481 host->plat->sdiowakeup_irq :
2482 host->core_irqres->start;
2483
2484 if (!host->irq_wake_enabled) {
2485 enable_irq_wake(wakeup_irq);
2486 host->irq_wake_enabled = true;
2487 }
2488}
2489
2490static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2491{
2492 unsigned int wakeup_irq;
2493
2494 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2495 host->plat->sdiowakeup_irq :
2496 host->core_irqres->start;
2497
2498 if (host->irq_wake_enabled) {
2499 disable_irq_wake(wakeup_irq);
2500 host->irq_wake_enabled = false;
2501 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302502}
2503
San Mehat9d2bd732009-09-22 16:44:22 -07002504static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302505msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
2506{
2507 struct mmc_host *mmc = host->mmc;
2508
2509 /*
2510 * SDIO_AL clients has different mechanism of handling LPM through
2511 * sdio_al driver itself. The sdio wakeup interrupt is configured as
2512 * part of that. Here, we are interested only in clients like WLAN.
2513 */
2514 if (!(mmc->card && mmc_card_sdio(mmc->card))
2515 || host->plat->is_sdio_al_client)
2516 goto out;
2517
2518 if (!host->sdcc_suspended) {
2519 /*
2520 * When MSM is not in power collapse and we
2521 * are disabling clocks, enable bit 22 in MASK0
2522 * to handle asynchronous SDIO interrupts.
2523 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302524 if (enable_wakeup_irq) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302525 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302526 mb();
2527 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302528 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302529 msmsdcc_sync_reg_wr(host);
2530 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302531 goto out;
2532 } else if (!mmc_card_wake_sdio_irq(mmc)) {
2533 /*
2534 * Wakeup MSM only if SDIO function drivers set
2535 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
2536 */
2537 goto out;
2538 }
2539
2540 if (enable_wakeup_irq) {
2541 if (!host->plat->sdiowakeup_irq) {
2542 /*
2543 * When there is no gpio line that can be configured
2544 * as wakeup interrupt handle it by configuring
2545 * asynchronous sdio interrupts and DAT1 line.
2546 */
2547 writel_relaxed(MCI_SDIOINTMASK,
2548 host->base + MMCIMASK0);
2549 mb();
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302550 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302551 /* configure sdcc core interrupt as wakeup interrupt */
2552 msmsdcc_enable_irq_wake(host);
2553 } else {
2554 /* Let gpio line handle wakeup interrupt */
2555 writel_relaxed(0, host->base + MMCIMASK0);
2556 mb();
2557 if (host->sdio_wakeupirq_disabled) {
2558 host->sdio_wakeupirq_disabled = 0;
2559 /* configure gpio line as wakeup interrupt */
2560 msmsdcc_enable_irq_wake(host);
2561 enable_irq(host->plat->sdiowakeup_irq);
2562 }
2563 }
2564 } else {
2565 if (!host->plat->sdiowakeup_irq) {
2566 /*
2567 * We may not have cleared bit 22 in the interrupt
2568 * handler as the clocks might be off at that time.
2569 */
2570 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302571 msmsdcc_sync_reg_wr(host);
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302572 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302573 msmsdcc_disable_irq_wake(host);
2574 } else if (!host->sdio_wakeupirq_disabled) {
2575 disable_irq_nosync(host->plat->sdiowakeup_irq);
2576 msmsdcc_disable_irq_wake(host);
2577 host->sdio_wakeupirq_disabled = 1;
2578 }
2579 }
2580out:
2581 return;
2582}
2583
2584static void
San Mehat9d2bd732009-09-22 16:44:22 -07002585msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2586{
2587 struct msmsdcc_host *host = mmc_priv(mmc);
2588 u32 clk = 0, pwr = 0;
2589 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002590 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002591 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002592
Sahitya Tummala7a892482011-01-18 11:22:49 +05302593
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302594 /*
2595 * Disable SDCC core interrupt until set_ios is completed.
2596 * This avoids any race conditions with interrupt raised
2597 * when turning on/off the clocks. One possible
2598 * scenario is SDIO operational interrupt while the clock
2599 * is turned off.
Asutosh Dasf5298c32012-04-03 14:51:47 +05302600 * host->lock is being released intermittently below.
2601 * Thus, prevent concurrent access to host.
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302602 */
2603
Asutosh Dasf5298c32012-04-03 14:51:47 +05302604 mutex_lock(&host->clk_mutex);
2605 DBG(host, "ios->clock = %u\n", ios->clock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302606 spin_lock_irqsave(&host->lock, flags);
2607 if (!host->sdcc_irq_disabled) {
2608 spin_unlock_irqrestore(&host->lock, flags);
2609 disable_irq(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002610 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302611 host->sdcc_irq_disabled = 1;
2612 }
2613 spin_unlock_irqrestore(&host->lock, flags);
2614
2615 pwr = msmsdcc_setup_pwr(host, ios);
2616
2617 spin_lock_irqsave(&host->lock, flags);
2618 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002619 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302620 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002621 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302622 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002623 host->clks_on = 1;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302624 writel_relaxed(host->mci_irqenable,
2625 host->base + MMCIMASK0);
2626 mb();
2627 msmsdcc_cfg_sdio_wakeup(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002628 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002629
2630 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2631 /*
2632 * For DDR50 mode, controller needs clock rate to be
2633 * double than what is required on the SD card CLK pin.
2634 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302635 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002636 /*
2637 * Make sure that we don't double the clock if
2638 * doubled clock rate is already set
2639 */
2640 if (!host->ddr_doubled_clk_rate ||
2641 (host->ddr_doubled_clk_rate &&
2642 (host->ddr_doubled_clk_rate != ios->clock))) {
2643 host->ddr_doubled_clk_rate =
2644 msmsdcc_get_sup_clk_rate(
2645 host, (ios->clock * 2));
2646 clock = host->ddr_doubled_clk_rate;
2647 }
2648 } else {
2649 host->ddr_doubled_clk_rate = 0;
2650 }
2651
2652 if (clock != host->clk_rate) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302653 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002654 rc = clk_set_rate(host->clk, clock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302655 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002656 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302657 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002658 mmc_hostname(mmc), clock);
2659 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302660 host->reg_write_delay =
2661 (1 + ((3 * USEC_PER_SEC) /
2662 (host->clk_rate ? host->clk_rate :
2663 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002664 }
2665 /*
2666 * give atleast 2 MCLK cycles delay for clocks
2667 * and SDCC core to stabilize
2668 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302669 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002670 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002671 clk |= MCI_CLK_ENABLE;
2672 }
2673
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002674 if (ios->bus_width == MMC_BUS_WIDTH_8)
2675 clk |= MCI_CLK_WIDEBUS_8;
2676 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2677 clk |= MCI_CLK_WIDEBUS_4;
2678 else
2679 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002680
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002681 if (msmsdcc_is_pwrsave(host))
2682 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002683
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002684 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002685
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002686 host->tuning_needed = 0;
2687 /*
2688 * Select the controller timing mode according
2689 * to current bus speed mode
2690 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302691 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2692 (ios->timing == MMC_TIMING_MMC_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002693 clk |= (4 << 14);
2694 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302695 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002696 clk |= (3 << 14);
2697 } else {
2698 clk |= (2 << 14); /* feedback clock */
2699 }
2700
2701 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2702 clk |= (2 << 23);
2703
Subhash Jadavani00083572012-02-15 16:18:01 +05302704 /* Clear IO_PAD_PWR_SWITCH while powering off the card */
2705 if (!ios->vdd)
2706 host->io_pad_pwr_switch = 0;
2707
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002708 if (host->io_pad_pwr_switch)
2709 clk |= IO_PAD_PWR_SWITCH;
2710
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302711 /* Don't write into registers if clocks are disabled */
2712 if (host->clks_on) {
2713 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
2714 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302715 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002716 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302717 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
2718 host->pwr = pwr;
2719 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302720 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002721 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002722 }
2723
2724 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302725 msmsdcc_cfg_sdio_wakeup(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302726 spin_unlock_irqrestore(&host->lock, flags);
2727 /*
2728 * May get a wake-up interrupt the instant we disable the
2729 * clocks. This would disable the wake-up interrupt.
2730 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002731 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302732 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002733 host->clks_on = 0;
2734 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302735
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302736 if (host->tuning_in_progress)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302737 WARN(!host->clks_on,
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302738 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302739
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302740 /* Let interrupts be disabled if the host is powered off */
2741 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
2742 enable_irq(host->core_irqres->start);
2743 host->sdcc_irq_disabled = 0;
2744 }
2745
San Mehat4adbbcc2009-11-08 13:00:37 -08002746 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302747 mutex_unlock(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07002748}
2749
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002750int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2751{
2752 struct msmsdcc_host *host = mmc_priv(mmc);
2753 u32 clk;
2754
2755 clk = readl_relaxed(host->base + MMCICLOCK);
2756 pr_debug("Changing to pwr_save=%d", pwrsave);
2757 if (pwrsave && msmsdcc_is_pwrsave(host))
2758 clk |= MCI_CLK_PWRSAVE;
2759 else
2760 clk &= ~MCI_CLK_PWRSAVE;
2761 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302762 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002763
2764 return 0;
2765}
2766
2767static int msmsdcc_get_ro(struct mmc_host *mmc)
2768{
2769 int status = -ENOSYS;
2770 struct msmsdcc_host *host = mmc_priv(mmc);
2771
2772 if (host->plat->wpswitch) {
2773 status = host->plat->wpswitch(mmc_dev(mmc));
2774 } else if (host->plat->wpswitch_gpio) {
2775 status = gpio_request(host->plat->wpswitch_gpio,
2776 "SD_WP_Switch");
2777 if (status) {
2778 pr_err("%s: %s: Failed to request GPIO %d\n",
2779 mmc_hostname(mmc), __func__,
2780 host->plat->wpswitch_gpio);
2781 } else {
2782 status = gpio_direction_input(
2783 host->plat->wpswitch_gpio);
2784 if (!status) {
2785 /*
2786 * Wait for atleast 300ms as debounce
2787 * time for GPIO input to stabilize.
2788 */
2789 msleep(300);
2790 status = gpio_get_value_cansleep(
2791 host->plat->wpswitch_gpio);
2792 status ^= !host->plat->wpswitch_polarity;
2793 }
2794 gpio_free(host->plat->wpswitch_gpio);
2795 }
2796 }
2797
2798 if (status < 0)
2799 status = -ENOSYS;
2800 pr_debug("%s: Card read-only status %d\n", __func__, status);
2801
2802 return status;
2803}
2804
San Mehat9d2bd732009-09-22 16:44:22 -07002805static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2806{
2807 struct msmsdcc_host *host = mmc_priv(mmc);
2808 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002809
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302810 /*
2811 * We may come here with clocks turned off in that case don't
2812 * attempt to write into MASK0 register. While turning on the
2813 * clocks mci_irqenable will be written to MASK0 register.
2814 */
2815
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002816 if (enable) {
2817 spin_lock_irqsave(&host->lock, flags);
2818 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302819 if (host->clks_on) {
2820 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002821 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302822 mb();
2823 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002824 spin_unlock_irqrestore(&host->lock, flags);
2825 } else {
2826 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302827 if (host->clks_on) {
2828 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002829 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302830 mb();
2831 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002832 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002833}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002834
2835#ifdef CONFIG_PM_RUNTIME
2836static int msmsdcc_enable(struct mmc_host *mmc)
2837{
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302838 int rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002839 struct device *dev = mmc->parent;
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302840 struct msmsdcc_host *host = mmc_priv(mmc);
2841
2842 msmsdcc_pm_qos_update_latency(host, 1);
2843
2844 if (mmc->card && mmc_card_sdio(mmc->card) && host->is_resumed)
2845 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002846
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302847 if (dev->power.runtime_status == RPM_SUSPENDING) {
2848 if (mmc->suspend_task == current) {
2849 pm_runtime_get_noresume(dev);
2850 goto out;
2851 }
2852 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002853
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302854 rc = pm_runtime_get_sync(dev);
2855
2856 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002857 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2858 __func__, rc);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302859 return rc;
2860 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302861
2862 host->is_resumed = true;
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302863out:
2864 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002865}
2866
2867static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2868{
2869 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302870 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002871
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302872 msmsdcc_pm_qos_update_latency(host, 0);
2873
2874 if (mmc->card && mmc_card_sdio(mmc->card))
2875 return 0;
2876
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302877 if (host->plat->disable_runtime_pm)
2878 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002879
2880 rc = pm_runtime_put_sync(mmc->parent);
2881
2882 if (rc < 0)
2883 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2884 __func__, rc);
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302885 else
2886 host->is_resumed = false;
2887
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002888 return rc;
2889}
2890#else
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302891static int msmsdcc_enable(struct mmc_host *mmc)
2892{
2893 struct msmsdcc_host *host = mmc_priv(mmc);
2894 unsigned long flags;
2895
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302896 msmsdcc_pm_qos_update_latency(host, 1);
2897
Asutosh Dasf5298c32012-04-03 14:51:47 +05302898 mutex_lock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302899 spin_lock_irqsave(&host->lock, flags);
2900 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302901 spin_unlock_irqrestore(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302902 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302903 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302904 host->clks_on = 1;
2905 }
2906 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302907 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302908
2909 return 0;
2910}
2911
2912static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2913{
2914 struct msmsdcc_host *host = mmc_priv(mmc);
2915 unsigned long flags;
2916
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302917 msmsdcc_pm_qos_update_latency(host, 0);
2918
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302919 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302920 return 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302921
Asutosh Dasf5298c32012-04-03 14:51:47 +05302922 mutex_lock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302923 spin_lock_irqsave(&host->lock, flags);
2924 if (host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302925 spin_unlock_irqrestore(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302926 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302927 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302928 host->clks_on = 0;
2929 }
2930 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302931 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302932
2933 return 0;
2934}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002935#endif
2936
2937static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2938 struct mmc_ios *ios)
2939{
2940 struct msmsdcc_host *host = mmc_priv(mmc);
2941 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302942 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002943
Subhash Jadavani00083572012-02-15 16:18:01 +05302944 spin_lock_irqsave(&host->lock, flags);
2945 host->io_pad_pwr_switch = 0;
2946 spin_unlock_irqrestore(&host->lock, flags);
2947
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302948 /*
2949 * For eMMC cards, VccQ voltage range must be changed
2950 * only if it operates in HS200 SDR 1.2V mode or in
2951 * DDR 1.2V mode.
2952 */
2953 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_120) {
2954 rc = msmsdcc_set_vccq_vol(host, 1200000);
2955 goto out;
2956 }
2957
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002958 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2959 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302960 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002961 goto out;
2962 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2963 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302964 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002965 goto out;
2966 }
San Mehat9d2bd732009-09-22 16:44:22 -07002967
2968 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002969 /*
2970 * If we are here means voltage switch from high voltage to
2971 * low voltage is required
2972 */
2973
2974 /*
2975 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2976 * register until they become all zeros.
2977 */
2978 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302979 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002980 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2981 mmc_hostname(mmc), __func__);
2982 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002983 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002984
2985 /* Stop SD CLK output. */
2986 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2987 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302988 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002989 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002990
2991 /*
2992 * Switch VDDPX from high voltage to low voltage
2993 * to change the VDD of the SD IO pads.
2994 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302995 rc = msmsdcc_set_vddp_low_vol(host);
2996 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002997 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002998
2999 spin_lock_irqsave(&host->lock, flags);
3000 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3001 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303002 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003003 host->io_pad_pwr_switch = 1;
3004 spin_unlock_irqrestore(&host->lock, flags);
3005
3006 /* Wait 5 ms for the voltage regulater in the card to become stable. */
3007 usleep_range(5000, 5500);
3008
3009 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303010 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003011 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3012 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303013 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003014 spin_unlock_irqrestore(&host->lock, flags);
3015
3016 /*
3017 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
3018 * don't become all ones within 1 ms then a Voltage Switch
3019 * sequence has failed and a power cycle to the card is required.
3020 * Otherwise Voltage Switch sequence is completed successfully.
3021 */
3022 usleep_range(1000, 1500);
3023
3024 spin_lock_irqsave(&host->lock, flags);
3025 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
3026 != (0xF << 1)) {
3027 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
3028 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303029 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003030 goto out_unlock;
3031 }
3032
3033out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303034 /* Enable PWRSAVE */
3035 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3036 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303037 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003038 spin_unlock_irqrestore(&host->lock, flags);
3039out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303040 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003041}
3042
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303043static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003044{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003045 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003046
3047 /* Program the MCLK value to MCLK_FREQ bit field */
3048 if (host->clk_rate <= 112000000)
3049 mclk_freq = 0;
3050 else if (host->clk_rate <= 125000000)
3051 mclk_freq = 1;
3052 else if (host->clk_rate <= 137000000)
3053 mclk_freq = 2;
3054 else if (host->clk_rate <= 150000000)
3055 mclk_freq = 3;
3056 else if (host->clk_rate <= 162000000)
3057 mclk_freq = 4;
3058 else if (host->clk_rate <= 175000000)
3059 mclk_freq = 5;
3060 else if (host->clk_rate <= 187000000)
3061 mclk_freq = 6;
3062 else if (host->clk_rate <= 200000000)
3063 mclk_freq = 7;
3064
3065 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3066 & ~(7 << 24)) | (mclk_freq << 24)),
3067 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003068}
3069
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303070/* Initialize the DLL (Programmable Delay Line ) */
3071static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003072{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003073 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303074 unsigned long flags;
3075 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003076
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303077 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003078 /*
3079 * Make sure that clock is always enabled when DLL
3080 * tuning is in progress. Keeping PWRSAVE ON may
3081 * turn off the clock. So let's disable the PWRSAVE
3082 * here and re-enable it once tuning is completed.
3083 */
3084 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3085 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303086 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303087
3088 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3089 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3090 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3091
3092 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3093 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3094 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3095
3096 msmsdcc_cm_sdc4_dll_set_freq(host);
3097
3098 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3099 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3100 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3101
3102 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3103 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3104 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3105
3106 /* Set DLL_EN bit to 1. */
3107 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3108 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3109
3110 /* Set CK_OUT_EN bit to 1. */
3111 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3112 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3113
3114 wait_cnt = 50;
3115 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3116 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3117 /* max. wait for 50us sec for LOCK bit to be set */
3118 if (--wait_cnt == 0) {
3119 pr_err("%s: %s: DLL failed to LOCK\n",
3120 mmc_hostname(host->mmc), __func__);
3121 rc = -ETIMEDOUT;
3122 goto out;
3123 }
3124 /* wait for 1us before polling again */
3125 udelay(1);
3126 }
3127
3128out:
3129 /* re-enable PWRSAVE */
3130 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3131 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303132 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303133 spin_unlock_irqrestore(&host->lock, flags);
3134
3135 return rc;
3136}
3137
3138static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3139 u8 poll)
3140{
3141 int rc = 0;
3142 u32 wait_cnt = 50;
3143 u8 ck_out_en = 0;
3144
3145 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3146 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3147 MCI_CK_OUT_EN);
3148
3149 while (ck_out_en != poll) {
3150 if (--wait_cnt == 0) {
3151 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3152 mmc_hostname(host->mmc), __func__, poll);
3153 rc = -ETIMEDOUT;
3154 goto out;
3155 }
3156 udelay(1);
3157
3158 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3159 MCI_CK_OUT_EN);
3160 }
3161out:
3162 return rc;
3163}
3164
3165/*
3166 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3167 * calibration sequence. This function should be called before
3168 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3169 * commands (CMD17/CMD18).
3170 *
3171 * This function gets called when host spinlock acquired.
3172 */
3173static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3174{
3175 int rc = 0;
3176 u32 config;
3177
3178 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3179 config |= MCI_CDR_EN;
3180 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3181 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3182
3183 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3184 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3185 if (rc)
3186 goto err_out;
3187
3188 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3189 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3190 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3191
3192 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3193 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3194 if (rc)
3195 goto err_out;
3196
3197 goto out;
3198
3199err_out:
3200 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3201out:
3202 return rc;
3203}
3204
3205static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3206 u8 phase)
3207{
3208 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303209 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3210 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3211 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303212 unsigned long flags;
3213 u32 config;
3214
3215 spin_lock_irqsave(&host->lock, flags);
3216
3217 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3218 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3219 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3220 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3221
3222 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3223 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3224 if (rc)
3225 goto err_out;
3226
3227 /*
3228 * Write the selected DLL clock output phase (0 ... 15)
3229 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
3230 */
3231 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3232 & ~(0xF << 20))
3233 | (grey_coded_phase_table[phase] << 20)),
3234 host->base + MCI_DLL_CONFIG);
3235
3236 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3237 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3238 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3239
3240 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3241 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3242 if (rc)
3243 goto err_out;
3244
3245 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3246 config |= MCI_CDR_EN;
3247 config &= ~MCI_CDR_EXT_EN;
3248 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3249 goto out;
3250
3251err_out:
3252 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3253 mmc_hostname(host->mmc), __func__, phase);
3254out:
3255 spin_unlock_irqrestore(&host->lock, flags);
3256 return rc;
3257}
3258
3259/*
3260 * Find out the greatest range of consecuitive selected
3261 * DLL clock output phases that can be used as sampling
3262 * setting for SD3.0 UHS-I card read operation (in SDR104
3263 * timing mode) or for eMMC4.5 card read operation (in HS200
3264 * timing mode).
3265 * Select the 3/4 of the range and configure the DLL with the
3266 * selected DLL clock output phase.
3267*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303268static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303269 u8 *phase_table, u8 total_phases)
3270{
Subhash Jadavani6159c622012-03-15 19:05:55 +05303271 #define MAX_PHASES 16
Subhash Jadavani34187042012-03-02 10:59:49 +05303272 int ret;
Subhash Jadavani6159c622012-03-15 19:05:55 +05303273 u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
3274 u8 phases_per_row[MAX_PHASES] = {0};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303275 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303276 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3277 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303278
Subhash Jadavani6159c622012-03-15 19:05:55 +05303279 if (!total_phases || (total_phases > MAX_PHASES)) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303280 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3281 mmc_hostname(host->mmc), __func__, total_phases);
3282 return -EINVAL;
3283 }
3284
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303285 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303286 ranges[row_index][col_index] = phase_table[cnt];
3287 phases_per_row[row_index] += 1;
3288 col_index++;
3289
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303290 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303291 continue;
3292 /* check if next phase in phase_table is consecutive or not */
3293 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3294 row_index++;
3295 col_index = 0;
3296 }
3297 }
3298
Subhash Jadavani6159c622012-03-15 19:05:55 +05303299 if (row_index >= MAX_PHASES)
3300 return -EINVAL;
3301
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303302 /* Check if phase-0 is present in first valid window? */
3303 if (!ranges[0][0]) {
3304 phase_0_found = true;
3305 phase_0_raw_index = 0;
3306 /* Check if cycle exist between 2 valid windows */
3307 for (cnt = 1; cnt <= row_index; cnt++) {
3308 if (phases_per_row[cnt]) {
Subhash Jadavani6159c622012-03-15 19:05:55 +05303309 for (i = 0; i < phases_per_row[cnt]; i++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303310 if (ranges[cnt][i] == 15) {
3311 phase_15_found = true;
3312 phase_15_raw_index = cnt;
3313 break;
3314 }
3315 }
3316 }
3317 }
3318 }
3319
3320 /* If 2 valid windows form cycle then merge them as single window */
3321 if (phase_0_found && phase_15_found) {
3322 /* number of phases in raw where phase 0 is present */
3323 u8 phases_0 = phases_per_row[phase_0_raw_index];
3324 /* number of phases in raw where phase 15 is present */
3325 u8 phases_15 = phases_per_row[phase_15_raw_index];
3326
Subhash Jadavani6159c622012-03-15 19:05:55 +05303327 if (phases_0 + phases_15 >= MAX_PHASES)
3328 /*
3329 * If there are more than 1 phase windows then total
3330 * number of phases in both the windows should not be
3331 * more than or equal to MAX_PHASES.
3332 */
3333 return -EINVAL;
3334
3335 /* Merge 2 cyclic windows */
3336 i = phases_15;
3337 for (cnt = 0; cnt < phases_0; cnt++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303338 ranges[phase_15_raw_index][i] =
3339 ranges[phase_0_raw_index][cnt];
Subhash Jadavani6159c622012-03-15 19:05:55 +05303340 if (++i >= MAX_PHASES)
3341 break;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303342 }
Subhash Jadavani6159c622012-03-15 19:05:55 +05303343
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303344 phases_per_row[phase_0_raw_index] = 0;
3345 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
3346 }
3347
3348 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303349 if (phases_per_row[cnt] > curr_max) {
3350 curr_max = phases_per_row[cnt];
3351 selected_row_index = cnt;
3352 }
3353 }
3354
Subhash Jadavani6159c622012-03-15 19:05:55 +05303355 i = ((curr_max * 3) / 4);
3356 if (i)
3357 i--;
3358
Subhash Jadavani34187042012-03-02 10:59:49 +05303359 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303360
Subhash Jadavani6159c622012-03-15 19:05:55 +05303361 if (ret >= MAX_PHASES) {
3362 ret = -EINVAL;
3363 pr_err("%s: %s: invalid phase selected=%d\n",
3364 mmc_hostname(host->mmc), __func__, ret);
3365 }
3366
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303367 return ret;
3368}
3369
Girish K Sa3f41692012-02-29 12:00:09 +05303370static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303371{
3372 int rc = 0;
3373 struct msmsdcc_host *host = mmc_priv(mmc);
3374 unsigned long flags;
3375 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303376 const u32 *tuning_block_pattern = tuning_block_64;
3377 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303378
3379 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
3380
3381 /* Tuning is only required for SDR104 modes */
3382 if (!host->tuning_needed) {
3383 rc = 0;
3384 goto exit;
3385 }
3386
3387 spin_lock_irqsave(&host->lock, flags);
3388 WARN(!host->pwr, "SDCC power is turned off\n");
3389 WARN(!host->clks_on, "SDCC clocks are turned off\n");
3390 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
3391
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303392 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303393 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
3394 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
3395 tuning_block_pattern = tuning_block_128;
3396 size = sizeof(tuning_block_128);
3397 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303398 spin_unlock_irqrestore(&host->lock, flags);
3399
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003400 /* first of all reset the tuning block */
3401 rc = msmsdcc_init_cm_sdc4_dll(host);
3402 if (rc)
3403 goto out;
3404
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303405 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003406 if (!data_buf) {
3407 rc = -ENOMEM;
3408 goto out;
3409 }
3410
3411 phase = 0;
3412 do {
3413 struct mmc_command cmd = {0};
3414 struct mmc_data data = {0};
3415 struct mmc_request mrq = {
3416 .cmd = &cmd,
3417 .data = &data
3418 };
3419 struct scatterlist sg;
3420
3421 /* set the phase in delay line hw block */
3422 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3423 if (rc)
3424 goto kfree;
3425
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303426 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003427 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
3428
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303429 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003430 data.blocks = 1;
3431 data.flags = MMC_DATA_READ;
3432 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
3433
3434 data.sg = &sg;
3435 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303436 sg_init_one(&sg, data_buf, size);
3437 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003438 mmc_wait_for_req(mmc, &mrq);
3439
3440 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303441 !memcmp(data_buf, tuning_block_pattern, size)) {
3442 /* tuning is successful at this tuning point */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003443 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303444 pr_debug("%s: %s: found good phase = %d\n",
3445 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003446 }
3447 } while (++phase < 16);
3448
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003449 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303450 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303451 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05303452 if (rc < 0)
3453 goto kfree;
3454 else
3455 phase = (u8)rc;
3456
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003457 /*
3458 * Finally set the selected phase in delay
3459 * line hw block.
3460 */
3461 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3462 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303463 goto kfree;
3464 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
3465 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003466 } else {
3467 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303468 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003469 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303470 msmsdcc_dump_sdcc_state(host);
3471 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003472 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003473
3474kfree:
3475 kfree(data_buf);
3476out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303477 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303478 host->tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303479 spin_unlock_irqrestore(&host->lock, flags);
3480exit:
3481 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003482 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07003483}
3484
3485static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003486 .enable = msmsdcc_enable,
3487 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07003488 .request = msmsdcc_request,
3489 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003490 .get_ro = msmsdcc_get_ro,
San Mehat9d2bd732009-09-22 16:44:22 -07003491 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003492 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
3493 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07003494};
3495
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003496static unsigned int
3497msmsdcc_slot_status(struct msmsdcc_host *host)
3498{
3499 int status;
3500 unsigned int gpio_no = host->plat->status_gpio;
3501
3502 status = gpio_request(gpio_no, "SD_HW_Detect");
3503 if (status) {
3504 pr_err("%s: %s: Failed to request GPIO %d\n",
3505 mmc_hostname(host->mmc), __func__, gpio_no);
3506 } else {
3507 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003508 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08003509 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003510 if (host->plat->is_status_gpio_active_low)
3511 status = !status;
3512 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003513 gpio_free(gpio_no);
3514 }
3515 return status;
3516}
3517
San Mehat9d2bd732009-09-22 16:44:22 -07003518static void
3519msmsdcc_check_status(unsigned long data)
3520{
3521 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3522 unsigned int status;
3523
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003524 if (host->plat->status || host->plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08003525 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003526 status = host->plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08003527 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003528 status = msmsdcc_slot_status(host);
3529
Krishna Konda941604a2012-01-10 17:46:34 -08003530 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08003531
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003532 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08003533 if (host->plat->status)
3534 pr_info("%s: Slot status change detected "
3535 "(%d -> %d)\n",
3536 mmc_hostname(host->mmc),
3537 host->oldstat, status);
3538 else if (host->plat->is_status_gpio_active_low)
3539 pr_info("%s: Slot status change detected "
3540 "(%d -> %d) and the card detect GPIO"
3541 " is ACTIVE_LOW\n",
3542 mmc_hostname(host->mmc),
3543 host->oldstat, status);
3544 else
3545 pr_info("%s: Slot status change detected "
3546 "(%d -> %d) and the card detect GPIO"
3547 " is ACTIVE_HIGH\n",
3548 mmc_hostname(host->mmc),
3549 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07003550 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003551 }
3552 host->oldstat = status;
3553 } else {
3554 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07003555 }
San Mehat9d2bd732009-09-22 16:44:22 -07003556}
3557
3558static irqreturn_t
3559msmsdcc_platform_status_irq(int irq, void *dev_id)
3560{
3561 struct msmsdcc_host *host = dev_id;
3562
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003563 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07003564 msmsdcc_check_status((unsigned long) host);
3565 return IRQ_HANDLED;
3566}
3567
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003568static irqreturn_t
3569msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
3570{
3571 struct msmsdcc_host *host = dev_id;
3572
3573 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
3574 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303575 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003576 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303577 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003578 wake_lock(&host->sdio_wlock);
3579 msmsdcc_disable_irq_wake(host);
3580 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303581 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003582 }
3583 if (host->plat->is_sdio_al_client) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003584 wake_lock(&host->sdio_wlock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303585 mmc_signal_sdio_irq(host->mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003586 }
3587 spin_unlock(&host->lock);
3588
3589 return IRQ_HANDLED;
3590}
3591
San Mehat9d2bd732009-09-22 16:44:22 -07003592static void
3593msmsdcc_status_notify_cb(int card_present, void *dev_id)
3594{
3595 struct msmsdcc_host *host = dev_id;
3596
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003597 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07003598 card_present);
3599 msmsdcc_check_status((unsigned long) host);
3600}
3601
San Mehat9d2bd732009-09-22 16:44:22 -07003602static int
3603msmsdcc_init_dma(struct msmsdcc_host *host)
3604{
3605 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
3606 host->dma.host = host;
3607 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003608 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003609
3610 if (!host->dmares)
3611 return -ENODEV;
3612
3613 host->dma.nc = dma_alloc_coherent(NULL,
3614 sizeof(struct msmsdcc_nc_dmadata),
3615 &host->dma.nc_busaddr,
3616 GFP_KERNEL);
3617 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003618 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07003619 return -ENOMEM;
3620 }
3621 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
3622 host->dma.cmd_busaddr = host->dma.nc_busaddr;
3623 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
3624 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
3625 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07003626 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07003627
3628 return 0;
3629}
3630
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003631#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
3632/**
3633 * Allocate and Connect a SDCC peripheral's SPS endpoint
3634 *
3635 * This function allocates endpoint context and
3636 * connect it with memory endpoint by calling
3637 * appropriate SPS driver APIs.
3638 *
3639 * Also registers a SPS callback function with
3640 * SPS driver
3641 *
3642 * This function should only be called once typically
3643 * during driver probe.
3644 *
3645 * @host - Pointer to sdcc host structure
3646 * @ep - Pointer to sps endpoint data structure
3647 * @is_produce - 1 means Producer endpoint
3648 * 0 means Consumer endpoint
3649 *
3650 * @return - 0 if successful else negative value.
3651 *
3652 */
3653static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
3654 struct msmsdcc_sps_ep_conn_data *ep,
3655 bool is_producer)
3656{
3657 int rc = 0;
3658 struct sps_pipe *sps_pipe_handle;
3659 struct sps_connect *sps_config = &ep->config;
3660 struct sps_register_event *sps_event = &ep->event;
3661
3662 /* Allocate endpoint context */
3663 sps_pipe_handle = sps_alloc_endpoint();
3664 if (!sps_pipe_handle) {
3665 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
3666 mmc_hostname(host->mmc), is_producer);
3667 rc = -ENOMEM;
3668 goto out;
3669 }
3670
3671 /* Get default connection configuration for an endpoint */
3672 rc = sps_get_config(sps_pipe_handle, sps_config);
3673 if (rc) {
3674 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
3675 " rc=%d", mmc_hostname(host->mmc),
3676 (u32)sps_pipe_handle, rc);
3677 goto get_config_err;
3678 }
3679
3680 /* Modify the default connection configuration */
3681 if (is_producer) {
3682 /*
3683 * For SDCC producer transfer, source should be
3684 * SDCC peripheral where as destination should
3685 * be system memory.
3686 */
3687 sps_config->source = host->sps.bam_handle;
3688 sps_config->destination = SPS_DEV_HANDLE_MEM;
3689 /* Producer pipe will handle this connection */
3690 sps_config->mode = SPS_MODE_SRC;
3691 sps_config->options =
3692 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3693 } else {
3694 /*
3695 * For SDCC consumer transfer, source should be
3696 * system memory where as destination should
3697 * SDCC peripheral
3698 */
3699 sps_config->source = SPS_DEV_HANDLE_MEM;
3700 sps_config->destination = host->sps.bam_handle;
3701 sps_config->mode = SPS_MODE_DEST;
3702 sps_config->options =
3703 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3704 }
3705
3706 /* Producer pipe index */
3707 sps_config->src_pipe_index = host->sps.src_pipe_index;
3708 /* Consumer pipe index */
3709 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
3710 /*
3711 * This event thresold value is only significant for BAM-to-BAM
3712 * transfer. It's ignored for BAM-to-System mode transfer.
3713 */
3714 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05303715
3716 /* Allocate maximum descriptor fifo size */
3717 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
3718 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003719 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
3720 sps_config->desc.size,
3721 &sps_config->desc.phys_base,
3722 GFP_KERNEL);
3723
Pratibhasagar V00b94332011-10-18 14:57:27 +05303724 if (!sps_config->desc.base) {
3725 rc = -ENOMEM;
3726 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3727 , mmc_hostname(host->mmc));
3728 goto get_config_err;
3729 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003730 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3731
3732 /* Establish connection between peripheral and memory endpoint */
3733 rc = sps_connect(sps_pipe_handle, sps_config);
3734 if (rc) {
3735 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3736 " rc=%d", mmc_hostname(host->mmc),
3737 (u32)sps_pipe_handle, rc);
3738 goto sps_connect_err;
3739 }
3740
3741 sps_event->mode = SPS_TRIGGER_CALLBACK;
3742 sps_event->options = SPS_O_EOT;
3743 sps_event->callback = msmsdcc_sps_complete_cb;
3744 sps_event->xfer_done = NULL;
3745 sps_event->user = (void *)host;
3746
3747 /* Register callback event for EOT (End of transfer) event. */
3748 rc = sps_register_event(sps_pipe_handle, sps_event);
3749 if (rc) {
3750 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3751 " rc=%d", mmc_hostname(host->mmc),
3752 (u32)sps_pipe_handle, rc);
3753 goto reg_event_err;
3754 }
3755 /* Now save the sps pipe handle */
3756 ep->pipe_handle = sps_pipe_handle;
3757 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3758 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3759 __func__, is_producer ? "READ" : "WRITE",
3760 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3761 goto out;
3762
3763reg_event_err:
3764 sps_disconnect(sps_pipe_handle);
3765sps_connect_err:
3766 dma_free_coherent(mmc_dev(host->mmc),
3767 sps_config->desc.size,
3768 sps_config->desc.base,
3769 sps_config->desc.phys_base);
3770get_config_err:
3771 sps_free_endpoint(sps_pipe_handle);
3772out:
3773 return rc;
3774}
3775
3776/**
3777 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3778 *
3779 * This function disconnect endpoint and deallocates
3780 * endpoint context.
3781 *
3782 * This function should only be called once typically
3783 * during driver remove.
3784 *
3785 * @host - Pointer to sdcc host structure
3786 * @ep - Pointer to sps endpoint data structure
3787 *
3788 */
3789static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3790 struct msmsdcc_sps_ep_conn_data *ep)
3791{
3792 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3793 struct sps_connect *sps_config = &ep->config;
3794 struct sps_register_event *sps_event = &ep->event;
3795
3796 sps_event->xfer_done = NULL;
3797 sps_event->callback = NULL;
3798 sps_register_event(sps_pipe_handle, sps_event);
3799 sps_disconnect(sps_pipe_handle);
3800 dma_free_coherent(mmc_dev(host->mmc),
3801 sps_config->desc.size,
3802 sps_config->desc.base,
3803 sps_config->desc.phys_base);
3804 sps_free_endpoint(sps_pipe_handle);
3805}
3806
3807/**
3808 * Reset SDCC peripheral's SPS endpoint
3809 *
3810 * This function disconnects an endpoint.
3811 *
3812 * This function should be called for reseting
3813 * SPS endpoint when data transfer error is
3814 * encountered during data transfer. This
3815 * can be considered as soft reset to endpoint.
3816 *
3817 * This function should only be called if
3818 * msmsdcc_sps_init() is already called.
3819 *
3820 * @host - Pointer to sdcc host structure
3821 * @ep - Pointer to sps endpoint data structure
3822 *
3823 * @return - 0 if successful else negative value.
3824 */
3825static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3826 struct msmsdcc_sps_ep_conn_data *ep)
3827{
3828 int rc = 0;
3829 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3830
3831 rc = sps_disconnect(sps_pipe_handle);
3832 if (rc) {
3833 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3834 " rc=%d", mmc_hostname(host->mmc), __func__,
3835 (u32)sps_pipe_handle, rc);
3836 goto out;
3837 }
3838 out:
3839 return rc;
3840}
3841
3842/**
3843 * Restore SDCC peripheral's SPS endpoint
3844 *
3845 * This function connects an endpoint.
3846 *
3847 * This function should be called for restoring
3848 * SPS endpoint after data transfer error is
3849 * encountered during data transfer. This
3850 * can be considered as soft reset to endpoint.
3851 *
3852 * This function should only be called if
3853 * msmsdcc_sps_reset_ep() is called before.
3854 *
3855 * @host - Pointer to sdcc host structure
3856 * @ep - Pointer to sps endpoint data structure
3857 *
3858 * @return - 0 if successful else negative value.
3859 */
3860static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3861 struct msmsdcc_sps_ep_conn_data *ep)
3862{
3863 int rc = 0;
3864 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3865 struct sps_connect *sps_config = &ep->config;
3866 struct sps_register_event *sps_event = &ep->event;
3867
3868 /* Establish connection between peripheral and memory endpoint */
3869 rc = sps_connect(sps_pipe_handle, sps_config);
3870 if (rc) {
3871 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3872 " rc=%d", mmc_hostname(host->mmc), __func__,
3873 (u32)sps_pipe_handle, rc);
3874 goto out;
3875 }
3876
3877 /* Register callback event for EOT (End of transfer) event. */
3878 rc = sps_register_event(sps_pipe_handle, sps_event);
3879 if (rc) {
3880 pr_err("%s: %s: sps_register_event() failed!!!"
3881 " pipe_handle=0x%x, rc=%d",
3882 mmc_hostname(host->mmc), __func__,
3883 (u32)sps_pipe_handle, rc);
3884 goto reg_event_err;
3885 }
3886 goto out;
3887
3888reg_event_err:
3889 sps_disconnect(sps_pipe_handle);
3890out:
3891 return rc;
3892}
3893
3894/**
3895 * Initialize SPS HW connected with SDCC core
3896 *
3897 * This function register BAM HW resources with
3898 * SPS driver and then initialize 2 SPS endpoints
3899 *
3900 * This function should only be called once typically
3901 * during driver probe.
3902 *
3903 * @host - Pointer to sdcc host structure
3904 *
3905 * @return - 0 if successful else negative value.
3906 *
3907 */
3908static int msmsdcc_sps_init(struct msmsdcc_host *host)
3909{
3910 int rc = 0;
3911 struct sps_bam_props bam = {0};
3912
3913 host->bam_base = ioremap(host->bam_memres->start,
3914 resource_size(host->bam_memres));
3915 if (!host->bam_base) {
3916 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3917 " size=0x%x", mmc_hostname(host->mmc),
3918 host->bam_memres->start,
3919 (host->bam_memres->end -
3920 host->bam_memres->start));
3921 rc = -ENOMEM;
3922 goto out;
3923 }
3924
3925 bam.phys_addr = host->bam_memres->start;
3926 bam.virt_addr = host->bam_base;
3927 /*
3928 * This event thresold value is only significant for BAM-to-BAM
3929 * transfer. It's ignored for BAM-to-System mode transfer.
3930 */
3931 bam.event_threshold = 0x10; /* Pipe event threshold */
3932 /*
3933 * This threshold controls when the BAM publish
3934 * the descriptor size on the sideband interface.
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05303935 * SPS HW will be used for data transfer size even
3936 * less than SDCC FIFO size. So let's set BAM summing
3937 * thresold to SPS_MIN_XFER_SIZE bytes.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003938 */
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05303939 bam.summing_threshold = SPS_MIN_XFER_SIZE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003940 /* SPS driver wll handle the SDCC BAM IRQ */
3941 bam.irq = (u32)host->bam_irqres->start;
3942 bam.manage = SPS_BAM_MGR_LOCAL;
3943
3944 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3945 (u32)bam.phys_addr);
3946 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3947 (u32)bam.virt_addr);
3948
3949 /* Register SDCC Peripheral BAM device to SPS driver */
3950 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3951 if (rc) {
3952 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3953 mmc_hostname(host->mmc), rc);
3954 goto reg_bam_err;
3955 }
3956 pr_info("%s: BAM device registered. bam_handle=0x%x",
3957 mmc_hostname(host->mmc), host->sps.bam_handle);
3958
3959 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3960 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3961
3962 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3963 SPS_PROD_PERIPHERAL);
3964 if (rc)
3965 goto sps_reset_err;
3966 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3967 SPS_CONS_PERIPHERAL);
3968 if (rc)
3969 goto cons_conn_err;
3970
3971 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3972 mmc_hostname(host->mmc),
3973 (unsigned long long)host->bam_memres->start,
3974 (unsigned int)host->bam_irqres->start);
3975 goto out;
3976
3977cons_conn_err:
3978 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3979sps_reset_err:
3980 sps_deregister_bam_device(host->sps.bam_handle);
3981reg_bam_err:
3982 iounmap(host->bam_base);
3983out:
3984 return rc;
3985}
3986
3987/**
3988 * De-initialize SPS HW connected with SDCC core
3989 *
3990 * This function deinitialize SPS endpoints and then
3991 * deregisters BAM resources from SPS driver.
3992 *
3993 * This function should only be called once typically
3994 * during driver remove.
3995 *
3996 * @host - Pointer to sdcc host structure
3997 *
3998 */
3999static void msmsdcc_sps_exit(struct msmsdcc_host *host)
4000{
4001 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
4002 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4003 sps_deregister_bam_device(host->sps.bam_handle);
4004 iounmap(host->bam_base);
4005}
4006#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
4007
4008static ssize_t
4009show_polling(struct device *dev, struct device_attribute *attr, char *buf)
4010{
4011 struct mmc_host *mmc = dev_get_drvdata(dev);
4012 struct msmsdcc_host *host = mmc_priv(mmc);
4013 int poll;
4014 unsigned long flags;
4015
4016 spin_lock_irqsave(&host->lock, flags);
4017 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
4018 spin_unlock_irqrestore(&host->lock, flags);
4019
4020 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
4021}
4022
4023static ssize_t
4024set_polling(struct device *dev, struct device_attribute *attr,
4025 const char *buf, size_t count)
4026{
4027 struct mmc_host *mmc = dev_get_drvdata(dev);
4028 struct msmsdcc_host *host = mmc_priv(mmc);
4029 int value;
4030 unsigned long flags;
4031
4032 sscanf(buf, "%d", &value);
4033
4034 spin_lock_irqsave(&host->lock, flags);
4035 if (value) {
4036 mmc->caps |= MMC_CAP_NEEDS_POLL;
4037 mmc_detect_change(host->mmc, 0);
4038 } else {
4039 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4040 }
4041#ifdef CONFIG_HAS_EARLYSUSPEND
4042 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
4043#endif
4044 spin_unlock_irqrestore(&host->lock, flags);
4045 return count;
4046}
4047
4048static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
4049 show_polling, set_polling);
4050static struct attribute *dev_attrs[] = {
4051 &dev_attr_polling.attr,
4052 NULL,
4053};
4054static struct attribute_group dev_attr_grp = {
4055 .attrs = dev_attrs,
4056};
4057
4058#ifdef CONFIG_HAS_EARLYSUSPEND
4059static void msmsdcc_early_suspend(struct early_suspend *h)
4060{
4061 struct msmsdcc_host *host =
4062 container_of(h, struct msmsdcc_host, early_suspend);
4063 unsigned long flags;
4064
4065 spin_lock_irqsave(&host->lock, flags);
4066 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
4067 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4068 spin_unlock_irqrestore(&host->lock, flags);
4069};
4070static void msmsdcc_late_resume(struct early_suspend *h)
4071{
4072 struct msmsdcc_host *host =
4073 container_of(h, struct msmsdcc_host, early_suspend);
4074 unsigned long flags;
4075
4076 if (host->polling_enabled) {
4077 spin_lock_irqsave(&host->lock, flags);
4078 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
4079 mmc_detect_change(host->mmc, 0);
4080 spin_unlock_irqrestore(&host->lock, flags);
4081 }
4082};
4083#endif
4084
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304085static void msmsdcc_print_regs(const char *name, void __iomem *base,
4086 u32 phys_base, unsigned int no_of_regs)
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304087{
4088 unsigned int i;
4089
4090 if (!base)
4091 return;
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304092
4093 pr_info("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
4094 " =====\n", name, phys_base, (u32)base);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304095 for (i = 0; i < no_of_regs; i = i + 4) {
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304096 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
4097 (u32)readl_relaxed(base + i*4),
4098 (u32)readl_relaxed(base + ((i+1)*4)),
4099 (u32)readl_relaxed(base + ((i+2)*4)),
4100 (u32)readl_relaxed(base + ((i+3)*4)));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304101 }
4102}
4103
4104static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
4105{
4106 /* Dump current state of SDCC clocks, power and irq */
4107 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304108 (host->pwr ? "ON" : "OFF"));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304109 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304110 mmc_hostname(host->mmc), (host->clks_on ? "ON" : "OFF"),
4111 (u32)clk_get_rate(host->clk));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304112 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
4113 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
4114
4115 /* Now dump SDCC registers. Don't print FIFO registers */
4116 if (host->clks_on)
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304117 msmsdcc_print_regs("SDCC-CORE", host->base,
4118 host->core_memres->start, 28);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304119
4120 if (host->curr.data) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304121 if (!msmsdcc_is_dma_possible(host, host->curr.data))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304122 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
4123 else if (host->is_dma_mode)
4124 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
4125 mmc_hostname(host->mmc), host->dma.busy,
4126 host->dma.channel, host->dma.crci);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304127 else if (host->is_sps_mode) {
4128 if (host->sps.busy)
4129 msmsdcc_print_regs("SDCC-DML", host->dml_base,
4130 host->dml_memres->start,
4131 16);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304132 pr_info("%s: SPS mode: busy=%d\n",
4133 mmc_hostname(host->mmc), host->sps.busy);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304134 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304135
4136 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
4137 mmc_hostname(host->mmc), host->curr.xfer_size,
4138 host->curr.data_xfered, host->curr.xfer_remain);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304139 }
4140
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304141 pr_info("%s: got_dataend=%d, prog_enable=%d,"
4142 " wait_for_auto_prog_done=%d, got_auto_prog_done=%d\n",
4143 mmc_hostname(host->mmc), host->curr.got_dataend,
4144 host->prog_enable, host->curr.wait_for_auto_prog_done,
4145 host->curr.got_auto_prog_done);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304146}
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304147
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004148static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
4149{
4150 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4151 struct mmc_request *mrq;
4152 unsigned long flags;
4153
4154 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004155 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004156 pr_info("%s: %s: dummy CMD52 timeout\n",
4157 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004158 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004159 }
4160
4161 mrq = host->curr.mrq;
4162
4163 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304164 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
4165 mrq->cmd->opcode);
4166 msmsdcc_dump_sdcc_state(host);
4167
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004168 if (!mrq->cmd->error)
4169 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304170 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004171 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004172 if (mrq->data && !mrq->data->error)
4173 mrq->data->error = -ETIMEDOUT;
4174 host->curr.data_xfered = 0;
4175 if (host->dma.sg && host->is_dma_mode) {
4176 msm_dmov_stop_cmd(host->dma.channel,
4177 &host->dma.hdr, 0);
4178 } else if (host->sps.sg && host->is_sps_mode) {
4179 /* Stop current SPS transfer */
4180 msmsdcc_sps_exit_curr_xfer(host);
4181 } else {
4182 msmsdcc_reset_and_restore(host);
4183 msmsdcc_stop_data(host);
4184 if (mrq->data && mrq->data->stop)
4185 msmsdcc_start_command(host,
4186 mrq->data->stop, 0);
4187 else
4188 msmsdcc_request_end(host, mrq);
4189 }
4190 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304191 host->prog_enable = 0;
Subhash Jadavanied6b0e42012-03-07 16:36:27 +05304192 host->curr.wait_for_auto_prog_done = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004193 msmsdcc_reset_and_restore(host);
4194 msmsdcc_request_end(host, mrq);
4195 }
4196 }
4197 spin_unlock_irqrestore(&host->lock, flags);
4198}
4199
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304200static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
4201{
4202 int i, ret;
4203 struct mmc_platform_data *pdata;
4204 struct device_node *np = dev->of_node;
4205 u32 bus_width = 0;
4206 u32 *clk_table;
4207 int clk_table_len;
4208 u32 *sup_voltages;
4209 int sup_volt_len;
4210
4211 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
4212 if (!pdata) {
4213 dev_err(dev, "could not allocate memory for platform data\n");
4214 goto err;
4215 }
4216
4217 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
4218 if (bus_width == 8) {
4219 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
4220 } else if (bus_width == 4) {
4221 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
4222 } else {
4223 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
4224 pdata->mmc_bus_width = 0;
4225 }
4226
4227 if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
4228 size_t sz;
4229 sz = sup_volt_len / sizeof(*sup_voltages);
4230 if (sz > 0) {
4231 sup_voltages = devm_kzalloc(dev,
4232 sz * sizeof(*sup_voltages), GFP_KERNEL);
4233 if (!sup_voltages) {
4234 dev_err(dev, "No memory for supported voltage\n");
4235 goto err;
4236 }
4237
4238 ret = of_property_read_u32_array(np,
4239 "qcom,sdcc-sup-voltages", sup_voltages, sz);
4240 if (ret < 0) {
4241 dev_err(dev, "error while reading voltage"
4242 "ranges %d\n", ret);
4243 goto err;
4244 }
4245 } else {
4246 dev_err(dev, "No supported voltages\n");
4247 goto err;
4248 }
4249 for (i = 0; i < sz; i += 2) {
4250 u32 mask;
4251
4252 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
4253 sup_voltages[i + 1]);
4254 if (!mask)
4255 dev_err(dev, "Invalide voltage range %d\n", i);
4256 pdata->ocr_mask |= mask;
4257 }
4258 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
4259 } else {
4260 dev_err(dev, "Supported voltage range not specified\n");
4261 }
4262
4263 if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
4264 size_t sz;
4265 sz = clk_table_len / sizeof(*clk_table);
4266
4267 if (sz > 0) {
4268 clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
4269 GFP_KERNEL);
4270 if (!clk_table) {
4271 dev_err(dev, "No memory for clock table\n");
4272 goto err;
4273 }
4274
4275 ret = of_property_read_u32_array(np,
4276 "qcom,sdcc-clk-rates", clk_table, sz);
4277 if (ret < 0) {
4278 dev_err(dev, "error while reading clk"
4279 "table %d\n", ret);
4280 goto err;
4281 }
4282 } else {
4283 dev_err(dev, "clk_table not specified\n");
4284 goto err;
4285 }
4286 pdata->sup_clk_table = clk_table;
4287 pdata->sup_clk_cnt = sz;
4288 } else {
4289 dev_err(dev, "Supported clock rates not specified\n");
4290 }
4291
4292 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
4293 pdata->nonremovable = true;
4294 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
4295 pdata->disable_cmd23 = true;
4296
4297 return pdata;
4298err:
4299 return NULL;
4300}
4301
San Mehat9d2bd732009-09-22 16:44:22 -07004302static int
4303msmsdcc_probe(struct platform_device *pdev)
4304{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304305 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07004306 struct msmsdcc_host *host;
4307 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004308 unsigned long flags;
4309 struct resource *core_irqres = NULL;
4310 struct resource *bam_irqres = NULL;
4311 struct resource *core_memres = NULL;
4312 struct resource *dml_memres = NULL;
4313 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07004314 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07004315 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05304316 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004317 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07004318
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304319 if (pdev->dev.of_node) {
4320 plat = msmsdcc_populate_pdata(&pdev->dev);
4321 of_property_read_u32((&pdev->dev)->of_node,
4322 "cell-index", &pdev->id);
4323 } else {
4324 plat = pdev->dev.platform_data;
4325 }
4326
San Mehat9d2bd732009-09-22 16:44:22 -07004327 /* must have platform data */
4328 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004329 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004330 ret = -EINVAL;
4331 goto out;
4332 }
4333
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004334 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07004335 return -EINVAL;
4336
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304337 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
4338 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
4339 return -EINVAL;
4340 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004341
San Mehat9d2bd732009-09-22 16:44:22 -07004342 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004343 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004344 return -ENXIO;
4345 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304346 if (pdev->dev.of_node) {
4347 /*
4348 * Device tree iomem resources are only accessible by index.
4349 * index = 0 -> SDCC register interface
4350 * index = 1 -> DML register interface
4351 * index = 2 -> BAM register interface
4352 * IRQ resources:
4353 * index = 0 -> SDCC IRQ
4354 * index = 1 -> BAM IRQ
4355 */
4356 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
4357 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
4358 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
4359 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
4360 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
4361 } else {
4362 for (i = 0; i < pdev->num_resources; i++) {
4363 if (pdev->resource[i].flags & IORESOURCE_MEM) {
4364 if (!strncmp(pdev->resource[i].name,
4365 "sdcc_dml_addr",
4366 sizeof("sdcc_dml_addr")))
4367 dml_memres = &pdev->resource[i];
4368 else if (!strncmp(pdev->resource[i].name,
4369 "sdcc_bam_addr",
4370 sizeof("sdcc_bam_addr")))
4371 bam_memres = &pdev->resource[i];
4372 else
4373 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07004374
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304375 }
4376 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
4377 if (!strncmp(pdev->resource[i].name,
4378 "sdcc_bam_irq",
4379 sizeof("sdcc_bam_irq")))
4380 bam_irqres = &pdev->resource[i];
4381 else
4382 core_irqres = &pdev->resource[i];
4383 }
4384 if (pdev->resource[i].flags & IORESOURCE_DMA) {
4385 if (!strncmp(pdev->resource[i].name,
4386 "sdcc_dma_chnl",
4387 sizeof("sdcc_dma_chnl")))
4388 dmares = &pdev->resource[i];
4389 else if (!strncmp(pdev->resource[i].name,
4390 "sdcc_dma_crci",
4391 sizeof("sdcc_dma_crci")))
4392 dma_crci_res = &pdev->resource[i];
4393 }
Krishna Konda25786ec2011-07-25 16:21:36 -07004394 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004395 }
4396
4397 if (!core_irqres || !core_memres) {
4398 pr_err("%s: Invalid sdcc core resource\n", __func__);
4399 return -ENXIO;
4400 }
4401
4402 /*
4403 * Both BAM and DML memory resource should be preset.
4404 * BAM IRQ resource should also be present.
4405 */
4406 if ((bam_memres && !dml_memres) ||
4407 (!bam_memres && dml_memres) ||
4408 ((bam_memres && dml_memres) && !bam_irqres)) {
4409 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004410 return -ENXIO;
4411 }
4412
4413 /*
4414 * Setup our host structure
4415 */
San Mehat9d2bd732009-09-22 16:44:22 -07004416 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
4417 if (!mmc) {
4418 ret = -ENOMEM;
4419 goto out;
4420 }
4421
4422 host = mmc_priv(mmc);
4423 host->pdev_id = pdev->id;
4424 host->plat = plat;
4425 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08004426 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05304427
4428 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004429 host->is_sps_mode = 1;
4430 else if (dmares)
4431 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07004432
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004433 host->base = ioremap(core_memres->start,
4434 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07004435 if (!host->base) {
4436 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004437 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004438 }
4439
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004440 host->core_irqres = core_irqres;
4441 host->bam_irqres = bam_irqres;
4442 host->core_memres = core_memres;
4443 host->dml_memres = dml_memres;
4444 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07004445 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07004446 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07004447 spin_lock_init(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304448 mutex_init(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07004449
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004450#ifdef CONFIG_MMC_EMBEDDED_SDIO
4451 if (plat->embedded_sdio)
4452 mmc_set_embedded_sdio_data(mmc,
4453 &plat->embedded_sdio->cis,
4454 &plat->embedded_sdio->cccr,
4455 plat->embedded_sdio->funcs,
4456 plat->embedded_sdio->num_funcs);
4457#endif
4458
Sahitya Tummala62612cf2010-12-08 15:03:03 +05304459 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
4460 (unsigned long)host);
4461
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004462 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
4463 (unsigned long)host);
4464 if (host->is_dma_mode) {
4465 /* Setup DMA */
4466 ret = msmsdcc_init_dma(host);
4467 if (ret)
4468 goto ioremap_free;
4469 } else {
4470 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004471 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004472 }
4473
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004474 /*
4475 * Setup SDCC clock if derived from Dayatona
4476 * fabric core clock.
4477 */
4478 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07004479 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004480 if (!IS_ERR(host->dfab_pclk)) {
4481 /* Set the clock rate to 64MHz for max. performance */
4482 ret = clk_set_rate(host->dfab_pclk, 64000000);
4483 if (ret)
4484 goto dfab_pclk_put;
Asutosh Dasf5298c32012-04-03 14:51:47 +05304485 ret = clk_prepare_enable(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004486 if (ret)
4487 goto dfab_pclk_put;
4488 } else
4489 goto dma_free;
4490 }
4491
4492 /*
4493 * Setup main peripheral bus clock
4494 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004495 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004496 if (!IS_ERR(host->pclk)) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05304497 ret = clk_prepare_enable(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004498 if (ret)
4499 goto pclk_put;
4500
4501 host->pclk_rate = clk_get_rate(host->pclk);
4502 }
4503
4504 /*
4505 * Setup SDC MMC clock
4506 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004507 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07004508 if (IS_ERR(host->clk)) {
4509 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004510 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07004511 }
4512
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004513 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
4514 if (ret) {
4515 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
4516 goto clk_put;
4517 }
4518
Asutosh Dasf5298c32012-04-03 14:51:47 +05304519 ret = clk_prepare_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004520 if (ret)
4521 goto clk_put;
4522
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004523 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304524 if (!host->clk_rate)
4525 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304526
4527 /*
4528 * Lookup the Controller Version, to identify the supported features
4529 * Version number read as 0 would indicate SDCC3 or earlier versions
4530 */
4531 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
4532 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
4533 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304534 /*
4535 * Set the register write delay according to min. clock frequency
4536 * supported and update later when the host->clk_rate changes.
4537 */
4538 host->reg_write_delay =
4539 (1 + ((3 * USEC_PER_SEC) /
4540 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004541
4542 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05304543 /* Apply Hard reset to SDCC to put it in power on default state */
4544 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004545
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304546 /* pm qos request to prevent apps idle power collapse */
4547 if (host->plat->swfi_latency)
4548 pm_qos_add_request(&host->pm_qos_req_dma,
4549 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
4550
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004551 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07004552 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004553 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07004554 goto clk_disable;
4555 }
4556
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004557
4558 /* Clocks has to be running before accessing SPS/DML HW blocks */
4559 if (host->is_sps_mode) {
4560 /* Initialize SPS */
4561 ret = msmsdcc_sps_init(host);
4562 if (ret)
4563 goto vreg_deinit;
4564 /* Initialize DML */
4565 ret = msmsdcc_dml_init(host);
4566 if (ret)
4567 goto sps_exit;
4568 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05304569 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07004570
San Mehat9d2bd732009-09-22 16:44:22 -07004571 /*
4572 * Setup MMC host structure
4573 */
4574 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004575 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
4576 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004577 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004578 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
4579 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07004580
San Mehat9d2bd732009-09-22 16:44:22 -07004581 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05304582 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304583
4584 /*
4585 * If we send the CMD23 before multi block write/read command
4586 * then we need not to send CMD12 at the end of the transfer.
4587 * If we don't send the CMD12 then only way to detect the PROG_DONE
4588 * status is to use the AUTO_PROG_DONE status provided by SDCC4
4589 * controller. So let's enable the CMD23 for SDCC4 only.
4590 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304591 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304592 mmc->caps |= MMC_CAP_CMD23;
4593
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004594 mmc->caps |= plat->uhs_caps;
4595 /*
4596 * XPC controls the maximum current in the default speed mode of SDXC
4597 * card. XPC=0 means 100mA (max.) but speed class is not supported.
4598 * XPC=1 means 150mA (max.) and speed class is supported.
4599 */
4600 if (plat->xpc_cap)
4601 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
4602 MMC_CAP_SET_XPC_180);
4603
Subhash Jadavani6bb34a82012-04-18 13:18:40 +05304604 mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304605 if (pdev->dev.of_node) {
4606 if (of_get_property((&pdev->dev)->of_node,
4607 "qcom,sdcc-hs200", NULL))
4608 mmc->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
4609 }
4610
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004611 if (plat->nonremovable)
4612 mmc->caps |= MMC_CAP_NONREMOVABLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004613 mmc->caps |= MMC_CAP_SDIO_IRQ;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004614
4615 if (plat->is_sdio_al_client)
4616 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07004617
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304618 mmc->max_segs = msmsdcc_get_nr_sg(host);
4619 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
4620 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07004621
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304622 mmc->max_req_size = MMC_MAX_REQ_SIZE;
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +05304623 mmc->max_seg_size = mmc->max_req_size;
San Mehat9d2bd732009-09-22 16:44:22 -07004624
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004625 writel_relaxed(0, host->base + MMCIMASK0);
4626 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05304627 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004628
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004629 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
4630 mb();
4631 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07004632
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004633 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
4634 DRIVER_NAME " (cmd)", host);
4635 if (ret)
4636 goto dml_exit;
4637
4638 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
4639 DRIVER_NAME " (pio)", host);
4640 if (ret)
4641 goto irq_free;
4642
4643 /*
4644 * Enable SDCC IRQ only when host is powered on. Otherwise, this
4645 * IRQ is un-necessarily being monitored by MPM (Modem power
4646 * management block) during idle-power collapse. The MPM will be
4647 * configured to monitor the DATA1 GPIO line with level-low trigger
4648 * and thus depending on the GPIO status, it prevents TCXO shutdown
4649 * during idle-power collapse.
4650 */
4651 disable_irq(core_irqres->start);
4652 host->sdcc_irq_disabled = 1;
4653
4654 if (plat->sdiowakeup_irq) {
4655 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4656 mmc_hostname(mmc));
4657 ret = request_irq(plat->sdiowakeup_irq,
4658 msmsdcc_platform_sdiowakeup_irq,
4659 IRQF_SHARED | IRQF_TRIGGER_LOW,
4660 DRIVER_NAME "sdiowakeup", host);
4661 if (ret) {
4662 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
4663 plat->sdiowakeup_irq, ret);
4664 goto pio_irq_free;
4665 } else {
4666 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304667 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004668 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304669 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004670 }
4671 spin_unlock_irqrestore(&host->lock, flags);
4672 }
4673 }
4674
Subhash Jadavanic9b85752012-04-13 11:16:49 +05304675 if (host->plat->mpm_sdiowakeup_int) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004676 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4677 mmc_hostname(mmc));
4678 }
4679
4680 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
4681 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004682 /*
4683 * Setup card detect change
4684 */
4685
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004686 if (plat->status || plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08004687 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004688 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08004689 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004690 host->oldstat = msmsdcc_slot_status(host);
Krishna Konda360aa422011-12-06 18:27:41 -08004691
Krishna Konda941604a2012-01-10 17:46:34 -08004692 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004693 }
San Mehat9d2bd732009-09-22 16:44:22 -07004694
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004695 if (plat->status_irq) {
4696 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07004697 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004698 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07004699 DRIVER_NAME " (slot)",
4700 host);
4701 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004702 pr_err("Unable to get slot IRQ %d (%d)\n",
4703 plat->status_irq, ret);
4704 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004705 }
4706 } else if (plat->register_status_notify) {
4707 plat->register_status_notify(msmsdcc_status_notify_cb, host);
4708 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004709 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07004710 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004711
4712 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004713
4714 ret = pm_runtime_set_active(&(pdev)->dev);
4715 if (ret < 0)
4716 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
4717 __func__, ret);
4718 /*
4719 * There is no notion of suspend/resume for SD/MMC/SDIO
4720 * cards. So host can be suspended/resumed with out
4721 * worrying about its children.
4722 */
4723 pm_suspend_ignore_children(&(pdev)->dev, true);
4724
4725 /*
4726 * MMC/SD/SDIO bus suspend/resume operations are defined
4727 * only for the slots that will be used for non-removable
4728 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
4729 * defined. Otherwise, they simply become card removal and
4730 * insertion events during suspend and resume respectively.
4731 * Hence, enable run-time PM only for slots for which bus
4732 * suspend/resume operations are defined.
4733 */
4734#ifdef CONFIG_MMC_UNSAFE_RESUME
4735 /*
4736 * If this capability is set, MMC core will enable/disable host
4737 * for every claim/release operation on a host. We use this
4738 * notification to increment/decrement runtime pm usage count.
4739 */
4740 mmc->caps |= MMC_CAP_DISABLE;
4741 pm_runtime_enable(&(pdev)->dev);
4742#else
4743 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
4744 mmc->caps |= MMC_CAP_DISABLE;
4745 pm_runtime_enable(&(pdev)->dev);
4746 }
4747#endif
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05304748#ifndef CONFIG_PM_RUNTIME
4749 mmc_set_disable_delay(mmc, MSM_MMC_DISABLE_TIMEOUT);
4750#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004751 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
4752 (unsigned long)host);
4753
San Mehat9d2bd732009-09-22 16:44:22 -07004754 mmc_add_host(mmc);
4755
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004756#ifdef CONFIG_HAS_EARLYSUSPEND
4757 host->early_suspend.suspend = msmsdcc_early_suspend;
4758 host->early_suspend.resume = msmsdcc_late_resume;
4759 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
4760 register_early_suspend(&host->early_suspend);
4761#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004762
Krishna Konda25786ec2011-07-25 16:21:36 -07004763 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
4764 " dmacrcri %d\n", mmc_hostname(mmc),
4765 (unsigned long long)core_memres->start,
4766 (unsigned int) core_irqres->start,
4767 (unsigned int) plat->status_irq, host->dma.channel,
4768 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004769
4770 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
4771 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
4772 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
4773 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
4774 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
4775 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
4776 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
4777 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
4778 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
4779 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
4780 host->eject);
4781 pr_info("%s: Power save feature enable = %d\n",
4782 mmc_hostname(mmc), msmsdcc_pwrsave);
4783
Krishna Konda25786ec2011-07-25 16:21:36 -07004784 if (host->is_dma_mode && host->dma.channel != -1
4785 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004786 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004787 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004788 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004789 mmc_hostname(mmc), host->dma.cmd_busaddr,
4790 host->dma.cmdptr_busaddr);
4791 } else if (host->is_sps_mode) {
4792 pr_info("%s: SPS-BAM data transfer mode available\n",
4793 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004794 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004795 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004796
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004797#if defined(CONFIG_DEBUG_FS)
4798 msmsdcc_dbg_createhost(host);
4799#endif
4800 if (!plat->status_irq) {
4801 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
4802 if (ret)
4803 goto platform_irq_free;
4804 }
San Mehat9d2bd732009-09-22 16:44:22 -07004805 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004806
4807 platform_irq_free:
4808 del_timer_sync(&host->req_tout_timer);
4809 pm_runtime_disable(&(pdev)->dev);
4810 pm_runtime_set_suspended(&(pdev)->dev);
4811
4812 if (plat->status_irq)
4813 free_irq(plat->status_irq, host);
4814 sdiowakeup_irq_free:
4815 wake_lock_destroy(&host->sdio_suspend_wlock);
4816 if (plat->sdiowakeup_irq)
4817 free_irq(plat->sdiowakeup_irq, host);
4818 pio_irq_free:
4819 if (plat->sdiowakeup_irq)
4820 wake_lock_destroy(&host->sdio_wlock);
4821 free_irq(core_irqres->start, host);
4822 irq_free:
4823 free_irq(core_irqres->start, host);
4824 dml_exit:
4825 if (host->is_sps_mode)
4826 msmsdcc_dml_exit(host);
4827 sps_exit:
4828 if (host->is_sps_mode)
4829 msmsdcc_sps_exit(host);
4830 vreg_deinit:
4831 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07004832 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004833 clk_disable(host->clk);
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304834 if (host->plat->swfi_latency)
4835 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07004836 clk_put:
4837 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004838 pclk_disable:
4839 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05304840 clk_disable_unprepare(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07004841 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004842 if (!IS_ERR(host->pclk))
4843 clk_put(host->pclk);
4844 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05304845 clk_disable_unprepare(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004846 dfab_pclk_put:
4847 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4848 clk_put(host->dfab_pclk);
4849 dma_free:
4850 if (host->is_dma_mode) {
4851 if (host->dmares)
4852 dma_free_coherent(NULL,
4853 sizeof(struct msmsdcc_nc_dmadata),
4854 host->dma.nc, host->dma.nc_busaddr);
4855 }
4856 ioremap_free:
4857 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07004858 host_free:
4859 mmc_free_host(mmc);
4860 out:
4861 return ret;
4862}
4863
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004864static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07004865{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004866 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4867 struct mmc_platform_data *plat;
4868 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004869
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004870 if (!mmc)
4871 return -ENXIO;
4872
4873 if (pm_runtime_suspended(&(pdev)->dev))
4874 pm_runtime_resume(&(pdev)->dev);
4875
4876 host = mmc_priv(mmc);
4877
4878 DBG(host, "Removing SDCC device = %d\n", pdev->id);
4879 plat = host->plat;
4880
4881 if (!plat->status_irq)
4882 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
4883
4884 del_timer_sync(&host->req_tout_timer);
4885 tasklet_kill(&host->dma_tlet);
4886 tasklet_kill(&host->sps.tlet);
4887 mmc_remove_host(mmc);
4888
4889 if (plat->status_irq)
4890 free_irq(plat->status_irq, host);
4891
4892 wake_lock_destroy(&host->sdio_suspend_wlock);
4893 if (plat->sdiowakeup_irq) {
4894 wake_lock_destroy(&host->sdio_wlock);
4895 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
4896 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07004897 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004898
4899 free_irq(host->core_irqres->start, host);
4900 free_irq(host->core_irqres->start, host);
4901
4902 clk_put(host->clk);
4903 if (!IS_ERR(host->pclk))
4904 clk_put(host->pclk);
4905 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4906 clk_put(host->dfab_pclk);
4907
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304908 if (host->plat->swfi_latency)
4909 pm_qos_remove_request(&host->pm_qos_req_dma);
4910
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004911 msmsdcc_vreg_init(host, false);
4912
4913 if (host->is_dma_mode) {
4914 if (host->dmares)
4915 dma_free_coherent(NULL,
4916 sizeof(struct msmsdcc_nc_dmadata),
4917 host->dma.nc, host->dma.nc_busaddr);
4918 }
4919
4920 if (host->is_sps_mode) {
4921 msmsdcc_dml_exit(host);
4922 msmsdcc_sps_exit(host);
4923 }
4924
4925 iounmap(host->base);
4926 mmc_free_host(mmc);
4927
4928#ifdef CONFIG_HAS_EARLYSUSPEND
4929 unregister_early_suspend(&host->early_suspend);
4930#endif
4931 pm_runtime_disable(&(pdev)->dev);
4932 pm_runtime_set_suspended(&(pdev)->dev);
4933
4934 return 0;
4935}
4936
4937#ifdef CONFIG_MSM_SDIO_AL
4938int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4939{
4940 struct msmsdcc_host *host = mmc_priv(mmc);
4941 unsigned long flags;
4942
Asutosh Dasf5298c32012-04-03 14:51:47 +05304943 mutex_lock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004944 spin_lock_irqsave(&host->lock, flags);
4945 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
4946 enable ? "En" : "Dis");
4947
4948 if (enable) {
4949 if (!host->sdcc_irq_disabled) {
4950 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05304951 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004952 host->sdcc_irq_disabled = 1;
4953 }
4954
4955 if (host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05304956 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004957 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304958 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004959 host->clks_on = 0;
4960 }
4961
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304962 if (host->plat->sdio_lpm_gpio_setup &&
4963 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004964 spin_unlock_irqrestore(&host->lock, flags);
4965 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
4966 spin_lock_irqsave(&host->lock, flags);
4967 host->sdio_gpio_lpm = 1;
4968 }
4969
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304970 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004971 msmsdcc_enable_irq_wake(host);
4972 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304973 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004974 }
4975 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304976 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004977 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304978 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004979 msmsdcc_disable_irq_wake(host);
4980 }
4981
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304982 if (host->plat->sdio_lpm_gpio_setup &&
4983 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004984 spin_unlock_irqrestore(&host->lock, flags);
4985 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
4986 spin_lock_irqsave(&host->lock, flags);
4987 host->sdio_gpio_lpm = 0;
4988 }
4989
4990 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05304991 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004992 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304993 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004994 host->clks_on = 1;
4995 }
4996
4997 if (host->sdcc_irq_disabled) {
4998 writel_relaxed(host->mci_irqenable,
4999 host->base + MMCIMASK0);
5000 mb();
5001 enable_irq(host->core_irqres->start);
5002 host->sdcc_irq_disabled = 0;
5003 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005004 }
5005 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305006 mutex_unlock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005007 return 0;
5008}
5009#else
5010int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
5011{
5012 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07005013}
5014#endif
5015
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005016#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07005017static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005018msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07005019{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005020 struct mmc_host *mmc = dev_get_drvdata(dev);
5021 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07005022 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305023 unsigned long flags;
5024
San Mehat9d2bd732009-09-22 16:44:22 -07005025
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005026 if (host->plat->is_sdio_al_client)
5027 return 0;
Sahitya Tummala7661a452011-07-18 13:28:35 +05305028 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005029 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005030 host->sdcc_suspending = 1;
5031 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07005032
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005033 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005034 * MMC core thinks that host is disabled by now since
5035 * runtime suspend is scheduled after msmsdcc_disable()
5036 * is called. Thus, MMC core will try to enable the host
5037 * while suspending it. This results in a synchronous
5038 * runtime resume request while in runtime suspending
5039 * context and hence inorder to complete this resume
5040 * requet, it will wait for suspend to be complete,
5041 * but runtime suspend also can not proceed further
5042 * until the host is resumed. Thus, it leads to a hang.
5043 * Hence, increase the pm usage count before suspending
5044 * the host so that any resume requests after this will
5045 * simple become pm usage counter increment operations.
5046 */
5047 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05305048 /* If there is pending detect work abort runtime suspend */
5049 if (unlikely(work_busy(&mmc->detect.work)))
5050 rc = -EAGAIN;
5051 else
5052 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005053 pm_runtime_put_noidle(dev);
5054
5055 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305056 spin_lock_irqsave(&host->lock, flags);
5057 host->sdcc_suspended = true;
5058 spin_unlock_irqrestore(&host->lock, flags);
5059 if (mmc->card && mmc_card_sdio(mmc->card) &&
5060 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005061 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305062 * If SDIO function driver doesn't want
5063 * to power off the card, atleast turn off
5064 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005065 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305066 mmc_host_clk_hold(mmc);
5067 spin_lock_irqsave(&mmc->clk_lock, flags);
5068 mmc->clk_old = mmc->ios.clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005069 mmc->ios.clock = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305070 mmc->clk_gated = true;
5071 spin_unlock_irqrestore(&mmc->clk_lock, flags);
5072 mmc_set_ios(mmc);
5073 mmc_host_clk_release(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005074 }
5075 }
5076 host->sdcc_suspending = 0;
5077 mmc->suspend_task = NULL;
5078 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
5079 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005080 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05305081 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
San Mehat9d2bd732009-09-22 16:44:22 -07005082 return rc;
5083}
5084
5085static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005086msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07005087{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005088 struct mmc_host *mmc = dev_get_drvdata(dev);
5089 struct msmsdcc_host *host = mmc_priv(mmc);
5090 unsigned long flags;
5091
5092 if (host->plat->is_sdio_al_client)
5093 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07005094
Sahitya Tummala7661a452011-07-18 13:28:35 +05305095 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005096 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305097 if (mmc->card && mmc_card_sdio(mmc->card) &&
5098 mmc_card_keep_power(mmc)) {
5099 mmc_host_clk_hold(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305100 mmc->ios.clock = host->clk_rate;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305101 mmc_set_ios(mmc);
5102 mmc_host_clk_release(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305103 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005104
5105 mmc_resume_host(mmc);
5106
5107 /*
5108 * FIXME: Clearing of flags must be handled in clients
5109 * resume handler.
5110 */
5111 spin_lock_irqsave(&host->lock, flags);
5112 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305113 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005114 spin_unlock_irqrestore(&host->lock, flags);
5115
5116 /*
5117 * After resuming the host wait for sometime so that
5118 * the SDIO work will be processed.
5119 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305120 if (mmc->card && mmc_card_sdio(mmc->card)) {
Subhash Jadavanic9b85752012-04-13 11:16:49 +05305121 if ((host->plat->mpm_sdiowakeup_int ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005122 host->plat->sdiowakeup_irq) &&
5123 wake_lock_active(&host->sdio_wlock))
5124 wake_lock_timeout(&host->sdio_wlock, 1);
5125 }
5126
5127 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005128 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05305129 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005130 return 0;
5131}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005132
5133static int msmsdcc_runtime_idle(struct device *dev)
5134{
5135 struct mmc_host *mmc = dev_get_drvdata(dev);
5136 struct msmsdcc_host *host = mmc_priv(mmc);
5137
5138 if (host->plat->is_sdio_al_client)
5139 return 0;
5140
5141 /* Idle timeout is not configurable for now */
5142 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
5143
5144 return -EAGAIN;
5145}
5146
5147static int msmsdcc_pm_suspend(struct device *dev)
5148{
5149 struct mmc_host *mmc = dev_get_drvdata(dev);
5150 struct msmsdcc_host *host = mmc_priv(mmc);
5151 int rc = 0;
5152
5153 if (host->plat->is_sdio_al_client)
5154 return 0;
5155
5156
5157 if (host->plat->status_irq)
5158 disable_irq(host->plat->status_irq);
5159
Subhash Jadavani18702212012-03-19 18:50:18 +05305160 if (!pm_runtime_suspended(dev)) {
5161 if (!(mmc->card && mmc_card_sdio(mmc->card))) {
5162 /*
5163 * decrement power.usage_counter if it's
5164 * not zero earlier
5165 */
5166 pm_runtime_put_noidle(dev);
5167 rc = pm_runtime_suspend(dev);
5168 }
5169
5170 /*
5171 * if device runtime PM status is still not suspended
5172 * then perform suspend here.
5173 */
5174 if (!pm_runtime_suspended(dev))
5175 rc = msmsdcc_runtime_suspend(dev);
5176 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005177
5178 return rc;
5179}
5180
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305181static int msmsdcc_suspend_noirq(struct device *dev)
5182{
5183 struct mmc_host *mmc = dev_get_drvdata(dev);
5184 struct msmsdcc_host *host = mmc_priv(mmc);
5185 int rc = 0;
5186
5187 /*
5188 * After platform suspend there may be active request
5189 * which might have enabled clocks. For example, in SDIO
5190 * case, ksdioirq thread might have scheduled after sdcc
5191 * suspend but before system freeze. In that case abort
5192 * suspend and retry instead of keeping the clocks on
5193 * during suspend and not allowing TCXO.
5194 */
5195
Asutosh Dasf5298c32012-04-03 14:51:47 +05305196 if (host->clks_on && !host->plat->is_sdio_al_client) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305197 pr_warn("%s: clocks are on after suspend, aborting system "
5198 "suspend\n", mmc_hostname(mmc));
5199 rc = -EAGAIN;
5200 }
5201
5202 return rc;
5203}
5204
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005205static int msmsdcc_pm_resume(struct device *dev)
5206{
5207 struct mmc_host *mmc = dev_get_drvdata(dev);
5208 struct msmsdcc_host *host = mmc_priv(mmc);
5209 int rc = 0;
5210
5211 if (host->plat->is_sdio_al_client)
5212 return 0;
5213
Sahitya Tummalafb486372011-09-02 19:01:49 +05305214 if (!pm_runtime_suspended(dev))
5215 rc = msmsdcc_runtime_resume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005216 if (host->plat->status_irq) {
5217 msmsdcc_check_status((unsigned long)host);
5218 enable_irq(host->plat->status_irq);
5219 }
5220
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005221 return rc;
5222}
5223
Daniel Walker08ecfde2010-06-23 12:32:20 -07005224#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005225#define msmsdcc_runtime_suspend NULL
5226#define msmsdcc_runtime_resume NULL
5227#define msmsdcc_runtime_idle NULL
5228#define msmsdcc_pm_suspend NULL
5229#define msmsdcc_pm_resume NULL
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305230#define msmsdcc_suspend_noirq NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07005231#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005232
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005233static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
5234 .runtime_suspend = msmsdcc_runtime_suspend,
5235 .runtime_resume = msmsdcc_runtime_resume,
5236 .runtime_idle = msmsdcc_runtime_idle,
5237 .suspend = msmsdcc_pm_suspend,
5238 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305239 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005240};
5241
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305242static const struct of_device_id msmsdcc_dt_match[] = {
5243 {.compatible = "qcom,msm-sdcc"},
5244
5245};
5246MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
5247
San Mehat9d2bd732009-09-22 16:44:22 -07005248static struct platform_driver msmsdcc_driver = {
5249 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005250 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07005251 .driver = {
5252 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005253 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305254 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07005255 },
5256};
5257
5258static int __init msmsdcc_init(void)
5259{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005260#if defined(CONFIG_DEBUG_FS)
5261 int ret = 0;
5262 ret = msmsdcc_dbg_init();
5263 if (ret) {
5264 pr_err("Failed to create debug fs dir \n");
5265 return ret;
5266 }
5267#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005268 return platform_driver_register(&msmsdcc_driver);
5269}
5270
5271static void __exit msmsdcc_exit(void)
5272{
5273 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005274
5275#if defined(CONFIG_DEBUG_FS)
5276 debugfs_remove(debugfs_file);
5277 debugfs_remove(debugfs_dir);
5278#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005279}
5280
5281module_init(msmsdcc_init);
5282module_exit(msmsdcc_exit);
5283
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005284MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07005285MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005286
5287#if defined(CONFIG_DEBUG_FS)
5288
5289static int
5290msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
5291{
5292 file->private_data = inode->i_private;
5293 return 0;
5294}
5295
5296static ssize_t
5297msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
5298 size_t count, loff_t *ppos)
5299{
5300 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08005301 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005302 int max, i;
5303
5304 i = 0;
5305 max = sizeof(buf) - 1;
5306
5307 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
5308 host->curr.cmd, host->curr.data);
5309 if (host->curr.cmd) {
5310 struct mmc_command *cmd = host->curr.cmd;
5311
5312 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
5313 cmd->opcode, cmd->arg, cmd->flags);
5314 }
5315 if (host->curr.data) {
5316 struct mmc_data *data = host->curr.data;
5317 i += scnprintf(buf + i, max - i,
5318 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
5319 data->timeout_ns, data->timeout_clks,
5320 data->blksz, data->blocks, data->error,
5321 data->flags);
5322 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
5323 host->curr.xfer_size, host->curr.xfer_remain,
5324 host->curr.data_xfered, host->dma.sg);
5325 }
5326
5327 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
5328}
5329
5330static const struct file_operations msmsdcc_dbg_state_ops = {
5331 .read = msmsdcc_dbg_state_read,
5332 .open = msmsdcc_dbg_state_open,
5333};
5334
5335static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
5336{
5337 if (debugfs_dir) {
5338 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
5339 0644, debugfs_dir, host,
5340 &msmsdcc_dbg_state_ops);
5341 }
5342}
5343
5344static int __init msmsdcc_dbg_init(void)
5345{
5346 int err;
5347
5348 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
5349 if (IS_ERR(debugfs_dir)) {
5350 err = PTR_ERR(debugfs_dir);
5351 debugfs_dir = NULL;
5352 return err;
5353 }
5354
5355 return 0;
5356}
5357#endif