blob: 5040fc8cd14efef0c5f7a7818d108325a68c6c84 [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);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -0700153static int msmsdcc_runtime_resume(struct device *dev);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530154
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530155static inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
156{
157 unsigned short ret = NR_SG;
158
159 if (host->is_sps_mode) {
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +0530160 ret = SPS_MAX_DESCS;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530161 } else { /* DMA or PIO mode */
162 if (NR_SG > MAX_NR_SG_DMA_PIO)
163 ret = MAX_NR_SG_DMA_PIO;
164 }
165
166 return ret;
167}
168
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530169/* Prevent idle power collapse(pc) while operating in peripheral mode */
170static void msmsdcc_pm_qos_update_latency(struct msmsdcc_host *host, int vote)
171{
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -0700172 if (!host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530173 return;
174
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530175 if (vote)
176 pm_qos_update_request(&host->pm_qos_req_dma,
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -0700177 host->cpu_dma_latency);
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530178 else
179 pm_qos_update_request(&host->pm_qos_req_dma,
180 PM_QOS_DEFAULT_VALUE);
181}
182
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700183#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
184static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
185 struct msmsdcc_sps_ep_conn_data *ep);
186static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
187 struct msmsdcc_sps_ep_conn_data *ep);
188#else
189static inline int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
190 struct msmsdcc_sps_ep_conn_data *ep,
191 bool is_producer) { return 0; }
192static inline void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
193 struct msmsdcc_sps_ep_conn_data *ep) { }
194static inline int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
195 struct msmsdcc_sps_ep_conn_data *ep)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530196{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700197 return 0;
198}
199static inline int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
200 struct msmsdcc_sps_ep_conn_data *ep)
201{
202 return 0;
203}
204static inline int msmsdcc_sps_init(struct msmsdcc_host *host) { return 0; }
205static inline void msmsdcc_sps_exit(struct msmsdcc_host *host) {}
206#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530207
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700208/**
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530209 * Apply soft reset to all SDCC BAM pipes
210 *
211 * This function applies soft reset to SDCC BAM pipe.
212 *
213 * This function should be called to recover from error
214 * conditions encountered during CMD/DATA tranfsers with card.
215 *
216 * @host - Pointer to driver's host structure
217 *
218 */
219static void msmsdcc_sps_pipes_reset_and_restore(struct msmsdcc_host *host)
220{
221 int rc;
222
223 /* Reset all SDCC BAM pipes */
224 rc = msmsdcc_sps_reset_ep(host, &host->sps.prod);
225 if (rc)
226 pr_err("%s:msmsdcc_sps_reset_ep(prod) error=%d\n",
227 mmc_hostname(host->mmc), rc);
228 rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
229 if (rc)
230 pr_err("%s:msmsdcc_sps_reset_ep(cons) error=%d\n",
231 mmc_hostname(host->mmc), rc);
232
233 /* Restore all BAM pipes connections */
234 rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
235 if (rc)
236 pr_err("%s:msmsdcc_sps_restore_ep(prod) error=%d\n",
237 mmc_hostname(host->mmc), rc);
238 rc = msmsdcc_sps_restore_ep(host, &host->sps.cons);
239 if (rc)
240 pr_err("%s:msmsdcc_sps_restore_ep(cons) error=%d\n",
241 mmc_hostname(host->mmc), rc);
242}
243
244/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700245 * Apply soft reset
246 *
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530247 * This function applies soft reset to SDCC core and DML core.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700248 *
249 * This function should be called to recover from error
250 * conditions encountered with CMD/DATA tranfsers with card.
251 *
252 * Soft reset should only be used with SDCC controller v4.
253 *
254 * @host - Pointer to driver's host structure
255 *
256 */
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530257static void msmsdcc_soft_reset(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700258{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700259 /*
260 * Reset SDCC controller's DPSM (data path state machine
261 * and CPSM (command path state machine).
262 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700263 writel_relaxed(0, host->base + MMCICOMMAND);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530264 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700265 writel_relaxed(0, host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530266 msmsdcc_sync_reg_wr(host);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530267}
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530268
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530269static void msmsdcc_hard_reset(struct msmsdcc_host *host)
270{
271 int ret;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530272
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530273 /* Reset the controller */
274 ret = clk_reset(host->clk, CLK_RESET_ASSERT);
275 if (ret)
276 pr_err("%s: Clock assert failed at %u Hz"
277 " with err %d\n", mmc_hostname(host->mmc),
278 host->clk_rate, ret);
279
280 ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
281 if (ret)
282 pr_err("%s: Clock deassert failed at %u Hz"
283 " with err %d\n", mmc_hostname(host->mmc),
284 host->clk_rate, ret);
285
Subhash Jadavanidd432952012-03-28 11:25:56 +0530286 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530287 /* Give some delay for clock reset to propogate to controller */
288 msmsdcc_delay(host);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530289}
290
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700291static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
292{
Pratibhasagar V1c11da62011-11-14 12:36:35 +0530293 if (host->sdcc_version) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530294 if (host->is_sps_mode) {
295 /* Reset DML first */
296 msmsdcc_dml_reset(host);
297 /*
298 * delay the SPS pipe reset in thread context as
299 * sps_connect/sps_disconnect APIs can be called
300 * only from non-atomic context.
301 */
302 host->sps.pipe_reset_pending = true;
303 }
304 mb();
305 msmsdcc_soft_reset(host);
306
307 pr_debug("%s: Applied soft reset to Controller\n",
308 mmc_hostname(host->mmc));
309
310 if (host->is_sps_mode)
311 msmsdcc_dml_init(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700312 } else {
313 /* Give Clock reset (hard reset) to controller */
314 u32 mci_clk = 0;
315 u32 mci_mask0 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700316
317 /* Save the controller state */
318 mci_clk = readl_relaxed(host->base + MMCICLOCK);
319 mci_mask0 = readl_relaxed(host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +0530320 host->pwr = readl_relaxed(host->base + MMCIPOWER);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700321 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700322
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530323 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700324 pr_debug("%s: Controller has been reinitialized\n",
325 mmc_hostname(host->mmc));
326
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700327 /* Restore the contoller state */
328 writel_relaxed(host->pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530329 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700330 writel_relaxed(mci_clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530331 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700332 writel_relaxed(mci_mask0, host->base + MMCIMASK0);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530333 mb(); /* no delay required after writing to MASK0 register */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700334 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530335
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700336 if (host->dummy_52_needed)
337 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700338}
339
340static int
San Mehat9d2bd732009-09-22 16:44:22 -0700341msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
342{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700343 int retval = 0;
344
San Mehat9d2bd732009-09-22 16:44:22 -0700345 BUG_ON(host->curr.data);
346
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700347 del_timer(&host->req_tout_timer);
348
San Mehat9d2bd732009-09-22 16:44:22 -0700349 if (mrq->data)
350 mrq->data->bytes_xfered = host->curr.data_xfered;
351 if (mrq->cmd->error == -ETIMEDOUT)
352 mdelay(5);
353
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530354 /* Clear current request information as current request has ended */
355 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
356
San Mehat9d2bd732009-09-22 16:44:22 -0700357 /*
358 * Need to drop the host lock here; mmc_request_done may call
359 * back into the driver...
360 */
361 spin_unlock(&host->lock);
362 mmc_request_done(host->mmc, mrq);
363 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700364
365 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700366}
367
368static void
369msmsdcc_stop_data(struct msmsdcc_host *host)
370{
San Mehat9d2bd732009-09-22 16:44:22 -0700371 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530372 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530373 host->curr.wait_for_auto_prog_done = 0;
374 host->curr.got_auto_prog_done = 0;
Krishna Konda3f5d48f2011-07-27 10:47:31 -0700375 writel_relaxed(readl_relaxed(host->base + MMCIDATACTRL) &
376 (~(MCI_DPSM_ENABLE)), host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530377 msmsdcc_sync_reg_wr(host); /* Allow the DPSM to be reset */
San Mehat9d2bd732009-09-22 16:44:22 -0700378}
379
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700380static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700381{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700382 return host->core_memres->start + MMCIFIFO;
383}
384
385static inline unsigned int msmsdcc_get_min_sup_clk_rate(
386 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530387
Subhash Jadavanidd432952012-03-28 11:25:56 +0530388static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700389{
390 mb();
Subhash Jadavanidd432952012-03-28 11:25:56 +0530391 if (!host->sdcc_version)
392 udelay(host->reg_write_delay);
393 else if (readl_relaxed(host->base + MCI_STATUS2) &
394 MCI_MCLK_REG_WR_ACTIVE) {
395 ktime_t start, diff;
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530396
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530397 start = ktime_get();
398 while (readl_relaxed(host->base + MCI_STATUS2) &
399 MCI_MCLK_REG_WR_ACTIVE) {
400 diff = ktime_sub(ktime_get(), start);
401 /* poll for max. 1 ms */
402 if (ktime_to_us(diff) > 1000) {
403 pr_warning("%s: previous reg. write is"
404 " still active\n",
405 mmc_hostname(host->mmc));
406 break;
407 }
408 }
409 }
San Mehat9d2bd732009-09-22 16:44:22 -0700410}
411
Subhash Jadavanidd432952012-03-28 11:25:56 +0530412static inline void msmsdcc_delay(struct msmsdcc_host *host)
413{
414 udelay(host->reg_write_delay);
415
416}
417
San Mehat56a8b5b2009-11-21 12:29:46 -0800418static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700419msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
420{
421 writel_relaxed(arg, host->base + MMCIARGUMENT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700422 writel_relaxed(c, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530423 /*
424 * As after sending the command, we don't write any of the
425 * controller registers and just wait for the
426 * CMD_RESPOND_END/CMD_SENT/Command failure notication
427 * from Controller.
428 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700429 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800430}
431
432static void
433msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
434{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700435 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800436
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700437 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
438 writel_relaxed((unsigned int)host->curr.xfer_size,
439 host->base + MMCIDATALENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700440 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530441 msmsdcc_sync_reg_wr(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800442
San Mehat6ac9ea62009-12-02 17:24:58 -0800443 if (host->cmd_cmd) {
444 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700445 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800446 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800447}
448
San Mehat9d2bd732009-09-22 16:44:22 -0700449static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530450msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700451{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530452 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700453 unsigned long flags;
454 struct mmc_request *mrq;
455
456 spin_lock_irqsave(&host->lock, flags);
457 mrq = host->curr.mrq;
458 BUG_ON(!mrq);
459
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530460 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700461 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700462 goto out;
463 }
464
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530465 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700466 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700467 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700468 } else {
469 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530470 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700471 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530472 mmc_hostname(host->mmc), host->dma.result);
473 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700474 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530475 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530476 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700477 host->dma.err.flush[0], host->dma.err.flush[1],
478 host->dma.err.flush[2], host->dma.err.flush[3],
479 host->dma.err.flush[4],
480 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530481 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700482 if (!mrq->data->error)
483 mrq->data->error = -EIO;
484 }
San Mehat9d2bd732009-09-22 16:44:22 -0700485 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents,
486 host->dma.dir);
487
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700488 if (host->curr.user_pages) {
489 struct scatterlist *sg = host->dma.sg;
490 int i;
491
492 for (i = 0; i < host->dma.num_ents; i++, sg++)
493 flush_dcache_page(sg_page(sg));
494 }
495
San Mehat9d2bd732009-09-22 16:44:22 -0700496 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800497 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700498
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530499 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
500 (host->curr.wait_for_auto_prog_done &&
501 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700502 /*
503 * If we've already gotten our DATAEND / DATABLKEND
504 * for this request, then complete it through here.
505 */
San Mehat9d2bd732009-09-22 16:44:22 -0700506
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700507 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700508 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700509 host->curr.xfer_remain -= host->curr.xfer_size;
510 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700511 if (host->dummy_52_needed) {
512 mrq->data->bytes_xfered = host->curr.data_xfered;
513 host->dummy_52_sent = 1;
514 msmsdcc_start_command(host, &dummy52cmd,
515 MCI_CPSM_PROGENA);
516 goto out;
517 }
518 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530519 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530520 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700521 mrq->data->bytes_xfered = host->curr.data_xfered;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700522 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530523 /*
524 * Clear current request information as current
525 * request has ended
526 */
527 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
San Mehat9d2bd732009-09-22 16:44:22 -0700528 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700529
San Mehat9d2bd732009-09-22 16:44:22 -0700530 mmc_request_done(host->mmc, mrq);
531 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530532 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
533 || !mrq->sbc)) {
534 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530535 }
San Mehat9d2bd732009-09-22 16:44:22 -0700536 }
537
538out:
539 spin_unlock_irqrestore(&host->lock, flags);
540 return;
541}
542
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700543#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
544/**
545 * Callback notification from SPS driver
546 *
547 * This callback function gets triggered called from
548 * SPS driver when requested SPS data transfer is
549 * completed.
550 *
551 * SPS driver invokes this callback in BAM irq context so
552 * SDCC driver schedule a tasklet for further processing
553 * this callback notification at later point of time in
554 * tasklet context and immediately returns control back
555 * to SPS driver.
556 *
557 * @nofity - Pointer to sps event notify sturcture
558 *
559 */
560static void
561msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
562{
563 struct msmsdcc_host *host =
564 (struct msmsdcc_host *)
565 ((struct sps_event_notify *)notify)->user;
566
567 host->sps.notify = *notify;
568 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
569 mmc_hostname(host->mmc), __func__, notify->event_id,
570 notify->data.transfer.iovec.addr,
571 notify->data.transfer.iovec.size,
572 notify->data.transfer.iovec.flags);
573 /* Schedule a tasklet for completing data transfer */
574 tasklet_schedule(&host->sps.tlet);
575}
576
577/**
578 * Tasklet handler for processing SPS callback event
579 *
580 * This function processing SPS event notification and
581 * checks if the SPS transfer is completed or not and
582 * then accordingly notifies status to MMC core layer.
583 *
584 * This function is called in tasklet context.
585 *
586 * @data - Pointer to sdcc driver data
587 *
588 */
589static void msmsdcc_sps_complete_tlet(unsigned long data)
590{
591 unsigned long flags;
592 int i, rc;
593 u32 data_xfered = 0;
594 struct mmc_request *mrq;
595 struct sps_iovec iovec;
596 struct sps_pipe *sps_pipe_handle;
597 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
598 struct sps_event_notify *notify = &host->sps.notify;
599
600 spin_lock_irqsave(&host->lock, flags);
601 if (host->sps.dir == DMA_FROM_DEVICE)
602 sps_pipe_handle = host->sps.prod.pipe_handle;
603 else
604 sps_pipe_handle = host->sps.cons.pipe_handle;
605 mrq = host->curr.mrq;
606
607 if (!mrq) {
608 spin_unlock_irqrestore(&host->lock, flags);
609 return;
610 }
611
612 pr_debug("%s: %s: sps event_id=%d\n",
613 mmc_hostname(host->mmc), __func__,
614 notify->event_id);
615
616 if (msmsdcc_is_dml_busy(host)) {
617 /* oops !!! this should never happen. */
618 pr_err("%s: %s: Received SPS EOT event"
619 " but DML HW is still busy !!!\n",
620 mmc_hostname(host->mmc), __func__);
621 }
622 /*
623 * Got End of transfer event!!! Check if all of the data
624 * has been transferred?
625 */
626 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
627 rc = sps_get_iovec(sps_pipe_handle, &iovec);
628 if (rc) {
629 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
630 mmc_hostname(host->mmc), __func__, rc, i);
631 break;
632 }
633 data_xfered += iovec.size;
634 }
635
636 if (data_xfered == host->curr.xfer_size) {
637 host->curr.data_xfered = host->curr.xfer_size;
638 host->curr.xfer_remain -= host->curr.xfer_size;
639 pr_debug("%s: Data xfer success. data_xfered=0x%x",
640 mmc_hostname(host->mmc),
641 host->curr.xfer_size);
642 } else {
643 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
644 " xfer_size=%d", mmc_hostname(host->mmc),
645 data_xfered, host->curr.xfer_size);
646 msmsdcc_reset_and_restore(host);
647 if (!mrq->data->error)
648 mrq->data->error = -EIO;
649 }
650
651 /* Unmap sg buffers */
652 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
653 host->sps.dir);
654
655 host->sps.sg = NULL;
656 host->sps.busy = 0;
657
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530658 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
659 (host->curr.wait_for_auto_prog_done &&
660 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700661 /*
662 * If we've already gotten our DATAEND / DATABLKEND
663 * for this request, then complete it through here.
664 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700665
666 if (!mrq->data->error) {
667 host->curr.data_xfered = host->curr.xfer_size;
668 host->curr.xfer_remain -= host->curr.xfer_size;
669 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700670 if (host->dummy_52_needed) {
671 mrq->data->bytes_xfered = host->curr.data_xfered;
672 host->dummy_52_sent = 1;
673 msmsdcc_start_command(host, &dummy52cmd,
674 MCI_CPSM_PROGENA);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700675 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700676 return;
677 }
678 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530679 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530680 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700681 mrq->data->bytes_xfered = host->curr.data_xfered;
682 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530683 /*
684 * Clear current request information as current
685 * request has ended
686 */
687 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700688 spin_unlock_irqrestore(&host->lock, flags);
689
690 mmc_request_done(host->mmc, mrq);
691 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530692 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
693 || !mrq->sbc)) {
694 msmsdcc_start_command(host, mrq->data->stop, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700695 }
696 }
697 spin_unlock_irqrestore(&host->lock, flags);
698}
699
700/**
701 * Exit from current SPS data transfer
702 *
703 * This function exits from current SPS data transfer.
704 *
705 * This function should be called when error condition
706 * is encountered during data transfer.
707 *
708 * @host - Pointer to sdcc host structure
709 *
710 */
711static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
712{
713 struct mmc_request *mrq;
714
715 mrq = host->curr.mrq;
716 BUG_ON(!mrq);
717
718 msmsdcc_reset_and_restore(host);
719 if (!mrq->data->error)
720 mrq->data->error = -EIO;
721
722 /* Unmap sg buffers */
723 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
724 host->sps.dir);
725
726 host->sps.sg = NULL;
727 host->sps.busy = 0;
728 if (host->curr.data)
729 msmsdcc_stop_data(host);
730
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530731 if (!mrq->data->stop || mrq->cmd->error ||
732 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700733 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530734 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
735 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700736 msmsdcc_start_command(host, mrq->data->stop, 0);
737
738}
739#else
740static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
741static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
742static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
743#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
744
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530745static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700746
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530747static void
748msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
749 unsigned int result,
750 struct msm_dmov_errdata *err)
751{
752 struct msmsdcc_dma_data *dma_data =
753 container_of(cmd, struct msmsdcc_dma_data, hdr);
754 struct msmsdcc_host *host = dma_data->host;
755
756 dma_data->result = result;
757 if (err)
758 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
759
760 tasklet_schedule(&host->dma_tlet);
761}
762
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530763static bool msmsdcc_is_dma_possible(struct msmsdcc_host *host,
764 struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700765{
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530766 bool ret = true;
767 u32 xfer_size = data->blksz * data->blocks;
768
769 if (host->is_sps_mode) {
770 /*
771 * BAM Mode: Fall back on PIO if size is less
772 * than or equal to SPS_MIN_XFER_SIZE bytes.
773 */
774 if (xfer_size <= SPS_MIN_XFER_SIZE)
775 ret = false;
776 } else if (host->is_dma_mode) {
777 /*
778 * ADM Mode: Fall back on PIO if size is less than FIFO size
779 * or not integer multiple of FIFO size
780 */
781 if (xfer_size % MCI_FIFOSIZE)
782 ret = false;
783 } else {
784 /* PIO Mode */
785 ret = false;
786 }
787
788 return ret;
San Mehat9d2bd732009-09-22 16:44:22 -0700789}
790
791static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
792{
793 struct msmsdcc_nc_dmadata *nc;
794 dmov_box *box;
795 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700796 unsigned int n;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530797 int i, err = 0, box_cmd_cnt = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700798 struct scatterlist *sg = data->sg;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530799 unsigned int len, offset;
San Mehat9d2bd732009-09-22 16:44:22 -0700800
Krishna Konda25786ec2011-07-25 16:21:36 -0700801 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700802 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700803
Krishna Konda25786ec2011-07-25 16:21:36 -0700804 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
805
San Mehat9d2bd732009-09-22 16:44:22 -0700806 host->dma.sg = data->sg;
807 host->dma.num_ents = data->sg_len;
808
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530809 /* Prevent memory corruption */
810 BUG_ON(host->dma.num_ents > msmsdcc_get_nr_sg(host));
San Mehat56a8b5b2009-11-21 12:29:46 -0800811
San Mehat9d2bd732009-09-22 16:44:22 -0700812 nc = host->dma.nc;
813
San Mehat9d2bd732009-09-22 16:44:22 -0700814 if (data->flags & MMC_DATA_READ)
815 host->dma.dir = DMA_FROM_DEVICE;
816 else
817 host->dma.dir = DMA_TO_DEVICE;
818
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700819 n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
820 host->dma.num_ents, host->dma.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700821
822 if (n != host->dma.num_ents) {
823 pr_err("%s: Unable to map in all sg elements\n",
824 mmc_hostname(host->mmc));
825 host->dma.sg = NULL;
826 host->dma.num_ents = 0;
827 return -ENOMEM;
San Mehat56a8b5b2009-11-21 12:29:46 -0800828 }
San Mehat9d2bd732009-09-22 16:44:22 -0700829
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530830 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
831 host->curr.user_pages = 0;
832 box = &nc->cmd[0];
833 for (i = 0; i < host->dma.num_ents; i++) {
834 len = sg_dma_len(sg);
835 offset = 0;
836
837 do {
838 /* Check if we can do DMA */
839 if (!len || (box_cmd_cnt >= MMC_MAX_DMA_CMDS)) {
840 err = -ENOTSUPP;
841 goto unmap;
842 }
843
844 box->cmd = CMD_MODE_BOX;
845
846 if (len >= MMC_MAX_DMA_BOX_LENGTH) {
847 len = MMC_MAX_DMA_BOX_LENGTH;
848 len -= len % data->blksz;
849 }
850 rows = (len % MCI_FIFOSIZE) ?
851 (len / MCI_FIFOSIZE) + 1 :
852 (len / MCI_FIFOSIZE);
853
854 if (data->flags & MMC_DATA_READ) {
855 box->src_row_addr = msmsdcc_fifo_addr(host);
856 box->dst_row_addr = sg_dma_address(sg) + offset;
857 box->src_dst_len = (MCI_FIFOSIZE << 16) |
858 (MCI_FIFOSIZE);
859 box->row_offset = MCI_FIFOSIZE;
860 box->num_rows = rows * ((1 << 16) + 1);
861 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
862 } else {
863 box->src_row_addr = sg_dma_address(sg) + offset;
864 box->dst_row_addr = msmsdcc_fifo_addr(host);
865 box->src_dst_len = (MCI_FIFOSIZE << 16) |
866 (MCI_FIFOSIZE);
867 box->row_offset = (MCI_FIFOSIZE << 16);
868 box->num_rows = rows * ((1 << 16) + 1);
869 box->cmd |= CMD_DST_CRCI(host->dma.crci);
870 }
871
872 offset += len;
873 len = sg_dma_len(sg) - offset;
874 box++;
875 box_cmd_cnt++;
876 } while (len);
877 sg++;
878 }
879 /* Mark last command */
880 box--;
881 box->cmd |= CMD_LC;
882
883 /* location of command block must be 64 bit aligned */
884 BUG_ON(host->dma.cmd_busaddr & 0x07);
885
886 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
887 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
888 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
889 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
890
891 /* Flush all data to memory before starting dma */
892 mb();
893
894unmap:
895 if (err) {
896 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
897 host->dma.num_ents, host->dma.dir);
898 pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
899 mmc_hostname(host->mmc), err);
900 }
901
902 return err;
San Mehat9d2bd732009-09-22 16:44:22 -0700903}
904
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700905#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
906/**
907 * Submits data transfer request to SPS driver
908 *
909 * This function make sg (scatter gather) data buffers
910 * DMA ready and then submits them to SPS driver for
911 * transfer.
912 *
913 * @host - Pointer to sdcc host structure
914 * @data - Pointer to mmc_data structure
915 *
916 * @return 0 if success else negative value
917 */
918static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
919 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -0800920{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700921 int rc = 0;
922 u32 flags;
923 int i;
924 u32 addr, len, data_cnt;
925 struct scatterlist *sg = data->sg;
926 struct sps_pipe *sps_pipe_handle;
927
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530928 /* Prevent memory corruption */
929 BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700930
931 host->sps.sg = data->sg;
932 host->sps.num_ents = data->sg_len;
933 host->sps.xfer_req_cnt = 0;
934 if (data->flags & MMC_DATA_READ) {
935 host->sps.dir = DMA_FROM_DEVICE;
936 sps_pipe_handle = host->sps.prod.pipe_handle;
937 } else {
938 host->sps.dir = DMA_TO_DEVICE;
939 sps_pipe_handle = host->sps.cons.pipe_handle;
940 }
941
942 /* Make sg buffers DMA ready */
943 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
944 host->sps.dir);
945
946 if (rc != data->sg_len) {
947 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
948 mmc_hostname(host->mmc), rc);
949 host->sps.sg = NULL;
950 host->sps.num_ents = 0;
951 rc = -ENOMEM;
952 goto dma_map_err;
953 }
954
955 pr_debug("%s: %s: %s: pipe=0x%x, total_xfer=0x%x, sg_len=%d\n",
956 mmc_hostname(host->mmc), __func__,
957 host->sps.dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
958 (u32)sps_pipe_handle, host->curr.xfer_size, data->sg_len);
959
960 for (i = 0; i < data->sg_len; i++) {
961 /*
962 * Check if this is the last buffer to transfer?
963 * If yes then set the INT and EOT flags.
964 */
965 len = sg_dma_len(sg);
966 addr = sg_dma_address(sg);
967 flags = 0;
968 while (len > 0) {
969 if (len > SPS_MAX_DESC_SIZE) {
970 data_cnt = SPS_MAX_DESC_SIZE;
971 } else {
972 data_cnt = len;
973 if (i == data->sg_len - 1)
974 flags = SPS_IOVEC_FLAG_INT |
975 SPS_IOVEC_FLAG_EOT;
976 }
977 rc = sps_transfer_one(sps_pipe_handle, addr,
978 data_cnt, host, flags);
979 if (rc) {
980 pr_err("%s: sps_transfer_one() error! rc=%d,"
981 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
982 mmc_hostname(host->mmc), rc,
983 (u32)sps_pipe_handle, (u32)sg, i);
984 goto dma_map_err;
985 }
986 addr += data_cnt;
987 len -= data_cnt;
988 host->sps.xfer_req_cnt++;
989 }
990 sg++;
991 }
992 goto out;
993
994dma_map_err:
995 /* unmap sg buffers */
996 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
997 host->sps.dir);
998out:
999 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07001000}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001001#else
1002static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
1003 struct mmc_data *data) { return 0; }
1004#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -07001005
1006static void
San Mehat56a8b5b2009-11-21 12:29:46 -08001007msmsdcc_start_command_deferred(struct msmsdcc_host *host,
1008 struct mmc_command *cmd, u32 *c)
1009{
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301010 DBG(host, "op %02x arg %08x flags %08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001011 cmd->opcode, cmd->arg, cmd->flags);
1012
San Mehat56a8b5b2009-11-21 12:29:46 -08001013 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
1014
1015 if (cmd->flags & MMC_RSP_PRESENT) {
1016 if (cmd->flags & MMC_RSP_136)
1017 *c |= MCI_CPSM_LONGRSP;
1018 *c |= MCI_CPSM_RESPONSE;
1019 }
1020
1021 if (/*interrupt*/0)
1022 *c |= MCI_CPSM_INTERRUPT;
1023
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301024 if (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
1025 cmd->opcode == MMC_READ_MULTIPLE_BLOCK ||
1026 cmd->opcode == MMC_WRITE_BLOCK ||
1027 cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK ||
1028 cmd->opcode == SD_IO_RW_EXTENDED)
San Mehat56a8b5b2009-11-21 12:29:46 -08001029 *c |= MCI_CSPM_DATCMD;
1030
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001031 /* Check if AUTO CMD19 is required or not? */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301032 if (host->tuning_needed &&
1033 !(host->mmc->ios.timing == MMC_TIMING_MMC_HS200)) {
1034
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301035 /*
1036 * For open ended block read operation (without CMD23),
1037 * AUTO_CMD19 bit should be set while sending the READ command.
1038 * For close ended block read operation (with CMD23),
1039 * AUTO_CMD19 bit should be set while sending CMD23.
1040 */
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301041 if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
1042 host->curr.mrq->cmd->opcode ==
1043 MMC_READ_MULTIPLE_BLOCK) ||
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301044 (!host->curr.mrq->sbc &&
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301045 (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
1046 cmd->opcode == MMC_READ_MULTIPLE_BLOCK))) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301047 msmsdcc_enable_cdr_cm_sdc4_dll(host);
1048 *c |= MCI_CSPM_AUTO_CMD19;
1049 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001050 }
1051
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05301052 /* Clear CDR_EN bit for write operations */
1053 if (host->tuning_needed && cmd->mrq->data &&
1054 (cmd->mrq->data->flags & MMC_DATA_WRITE))
1055 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) &
1056 ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
1057
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301058 if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301059 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001060 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301061 }
1062
San Mehat56a8b5b2009-11-21 12:29:46 -08001063 if (cmd == cmd->mrq->stop)
1064 *c |= MCI_CSPM_MCIABORT;
1065
San Mehat56a8b5b2009-11-21 12:29:46 -08001066 if (host->curr.cmd != NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001067 pr_err("%s: Overlapping command requests\n",
1068 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -08001069 }
1070 host->curr.cmd = cmd;
1071}
1072
1073static void
1074msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1075 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001076{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301077 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001078 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001079 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001080 unsigned int pio_irqmask = 0;
1081
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301082 BUG_ON(!data->sg);
1083 BUG_ON(!data->sg_len);
1084
San Mehat9d2bd732009-09-22 16:44:22 -07001085 host->curr.data = data;
1086 host->curr.xfer_size = data->blksz * data->blocks;
1087 host->curr.xfer_remain = host->curr.xfer_size;
1088 host->curr.data_xfered = 0;
1089 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301090 host->curr.got_auto_prog_done = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001091
San Mehat9d2bd732009-09-22 16:44:22 -07001092 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1093
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301094 if (host->curr.wait_for_auto_prog_done)
1095 datactrl |= MCI_AUTO_PROG_DONE;
1096
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05301097 if (msmsdcc_is_dma_possible(host, data)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001098 if (host->is_dma_mode && !msmsdcc_config_dma(host, data)) {
1099 datactrl |= MCI_DPSM_DMAENABLE;
1100 } else if (host->is_sps_mode) {
1101 if (!msmsdcc_is_dml_busy(host)) {
1102 if (!msmsdcc_sps_start_xfer(host, data)) {
1103 /* Now kick start DML transfer */
1104 mb();
1105 msmsdcc_dml_start_xfer(host, data);
1106 datactrl |= MCI_DPSM_DMAENABLE;
1107 host->sps.busy = 1;
1108 }
1109 } else {
1110 /*
1111 * Can't proceed with new transfer as
1112 * previous trasnfer is already in progress.
1113 * There is no point of going into PIO mode
1114 * as well. Is this a time to do kernel panic?
1115 */
1116 pr_err("%s: %s: DML HW is busy!!!"
1117 " Can't perform new SPS transfers"
1118 " now\n", mmc_hostname(host->mmc),
1119 __func__);
1120 }
1121 }
1122 }
1123
1124 /* Is data transfer in PIO mode required? */
1125 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001126 if (data->flags & MMC_DATA_READ) {
1127 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1128 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1129 pio_irqmask |= MCI_RXDATAAVLBLMASK;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001130 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001131 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1132 MCI_TXFIFOEMPTYMASK;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001133
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001134 msmsdcc_sg_start(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001135 }
1136
1137 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301138 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
San Mehat9d2bd732009-09-22 16:44:22 -07001139
San Mehat56a8b5b2009-11-21 12:29:46 -08001140 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001141 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001142 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -07001143
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001144 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
1145 /* Use ADM (Application Data Mover) HW for Data transfer */
1146 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001147 host->cmd_timeout = timeout;
1148 host->cmd_pio_irqmask = pio_irqmask;
1149 host->cmd_datactrl = datactrl;
1150 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001151
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001152 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1153 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001154 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001155
1156 if (cmd) {
1157 msmsdcc_start_command_deferred(host, cmd, &c);
1158 host->cmd_c = c;
1159 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001160 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1161 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1162 host->base + MMCIMASK0);
1163 mb();
1164 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001165 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001166 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001167 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001168
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001169 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001170
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001171 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1172 (~(MCI_IRQ_PIO))) | pio_irqmask,
1173 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001174 writel_relaxed(datactrl, base + MMCIDATACTRL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001175
1176 if (cmd) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05301177 /* Delay between data/command */
1178 msmsdcc_sync_reg_wr(host);
San Mehat56a8b5b2009-11-21 12:29:46 -08001179 /* Daisy-chain the command if requested */
1180 msmsdcc_start_command(host, cmd, c);
Subhash Jadavanidd432952012-03-28 11:25:56 +05301181 } else {
1182 /*
1183 * We don't need delay after writing to DATA_CTRL
1184 * register if we are not writing to CMD register
1185 * immediately after this. As we already have delay
1186 * before sending the command, we just need mb() here.
1187 */
1188 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001189 }
San Mehat9d2bd732009-09-22 16:44:22 -07001190 }
1191}
1192
1193static void
1194msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1195{
San Mehat56a8b5b2009-11-21 12:29:46 -08001196 msmsdcc_start_command_deferred(host, cmd, &c);
1197 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001198}
1199
1200static void
1201msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1202 unsigned int status)
1203{
1204 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001205 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
Subhash Jadavanib30c9822012-03-27 18:03:16 +05301206 || data->mrq->cmd->opcode == MMC_BUS_TEST_R
1207 || data->mrq->cmd->opcode ==
1208 MMC_SEND_TUNING_BLOCK_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001209 pr_err("%s: Data CRC error\n",
1210 mmc_hostname(host->mmc));
1211 pr_err("%s: opcode 0x%.8x\n", __func__,
1212 data->mrq->cmd->opcode);
1213 pr_err("%s: blksz %d, blocks %d\n", __func__,
1214 data->blksz, data->blocks);
1215 data->error = -EILSEQ;
1216 }
San Mehat9d2bd732009-09-22 16:44:22 -07001217 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001218 /* CRC is optional for the bus test commands, not all
1219 * cards respond back with CRC. However controller
1220 * waits for the CRC and times out. Hence ignore the
1221 * data timeouts during the Bustest.
1222 */
1223 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1224 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301225 pr_err("%s: CMD%d: Data timeout\n",
1226 mmc_hostname(host->mmc),
1227 data->mrq->cmd->opcode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001228 data->error = -ETIMEDOUT;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301229 msmsdcc_dump_sdcc_state(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001230 }
San Mehat9d2bd732009-09-22 16:44:22 -07001231 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001232 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001233 data->error = -EIO;
1234 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001235 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001236 data->error = -EIO;
1237 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001238 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001239 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001240 data->error = -EIO;
1241 }
San Mehat9d2bd732009-09-22 16:44:22 -07001242
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001243 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001244 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001245 host->dummy_52_needed = 0;
1246}
San Mehat9d2bd732009-09-22 16:44:22 -07001247
1248static int
1249msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1250{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001251 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001252 uint32_t *ptr = (uint32_t *) buffer;
1253 int count = 0;
1254
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301255 if (remain % 4)
1256 remain = ((remain >> 2) + 1) << 2;
1257
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001258 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1259
1260 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001261 ptr++;
1262 count += sizeof(uint32_t);
1263
1264 remain -= sizeof(uint32_t);
1265 if (remain == 0)
1266 break;
1267 }
1268 return count;
1269}
1270
1271static int
1272msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001273 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001274{
1275 void __iomem *base = host->base;
1276 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001277 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001278
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001279 while (readl_relaxed(base + MMCISTATUS) &
1280 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1281 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001282
San Mehat9d2bd732009-09-22 16:44:22 -07001283 count = min(remain, maxcnt);
1284
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301285 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1286 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001287 ptr += count;
1288 remain -= count;
1289
1290 if (remain == 0)
1291 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001292 }
1293 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001294
1295 return ptr - buffer;
1296}
1297
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001298/*
1299 * Copy up to a word (4 bytes) between a scatterlist
1300 * and a temporary bounce buffer when the word lies across
1301 * two pages. The temporary buffer can then be read to/
1302 * written from the FIFO once.
1303 */
1304static void _msmsdcc_sg_consume_word(struct msmsdcc_host *host)
1305{
1306 struct msmsdcc_pio_data *pio = &host->pio;
1307 unsigned int bytes_avail;
1308
1309 if (host->curr.data->flags & MMC_DATA_READ)
1310 memcpy(pio->sg_miter.addr, pio->bounce_buf,
1311 pio->bounce_buf_len);
1312 else
1313 memcpy(pio->bounce_buf, pio->sg_miter.addr,
1314 pio->bounce_buf_len);
1315
1316 while (pio->bounce_buf_len != 4) {
1317 if (!sg_miter_next(&pio->sg_miter))
1318 break;
1319 bytes_avail = min_t(unsigned int, pio->sg_miter.length,
1320 4 - pio->bounce_buf_len);
1321 if (host->curr.data->flags & MMC_DATA_READ)
1322 memcpy(pio->sg_miter.addr,
1323 &pio->bounce_buf[pio->bounce_buf_len],
1324 bytes_avail);
1325 else
1326 memcpy(&pio->bounce_buf[pio->bounce_buf_len],
1327 pio->sg_miter.addr, bytes_avail);
1328
1329 pio->sg_miter.consumed = bytes_avail;
1330 pio->bounce_buf_len += bytes_avail;
1331 }
1332}
1333
1334/*
1335 * Use sg_miter_next to return as many 4-byte aligned
1336 * chunks as possible, using a temporary 4 byte buffer
1337 * for alignment if necessary
1338 */
1339static int msmsdcc_sg_next(struct msmsdcc_host *host, char **buf, int *len)
1340{
1341 struct msmsdcc_pio_data *pio = &host->pio;
1342 unsigned int length, rlength;
1343 char *buffer;
1344
1345 if (!sg_miter_next(&pio->sg_miter))
1346 return 0;
1347
1348 buffer = pio->sg_miter.addr;
1349 length = pio->sg_miter.length;
1350
1351 if (length < host->curr.xfer_remain) {
1352 rlength = round_down(length, 4);
1353 if (rlength) {
1354 /*
1355 * We have a 4-byte aligned chunk.
1356 * The rounding will be reflected by
1357 * a call to msmsdcc_sg_consumed
1358 */
1359 length = rlength;
1360 goto sg_next_end;
1361 }
1362 /*
1363 * We have a length less than 4 bytes. Check to
1364 * see if more buffer is available, and combine
1365 * to make 4 bytes if possible.
1366 */
1367 pio->bounce_buf_len = length;
1368 memset(pio->bounce_buf, 0, 4);
1369
1370 /*
1371 * On a read, get 4 bytes from FIFO, and distribute
1372 * (4-bouce_buf_len) bytes into consecutive
1373 * sgl buffers when msmsdcc_sg_consumed is called
1374 */
1375 if (host->curr.data->flags & MMC_DATA_READ) {
1376 buffer = pio->bounce_buf;
1377 length = 4;
1378 goto sg_next_end;
1379 } else {
1380 _msmsdcc_sg_consume_word(host);
1381 buffer = pio->bounce_buf;
1382 length = pio->bounce_buf_len;
1383 }
1384 }
1385
1386sg_next_end:
1387 *buf = buffer;
1388 *len = length;
1389 return 1;
1390}
1391
1392/*
1393 * Update sg_miter.consumed based on how many bytes were
1394 * consumed. If the bounce buffer was used to read from FIFO,
1395 * redistribute into sgls.
1396 */
1397static void msmsdcc_sg_consumed(struct msmsdcc_host *host,
1398 unsigned int length)
1399{
1400 struct msmsdcc_pio_data *pio = &host->pio;
1401
1402 if (host->curr.data->flags & MMC_DATA_READ) {
1403 if (length > pio->sg_miter.consumed)
1404 /*
1405 * consumed 4 bytes, but sgl
1406 * describes < 4 bytes
1407 */
1408 _msmsdcc_sg_consume_word(host);
1409 else
1410 pio->sg_miter.consumed = length;
1411 } else
1412 if (length < pio->sg_miter.consumed)
1413 pio->sg_miter.consumed = length;
1414}
1415
1416static void msmsdcc_sg_start(struct msmsdcc_host *host)
1417{
1418 unsigned int sg_miter_flags = SG_MITER_ATOMIC;
1419
1420 host->pio.bounce_buf_len = 0;
1421
1422 if (host->curr.data->flags & MMC_DATA_READ)
1423 sg_miter_flags |= SG_MITER_TO_SG;
1424 else
1425 sg_miter_flags |= SG_MITER_FROM_SG;
1426
1427 sg_miter_start(&host->pio.sg_miter, host->curr.data->sg,
1428 host->curr.data->sg_len, sg_miter_flags);
1429}
1430
1431static void msmsdcc_sg_stop(struct msmsdcc_host *host)
1432{
1433 sg_miter_stop(&host->pio.sg_miter);
1434}
1435
San Mehat1cd22962010-02-03 12:59:29 -08001436static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001437msmsdcc_pio_irq(int irq, void *dev_id)
1438{
1439 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001440 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001441 uint32_t status;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001442 unsigned long flags;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001443 unsigned int remain;
1444 char *buffer;
San Mehat9d2bd732009-09-22 16:44:22 -07001445
Murali Palnati36448a42011-09-02 15:06:18 +05301446 spin_lock(&host->lock);
1447
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001448 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001449
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001450 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301451 (MCI_IRQ_PIO)) == 0) {
1452 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001453 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301454 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001455#if IRQ_DEBUG
1456 msmsdcc_print_status(host, "irq1-r", status);
1457#endif
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001458 local_irq_save(flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001459
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001460 do {
1461 unsigned int len;
San Mehat9d2bd732009-09-22 16:44:22 -07001462
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001463 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1464 | MCI_RXDATAAVLBL)))
1465 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001466
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001467 if (!msmsdcc_sg_next(host, &buffer, &remain))
1468 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001469
San Mehat9d2bd732009-09-22 16:44:22 -07001470 len = 0;
1471 if (status & MCI_RXACTIVE)
1472 len = msmsdcc_pio_read(host, buffer, remain);
1473 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001474 len = msmsdcc_pio_write(host, buffer, remain);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001475
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301476 /* len might have aligned to 32bits above */
1477 if (len > remain)
1478 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001479
San Mehat9d2bd732009-09-22 16:44:22 -07001480 host->curr.xfer_remain -= len;
1481 host->curr.data_xfered += len;
1482 remain -= len;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001483 msmsdcc_sg_consumed(host, len);
San Mehat9d2bd732009-09-22 16:44:22 -07001484
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001485 if (remain) /* Done with this page? */
1486 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001487
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001488 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001489 } while (1);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001490
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001491 msmsdcc_sg_stop(host);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001492 local_irq_restore(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001493
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001494 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1495 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1496 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1497 host->base + MMCIMASK0);
1498 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301499 /*
1500 * back to back write to MASK0 register don't need
1501 * synchronization delay.
1502 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001503 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1504 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1505 }
1506 mb();
1507 } else if (!host->curr.xfer_remain) {
1508 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1509 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1510 mb();
1511 }
San Mehat9d2bd732009-09-22 16:44:22 -07001512
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001513 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001514
1515 return IRQ_HANDLED;
1516}
1517
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001518static void
1519msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1520
1521static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1522 struct mmc_data *data)
1523{
1524 u32 loop_cnt = 0;
1525
1526 /*
1527 * For read commands with data less than fifo size, it is possible to
1528 * get DATAEND first and RXDATA_AVAIL might be set later because of
1529 * synchronization delay through the asynchronous RX FIFO. Thus, for
1530 * such cases, even after DATAEND interrupt is received software
1531 * should poll for RXDATA_AVAIL until the requested data is read out
1532 * of FIFO. This change is needed to get around this abnormal but
1533 * sometimes expected behavior of SDCC3 controller.
1534 *
1535 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1536 * after the data is loaded into RX FIFO. This would amount to less
1537 * than a microsecond and thus looping for 1000 times is good enough
1538 * for that delay.
1539 */
1540 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1541 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1542 spin_unlock(&host->lock);
1543 msmsdcc_pio_irq(1, host);
1544 spin_lock(&host->lock);
1545 }
1546 }
1547 if (loop_cnt == 1000) {
1548 pr_info("%s: Timed out while polling for Rx Data\n",
1549 mmc_hostname(host->mmc));
1550 data->error = -ETIMEDOUT;
1551 msmsdcc_reset_and_restore(host);
1552 }
1553}
1554
San Mehat9d2bd732009-09-22 16:44:22 -07001555static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1556{
1557 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001558
1559 host->curr.cmd = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001560 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1561 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1562 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1563 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -07001564
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001565 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301566 pr_debug("%s: CMD%d: Command timeout\n",
1567 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001568 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001569 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301570 !host->tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301571 pr_err("%s: CMD%d: Command CRC error\n",
1572 mmc_hostname(host->mmc), cmd->opcode);
1573 msmsdcc_dump_sdcc_state(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001574 cmd->error = -EILSEQ;
1575 }
1576
1577 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001578 if (host->curr.data && host->dma.sg &&
1579 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001580 msm_dmov_stop_cmd(host->dma.channel,
1581 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001582 else if (host->curr.data && host->sps.sg &&
1583 host->is_sps_mode){
1584 /* Stop current SPS transfer */
1585 msmsdcc_sps_exit_curr_xfer(host);
1586 }
San Mehat9d2bd732009-09-22 16:44:22 -07001587 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301588 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001589 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301590 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301591 } else { /* host->data == NULL */
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301592 if (!cmd->error && host->prog_enable) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301593 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001594 host->prog_enable = 0;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301595 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001596 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301597 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301598 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301599 host->prog_enable = 0;
Subhash Jadavanied6b0e42012-03-07 16:36:27 +05301600 host->curr.wait_for_auto_prog_done = 0;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001601 if (host->dummy_52_needed)
1602 host->dummy_52_needed = 0;
1603 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001604 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301605 msmsdcc_request_end(host, cmd->mrq);
1606 }
1607 }
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301608 } else if ((cmd == host->curr.mrq->sbc) && cmd->data) {
1609 if (cmd->data->flags & MMC_DATA_READ)
1610 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1611 else
1612 msmsdcc_request_start(host, host->curr.mrq);
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301613 } else if (cmd->data) {
1614 if (!(cmd->data->flags & MMC_DATA_READ))
1615 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001616 }
1617}
1618
San Mehat9d2bd732009-09-22 16:44:22 -07001619static irqreturn_t
1620msmsdcc_irq(int irq, void *dev_id)
1621{
1622 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001623 u32 status;
1624 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001625 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001626
1627 spin_lock(&host->lock);
1628
1629 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001630 struct mmc_command *cmd;
1631 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001632
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001633 if (timer) {
1634 timer = 0;
1635 msmsdcc_delay(host);
1636 }
San Mehat865c8062009-11-13 13:42:06 -08001637
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001638 if (!host->clks_on) {
1639 pr_debug("%s: %s: SDIO async irq received\n",
1640 mmc_hostname(host->mmc), __func__);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301641
1642 /*
1643 * Only async interrupt can come when clocks are off,
1644 * disable further interrupts and enable them when
1645 * clocks are on.
1646 */
1647 if (!host->sdcc_irq_disabled) {
1648 disable_irq_nosync(irq);
1649 host->sdcc_irq_disabled = 1;
1650 }
1651
1652 /*
1653 * If mmc_card_wake_sdio_irq() is set, mmc core layer
1654 * will take care of signaling sdio irq during
1655 * mmc_sdio_resume().
1656 */
1657 if (host->sdcc_suspended)
1658 /*
1659 * This is a wakeup interrupt so hold wakelock
1660 * until SDCC resume is handled.
1661 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001662 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301663 else
1664 mmc_signal_sdio_irq(host->mmc);
1665 ret = 1;
1666 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001667 }
1668
1669 status = readl_relaxed(host->base + MMCISTATUS);
1670
1671 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1672 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001673 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001674
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001675#if IRQ_DEBUG
1676 msmsdcc_print_status(host, "irq0-r", status);
1677#endif
1678 status &= readl_relaxed(host->base + MMCIMASK0);
1679 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301680 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301681 if (host->clk_rate <=
1682 msmsdcc_get_min_sup_clk_rate(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +05301683 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001684#if IRQ_DEBUG
1685 msmsdcc_print_status(host, "irq0-p", status);
1686#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001687
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001688 if (status & MCI_SDIOINTROPE) {
1689 if (host->sdcc_suspending)
1690 wake_lock(&host->sdio_suspend_wlock);
1691 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001692 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001693 data = host->curr.data;
1694
1695 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001696 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1697 MCI_CMDTIMEOUT)) {
1698 if (status & MCI_CMDTIMEOUT)
1699 pr_debug("%s: dummy CMD52 timeout\n",
1700 mmc_hostname(host->mmc));
1701 if (status & MCI_CMDCRCFAIL)
1702 pr_debug("%s: dummy CMD52 CRC failed\n",
1703 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001704 host->dummy_52_sent = 0;
1705 host->dummy_52_needed = 0;
1706 if (data) {
1707 msmsdcc_stop_data(host);
1708 msmsdcc_request_end(host, data->mrq);
1709 }
1710 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001711 spin_unlock(&host->lock);
1712 return IRQ_HANDLED;
1713 }
1714 break;
1715 }
1716
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001717 /*
1718 * Check for proper command response
1719 */
1720 cmd = host->curr.cmd;
1721 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1722 MCI_CMDTIMEOUT | MCI_PROGDONE |
1723 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1724 msmsdcc_do_cmdirq(host, status);
1725 }
1726
Sathish Ambley081d7842011-11-29 11:19:41 -08001727 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001728 /* Check for data errors */
1729 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1730 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1731 msmsdcc_data_err(host, data, status);
1732 host->curr.data_xfered = 0;
1733 if (host->dma.sg && host->is_dma_mode)
1734 msm_dmov_stop_cmd(host->dma.channel,
1735 &host->dma.hdr, 0);
1736 else if (host->sps.sg && host->is_sps_mode) {
1737 /* Stop current SPS transfer */
1738 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301739 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001740 msmsdcc_reset_and_restore(host);
1741 if (host->curr.data)
1742 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301743 if (!data->stop || (host->curr.mrq->sbc
1744 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001745 timer |=
1746 msmsdcc_request_end(host,
1747 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301748 else if ((host->curr.mrq->sbc
1749 && data->error) ||
1750 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001751 msmsdcc_start_command(host,
1752 data->stop,
1753 0);
1754 timer = 1;
1755 }
1756 }
1757 }
1758
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301759 /* Check for prog done */
1760 if (host->curr.wait_for_auto_prog_done &&
1761 (status & MCI_PROGDONE))
1762 host->curr.got_auto_prog_done = 1;
1763
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001764 /* Check for data done */
1765 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1766 host->curr.got_dataend = 1;
1767
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301768 if (host->curr.got_dataend &&
1769 (!host->curr.wait_for_auto_prog_done ||
1770 (host->curr.wait_for_auto_prog_done &&
1771 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001772 /*
1773 * If DMA is still in progress, we complete
1774 * via the completion handler
1775 */
1776 if (!host->dma.busy && !host->sps.busy) {
1777 /*
1778 * There appears to be an issue in the
1779 * controller where if you request a
1780 * small block transfer (< fifo size),
1781 * you may get your DATAEND/DATABLKEND
1782 * irq without the PIO data irq.
1783 *
1784 * Check to see if theres still data
1785 * to be read, and simulate a PIO irq.
1786 */
1787 if (data->flags & MMC_DATA_READ)
1788 msmsdcc_wait_for_rxdata(host,
1789 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001790 if (!data->error) {
1791 host->curr.data_xfered =
1792 host->curr.xfer_size;
1793 host->curr.xfer_remain -=
1794 host->curr.xfer_size;
1795 }
1796
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001797 if (!host->dummy_52_needed) {
1798 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301799 if (!data->stop ||
1800 (host->curr.mrq->sbc
1801 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001802 msmsdcc_request_end(
1803 host,
1804 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301805 else if ((host->curr.mrq->sbc
1806 && data->error) ||
1807 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001808 msmsdcc_start_command(
1809 host,
1810 data->stop, 0);
1811 timer = 1;
1812 }
1813 } else {
1814 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001815 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001816 &dummy52cmd,
1817 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001818 }
1819 }
1820 }
1821 }
1822
San Mehat9d2bd732009-09-22 16:44:22 -07001823 ret = 1;
1824 } while (status);
1825
1826 spin_unlock(&host->lock);
1827
San Mehat9d2bd732009-09-22 16:44:22 -07001828 return IRQ_RETVAL(ret);
1829}
1830
1831static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001832msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1833{
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301834 if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001835 /* Queue/read data, daisy-chain command when data starts */
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301836 if (mrq->sbc)
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301837 msmsdcc_start_data(host, mrq->data, mrq->sbc, 0);
1838 else
1839 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001840 } else {
1841 msmsdcc_start_command(host, mrq->cmd, 0);
1842 }
1843}
1844
1845static void
San Mehat9d2bd732009-09-22 16:44:22 -07001846msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1847{
1848 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001849 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001850
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001851 /*
1852 * Get the SDIO AL client out of LPM.
1853 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001854 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001855 if (host->plat->is_sdio_al_client)
1856 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001857
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301858 /* check if sps pipe reset is pending? */
1859 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1860 msmsdcc_sps_pipes_reset_and_restore(host);
1861 host->sps.pipe_reset_pending = false;
1862 }
1863
San Mehat9d2bd732009-09-22 16:44:22 -07001864 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001865 WARN(host->curr.mrq, "Request in progress\n");
1866 WARN(!host->pwr, "SDCC power is turned off\n");
1867 WARN(!host->clks_on, "SDCC clocks are turned off\n");
1868 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
San Mehat9d2bd732009-09-22 16:44:22 -07001869
1870 if (host->eject) {
1871 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1872 mrq->cmd->error = 0;
1873 mrq->data->bytes_xfered = mrq->data->blksz *
1874 mrq->data->blocks;
1875 } else
1876 mrq->cmd->error = -ENOMEDIUM;
1877
1878 spin_unlock_irqrestore(&host->lock, flags);
1879 mmc_request_done(mmc, mrq);
1880 return;
1881 }
1882
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301883 /*
1884 * Kick the software command timeout timer here.
1885 * Timer expires in 10 secs.
1886 */
1887 mod_timer(&host->req_tout_timer,
1888 (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
San Mehat9d2bd732009-09-22 16:44:22 -07001889
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301890 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301891 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301892 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
1893 mrq->cmd->opcode == 54) {
Pratibhasagar V1c11da62011-11-14 12:36:35 +05301894 if (!host->sdcc_version)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001895 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301896 else
1897 /*
1898 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
1899 * write operations using CMD53 and CMD54.
1900 * Setting this bit with CMD53 would
1901 * automatically triggers PROG_DONE interrupt
1902 * without the need of sending dummy CMD52.
1903 */
1904 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani758cf8c2011-11-13 11:59:55 +05301905 } else if (mrq->cmd->opcode == MMC_WRITE_BLOCK &&
1906 host->sdcc_version) {
1907 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001908 }
San Mehat9d2bd732009-09-22 16:44:22 -07001909 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301910
Pratibhasagar V00b94332011-10-18 14:57:27 +05301911 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301912 mrq->sbc->mrq = mrq;
1913 mrq->sbc->data = mrq->data;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301914 if (mrq->data->flags & MMC_DATA_WRITE) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301915 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301916 msmsdcc_start_command(host, mrq->sbc, 0);
1917 } else {
1918 msmsdcc_request_start(host, mrq);
1919 }
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301920 } else {
1921 msmsdcc_request_start(host, mrq);
1922 }
1923
San Mehat9d2bd732009-09-22 16:44:22 -07001924 spin_unlock_irqrestore(&host->lock, flags);
1925}
1926
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001927static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1928 int min_uV, int max_uV)
1929{
1930 int rc = 0;
1931
1932 if (vreg->set_voltage_sup) {
1933 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1934 if (rc) {
1935 pr_err("%s: regulator_set_voltage(%s) failed."
1936 " min_uV=%d, max_uV=%d, rc=%d\n",
1937 __func__, vreg->name, min_uV, max_uV, rc);
1938 }
1939 }
1940
1941 return rc;
1942}
1943
1944static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1945 int uA_load)
1946{
1947 int rc = 0;
1948
Krishna Kondafea60182011-11-01 16:01:34 -07001949 /* regulators that do not support regulator_set_voltage also
1950 do not support regulator_set_optimum_mode */
1951 if (vreg->set_voltage_sup) {
1952 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1953 if (rc < 0)
1954 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
1955 "uA_load=%d) failed. rc=%d\n", __func__,
1956 vreg->name, uA_load, rc);
1957 else
1958 /* regulator_set_optimum_mode() can return non zero
1959 * value even for success case.
1960 */
1961 rc = 0;
1962 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001963
1964 return rc;
1965}
1966
1967static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1968 struct device *dev)
1969{
1970 int rc = 0;
1971
1972 /* check if regulator is already initialized? */
1973 if (vreg->reg)
1974 goto out;
1975
1976 /* Get the regulator handle */
1977 vreg->reg = regulator_get(dev, vreg->name);
1978 if (IS_ERR(vreg->reg)) {
1979 rc = PTR_ERR(vreg->reg);
1980 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
1981 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001982 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001983 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001984
1985 if (regulator_count_voltages(vreg->reg) > 0)
1986 vreg->set_voltage_sup = 1;
1987
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001988out:
1989 return rc;
1990}
1991
1992static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
1993{
1994 if (vreg->reg)
1995 regulator_put(vreg->reg);
1996}
1997
1998/* This init function should be called only once for each SDCC slot */
1999static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
2000{
2001 int rc = 0;
2002 struct msm_mmc_slot_reg_data *curr_slot;
2003 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
2004 struct device *dev = mmc_dev(host->mmc);
2005
2006 curr_slot = host->plat->vreg_data;
2007 if (!curr_slot)
2008 goto out;
2009
2010 curr_vdd_reg = curr_slot->vdd_data;
2011 curr_vccq_reg = curr_slot->vccq_data;
2012 curr_vddp_reg = curr_slot->vddp_data;
2013
2014 if (is_init) {
2015 /*
2016 * Get the regulator handle from voltage regulator framework
2017 * and then try to set the voltage level for the regulator
2018 */
2019 if (curr_vdd_reg) {
2020 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
2021 if (rc)
2022 goto out;
2023 }
2024 if (curr_vccq_reg) {
2025 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
2026 if (rc)
2027 goto vdd_reg_deinit;
2028 }
2029 if (curr_vddp_reg) {
2030 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
2031 if (rc)
2032 goto vccq_reg_deinit;
2033 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002034 rc = msmsdcc_vreg_reset(host);
2035 if (rc)
2036 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
2037 host->pdev_id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002038 goto out;
2039 } else {
2040 /* Deregister all regulators from regulator framework */
2041 goto vddp_reg_deinit;
2042 }
2043vddp_reg_deinit:
2044 if (curr_vddp_reg)
2045 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
2046vccq_reg_deinit:
2047 if (curr_vccq_reg)
2048 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
2049vdd_reg_deinit:
2050 if (curr_vdd_reg)
2051 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2052out:
2053 return rc;
2054}
2055
2056static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2057{
2058 int rc = 0;
2059
Subhash Jadavanicc922692011-08-01 23:05:01 +05302060 /* Put regulator in HPM (high power mode) */
2061 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2062 if (rc < 0)
2063 goto out;
2064
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002065 if (!vreg->is_enabled) {
2066 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302067 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2068 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002069 if (rc)
2070 goto out;
2071
2072 rc = regulator_enable(vreg->reg);
2073 if (rc) {
2074 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2075 __func__, vreg->name, rc);
2076 goto out;
2077 }
2078 vreg->is_enabled = true;
2079 }
2080
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002081out:
2082 return rc;
2083}
2084
2085static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
2086{
2087 int rc = 0;
2088
2089 /* Never disable regulator marked as always_on */
2090 if (vreg->is_enabled && !vreg->always_on) {
2091 rc = regulator_disable(vreg->reg);
2092 if (rc) {
2093 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2094 __func__, vreg->name, rc);
2095 goto out;
2096 }
2097 vreg->is_enabled = false;
2098
2099 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2100 if (rc < 0)
2101 goto out;
2102
2103 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302104 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002105 if (rc)
2106 goto out;
2107 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
2108 /* Put always_on regulator in LPM (low power mode) */
2109 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2110 if (rc < 0)
2111 goto out;
2112 }
2113out:
2114 return rc;
2115}
2116
2117static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
2118{
2119 int rc = 0, i;
2120 struct msm_mmc_slot_reg_data *curr_slot;
2121 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
2122 struct msm_mmc_reg_data *vreg_table[3];
2123
2124 curr_slot = host->plat->vreg_data;
2125 if (!curr_slot)
2126 goto out;
2127
2128 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
2129 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
2130 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
2131
2132 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2133 if (vreg_table[i]) {
2134 if (enable)
2135 rc = msmsdcc_vreg_enable(vreg_table[i]);
2136 else
2137 rc = msmsdcc_vreg_disable(vreg_table[i]);
2138 if (rc)
2139 goto out;
2140 }
2141 }
2142out:
2143 return rc;
2144}
2145
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002146/*
2147 * Reset vreg by ensuring it is off during probe. A call
2148 * to enable vreg is needed to balance disable vreg
2149 */
2150static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2151{
2152 int rc;
2153
2154 rc = msmsdcc_setup_vreg(host, 1);
2155 if (rc)
2156 return rc;
2157 rc = msmsdcc_setup_vreg(host, 0);
2158 return rc;
2159}
2160
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302161static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002162{
2163 int rc = 0;
2164
2165 if (host->plat->vreg_data) {
2166 struct msm_mmc_reg_data *vddp_reg =
2167 host->plat->vreg_data->vddp_data;
2168
2169 if (vddp_reg && vddp_reg->is_enabled)
2170 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
2171 }
2172
2173 return rc;
2174}
2175
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302176static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
2177{
2178 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2179 int rc = 0;
2180
2181 if (curr_slot && curr_slot->vddp_data) {
2182 rc = msmsdcc_set_vddp_level(host,
2183 curr_slot->vddp_data->low_vol_level);
2184
2185 if (rc)
2186 pr_err("%s: %s: failed to change vddp level to %d",
2187 mmc_hostname(host->mmc), __func__,
2188 curr_slot->vddp_data->low_vol_level);
2189 }
2190
2191 return rc;
2192}
2193
2194static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
2195{
2196 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2197 int rc = 0;
2198
2199 if (curr_slot && curr_slot->vddp_data) {
2200 rc = msmsdcc_set_vddp_level(host,
2201 curr_slot->vddp_data->high_vol_level);
2202
2203 if (rc)
2204 pr_err("%s: %s: failed to change vddp level to %d",
2205 mmc_hostname(host->mmc), __func__,
2206 curr_slot->vddp_data->high_vol_level);
2207 }
2208
2209 return rc;
2210}
2211
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302212static inline int msmsdcc_set_vccq_vol(struct msmsdcc_host *host, int level)
2213{
2214 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2215 int rc = 0;
2216
2217 if (curr_slot && curr_slot->vccq_data) {
2218 rc = msmsdcc_vreg_set_voltage(curr_slot->vccq_data,
2219 level, level);
2220 if (rc)
2221 pr_err("%s: %s: failed to change vccq level to %d",
2222 mmc_hostname(host->mmc), __func__, level);
2223 }
2224
2225 return rc;
2226}
2227
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002228static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2229{
2230 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2231 return 1;
2232 return 0;
2233}
2234
Asutosh Dasf5298c32012-04-03 14:51:47 +05302235/*
2236 * Any function calling msmsdcc_setup_clocks must
2237 * acquire clk_mutex. May sleep.
2238 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002239static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
2240{
2241 if (enable) {
2242 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302243 clk_prepare_enable(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002244 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302245 clk_prepare_enable(host->pclk);
2246 clk_prepare_enable(host->clk);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302247 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302248 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002249 } else {
Subhash Jadavanidd432952012-03-28 11:25:56 +05302250 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302251 msmsdcc_delay(host);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302252 clk_disable_unprepare(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002253 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302254 clk_disable_unprepare(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002255 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302256 clk_disable_unprepare(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002257 }
2258}
2259
2260static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2261 unsigned int req_clk)
2262{
2263 unsigned int sel_clk = -1;
2264
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302265 if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
2266 sel_clk = msmsdcc_get_min_sup_clk_rate(host);
2267 goto out;
2268 }
2269
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002270 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2271 unsigned char cnt;
2272
2273 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2274 if (host->plat->sup_clk_table[cnt] > req_clk)
2275 break;
2276 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2277 sel_clk = host->plat->sup_clk_table[cnt];
2278 break;
2279 } else
2280 sel_clk = host->plat->sup_clk_table[cnt];
2281 }
2282 } else {
2283 if ((req_clk < host->plat->msmsdcc_fmax) &&
2284 (req_clk > host->plat->msmsdcc_fmid))
2285 sel_clk = host->plat->msmsdcc_fmid;
2286 else
2287 sel_clk = req_clk;
2288 }
2289
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302290out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002291 return sel_clk;
2292}
2293
2294static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2295 struct msmsdcc_host *host)
2296{
2297 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2298 return host->plat->sup_clk_table[0];
2299 else
2300 return host->plat->msmsdcc_fmin;
2301}
2302
2303static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2304 struct msmsdcc_host *host)
2305{
2306 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2307 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2308 else
2309 return host->plat->msmsdcc_fmax;
2310}
2311
2312static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302313{
2314 struct msm_mmc_gpio_data *curr;
2315 int i, rc = 0;
2316
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002317 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302318 for (i = 0; i < curr->size; i++) {
2319 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002320 if (curr->gpio[i].is_always_on &&
2321 curr->gpio[i].is_enabled)
2322 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302323 rc = gpio_request(curr->gpio[i].no,
2324 curr->gpio[i].name);
2325 if (rc) {
2326 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2327 mmc_hostname(host->mmc),
2328 curr->gpio[i].no,
2329 curr->gpio[i].name, rc);
2330 goto free_gpios;
2331 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002332 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302333 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002334 if (curr->gpio[i].is_always_on)
2335 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302336 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002337 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302338 }
2339 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002340 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302341
2342free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002343 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302344 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002345 curr->gpio[i].is_enabled = false;
2346 }
2347out:
2348 return rc;
2349}
2350
2351static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2352{
2353 struct msm_mmc_pad_data *curr;
2354 int i;
2355
2356 curr = host->plat->pin_data->pad_data;
2357 for (i = 0; i < curr->drv->size; i++) {
2358 if (enable)
2359 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2360 curr->drv->on[i].val);
2361 else
2362 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2363 curr->drv->off[i].val);
2364 }
2365
2366 for (i = 0; i < curr->pull->size; i++) {
2367 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002368 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002369 curr->pull->on[i].val);
2370 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002371 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002372 curr->pull->off[i].val);
2373 }
2374
2375 return 0;
2376}
2377
2378static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2379{
2380 int rc = 0;
2381
2382 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2383 return 0;
2384
2385 if (host->plat->pin_data->is_gpio)
2386 rc = msmsdcc_setup_gpio(host, enable);
2387 else
2388 rc = msmsdcc_setup_pad(host, enable);
2389
2390 if (!rc)
2391 host->plat->pin_data->cfg_sts = enable;
2392
2393 return rc;
2394}
2395
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302396static int msmsdcc_cfg_mpm_sdiowakeup(struct msmsdcc_host *host,
2397 unsigned mode)
2398{
2399 int ret = 0;
2400 unsigned int pin = host->plat->mpm_sdiowakeup_int;
2401
2402 if (!pin)
2403 return 0;
2404
2405 switch (mode) {
2406 case SDC_DAT1_DISABLE:
2407 ret = msm_mpm_enable_pin(pin, 0);
2408 break;
2409 case SDC_DAT1_ENABLE:
2410 ret = msm_mpm_set_pin_type(pin, IRQ_TYPE_LEVEL_LOW);
2411 ret = msm_mpm_enable_pin(pin, 1);
2412 break;
2413 case SDC_DAT1_ENWAKE:
2414 ret = msm_mpm_set_pin_wake(pin, 1);
2415 break;
2416 case SDC_DAT1_DISWAKE:
2417 ret = msm_mpm_set_pin_wake(pin, 0);
2418 break;
2419 default:
2420 ret = -EINVAL;
2421 break;
2422 }
2423
2424 return ret;
2425}
2426
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302427static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2428{
2429 u32 pwr = 0;
2430 int ret = 0;
2431 struct mmc_host *mmc = host->mmc;
2432
2433 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2434 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2435 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2436 ret = msmsdcc_setup_vreg(host, !!ios->vdd);
2437
2438 if (ret) {
2439 pr_err("%s: Failed to setup voltage regulators\n",
2440 mmc_hostname(host->mmc));
2441 goto out;
2442 }
2443
2444 switch (ios->power_mode) {
2445 case MMC_POWER_OFF:
2446 pwr = MCI_PWR_OFF;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302447 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302448 /*
2449 * As VDD pad rail is always on, set low voltage for VDD
2450 * pad rail when slot is unused (when card is not present
2451 * or during system suspend).
2452 */
2453 msmsdcc_set_vddp_low_vol(host);
2454 msmsdcc_setup_pins(host, false);
2455 break;
2456 case MMC_POWER_UP:
2457 /* writing PWR_UP bit is redundant */
2458 pwr = MCI_PWR_UP;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302459 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302460
2461 msmsdcc_set_vddp_high_vol(host);
2462 msmsdcc_setup_pins(host, true);
2463 break;
2464 case MMC_POWER_ON:
2465 pwr = MCI_PWR_ON;
2466 break;
2467 }
2468
2469out:
2470 return pwr;
2471}
2472
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002473static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2474{
2475 unsigned int wakeup_irq;
2476
2477 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2478 host->plat->sdiowakeup_irq :
2479 host->core_irqres->start;
2480
2481 if (!host->irq_wake_enabled) {
2482 enable_irq_wake(wakeup_irq);
2483 host->irq_wake_enabled = true;
2484 }
2485}
2486
2487static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2488{
2489 unsigned int wakeup_irq;
2490
2491 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2492 host->plat->sdiowakeup_irq :
2493 host->core_irqres->start;
2494
2495 if (host->irq_wake_enabled) {
2496 disable_irq_wake(wakeup_irq);
2497 host->irq_wake_enabled = false;
2498 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302499}
2500
San Mehat9d2bd732009-09-22 16:44:22 -07002501static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302502msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
2503{
2504 struct mmc_host *mmc = host->mmc;
2505
2506 /*
2507 * SDIO_AL clients has different mechanism of handling LPM through
2508 * sdio_al driver itself. The sdio wakeup interrupt is configured as
2509 * part of that. Here, we are interested only in clients like WLAN.
2510 */
2511 if (!(mmc->card && mmc_card_sdio(mmc->card))
2512 || host->plat->is_sdio_al_client)
2513 goto out;
2514
2515 if (!host->sdcc_suspended) {
2516 /*
2517 * When MSM is not in power collapse and we
2518 * are disabling clocks, enable bit 22 in MASK0
2519 * to handle asynchronous SDIO interrupts.
2520 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302521 if (enable_wakeup_irq) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302522 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302523 mb();
2524 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302525 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302526 msmsdcc_sync_reg_wr(host);
2527 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302528 goto out;
2529 } else if (!mmc_card_wake_sdio_irq(mmc)) {
2530 /*
2531 * Wakeup MSM only if SDIO function drivers set
2532 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
2533 */
2534 goto out;
2535 }
2536
2537 if (enable_wakeup_irq) {
2538 if (!host->plat->sdiowakeup_irq) {
2539 /*
2540 * When there is no gpio line that can be configured
2541 * as wakeup interrupt handle it by configuring
2542 * asynchronous sdio interrupts and DAT1 line.
2543 */
2544 writel_relaxed(MCI_SDIOINTMASK,
2545 host->base + MMCIMASK0);
2546 mb();
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302547 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302548 /* configure sdcc core interrupt as wakeup interrupt */
2549 msmsdcc_enable_irq_wake(host);
2550 } else {
2551 /* Let gpio line handle wakeup interrupt */
2552 writel_relaxed(0, host->base + MMCIMASK0);
2553 mb();
2554 if (host->sdio_wakeupirq_disabled) {
2555 host->sdio_wakeupirq_disabled = 0;
2556 /* configure gpio line as wakeup interrupt */
2557 msmsdcc_enable_irq_wake(host);
2558 enable_irq(host->plat->sdiowakeup_irq);
2559 }
2560 }
2561 } else {
2562 if (!host->plat->sdiowakeup_irq) {
2563 /*
2564 * We may not have cleared bit 22 in the interrupt
2565 * handler as the clocks might be off at that time.
2566 */
2567 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302568 msmsdcc_sync_reg_wr(host);
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302569 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302570 msmsdcc_disable_irq_wake(host);
2571 } else if (!host->sdio_wakeupirq_disabled) {
2572 disable_irq_nosync(host->plat->sdiowakeup_irq);
2573 msmsdcc_disable_irq_wake(host);
2574 host->sdio_wakeupirq_disabled = 1;
2575 }
2576 }
2577out:
2578 return;
2579}
2580
2581static void
San Mehat9d2bd732009-09-22 16:44:22 -07002582msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2583{
2584 struct msmsdcc_host *host = mmc_priv(mmc);
2585 u32 clk = 0, pwr = 0;
2586 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002587 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002588 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002589
Sahitya Tummala7a892482011-01-18 11:22:49 +05302590
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302591 /*
2592 * Disable SDCC core interrupt until set_ios is completed.
2593 * This avoids any race conditions with interrupt raised
2594 * when turning on/off the clocks. One possible
2595 * scenario is SDIO operational interrupt while the clock
2596 * is turned off.
Asutosh Dasf5298c32012-04-03 14:51:47 +05302597 * host->lock is being released intermittently below.
2598 * Thus, prevent concurrent access to host.
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302599 */
2600
Asutosh Dasf5298c32012-04-03 14:51:47 +05302601 mutex_lock(&host->clk_mutex);
2602 DBG(host, "ios->clock = %u\n", ios->clock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302603 spin_lock_irqsave(&host->lock, flags);
2604 if (!host->sdcc_irq_disabled) {
2605 spin_unlock_irqrestore(&host->lock, flags);
2606 disable_irq(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002607 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302608 host->sdcc_irq_disabled = 1;
2609 }
2610 spin_unlock_irqrestore(&host->lock, flags);
2611
2612 pwr = msmsdcc_setup_pwr(host, ios);
2613
2614 spin_lock_irqsave(&host->lock, flags);
2615 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002616 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302617 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002618 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302619 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002620 host->clks_on = 1;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302621 writel_relaxed(host->mci_irqenable,
2622 host->base + MMCIMASK0);
2623 mb();
2624 msmsdcc_cfg_sdio_wakeup(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002625 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002626
2627 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2628 /*
2629 * For DDR50 mode, controller needs clock rate to be
2630 * double than what is required on the SD card CLK pin.
2631 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302632 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002633 /*
2634 * Make sure that we don't double the clock if
2635 * doubled clock rate is already set
2636 */
2637 if (!host->ddr_doubled_clk_rate ||
2638 (host->ddr_doubled_clk_rate &&
2639 (host->ddr_doubled_clk_rate != ios->clock))) {
2640 host->ddr_doubled_clk_rate =
2641 msmsdcc_get_sup_clk_rate(
2642 host, (ios->clock * 2));
2643 clock = host->ddr_doubled_clk_rate;
2644 }
2645 } else {
2646 host->ddr_doubled_clk_rate = 0;
2647 }
2648
2649 if (clock != host->clk_rate) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302650 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002651 rc = clk_set_rate(host->clk, clock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302652 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002653 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302654 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002655 mmc_hostname(mmc), clock);
2656 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302657 host->reg_write_delay =
2658 (1 + ((3 * USEC_PER_SEC) /
2659 (host->clk_rate ? host->clk_rate :
2660 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002661 }
2662 /*
2663 * give atleast 2 MCLK cycles delay for clocks
2664 * and SDCC core to stabilize
2665 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302666 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002667 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002668 clk |= MCI_CLK_ENABLE;
2669 }
2670
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002671 if (ios->bus_width == MMC_BUS_WIDTH_8)
2672 clk |= MCI_CLK_WIDEBUS_8;
2673 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2674 clk |= MCI_CLK_WIDEBUS_4;
2675 else
2676 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002677
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002678 if (msmsdcc_is_pwrsave(host))
2679 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002680
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002681 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002682
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002683 host->tuning_needed = 0;
2684 /*
2685 * Select the controller timing mode according
2686 * to current bus speed mode
2687 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302688 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2689 (ios->timing == MMC_TIMING_MMC_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002690 clk |= (4 << 14);
2691 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302692 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002693 clk |= (3 << 14);
2694 } else {
2695 clk |= (2 << 14); /* feedback clock */
2696 }
2697
2698 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2699 clk |= (2 << 23);
2700
Subhash Jadavani00083572012-02-15 16:18:01 +05302701 /* Clear IO_PAD_PWR_SWITCH while powering off the card */
2702 if (!ios->vdd)
2703 host->io_pad_pwr_switch = 0;
2704
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002705 if (host->io_pad_pwr_switch)
2706 clk |= IO_PAD_PWR_SWITCH;
2707
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302708 /* Don't write into registers if clocks are disabled */
2709 if (host->clks_on) {
2710 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
2711 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302712 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002713 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302714 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
2715 host->pwr = pwr;
2716 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302717 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002718 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002719 }
2720
2721 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302722 msmsdcc_cfg_sdio_wakeup(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302723 spin_unlock_irqrestore(&host->lock, flags);
2724 /*
2725 * May get a wake-up interrupt the instant we disable the
2726 * clocks. This would disable the wake-up interrupt.
2727 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002728 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302729 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002730 host->clks_on = 0;
2731 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302732
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302733 if (host->tuning_in_progress)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302734 WARN(!host->clks_on,
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302735 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302736
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302737 /* Let interrupts be disabled if the host is powered off */
2738 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
2739 enable_irq(host->core_irqres->start);
2740 host->sdcc_irq_disabled = 0;
2741 }
2742
San Mehat4adbbcc2009-11-08 13:00:37 -08002743 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302744 mutex_unlock(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07002745}
2746
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002747int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2748{
2749 struct msmsdcc_host *host = mmc_priv(mmc);
2750 u32 clk;
2751
2752 clk = readl_relaxed(host->base + MMCICLOCK);
2753 pr_debug("Changing to pwr_save=%d", pwrsave);
2754 if (pwrsave && msmsdcc_is_pwrsave(host))
2755 clk |= MCI_CLK_PWRSAVE;
2756 else
2757 clk &= ~MCI_CLK_PWRSAVE;
2758 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302759 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002760
2761 return 0;
2762}
2763
2764static int msmsdcc_get_ro(struct mmc_host *mmc)
2765{
2766 int status = -ENOSYS;
2767 struct msmsdcc_host *host = mmc_priv(mmc);
2768
2769 if (host->plat->wpswitch) {
2770 status = host->plat->wpswitch(mmc_dev(mmc));
2771 } else if (host->plat->wpswitch_gpio) {
2772 status = gpio_request(host->plat->wpswitch_gpio,
2773 "SD_WP_Switch");
2774 if (status) {
2775 pr_err("%s: %s: Failed to request GPIO %d\n",
2776 mmc_hostname(mmc), __func__,
2777 host->plat->wpswitch_gpio);
2778 } else {
2779 status = gpio_direction_input(
2780 host->plat->wpswitch_gpio);
2781 if (!status) {
2782 /*
2783 * Wait for atleast 300ms as debounce
2784 * time for GPIO input to stabilize.
2785 */
2786 msleep(300);
2787 status = gpio_get_value_cansleep(
2788 host->plat->wpswitch_gpio);
2789 status ^= !host->plat->wpswitch_polarity;
2790 }
2791 gpio_free(host->plat->wpswitch_gpio);
2792 }
2793 }
2794
2795 if (status < 0)
2796 status = -ENOSYS;
2797 pr_debug("%s: Card read-only status %d\n", __func__, status);
2798
2799 return status;
2800}
2801
San Mehat9d2bd732009-09-22 16:44:22 -07002802static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2803{
2804 struct msmsdcc_host *host = mmc_priv(mmc);
2805 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002806
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302807 /*
2808 * We may come here with clocks turned off in that case don't
2809 * attempt to write into MASK0 register. While turning on the
2810 * clocks mci_irqenable will be written to MASK0 register.
2811 */
2812
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002813 if (enable) {
2814 spin_lock_irqsave(&host->lock, flags);
2815 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302816 if (host->clks_on) {
2817 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002818 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302819 mb();
2820 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002821 spin_unlock_irqrestore(&host->lock, flags);
2822 } else {
2823 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302824 if (host->clks_on) {
2825 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002826 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302827 mb();
2828 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002829 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002830}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002831
2832#ifdef CONFIG_PM_RUNTIME
2833static int msmsdcc_enable(struct mmc_host *mmc)
2834{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002835 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002836 struct device *dev = mmc->parent;
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302837 struct msmsdcc_host *host = mmc_priv(mmc);
2838
2839 msmsdcc_pm_qos_update_latency(host, 1);
2840
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002841 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302842 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002843
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002844 if (host->sdcc_suspended && host->pending_resume &&
2845 !pm_runtime_suspended(dev)) {
2846 host->pending_resume = false;
2847 pm_runtime_get_noresume(dev);
2848 rc = msmsdcc_runtime_resume(dev);
2849 goto out;
2850 }
2851
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302852 if (dev->power.runtime_status == RPM_SUSPENDING) {
2853 if (mmc->suspend_task == current) {
2854 pm_runtime_get_noresume(dev);
2855 goto out;
2856 }
2857 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002858
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302859 rc = pm_runtime_get_sync(dev);
2860
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002861out:
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302862 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002863 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2864 __func__, rc);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302865 return rc;
2866 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302867
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302868 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002869}
2870
2871static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2872{
2873 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302874 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002875
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302876 msmsdcc_pm_qos_update_latency(host, 0);
2877
2878 if (mmc->card && mmc_card_sdio(mmc->card))
2879 return 0;
2880
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302881 if (host->plat->disable_runtime_pm)
2882 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002883
2884 rc = pm_runtime_put_sync(mmc->parent);
2885
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002886 /*
2887 * Ignore -EAGAIN as that is not fatal, it means that
2888 * either runtime usage count is non-zero or the runtime
2889 * pm itself is disabled or not in proper state to process
2890 * idle notification.
2891 */
2892 if (rc < 0 && (rc != -EAGAIN)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002893 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2894 __func__, rc);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002895 return rc;
2896 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302897
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002898 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002899}
2900#else
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302901static int msmsdcc_enable(struct mmc_host *mmc)
2902{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002903 struct device *dev = mmc->parent;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302904 struct msmsdcc_host *host = mmc_priv(mmc);
2905 unsigned long flags;
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002906 int rc;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302907
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302908 msmsdcc_pm_qos_update_latency(host, 1);
2909
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002910 if (mmc->card && mmc_card_sdio(mmc->card))
2911 return 0;
2912
2913 if (host->sdcc_suspended && host->pending_resume) {
2914 host->pending_resume = false;
2915 rc = msmsdcc_runtime_resume(dev);
2916 goto out;
2917 }
2918
Asutosh Dasf5298c32012-04-03 14:51:47 +05302919 mutex_lock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302920 spin_lock_irqsave(&host->lock, flags);
2921 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302922 spin_unlock_irqrestore(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302923 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302924 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302925 host->clks_on = 1;
2926 }
2927 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302928 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302929
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002930out:
2931 if (rc < 0) {
2932 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2933 __func__, rc);
2934 return rc;
2935 }
2936
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302937 return 0;
2938}
2939
2940static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2941{
2942 struct msmsdcc_host *host = mmc_priv(mmc);
2943 unsigned long flags;
2944
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302945 msmsdcc_pm_qos_update_latency(host, 0);
2946
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302947 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302948 return 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302949
Asutosh Dasf5298c32012-04-03 14:51:47 +05302950 mutex_lock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302951 spin_lock_irqsave(&host->lock, flags);
2952 if (host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302953 spin_unlock_irqrestore(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302954 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302955 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302956 host->clks_on = 0;
2957 }
2958 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302959 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302960
2961 return 0;
2962}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002963#endif
2964
2965static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2966 struct mmc_ios *ios)
2967{
2968 struct msmsdcc_host *host = mmc_priv(mmc);
2969 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302970 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002971
Subhash Jadavani00083572012-02-15 16:18:01 +05302972 spin_lock_irqsave(&host->lock, flags);
2973 host->io_pad_pwr_switch = 0;
2974 spin_unlock_irqrestore(&host->lock, flags);
2975
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302976 /*
2977 * For eMMC cards, VccQ voltage range must be changed
2978 * only if it operates in HS200 SDR 1.2V mode or in
2979 * DDR 1.2V mode.
2980 */
2981 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_120) {
2982 rc = msmsdcc_set_vccq_vol(host, 1200000);
2983 goto out;
2984 }
2985
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002986 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2987 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302988 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002989 goto out;
2990 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2991 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302992 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002993 goto out;
2994 }
San Mehat9d2bd732009-09-22 16:44:22 -07002995
2996 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002997 /*
2998 * If we are here means voltage switch from high voltage to
2999 * low voltage is required
3000 */
3001
3002 /*
3003 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
3004 * register until they become all zeros.
3005 */
3006 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303007 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003008 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
3009 mmc_hostname(mmc), __func__);
3010 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07003011 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003012
3013 /* Stop SD CLK output. */
3014 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3015 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303016 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003017 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003018
3019 /*
3020 * Switch VDDPX from high voltage to low voltage
3021 * to change the VDD of the SD IO pads.
3022 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303023 rc = msmsdcc_set_vddp_low_vol(host);
3024 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003025 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003026
3027 spin_lock_irqsave(&host->lock, flags);
3028 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3029 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303030 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003031 host->io_pad_pwr_switch = 1;
3032 spin_unlock_irqrestore(&host->lock, flags);
3033
3034 /* Wait 5 ms for the voltage regulater in the card to become stable. */
3035 usleep_range(5000, 5500);
3036
3037 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303038 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003039 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3040 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303041 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003042 spin_unlock_irqrestore(&host->lock, flags);
3043
3044 /*
3045 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
3046 * don't become all ones within 1 ms then a Voltage Switch
3047 * sequence has failed and a power cycle to the card is required.
3048 * Otherwise Voltage Switch sequence is completed successfully.
3049 */
3050 usleep_range(1000, 1500);
3051
3052 spin_lock_irqsave(&host->lock, flags);
3053 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
3054 != (0xF << 1)) {
3055 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
3056 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303057 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003058 goto out_unlock;
3059 }
3060
3061out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303062 /* Enable PWRSAVE */
3063 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3064 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303065 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003066 spin_unlock_irqrestore(&host->lock, flags);
3067out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303068 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003069}
3070
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303071static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003072{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003073 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003074
3075 /* Program the MCLK value to MCLK_FREQ bit field */
3076 if (host->clk_rate <= 112000000)
3077 mclk_freq = 0;
3078 else if (host->clk_rate <= 125000000)
3079 mclk_freq = 1;
3080 else if (host->clk_rate <= 137000000)
3081 mclk_freq = 2;
3082 else if (host->clk_rate <= 150000000)
3083 mclk_freq = 3;
3084 else if (host->clk_rate <= 162000000)
3085 mclk_freq = 4;
3086 else if (host->clk_rate <= 175000000)
3087 mclk_freq = 5;
3088 else if (host->clk_rate <= 187000000)
3089 mclk_freq = 6;
3090 else if (host->clk_rate <= 200000000)
3091 mclk_freq = 7;
3092
3093 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3094 & ~(7 << 24)) | (mclk_freq << 24)),
3095 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003096}
3097
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303098/* Initialize the DLL (Programmable Delay Line ) */
3099static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003100{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003101 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303102 unsigned long flags;
3103 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003104
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303105 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003106 /*
3107 * Make sure that clock is always enabled when DLL
3108 * tuning is in progress. Keeping PWRSAVE ON may
3109 * turn off the clock. So let's disable the PWRSAVE
3110 * here and re-enable it once tuning is completed.
3111 */
3112 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3113 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303114 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303115
3116 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3117 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3118 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3119
3120 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3121 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3122 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3123
3124 msmsdcc_cm_sdc4_dll_set_freq(host);
3125
3126 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3127 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3128 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3129
3130 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3131 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3132 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3133
3134 /* Set DLL_EN bit to 1. */
3135 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3136 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3137
3138 /* Set CK_OUT_EN bit to 1. */
3139 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3140 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3141
3142 wait_cnt = 50;
3143 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3144 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3145 /* max. wait for 50us sec for LOCK bit to be set */
3146 if (--wait_cnt == 0) {
3147 pr_err("%s: %s: DLL failed to LOCK\n",
3148 mmc_hostname(host->mmc), __func__);
3149 rc = -ETIMEDOUT;
3150 goto out;
3151 }
3152 /* wait for 1us before polling again */
3153 udelay(1);
3154 }
3155
3156out:
3157 /* re-enable PWRSAVE */
3158 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3159 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303160 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303161 spin_unlock_irqrestore(&host->lock, flags);
3162
3163 return rc;
3164}
3165
3166static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3167 u8 poll)
3168{
3169 int rc = 0;
3170 u32 wait_cnt = 50;
3171 u8 ck_out_en = 0;
3172
3173 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3174 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3175 MCI_CK_OUT_EN);
3176
3177 while (ck_out_en != poll) {
3178 if (--wait_cnt == 0) {
3179 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3180 mmc_hostname(host->mmc), __func__, poll);
3181 rc = -ETIMEDOUT;
3182 goto out;
3183 }
3184 udelay(1);
3185
3186 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3187 MCI_CK_OUT_EN);
3188 }
3189out:
3190 return rc;
3191}
3192
3193/*
3194 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3195 * calibration sequence. This function should be called before
3196 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3197 * commands (CMD17/CMD18).
3198 *
3199 * This function gets called when host spinlock acquired.
3200 */
3201static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3202{
3203 int rc = 0;
3204 u32 config;
3205
3206 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3207 config |= MCI_CDR_EN;
3208 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3209 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3210
3211 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3212 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3213 if (rc)
3214 goto err_out;
3215
3216 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3217 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3218 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3219
3220 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3221 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3222 if (rc)
3223 goto err_out;
3224
3225 goto out;
3226
3227err_out:
3228 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3229out:
3230 return rc;
3231}
3232
3233static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3234 u8 phase)
3235{
3236 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303237 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3238 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3239 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303240 unsigned long flags;
3241 u32 config;
3242
3243 spin_lock_irqsave(&host->lock, flags);
3244
3245 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3246 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3247 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3248 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3249
3250 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3251 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3252 if (rc)
3253 goto err_out;
3254
3255 /*
3256 * Write the selected DLL clock output phase (0 ... 15)
3257 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
3258 */
3259 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3260 & ~(0xF << 20))
3261 | (grey_coded_phase_table[phase] << 20)),
3262 host->base + MCI_DLL_CONFIG);
3263
3264 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3265 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3266 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3267
3268 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3269 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3270 if (rc)
3271 goto err_out;
3272
3273 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3274 config |= MCI_CDR_EN;
3275 config &= ~MCI_CDR_EXT_EN;
3276 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3277 goto out;
3278
3279err_out:
3280 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3281 mmc_hostname(host->mmc), __func__, phase);
3282out:
3283 spin_unlock_irqrestore(&host->lock, flags);
3284 return rc;
3285}
3286
3287/*
3288 * Find out the greatest range of consecuitive selected
3289 * DLL clock output phases that can be used as sampling
3290 * setting for SD3.0 UHS-I card read operation (in SDR104
3291 * timing mode) or for eMMC4.5 card read operation (in HS200
3292 * timing mode).
3293 * Select the 3/4 of the range and configure the DLL with the
3294 * selected DLL clock output phase.
3295*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303296static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303297 u8 *phase_table, u8 total_phases)
3298{
Subhash Jadavani6159c622012-03-15 19:05:55 +05303299 #define MAX_PHASES 16
Subhash Jadavani34187042012-03-02 10:59:49 +05303300 int ret;
Subhash Jadavani6159c622012-03-15 19:05:55 +05303301 u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
3302 u8 phases_per_row[MAX_PHASES] = {0};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303303 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303304 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3305 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303306
Subhash Jadavani6159c622012-03-15 19:05:55 +05303307 if (!total_phases || (total_phases > MAX_PHASES)) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303308 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3309 mmc_hostname(host->mmc), __func__, total_phases);
3310 return -EINVAL;
3311 }
3312
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303313 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303314 ranges[row_index][col_index] = phase_table[cnt];
3315 phases_per_row[row_index] += 1;
3316 col_index++;
3317
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303318 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303319 continue;
3320 /* check if next phase in phase_table is consecutive or not */
3321 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3322 row_index++;
3323 col_index = 0;
3324 }
3325 }
3326
Subhash Jadavani6159c622012-03-15 19:05:55 +05303327 if (row_index >= MAX_PHASES)
3328 return -EINVAL;
3329
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303330 /* Check if phase-0 is present in first valid window? */
3331 if (!ranges[0][0]) {
3332 phase_0_found = true;
3333 phase_0_raw_index = 0;
3334 /* Check if cycle exist between 2 valid windows */
3335 for (cnt = 1; cnt <= row_index; cnt++) {
3336 if (phases_per_row[cnt]) {
Subhash Jadavani6159c622012-03-15 19:05:55 +05303337 for (i = 0; i < phases_per_row[cnt]; i++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303338 if (ranges[cnt][i] == 15) {
3339 phase_15_found = true;
3340 phase_15_raw_index = cnt;
3341 break;
3342 }
3343 }
3344 }
3345 }
3346 }
3347
3348 /* If 2 valid windows form cycle then merge them as single window */
3349 if (phase_0_found && phase_15_found) {
3350 /* number of phases in raw where phase 0 is present */
3351 u8 phases_0 = phases_per_row[phase_0_raw_index];
3352 /* number of phases in raw where phase 15 is present */
3353 u8 phases_15 = phases_per_row[phase_15_raw_index];
3354
Subhash Jadavani6159c622012-03-15 19:05:55 +05303355 if (phases_0 + phases_15 >= MAX_PHASES)
3356 /*
3357 * If there are more than 1 phase windows then total
3358 * number of phases in both the windows should not be
3359 * more than or equal to MAX_PHASES.
3360 */
3361 return -EINVAL;
3362
3363 /* Merge 2 cyclic windows */
3364 i = phases_15;
3365 for (cnt = 0; cnt < phases_0; cnt++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303366 ranges[phase_15_raw_index][i] =
3367 ranges[phase_0_raw_index][cnt];
Subhash Jadavani6159c622012-03-15 19:05:55 +05303368 if (++i >= MAX_PHASES)
3369 break;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303370 }
Subhash Jadavani6159c622012-03-15 19:05:55 +05303371
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303372 phases_per_row[phase_0_raw_index] = 0;
3373 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
3374 }
3375
3376 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303377 if (phases_per_row[cnt] > curr_max) {
3378 curr_max = phases_per_row[cnt];
3379 selected_row_index = cnt;
3380 }
3381 }
3382
Subhash Jadavani6159c622012-03-15 19:05:55 +05303383 i = ((curr_max * 3) / 4);
3384 if (i)
3385 i--;
3386
Subhash Jadavani34187042012-03-02 10:59:49 +05303387 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303388
Subhash Jadavani6159c622012-03-15 19:05:55 +05303389 if (ret >= MAX_PHASES) {
3390 ret = -EINVAL;
3391 pr_err("%s: %s: invalid phase selected=%d\n",
3392 mmc_hostname(host->mmc), __func__, ret);
3393 }
3394
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303395 return ret;
3396}
3397
Girish K Sa3f41692012-02-29 12:00:09 +05303398static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303399{
3400 int rc = 0;
3401 struct msmsdcc_host *host = mmc_priv(mmc);
3402 unsigned long flags;
3403 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303404 const u32 *tuning_block_pattern = tuning_block_64;
3405 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303406
3407 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
3408
3409 /* Tuning is only required for SDR104 modes */
3410 if (!host->tuning_needed) {
3411 rc = 0;
3412 goto exit;
3413 }
3414
3415 spin_lock_irqsave(&host->lock, flags);
3416 WARN(!host->pwr, "SDCC power is turned off\n");
3417 WARN(!host->clks_on, "SDCC clocks are turned off\n");
3418 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
3419
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303420 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303421 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
3422 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
3423 tuning_block_pattern = tuning_block_128;
3424 size = sizeof(tuning_block_128);
3425 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303426 spin_unlock_irqrestore(&host->lock, flags);
3427
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003428 /* first of all reset the tuning block */
3429 rc = msmsdcc_init_cm_sdc4_dll(host);
3430 if (rc)
3431 goto out;
3432
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303433 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003434 if (!data_buf) {
3435 rc = -ENOMEM;
3436 goto out;
3437 }
3438
3439 phase = 0;
3440 do {
3441 struct mmc_command cmd = {0};
3442 struct mmc_data data = {0};
3443 struct mmc_request mrq = {
3444 .cmd = &cmd,
3445 .data = &data
3446 };
3447 struct scatterlist sg;
3448
3449 /* set the phase in delay line hw block */
3450 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3451 if (rc)
3452 goto kfree;
3453
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303454 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003455 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
3456
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303457 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003458 data.blocks = 1;
3459 data.flags = MMC_DATA_READ;
3460 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
3461
3462 data.sg = &sg;
3463 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303464 sg_init_one(&sg, data_buf, size);
3465 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003466 mmc_wait_for_req(mmc, &mrq);
3467
3468 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303469 !memcmp(data_buf, tuning_block_pattern, size)) {
3470 /* tuning is successful at this tuning point */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003471 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303472 pr_debug("%s: %s: found good phase = %d\n",
3473 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003474 }
3475 } while (++phase < 16);
3476
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003477 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303478 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303479 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05303480 if (rc < 0)
3481 goto kfree;
3482 else
3483 phase = (u8)rc;
3484
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003485 /*
3486 * Finally set the selected phase in delay
3487 * line hw block.
3488 */
3489 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3490 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303491 goto kfree;
3492 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
3493 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003494 } else {
3495 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303496 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003497 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303498 msmsdcc_dump_sdcc_state(host);
3499 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003500 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003501
3502kfree:
3503 kfree(data_buf);
3504out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303505 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303506 host->tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303507 spin_unlock_irqrestore(&host->lock, flags);
3508exit:
3509 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003510 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07003511}
3512
3513static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003514 .enable = msmsdcc_enable,
3515 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07003516 .request = msmsdcc_request,
3517 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003518 .get_ro = msmsdcc_get_ro,
San Mehat9d2bd732009-09-22 16:44:22 -07003519 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003520 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
3521 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07003522};
3523
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003524static unsigned int
3525msmsdcc_slot_status(struct msmsdcc_host *host)
3526{
3527 int status;
3528 unsigned int gpio_no = host->plat->status_gpio;
3529
3530 status = gpio_request(gpio_no, "SD_HW_Detect");
3531 if (status) {
3532 pr_err("%s: %s: Failed to request GPIO %d\n",
3533 mmc_hostname(host->mmc), __func__, gpio_no);
3534 } else {
3535 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003536 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08003537 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003538 if (host->plat->is_status_gpio_active_low)
3539 status = !status;
3540 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003541 gpio_free(gpio_no);
3542 }
3543 return status;
3544}
3545
San Mehat9d2bd732009-09-22 16:44:22 -07003546static void
3547msmsdcc_check_status(unsigned long data)
3548{
3549 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3550 unsigned int status;
3551
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003552 if (host->plat->status || host->plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08003553 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003554 status = host->plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08003555 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003556 status = msmsdcc_slot_status(host);
3557
Krishna Konda941604a2012-01-10 17:46:34 -08003558 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08003559
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003560 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08003561 if (host->plat->status)
3562 pr_info("%s: Slot status change detected "
3563 "(%d -> %d)\n",
3564 mmc_hostname(host->mmc),
3565 host->oldstat, status);
3566 else if (host->plat->is_status_gpio_active_low)
3567 pr_info("%s: Slot status change detected "
3568 "(%d -> %d) and the card detect GPIO"
3569 " is ACTIVE_LOW\n",
3570 mmc_hostname(host->mmc),
3571 host->oldstat, status);
3572 else
3573 pr_info("%s: Slot status change detected "
3574 "(%d -> %d) and the card detect GPIO"
3575 " is ACTIVE_HIGH\n",
3576 mmc_hostname(host->mmc),
3577 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07003578 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003579 }
3580 host->oldstat = status;
3581 } else {
3582 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07003583 }
San Mehat9d2bd732009-09-22 16:44:22 -07003584}
3585
3586static irqreturn_t
3587msmsdcc_platform_status_irq(int irq, void *dev_id)
3588{
3589 struct msmsdcc_host *host = dev_id;
3590
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003591 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07003592 msmsdcc_check_status((unsigned long) host);
3593 return IRQ_HANDLED;
3594}
3595
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003596static irqreturn_t
3597msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
3598{
3599 struct msmsdcc_host *host = dev_id;
3600
3601 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
3602 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303603 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003604 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303605 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003606 wake_lock(&host->sdio_wlock);
3607 msmsdcc_disable_irq_wake(host);
3608 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303609 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003610 }
3611 if (host->plat->is_sdio_al_client) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003612 wake_lock(&host->sdio_wlock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303613 mmc_signal_sdio_irq(host->mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003614 }
3615 spin_unlock(&host->lock);
3616
3617 return IRQ_HANDLED;
3618}
3619
San Mehat9d2bd732009-09-22 16:44:22 -07003620static void
3621msmsdcc_status_notify_cb(int card_present, void *dev_id)
3622{
3623 struct msmsdcc_host *host = dev_id;
3624
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003625 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07003626 card_present);
3627 msmsdcc_check_status((unsigned long) host);
3628}
3629
San Mehat9d2bd732009-09-22 16:44:22 -07003630static int
3631msmsdcc_init_dma(struct msmsdcc_host *host)
3632{
3633 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
3634 host->dma.host = host;
3635 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003636 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003637
3638 if (!host->dmares)
3639 return -ENODEV;
3640
3641 host->dma.nc = dma_alloc_coherent(NULL,
3642 sizeof(struct msmsdcc_nc_dmadata),
3643 &host->dma.nc_busaddr,
3644 GFP_KERNEL);
3645 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003646 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07003647 return -ENOMEM;
3648 }
3649 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
3650 host->dma.cmd_busaddr = host->dma.nc_busaddr;
3651 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
3652 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
3653 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07003654 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07003655
3656 return 0;
3657}
3658
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003659#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
3660/**
3661 * Allocate and Connect a SDCC peripheral's SPS endpoint
3662 *
3663 * This function allocates endpoint context and
3664 * connect it with memory endpoint by calling
3665 * appropriate SPS driver APIs.
3666 *
3667 * Also registers a SPS callback function with
3668 * SPS driver
3669 *
3670 * This function should only be called once typically
3671 * during driver probe.
3672 *
3673 * @host - Pointer to sdcc host structure
3674 * @ep - Pointer to sps endpoint data structure
3675 * @is_produce - 1 means Producer endpoint
3676 * 0 means Consumer endpoint
3677 *
3678 * @return - 0 if successful else negative value.
3679 *
3680 */
3681static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
3682 struct msmsdcc_sps_ep_conn_data *ep,
3683 bool is_producer)
3684{
3685 int rc = 0;
3686 struct sps_pipe *sps_pipe_handle;
3687 struct sps_connect *sps_config = &ep->config;
3688 struct sps_register_event *sps_event = &ep->event;
3689
3690 /* Allocate endpoint context */
3691 sps_pipe_handle = sps_alloc_endpoint();
3692 if (!sps_pipe_handle) {
3693 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
3694 mmc_hostname(host->mmc), is_producer);
3695 rc = -ENOMEM;
3696 goto out;
3697 }
3698
3699 /* Get default connection configuration for an endpoint */
3700 rc = sps_get_config(sps_pipe_handle, sps_config);
3701 if (rc) {
3702 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
3703 " rc=%d", mmc_hostname(host->mmc),
3704 (u32)sps_pipe_handle, rc);
3705 goto get_config_err;
3706 }
3707
3708 /* Modify the default connection configuration */
3709 if (is_producer) {
3710 /*
3711 * For SDCC producer transfer, source should be
3712 * SDCC peripheral where as destination should
3713 * be system memory.
3714 */
3715 sps_config->source = host->sps.bam_handle;
3716 sps_config->destination = SPS_DEV_HANDLE_MEM;
3717 /* Producer pipe will handle this connection */
3718 sps_config->mode = SPS_MODE_SRC;
3719 sps_config->options =
3720 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3721 } else {
3722 /*
3723 * For SDCC consumer transfer, source should be
3724 * system memory where as destination should
3725 * SDCC peripheral
3726 */
3727 sps_config->source = SPS_DEV_HANDLE_MEM;
3728 sps_config->destination = host->sps.bam_handle;
3729 sps_config->mode = SPS_MODE_DEST;
3730 sps_config->options =
3731 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3732 }
3733
3734 /* Producer pipe index */
3735 sps_config->src_pipe_index = host->sps.src_pipe_index;
3736 /* Consumer pipe index */
3737 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
3738 /*
3739 * This event thresold value is only significant for BAM-to-BAM
3740 * transfer. It's ignored for BAM-to-System mode transfer.
3741 */
3742 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05303743
3744 /* Allocate maximum descriptor fifo size */
3745 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
3746 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003747 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
3748 sps_config->desc.size,
3749 &sps_config->desc.phys_base,
3750 GFP_KERNEL);
3751
Pratibhasagar V00b94332011-10-18 14:57:27 +05303752 if (!sps_config->desc.base) {
3753 rc = -ENOMEM;
3754 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3755 , mmc_hostname(host->mmc));
3756 goto get_config_err;
3757 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003758 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3759
3760 /* Establish connection between peripheral and memory endpoint */
3761 rc = sps_connect(sps_pipe_handle, sps_config);
3762 if (rc) {
3763 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3764 " rc=%d", mmc_hostname(host->mmc),
3765 (u32)sps_pipe_handle, rc);
3766 goto sps_connect_err;
3767 }
3768
3769 sps_event->mode = SPS_TRIGGER_CALLBACK;
3770 sps_event->options = SPS_O_EOT;
3771 sps_event->callback = msmsdcc_sps_complete_cb;
3772 sps_event->xfer_done = NULL;
3773 sps_event->user = (void *)host;
3774
3775 /* Register callback event for EOT (End of transfer) event. */
3776 rc = sps_register_event(sps_pipe_handle, sps_event);
3777 if (rc) {
3778 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3779 " rc=%d", mmc_hostname(host->mmc),
3780 (u32)sps_pipe_handle, rc);
3781 goto reg_event_err;
3782 }
3783 /* Now save the sps pipe handle */
3784 ep->pipe_handle = sps_pipe_handle;
3785 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3786 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3787 __func__, is_producer ? "READ" : "WRITE",
3788 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3789 goto out;
3790
3791reg_event_err:
3792 sps_disconnect(sps_pipe_handle);
3793sps_connect_err:
3794 dma_free_coherent(mmc_dev(host->mmc),
3795 sps_config->desc.size,
3796 sps_config->desc.base,
3797 sps_config->desc.phys_base);
3798get_config_err:
3799 sps_free_endpoint(sps_pipe_handle);
3800out:
3801 return rc;
3802}
3803
3804/**
3805 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3806 *
3807 * This function disconnect endpoint and deallocates
3808 * endpoint context.
3809 *
3810 * This function should only be called once typically
3811 * during driver remove.
3812 *
3813 * @host - Pointer to sdcc host structure
3814 * @ep - Pointer to sps endpoint data structure
3815 *
3816 */
3817static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3818 struct msmsdcc_sps_ep_conn_data *ep)
3819{
3820 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3821 struct sps_connect *sps_config = &ep->config;
3822 struct sps_register_event *sps_event = &ep->event;
3823
3824 sps_event->xfer_done = NULL;
3825 sps_event->callback = NULL;
3826 sps_register_event(sps_pipe_handle, sps_event);
3827 sps_disconnect(sps_pipe_handle);
3828 dma_free_coherent(mmc_dev(host->mmc),
3829 sps_config->desc.size,
3830 sps_config->desc.base,
3831 sps_config->desc.phys_base);
3832 sps_free_endpoint(sps_pipe_handle);
3833}
3834
3835/**
3836 * Reset SDCC peripheral's SPS endpoint
3837 *
3838 * This function disconnects an endpoint.
3839 *
3840 * This function should be called for reseting
3841 * SPS endpoint when data transfer error is
3842 * encountered during data transfer. This
3843 * can be considered as soft reset to endpoint.
3844 *
3845 * This function should only be called if
3846 * msmsdcc_sps_init() is already called.
3847 *
3848 * @host - Pointer to sdcc host structure
3849 * @ep - Pointer to sps endpoint data structure
3850 *
3851 * @return - 0 if successful else negative value.
3852 */
3853static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3854 struct msmsdcc_sps_ep_conn_data *ep)
3855{
3856 int rc = 0;
3857 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3858
3859 rc = sps_disconnect(sps_pipe_handle);
3860 if (rc) {
3861 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3862 " rc=%d", mmc_hostname(host->mmc), __func__,
3863 (u32)sps_pipe_handle, rc);
3864 goto out;
3865 }
3866 out:
3867 return rc;
3868}
3869
3870/**
3871 * Restore SDCC peripheral's SPS endpoint
3872 *
3873 * This function connects an endpoint.
3874 *
3875 * This function should be called for restoring
3876 * SPS endpoint after data transfer error is
3877 * encountered during data transfer. This
3878 * can be considered as soft reset to endpoint.
3879 *
3880 * This function should only be called if
3881 * msmsdcc_sps_reset_ep() is called before.
3882 *
3883 * @host - Pointer to sdcc host structure
3884 * @ep - Pointer to sps endpoint data structure
3885 *
3886 * @return - 0 if successful else negative value.
3887 */
3888static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3889 struct msmsdcc_sps_ep_conn_data *ep)
3890{
3891 int rc = 0;
3892 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3893 struct sps_connect *sps_config = &ep->config;
3894 struct sps_register_event *sps_event = &ep->event;
3895
3896 /* Establish connection between peripheral and memory endpoint */
3897 rc = sps_connect(sps_pipe_handle, sps_config);
3898 if (rc) {
3899 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3900 " rc=%d", mmc_hostname(host->mmc), __func__,
3901 (u32)sps_pipe_handle, rc);
3902 goto out;
3903 }
3904
3905 /* Register callback event for EOT (End of transfer) event. */
3906 rc = sps_register_event(sps_pipe_handle, sps_event);
3907 if (rc) {
3908 pr_err("%s: %s: sps_register_event() failed!!!"
3909 " pipe_handle=0x%x, rc=%d",
3910 mmc_hostname(host->mmc), __func__,
3911 (u32)sps_pipe_handle, rc);
3912 goto reg_event_err;
3913 }
3914 goto out;
3915
3916reg_event_err:
3917 sps_disconnect(sps_pipe_handle);
3918out:
3919 return rc;
3920}
3921
3922/**
3923 * Initialize SPS HW connected with SDCC core
3924 *
3925 * This function register BAM HW resources with
3926 * SPS driver and then initialize 2 SPS endpoints
3927 *
3928 * This function should only be called once typically
3929 * during driver probe.
3930 *
3931 * @host - Pointer to sdcc host structure
3932 *
3933 * @return - 0 if successful else negative value.
3934 *
3935 */
3936static int msmsdcc_sps_init(struct msmsdcc_host *host)
3937{
3938 int rc = 0;
3939 struct sps_bam_props bam = {0};
3940
3941 host->bam_base = ioremap(host->bam_memres->start,
3942 resource_size(host->bam_memres));
3943 if (!host->bam_base) {
3944 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3945 " size=0x%x", mmc_hostname(host->mmc),
3946 host->bam_memres->start,
3947 (host->bam_memres->end -
3948 host->bam_memres->start));
3949 rc = -ENOMEM;
3950 goto out;
3951 }
3952
3953 bam.phys_addr = host->bam_memres->start;
3954 bam.virt_addr = host->bam_base;
3955 /*
3956 * This event thresold value is only significant for BAM-to-BAM
3957 * transfer. It's ignored for BAM-to-System mode transfer.
3958 */
3959 bam.event_threshold = 0x10; /* Pipe event threshold */
3960 /*
3961 * This threshold controls when the BAM publish
3962 * the descriptor size on the sideband interface.
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05303963 * SPS HW will be used for data transfer size even
3964 * less than SDCC FIFO size. So let's set BAM summing
3965 * thresold to SPS_MIN_XFER_SIZE bytes.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003966 */
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05303967 bam.summing_threshold = SPS_MIN_XFER_SIZE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003968 /* SPS driver wll handle the SDCC BAM IRQ */
3969 bam.irq = (u32)host->bam_irqres->start;
3970 bam.manage = SPS_BAM_MGR_LOCAL;
3971
3972 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3973 (u32)bam.phys_addr);
3974 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3975 (u32)bam.virt_addr);
3976
3977 /* Register SDCC Peripheral BAM device to SPS driver */
3978 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3979 if (rc) {
3980 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3981 mmc_hostname(host->mmc), rc);
3982 goto reg_bam_err;
3983 }
3984 pr_info("%s: BAM device registered. bam_handle=0x%x",
3985 mmc_hostname(host->mmc), host->sps.bam_handle);
3986
3987 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3988 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3989
3990 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3991 SPS_PROD_PERIPHERAL);
3992 if (rc)
3993 goto sps_reset_err;
3994 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3995 SPS_CONS_PERIPHERAL);
3996 if (rc)
3997 goto cons_conn_err;
3998
3999 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
4000 mmc_hostname(host->mmc),
4001 (unsigned long long)host->bam_memres->start,
4002 (unsigned int)host->bam_irqres->start);
4003 goto out;
4004
4005cons_conn_err:
4006 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4007sps_reset_err:
4008 sps_deregister_bam_device(host->sps.bam_handle);
4009reg_bam_err:
4010 iounmap(host->bam_base);
4011out:
4012 return rc;
4013}
4014
4015/**
4016 * De-initialize SPS HW connected with SDCC core
4017 *
4018 * This function deinitialize SPS endpoints and then
4019 * deregisters BAM resources from SPS driver.
4020 *
4021 * This function should only be called once typically
4022 * during driver remove.
4023 *
4024 * @host - Pointer to sdcc host structure
4025 *
4026 */
4027static void msmsdcc_sps_exit(struct msmsdcc_host *host)
4028{
4029 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
4030 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4031 sps_deregister_bam_device(host->sps.bam_handle);
4032 iounmap(host->bam_base);
4033}
4034#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
4035
4036static ssize_t
4037show_polling(struct device *dev, struct device_attribute *attr, char *buf)
4038{
4039 struct mmc_host *mmc = dev_get_drvdata(dev);
4040 struct msmsdcc_host *host = mmc_priv(mmc);
4041 int poll;
4042 unsigned long flags;
4043
4044 spin_lock_irqsave(&host->lock, flags);
4045 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
4046 spin_unlock_irqrestore(&host->lock, flags);
4047
4048 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
4049}
4050
4051static ssize_t
4052set_polling(struct device *dev, struct device_attribute *attr,
4053 const char *buf, size_t count)
4054{
4055 struct mmc_host *mmc = dev_get_drvdata(dev);
4056 struct msmsdcc_host *host = mmc_priv(mmc);
4057 int value;
4058 unsigned long flags;
4059
4060 sscanf(buf, "%d", &value);
4061
4062 spin_lock_irqsave(&host->lock, flags);
4063 if (value) {
4064 mmc->caps |= MMC_CAP_NEEDS_POLL;
4065 mmc_detect_change(host->mmc, 0);
4066 } else {
4067 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4068 }
4069#ifdef CONFIG_HAS_EARLYSUSPEND
4070 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
4071#endif
4072 spin_unlock_irqrestore(&host->lock, flags);
4073 return count;
4074}
4075
4076static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
4077 show_polling, set_polling);
4078static struct attribute *dev_attrs[] = {
4079 &dev_attr_polling.attr,
4080 NULL,
4081};
4082static struct attribute_group dev_attr_grp = {
4083 .attrs = dev_attrs,
4084};
4085
4086#ifdef CONFIG_HAS_EARLYSUSPEND
4087static void msmsdcc_early_suspend(struct early_suspend *h)
4088{
4089 struct msmsdcc_host *host =
4090 container_of(h, struct msmsdcc_host, early_suspend);
4091 unsigned long flags;
4092
4093 spin_lock_irqsave(&host->lock, flags);
4094 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
4095 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4096 spin_unlock_irqrestore(&host->lock, flags);
4097};
4098static void msmsdcc_late_resume(struct early_suspend *h)
4099{
4100 struct msmsdcc_host *host =
4101 container_of(h, struct msmsdcc_host, early_suspend);
4102 unsigned long flags;
4103
4104 if (host->polling_enabled) {
4105 spin_lock_irqsave(&host->lock, flags);
4106 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
4107 mmc_detect_change(host->mmc, 0);
4108 spin_unlock_irqrestore(&host->lock, flags);
4109 }
4110};
4111#endif
4112
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304113static void msmsdcc_print_regs(const char *name, void __iomem *base,
4114 u32 phys_base, unsigned int no_of_regs)
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304115{
4116 unsigned int i;
4117
4118 if (!base)
4119 return;
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304120
4121 pr_info("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
4122 " =====\n", name, phys_base, (u32)base);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304123 for (i = 0; i < no_of_regs; i = i + 4) {
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304124 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
4125 (u32)readl_relaxed(base + i*4),
4126 (u32)readl_relaxed(base + ((i+1)*4)),
4127 (u32)readl_relaxed(base + ((i+2)*4)),
4128 (u32)readl_relaxed(base + ((i+3)*4)));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304129 }
4130}
4131
4132static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
4133{
4134 /* Dump current state of SDCC clocks, power and irq */
4135 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304136 (host->pwr ? "ON" : "OFF"));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304137 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304138 mmc_hostname(host->mmc), (host->clks_on ? "ON" : "OFF"),
4139 (u32)clk_get_rate(host->clk));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304140 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
4141 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
4142
4143 /* Now dump SDCC registers. Don't print FIFO registers */
4144 if (host->clks_on)
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304145 msmsdcc_print_regs("SDCC-CORE", host->base,
4146 host->core_memres->start, 28);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304147
4148 if (host->curr.data) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304149 if (!msmsdcc_is_dma_possible(host, host->curr.data))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304150 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
4151 else if (host->is_dma_mode)
4152 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
4153 mmc_hostname(host->mmc), host->dma.busy,
4154 host->dma.channel, host->dma.crci);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304155 else if (host->is_sps_mode) {
4156 if (host->sps.busy)
4157 msmsdcc_print_regs("SDCC-DML", host->dml_base,
4158 host->dml_memres->start,
4159 16);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304160 pr_info("%s: SPS mode: busy=%d\n",
4161 mmc_hostname(host->mmc), host->sps.busy);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304162 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304163
4164 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
4165 mmc_hostname(host->mmc), host->curr.xfer_size,
4166 host->curr.data_xfered, host->curr.xfer_remain);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304167 }
4168
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304169 pr_info("%s: got_dataend=%d, prog_enable=%d,"
4170 " wait_for_auto_prog_done=%d, got_auto_prog_done=%d\n",
4171 mmc_hostname(host->mmc), host->curr.got_dataend,
4172 host->prog_enable, host->curr.wait_for_auto_prog_done,
4173 host->curr.got_auto_prog_done);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304174}
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304175
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004176static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
4177{
4178 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4179 struct mmc_request *mrq;
4180 unsigned long flags;
4181
4182 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004183 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004184 pr_info("%s: %s: dummy CMD52 timeout\n",
4185 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004186 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004187 }
4188
4189 mrq = host->curr.mrq;
4190
4191 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304192 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
4193 mrq->cmd->opcode);
4194 msmsdcc_dump_sdcc_state(host);
4195
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004196 if (!mrq->cmd->error)
4197 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304198 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004199 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004200 if (mrq->data && !mrq->data->error)
4201 mrq->data->error = -ETIMEDOUT;
4202 host->curr.data_xfered = 0;
4203 if (host->dma.sg && host->is_dma_mode) {
4204 msm_dmov_stop_cmd(host->dma.channel,
4205 &host->dma.hdr, 0);
4206 } else if (host->sps.sg && host->is_sps_mode) {
4207 /* Stop current SPS transfer */
4208 msmsdcc_sps_exit_curr_xfer(host);
4209 } else {
4210 msmsdcc_reset_and_restore(host);
4211 msmsdcc_stop_data(host);
4212 if (mrq->data && mrq->data->stop)
4213 msmsdcc_start_command(host,
4214 mrq->data->stop, 0);
4215 else
4216 msmsdcc_request_end(host, mrq);
4217 }
4218 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304219 host->prog_enable = 0;
Subhash Jadavanied6b0e42012-03-07 16:36:27 +05304220 host->curr.wait_for_auto_prog_done = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004221 msmsdcc_reset_and_restore(host);
4222 msmsdcc_request_end(host, mrq);
4223 }
4224 }
4225 spin_unlock_irqrestore(&host->lock, flags);
4226}
4227
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304228static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
4229{
4230 int i, ret;
4231 struct mmc_platform_data *pdata;
4232 struct device_node *np = dev->of_node;
4233 u32 bus_width = 0;
4234 u32 *clk_table;
4235 int clk_table_len;
4236 u32 *sup_voltages;
4237 int sup_volt_len;
4238
4239 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
4240 if (!pdata) {
4241 dev_err(dev, "could not allocate memory for platform data\n");
4242 goto err;
4243 }
4244
4245 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
4246 if (bus_width == 8) {
4247 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
4248 } else if (bus_width == 4) {
4249 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
4250 } else {
4251 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
4252 pdata->mmc_bus_width = 0;
4253 }
4254
4255 if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
4256 size_t sz;
4257 sz = sup_volt_len / sizeof(*sup_voltages);
4258 if (sz > 0) {
4259 sup_voltages = devm_kzalloc(dev,
4260 sz * sizeof(*sup_voltages), GFP_KERNEL);
4261 if (!sup_voltages) {
4262 dev_err(dev, "No memory for supported voltage\n");
4263 goto err;
4264 }
4265
4266 ret = of_property_read_u32_array(np,
4267 "qcom,sdcc-sup-voltages", sup_voltages, sz);
4268 if (ret < 0) {
4269 dev_err(dev, "error while reading voltage"
4270 "ranges %d\n", ret);
4271 goto err;
4272 }
4273 } else {
4274 dev_err(dev, "No supported voltages\n");
4275 goto err;
4276 }
4277 for (i = 0; i < sz; i += 2) {
4278 u32 mask;
4279
4280 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
4281 sup_voltages[i + 1]);
4282 if (!mask)
4283 dev_err(dev, "Invalide voltage range %d\n", i);
4284 pdata->ocr_mask |= mask;
4285 }
4286 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
4287 } else {
4288 dev_err(dev, "Supported voltage range not specified\n");
4289 }
4290
4291 if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
4292 size_t sz;
4293 sz = clk_table_len / sizeof(*clk_table);
4294
4295 if (sz > 0) {
4296 clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
4297 GFP_KERNEL);
4298 if (!clk_table) {
4299 dev_err(dev, "No memory for clock table\n");
4300 goto err;
4301 }
4302
4303 ret = of_property_read_u32_array(np,
4304 "qcom,sdcc-clk-rates", clk_table, sz);
4305 if (ret < 0) {
4306 dev_err(dev, "error while reading clk"
4307 "table %d\n", ret);
4308 goto err;
4309 }
4310 } else {
4311 dev_err(dev, "clk_table not specified\n");
4312 goto err;
4313 }
4314 pdata->sup_clk_table = clk_table;
4315 pdata->sup_clk_cnt = sz;
4316 } else {
4317 dev_err(dev, "Supported clock rates not specified\n");
4318 }
4319
4320 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
4321 pdata->nonremovable = true;
4322 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
4323 pdata->disable_cmd23 = true;
4324
4325 return pdata;
4326err:
4327 return NULL;
4328}
4329
San Mehat9d2bd732009-09-22 16:44:22 -07004330static int
4331msmsdcc_probe(struct platform_device *pdev)
4332{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304333 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07004334 struct msmsdcc_host *host;
4335 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004336 unsigned long flags;
4337 struct resource *core_irqres = NULL;
4338 struct resource *bam_irqres = NULL;
4339 struct resource *core_memres = NULL;
4340 struct resource *dml_memres = NULL;
4341 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07004342 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07004343 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05304344 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004345 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07004346
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304347 if (pdev->dev.of_node) {
4348 plat = msmsdcc_populate_pdata(&pdev->dev);
4349 of_property_read_u32((&pdev->dev)->of_node,
4350 "cell-index", &pdev->id);
4351 } else {
4352 plat = pdev->dev.platform_data;
4353 }
4354
San Mehat9d2bd732009-09-22 16:44:22 -07004355 /* must have platform data */
4356 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004357 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004358 ret = -EINVAL;
4359 goto out;
4360 }
4361
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004362 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07004363 return -EINVAL;
4364
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304365 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
4366 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
4367 return -EINVAL;
4368 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004369
San Mehat9d2bd732009-09-22 16:44:22 -07004370 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004371 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004372 return -ENXIO;
4373 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304374 if (pdev->dev.of_node) {
4375 /*
4376 * Device tree iomem resources are only accessible by index.
4377 * index = 0 -> SDCC register interface
4378 * index = 1 -> DML register interface
4379 * index = 2 -> BAM register interface
4380 * IRQ resources:
4381 * index = 0 -> SDCC IRQ
4382 * index = 1 -> BAM IRQ
4383 */
4384 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
4385 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
4386 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
4387 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
4388 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
4389 } else {
4390 for (i = 0; i < pdev->num_resources; i++) {
4391 if (pdev->resource[i].flags & IORESOURCE_MEM) {
4392 if (!strncmp(pdev->resource[i].name,
4393 "sdcc_dml_addr",
4394 sizeof("sdcc_dml_addr")))
4395 dml_memres = &pdev->resource[i];
4396 else if (!strncmp(pdev->resource[i].name,
4397 "sdcc_bam_addr",
4398 sizeof("sdcc_bam_addr")))
4399 bam_memres = &pdev->resource[i];
4400 else
4401 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07004402
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304403 }
4404 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
4405 if (!strncmp(pdev->resource[i].name,
4406 "sdcc_bam_irq",
4407 sizeof("sdcc_bam_irq")))
4408 bam_irqres = &pdev->resource[i];
4409 else
4410 core_irqres = &pdev->resource[i];
4411 }
4412 if (pdev->resource[i].flags & IORESOURCE_DMA) {
4413 if (!strncmp(pdev->resource[i].name,
4414 "sdcc_dma_chnl",
4415 sizeof("sdcc_dma_chnl")))
4416 dmares = &pdev->resource[i];
4417 else if (!strncmp(pdev->resource[i].name,
4418 "sdcc_dma_crci",
4419 sizeof("sdcc_dma_crci")))
4420 dma_crci_res = &pdev->resource[i];
4421 }
Krishna Konda25786ec2011-07-25 16:21:36 -07004422 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004423 }
4424
4425 if (!core_irqres || !core_memres) {
4426 pr_err("%s: Invalid sdcc core resource\n", __func__);
4427 return -ENXIO;
4428 }
4429
4430 /*
4431 * Both BAM and DML memory resource should be preset.
4432 * BAM IRQ resource should also be present.
4433 */
4434 if ((bam_memres && !dml_memres) ||
4435 (!bam_memres && dml_memres) ||
4436 ((bam_memres && dml_memres) && !bam_irqres)) {
4437 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004438 return -ENXIO;
4439 }
4440
4441 /*
4442 * Setup our host structure
4443 */
San Mehat9d2bd732009-09-22 16:44:22 -07004444 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
4445 if (!mmc) {
4446 ret = -ENOMEM;
4447 goto out;
4448 }
4449
4450 host = mmc_priv(mmc);
4451 host->pdev_id = pdev->id;
4452 host->plat = plat;
4453 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08004454 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05304455
4456 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004457 host->is_sps_mode = 1;
4458 else if (dmares)
4459 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07004460
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004461 host->base = ioremap(core_memres->start,
4462 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07004463 if (!host->base) {
4464 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004465 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004466 }
4467
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004468 host->core_irqres = core_irqres;
4469 host->bam_irqres = bam_irqres;
4470 host->core_memres = core_memres;
4471 host->dml_memres = dml_memres;
4472 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07004473 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07004474 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07004475 spin_lock_init(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304476 mutex_init(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07004477
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004478#ifdef CONFIG_MMC_EMBEDDED_SDIO
4479 if (plat->embedded_sdio)
4480 mmc_set_embedded_sdio_data(mmc,
4481 &plat->embedded_sdio->cis,
4482 &plat->embedded_sdio->cccr,
4483 plat->embedded_sdio->funcs,
4484 plat->embedded_sdio->num_funcs);
4485#endif
4486
Sahitya Tummala62612cf2010-12-08 15:03:03 +05304487 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
4488 (unsigned long)host);
4489
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004490 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
4491 (unsigned long)host);
4492 if (host->is_dma_mode) {
4493 /* Setup DMA */
4494 ret = msmsdcc_init_dma(host);
4495 if (ret)
4496 goto ioremap_free;
4497 } else {
4498 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004499 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004500 }
4501
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004502 /*
4503 * Setup SDCC clock if derived from Dayatona
4504 * fabric core clock.
4505 */
4506 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07004507 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004508 if (!IS_ERR(host->dfab_pclk)) {
4509 /* Set the clock rate to 64MHz for max. performance */
4510 ret = clk_set_rate(host->dfab_pclk, 64000000);
4511 if (ret)
4512 goto dfab_pclk_put;
Asutosh Dasf5298c32012-04-03 14:51:47 +05304513 ret = clk_prepare_enable(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004514 if (ret)
4515 goto dfab_pclk_put;
4516 } else
4517 goto dma_free;
4518 }
4519
4520 /*
4521 * Setup main peripheral bus clock
4522 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004523 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004524 if (!IS_ERR(host->pclk)) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05304525 ret = clk_prepare_enable(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004526 if (ret)
4527 goto pclk_put;
4528
4529 host->pclk_rate = clk_get_rate(host->pclk);
4530 }
4531
4532 /*
4533 * Setup SDC MMC clock
4534 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004535 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07004536 if (IS_ERR(host->clk)) {
4537 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004538 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07004539 }
4540
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004541 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
4542 if (ret) {
4543 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
4544 goto clk_put;
4545 }
4546
Asutosh Dasf5298c32012-04-03 14:51:47 +05304547 ret = clk_prepare_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004548 if (ret)
4549 goto clk_put;
4550
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004551 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304552 if (!host->clk_rate)
4553 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304554
4555 /*
4556 * Lookup the Controller Version, to identify the supported features
4557 * Version number read as 0 would indicate SDCC3 or earlier versions
4558 */
4559 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
4560 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
4561 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304562 /*
4563 * Set the register write delay according to min. clock frequency
4564 * supported and update later when the host->clk_rate changes.
4565 */
4566 host->reg_write_delay =
4567 (1 + ((3 * USEC_PER_SEC) /
4568 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004569
4570 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05304571 /* Apply Hard reset to SDCC to put it in power on default state */
4572 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004573
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004574#define MSM_MMC_DEFAULT_CPUDMA_LATENCY 200 /* usecs */
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304575 /* pm qos request to prevent apps idle power collapse */
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004576 if (host->plat->cpu_dma_latency)
4577 host->cpu_dma_latency = host->plat->cpu_dma_latency;
4578 else
4579 host->cpu_dma_latency = MSM_MMC_DEFAULT_CPUDMA_LATENCY;
4580 pm_qos_add_request(&host->pm_qos_req_dma,
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304581 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
4582
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004583 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07004584 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004585 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07004586 goto clk_disable;
4587 }
4588
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004589
4590 /* Clocks has to be running before accessing SPS/DML HW blocks */
4591 if (host->is_sps_mode) {
4592 /* Initialize SPS */
4593 ret = msmsdcc_sps_init(host);
4594 if (ret)
4595 goto vreg_deinit;
4596 /* Initialize DML */
4597 ret = msmsdcc_dml_init(host);
4598 if (ret)
4599 goto sps_exit;
4600 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05304601 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07004602
San Mehat9d2bd732009-09-22 16:44:22 -07004603 /*
4604 * Setup MMC host structure
4605 */
4606 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004607 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
4608 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004609 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004610 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
4611 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07004612
San Mehat9d2bd732009-09-22 16:44:22 -07004613 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05304614 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304615
4616 /*
4617 * If we send the CMD23 before multi block write/read command
4618 * then we need not to send CMD12 at the end of the transfer.
4619 * If we don't send the CMD12 then only way to detect the PROG_DONE
4620 * status is to use the AUTO_PROG_DONE status provided by SDCC4
4621 * controller. So let's enable the CMD23 for SDCC4 only.
4622 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304623 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304624 mmc->caps |= MMC_CAP_CMD23;
4625
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004626 mmc->caps |= plat->uhs_caps;
4627 /*
4628 * XPC controls the maximum current in the default speed mode of SDXC
4629 * card. XPC=0 means 100mA (max.) but speed class is not supported.
4630 * XPC=1 means 150mA (max.) and speed class is supported.
4631 */
4632 if (plat->xpc_cap)
4633 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
4634 MMC_CAP_SET_XPC_180);
4635
Subhash Jadavani6bb34a82012-04-18 13:18:40 +05304636 mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304637 if (pdev->dev.of_node) {
4638 if (of_get_property((&pdev->dev)->of_node,
4639 "qcom,sdcc-hs200", NULL))
4640 mmc->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
4641 }
4642
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004643 if (plat->nonremovable)
4644 mmc->caps |= MMC_CAP_NONREMOVABLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004645 mmc->caps |= MMC_CAP_SDIO_IRQ;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004646
4647 if (plat->is_sdio_al_client)
4648 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07004649
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304650 mmc->max_segs = msmsdcc_get_nr_sg(host);
4651 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
4652 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07004653
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304654 mmc->max_req_size = MMC_MAX_REQ_SIZE;
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +05304655 mmc->max_seg_size = mmc->max_req_size;
San Mehat9d2bd732009-09-22 16:44:22 -07004656
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004657 writel_relaxed(0, host->base + MMCIMASK0);
4658 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05304659 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004660
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004661 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
4662 mb();
4663 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07004664
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004665 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
4666 DRIVER_NAME " (cmd)", host);
4667 if (ret)
4668 goto dml_exit;
4669
4670 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
4671 DRIVER_NAME " (pio)", host);
4672 if (ret)
4673 goto irq_free;
4674
4675 /*
4676 * Enable SDCC IRQ only when host is powered on. Otherwise, this
4677 * IRQ is un-necessarily being monitored by MPM (Modem power
4678 * management block) during idle-power collapse. The MPM will be
4679 * configured to monitor the DATA1 GPIO line with level-low trigger
4680 * and thus depending on the GPIO status, it prevents TCXO shutdown
4681 * during idle-power collapse.
4682 */
4683 disable_irq(core_irqres->start);
4684 host->sdcc_irq_disabled = 1;
4685
4686 if (plat->sdiowakeup_irq) {
4687 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4688 mmc_hostname(mmc));
4689 ret = request_irq(plat->sdiowakeup_irq,
4690 msmsdcc_platform_sdiowakeup_irq,
4691 IRQF_SHARED | IRQF_TRIGGER_LOW,
4692 DRIVER_NAME "sdiowakeup", host);
4693 if (ret) {
4694 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
4695 plat->sdiowakeup_irq, ret);
4696 goto pio_irq_free;
4697 } else {
4698 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304699 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004700 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304701 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004702 }
4703 spin_unlock_irqrestore(&host->lock, flags);
4704 }
4705 }
4706
Subhash Jadavanic9b85752012-04-13 11:16:49 +05304707 if (host->plat->mpm_sdiowakeup_int) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004708 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4709 mmc_hostname(mmc));
4710 }
4711
4712 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
4713 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004714 /*
4715 * Setup card detect change
4716 */
4717
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004718 if (plat->status || plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08004719 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004720 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08004721 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004722 host->oldstat = msmsdcc_slot_status(host);
Krishna Konda360aa422011-12-06 18:27:41 -08004723
Krishna Konda941604a2012-01-10 17:46:34 -08004724 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004725 }
San Mehat9d2bd732009-09-22 16:44:22 -07004726
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004727 if (plat->status_irq) {
4728 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07004729 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004730 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07004731 DRIVER_NAME " (slot)",
4732 host);
4733 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004734 pr_err("Unable to get slot IRQ %d (%d)\n",
4735 plat->status_irq, ret);
4736 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004737 }
4738 } else if (plat->register_status_notify) {
4739 plat->register_status_notify(msmsdcc_status_notify_cb, host);
4740 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004741 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07004742 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004743
4744 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004745
4746 ret = pm_runtime_set_active(&(pdev)->dev);
4747 if (ret < 0)
4748 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
4749 __func__, ret);
4750 /*
4751 * There is no notion of suspend/resume for SD/MMC/SDIO
4752 * cards. So host can be suspended/resumed with out
4753 * worrying about its children.
4754 */
4755 pm_suspend_ignore_children(&(pdev)->dev, true);
4756
4757 /*
4758 * MMC/SD/SDIO bus suspend/resume operations are defined
4759 * only for the slots that will be used for non-removable
4760 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
4761 * defined. Otherwise, they simply become card removal and
4762 * insertion events during suspend and resume respectively.
4763 * Hence, enable run-time PM only for slots for which bus
4764 * suspend/resume operations are defined.
4765 */
4766#ifdef CONFIG_MMC_UNSAFE_RESUME
4767 /*
4768 * If this capability is set, MMC core will enable/disable host
4769 * for every claim/release operation on a host. We use this
4770 * notification to increment/decrement runtime pm usage count.
4771 */
4772 mmc->caps |= MMC_CAP_DISABLE;
4773 pm_runtime_enable(&(pdev)->dev);
4774#else
4775 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
4776 mmc->caps |= MMC_CAP_DISABLE;
4777 pm_runtime_enable(&(pdev)->dev);
4778 }
4779#endif
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05304780#ifndef CONFIG_PM_RUNTIME
4781 mmc_set_disable_delay(mmc, MSM_MMC_DISABLE_TIMEOUT);
4782#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004783 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
4784 (unsigned long)host);
4785
San Mehat9d2bd732009-09-22 16:44:22 -07004786 mmc_add_host(mmc);
4787
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004788#ifdef CONFIG_HAS_EARLYSUSPEND
4789 host->early_suspend.suspend = msmsdcc_early_suspend;
4790 host->early_suspend.resume = msmsdcc_late_resume;
4791 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
4792 register_early_suspend(&host->early_suspend);
4793#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004794
Krishna Konda25786ec2011-07-25 16:21:36 -07004795 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
4796 " dmacrcri %d\n", mmc_hostname(mmc),
4797 (unsigned long long)core_memres->start,
4798 (unsigned int) core_irqres->start,
4799 (unsigned int) plat->status_irq, host->dma.channel,
4800 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004801
4802 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
4803 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
4804 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
4805 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
4806 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
4807 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
4808 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
4809 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
4810 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
4811 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
4812 host->eject);
4813 pr_info("%s: Power save feature enable = %d\n",
4814 mmc_hostname(mmc), msmsdcc_pwrsave);
4815
Krishna Konda25786ec2011-07-25 16:21:36 -07004816 if (host->is_dma_mode && host->dma.channel != -1
4817 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004818 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004819 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004820 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004821 mmc_hostname(mmc), host->dma.cmd_busaddr,
4822 host->dma.cmdptr_busaddr);
4823 } else if (host->is_sps_mode) {
4824 pr_info("%s: SPS-BAM data transfer mode available\n",
4825 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004826 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004827 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004828
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004829#if defined(CONFIG_DEBUG_FS)
4830 msmsdcc_dbg_createhost(host);
4831#endif
4832 if (!plat->status_irq) {
4833 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
4834 if (ret)
4835 goto platform_irq_free;
4836 }
San Mehat9d2bd732009-09-22 16:44:22 -07004837 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004838
4839 platform_irq_free:
4840 del_timer_sync(&host->req_tout_timer);
4841 pm_runtime_disable(&(pdev)->dev);
4842 pm_runtime_set_suspended(&(pdev)->dev);
4843
4844 if (plat->status_irq)
4845 free_irq(plat->status_irq, host);
4846 sdiowakeup_irq_free:
4847 wake_lock_destroy(&host->sdio_suspend_wlock);
4848 if (plat->sdiowakeup_irq)
4849 free_irq(plat->sdiowakeup_irq, host);
4850 pio_irq_free:
4851 if (plat->sdiowakeup_irq)
4852 wake_lock_destroy(&host->sdio_wlock);
4853 free_irq(core_irqres->start, host);
4854 irq_free:
4855 free_irq(core_irqres->start, host);
4856 dml_exit:
4857 if (host->is_sps_mode)
4858 msmsdcc_dml_exit(host);
4859 sps_exit:
4860 if (host->is_sps_mode)
4861 msmsdcc_sps_exit(host);
4862 vreg_deinit:
4863 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07004864 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004865 clk_disable(host->clk);
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004866 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304867 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07004868 clk_put:
4869 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004870 pclk_disable:
4871 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05304872 clk_disable_unprepare(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07004873 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004874 if (!IS_ERR(host->pclk))
4875 clk_put(host->pclk);
4876 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05304877 clk_disable_unprepare(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004878 dfab_pclk_put:
4879 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4880 clk_put(host->dfab_pclk);
4881 dma_free:
4882 if (host->is_dma_mode) {
4883 if (host->dmares)
4884 dma_free_coherent(NULL,
4885 sizeof(struct msmsdcc_nc_dmadata),
4886 host->dma.nc, host->dma.nc_busaddr);
4887 }
4888 ioremap_free:
4889 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07004890 host_free:
4891 mmc_free_host(mmc);
4892 out:
4893 return ret;
4894}
4895
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004896static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07004897{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004898 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4899 struct mmc_platform_data *plat;
4900 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004901
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004902 if (!mmc)
4903 return -ENXIO;
4904
4905 if (pm_runtime_suspended(&(pdev)->dev))
4906 pm_runtime_resume(&(pdev)->dev);
4907
4908 host = mmc_priv(mmc);
4909
4910 DBG(host, "Removing SDCC device = %d\n", pdev->id);
4911 plat = host->plat;
4912
4913 if (!plat->status_irq)
4914 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
4915
4916 del_timer_sync(&host->req_tout_timer);
4917 tasklet_kill(&host->dma_tlet);
4918 tasklet_kill(&host->sps.tlet);
4919 mmc_remove_host(mmc);
4920
4921 if (plat->status_irq)
4922 free_irq(plat->status_irq, host);
4923
4924 wake_lock_destroy(&host->sdio_suspend_wlock);
4925 if (plat->sdiowakeup_irq) {
4926 wake_lock_destroy(&host->sdio_wlock);
4927 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
4928 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07004929 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004930
4931 free_irq(host->core_irqres->start, host);
4932 free_irq(host->core_irqres->start, host);
4933
4934 clk_put(host->clk);
4935 if (!IS_ERR(host->pclk))
4936 clk_put(host->pclk);
4937 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4938 clk_put(host->dfab_pclk);
4939
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004940 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304941 pm_qos_remove_request(&host->pm_qos_req_dma);
4942
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004943 msmsdcc_vreg_init(host, false);
4944
4945 if (host->is_dma_mode) {
4946 if (host->dmares)
4947 dma_free_coherent(NULL,
4948 sizeof(struct msmsdcc_nc_dmadata),
4949 host->dma.nc, host->dma.nc_busaddr);
4950 }
4951
4952 if (host->is_sps_mode) {
4953 msmsdcc_dml_exit(host);
4954 msmsdcc_sps_exit(host);
4955 }
4956
4957 iounmap(host->base);
4958 mmc_free_host(mmc);
4959
4960#ifdef CONFIG_HAS_EARLYSUSPEND
4961 unregister_early_suspend(&host->early_suspend);
4962#endif
4963 pm_runtime_disable(&(pdev)->dev);
4964 pm_runtime_set_suspended(&(pdev)->dev);
4965
4966 return 0;
4967}
4968
4969#ifdef CONFIG_MSM_SDIO_AL
4970int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4971{
4972 struct msmsdcc_host *host = mmc_priv(mmc);
4973 unsigned long flags;
4974
Asutosh Dasf5298c32012-04-03 14:51:47 +05304975 mutex_lock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004976 spin_lock_irqsave(&host->lock, flags);
4977 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
4978 enable ? "En" : "Dis");
4979
4980 if (enable) {
4981 if (!host->sdcc_irq_disabled) {
4982 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05304983 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004984 host->sdcc_irq_disabled = 1;
4985 }
4986
4987 if (host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05304988 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004989 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304990 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004991 host->clks_on = 0;
4992 }
4993
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304994 if (host->plat->sdio_lpm_gpio_setup &&
4995 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004996 spin_unlock_irqrestore(&host->lock, flags);
4997 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
4998 spin_lock_irqsave(&host->lock, flags);
4999 host->sdio_gpio_lpm = 1;
5000 }
5001
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305002 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005003 msmsdcc_enable_irq_wake(host);
5004 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305005 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005006 }
5007 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305008 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005009 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305010 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005011 msmsdcc_disable_irq_wake(host);
5012 }
5013
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305014 if (host->plat->sdio_lpm_gpio_setup &&
5015 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005016 spin_unlock_irqrestore(&host->lock, flags);
5017 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
5018 spin_lock_irqsave(&host->lock, flags);
5019 host->sdio_gpio_lpm = 0;
5020 }
5021
5022 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305023 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005024 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305025 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005026 host->clks_on = 1;
5027 }
5028
5029 if (host->sdcc_irq_disabled) {
5030 writel_relaxed(host->mci_irqenable,
5031 host->base + MMCIMASK0);
5032 mb();
5033 enable_irq(host->core_irqres->start);
5034 host->sdcc_irq_disabled = 0;
5035 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005036 }
5037 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305038 mutex_unlock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005039 return 0;
5040}
5041#else
5042int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
5043{
5044 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07005045}
5046#endif
5047
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005048#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07005049static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005050msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07005051{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005052 struct mmc_host *mmc = dev_get_drvdata(dev);
5053 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07005054 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305055 unsigned long flags;
5056
San Mehat9d2bd732009-09-22 16:44:22 -07005057
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005058 if (host->plat->is_sdio_al_client)
5059 return 0;
Sahitya Tummala7661a452011-07-18 13:28:35 +05305060 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005061 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005062 host->sdcc_suspending = 1;
5063 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07005064
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005065 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005066 * MMC core thinks that host is disabled by now since
5067 * runtime suspend is scheduled after msmsdcc_disable()
5068 * is called. Thus, MMC core will try to enable the host
5069 * while suspending it. This results in a synchronous
5070 * runtime resume request while in runtime suspending
5071 * context and hence inorder to complete this resume
5072 * requet, it will wait for suspend to be complete,
5073 * but runtime suspend also can not proceed further
5074 * until the host is resumed. Thus, it leads to a hang.
5075 * Hence, increase the pm usage count before suspending
5076 * the host so that any resume requests after this will
5077 * simple become pm usage counter increment operations.
5078 */
5079 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05305080 /* If there is pending detect work abort runtime suspend */
5081 if (unlikely(work_busy(&mmc->detect.work)))
5082 rc = -EAGAIN;
5083 else
5084 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005085 pm_runtime_put_noidle(dev);
5086
5087 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305088 spin_lock_irqsave(&host->lock, flags);
5089 host->sdcc_suspended = true;
5090 spin_unlock_irqrestore(&host->lock, flags);
5091 if (mmc->card && mmc_card_sdio(mmc->card) &&
5092 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005093 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305094 * If SDIO function driver doesn't want
5095 * to power off the card, atleast turn off
5096 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005097 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305098 mmc_host_clk_hold(mmc);
5099 spin_lock_irqsave(&mmc->clk_lock, flags);
5100 mmc->clk_old = mmc->ios.clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005101 mmc->ios.clock = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305102 mmc->clk_gated = true;
5103 spin_unlock_irqrestore(&mmc->clk_lock, flags);
5104 mmc_set_ios(mmc);
5105 mmc_host_clk_release(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005106 }
5107 }
5108 host->sdcc_suspending = 0;
5109 mmc->suspend_task = NULL;
5110 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
5111 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005112 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05305113 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
San Mehat9d2bd732009-09-22 16:44:22 -07005114 return rc;
5115}
5116
5117static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005118msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07005119{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005120 struct mmc_host *mmc = dev_get_drvdata(dev);
5121 struct msmsdcc_host *host = mmc_priv(mmc);
5122 unsigned long flags;
5123
5124 if (host->plat->is_sdio_al_client)
5125 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07005126
Sahitya Tummala7661a452011-07-18 13:28:35 +05305127 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005128 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305129 if (mmc->card && mmc_card_sdio(mmc->card) &&
5130 mmc_card_keep_power(mmc)) {
5131 mmc_host_clk_hold(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305132 mmc->ios.clock = host->clk_rate;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305133 mmc_set_ios(mmc);
5134 mmc_host_clk_release(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305135 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005136
5137 mmc_resume_host(mmc);
5138
5139 /*
5140 * FIXME: Clearing of flags must be handled in clients
5141 * resume handler.
5142 */
5143 spin_lock_irqsave(&host->lock, flags);
5144 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305145 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005146 spin_unlock_irqrestore(&host->lock, flags);
5147
5148 /*
5149 * After resuming the host wait for sometime so that
5150 * the SDIO work will be processed.
5151 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305152 if (mmc->card && mmc_card_sdio(mmc->card)) {
Subhash Jadavanic9b85752012-04-13 11:16:49 +05305153 if ((host->plat->mpm_sdiowakeup_int ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005154 host->plat->sdiowakeup_irq) &&
5155 wake_lock_active(&host->sdio_wlock))
5156 wake_lock_timeout(&host->sdio_wlock, 1);
5157 }
5158
5159 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005160 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05305161 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005162 return 0;
5163}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005164
5165static int msmsdcc_runtime_idle(struct device *dev)
5166{
5167 struct mmc_host *mmc = dev_get_drvdata(dev);
5168 struct msmsdcc_host *host = mmc_priv(mmc);
5169
5170 if (host->plat->is_sdio_al_client)
5171 return 0;
5172
5173 /* Idle timeout is not configurable for now */
5174 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
5175
5176 return -EAGAIN;
5177}
5178
5179static int msmsdcc_pm_suspend(struct device *dev)
5180{
5181 struct mmc_host *mmc = dev_get_drvdata(dev);
5182 struct msmsdcc_host *host = mmc_priv(mmc);
5183 int rc = 0;
5184
5185 if (host->plat->is_sdio_al_client)
5186 return 0;
5187
5188
5189 if (host->plat->status_irq)
5190 disable_irq(host->plat->status_irq);
5191
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005192 if (!pm_runtime_suspended(dev))
5193 rc = msmsdcc_runtime_suspend(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005194
5195 return rc;
5196}
5197
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305198static int msmsdcc_suspend_noirq(struct device *dev)
5199{
5200 struct mmc_host *mmc = dev_get_drvdata(dev);
5201 struct msmsdcc_host *host = mmc_priv(mmc);
5202 int rc = 0;
5203
5204 /*
5205 * After platform suspend there may be active request
5206 * which might have enabled clocks. For example, in SDIO
5207 * case, ksdioirq thread might have scheduled after sdcc
5208 * suspend but before system freeze. In that case abort
5209 * suspend and retry instead of keeping the clocks on
5210 * during suspend and not allowing TCXO.
5211 */
5212
Asutosh Dasf5298c32012-04-03 14:51:47 +05305213 if (host->clks_on && !host->plat->is_sdio_al_client) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305214 pr_warn("%s: clocks are on after suspend, aborting system "
5215 "suspend\n", mmc_hostname(mmc));
5216 rc = -EAGAIN;
5217 }
5218
5219 return rc;
5220}
5221
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005222static int msmsdcc_pm_resume(struct device *dev)
5223{
5224 struct mmc_host *mmc = dev_get_drvdata(dev);
5225 struct msmsdcc_host *host = mmc_priv(mmc);
5226 int rc = 0;
5227
5228 if (host->plat->is_sdio_al_client)
5229 return 0;
5230
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005231 if (mmc->card && mmc_card_sdio(mmc->card))
Sahitya Tummalafb486372011-09-02 19:01:49 +05305232 rc = msmsdcc_runtime_resume(dev);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005233 else
5234 host->pending_resume = true;
5235
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005236 if (host->plat->status_irq) {
5237 msmsdcc_check_status((unsigned long)host);
5238 enable_irq(host->plat->status_irq);
5239 }
5240
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005241 return rc;
5242}
5243
Daniel Walker08ecfde2010-06-23 12:32:20 -07005244#else
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005245static int msmsdcc_runtime_suspend(struct device *dev)
5246{
5247 return 0;
5248}
5249static int msmsdcc_runtime_idle(struct device *dev)
5250{
5251 return 0;
5252}
5253static int msmsdcc_pm_suspend(struct device *dev)
5254{
5255 return 0;
5256}
5257static int msmsdcc_pm_resume(struct device *dev)
5258{
5259 return 0;
5260}
5261static int msmsdcc_suspend_noirq(struct device *dev)
5262{
5263 return 0;
5264}
5265static int msmsdcc_runtime_resume(struct device *dev)
5266{
5267 return 0;
5268}
Daniel Walker08ecfde2010-06-23 12:32:20 -07005269#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005270
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005271static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
5272 .runtime_suspend = msmsdcc_runtime_suspend,
5273 .runtime_resume = msmsdcc_runtime_resume,
5274 .runtime_idle = msmsdcc_runtime_idle,
5275 .suspend = msmsdcc_pm_suspend,
5276 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305277 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005278};
5279
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305280static const struct of_device_id msmsdcc_dt_match[] = {
5281 {.compatible = "qcom,msm-sdcc"},
5282
5283};
5284MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
5285
San Mehat9d2bd732009-09-22 16:44:22 -07005286static struct platform_driver msmsdcc_driver = {
5287 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005288 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07005289 .driver = {
5290 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005291 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305292 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07005293 },
5294};
5295
5296static int __init msmsdcc_init(void)
5297{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005298#if defined(CONFIG_DEBUG_FS)
5299 int ret = 0;
5300 ret = msmsdcc_dbg_init();
5301 if (ret) {
5302 pr_err("Failed to create debug fs dir \n");
5303 return ret;
5304 }
5305#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005306 return platform_driver_register(&msmsdcc_driver);
5307}
5308
5309static void __exit msmsdcc_exit(void)
5310{
5311 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005312
5313#if defined(CONFIG_DEBUG_FS)
5314 debugfs_remove(debugfs_file);
5315 debugfs_remove(debugfs_dir);
5316#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005317}
5318
5319module_init(msmsdcc_init);
5320module_exit(msmsdcc_exit);
5321
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005322MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07005323MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005324
5325#if defined(CONFIG_DEBUG_FS)
5326
5327static int
5328msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
5329{
5330 file->private_data = inode->i_private;
5331 return 0;
5332}
5333
5334static ssize_t
5335msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
5336 size_t count, loff_t *ppos)
5337{
5338 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08005339 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005340 int max, i;
5341
5342 i = 0;
5343 max = sizeof(buf) - 1;
5344
5345 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
5346 host->curr.cmd, host->curr.data);
5347 if (host->curr.cmd) {
5348 struct mmc_command *cmd = host->curr.cmd;
5349
5350 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
5351 cmd->opcode, cmd->arg, cmd->flags);
5352 }
5353 if (host->curr.data) {
5354 struct mmc_data *data = host->curr.data;
5355 i += scnprintf(buf + i, max - i,
5356 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
5357 data->timeout_ns, data->timeout_clks,
5358 data->blksz, data->blocks, data->error,
5359 data->flags);
5360 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
5361 host->curr.xfer_size, host->curr.xfer_remain,
5362 host->curr.data_xfered, host->dma.sg);
5363 }
5364
5365 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
5366}
5367
5368static const struct file_operations msmsdcc_dbg_state_ops = {
5369 .read = msmsdcc_dbg_state_read,
5370 .open = msmsdcc_dbg_state_open,
5371};
5372
5373static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
5374{
5375 if (debugfs_dir) {
5376 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
5377 0644, debugfs_dir, host,
5378 &msmsdcc_dbg_state_ops);
5379 }
5380}
5381
5382static int __init msmsdcc_dbg_init(void)
5383{
5384 int err;
5385
5386 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
5387 if (IS_ERR(debugfs_dir)) {
5388 err = PTR_ERR(debugfs_dir);
5389 debugfs_dir = NULL;
5390 return err;
5391 }
5392
5393 return 0;
5394}
5395#endif