blob: c194f9c85782bbda87be39895a68dcc6b3a16101 [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);
San Mehat9d2bd732009-09-22 16:44:22 -07001865
1866 if (host->eject) {
1867 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1868 mrq->cmd->error = 0;
1869 mrq->data->bytes_xfered = mrq->data->blksz *
1870 mrq->data->blocks;
1871 } else
1872 mrq->cmd->error = -ENOMEDIUM;
1873
1874 spin_unlock_irqrestore(&host->lock, flags);
1875 mmc_request_done(mmc, mrq);
1876 return;
1877 }
1878
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301879 /*
subhashjf181c292012-05-02 13:07:40 +05301880 * Don't start the request if SDCC is not in proper state to handle it
1881 */
1882 if (!host->pwr || !host->clks_on || host->sdcc_irq_disabled) {
1883 WARN(1, "%s: %s: SDCC is in bad state. don't process"
1884 " new request (CMD%d)\n", mmc_hostname(host->mmc),
1885 __func__, mrq->cmd->opcode);
1886 msmsdcc_dump_sdcc_state(host);
1887 mrq->cmd->error = -EIO;
1888 if (mrq->data) {
1889 mrq->data->error = -EIO;
1890 mrq->data->bytes_xfered = 0;
1891 }
1892 spin_unlock_irqrestore(&host->lock, flags);
1893 mmc_request_done(mmc, mrq);
1894 return;
1895 }
1896
1897 WARN(host->curr.mrq, "%s: %s: New request (CMD%d) received while"
1898 " other request (CMD%d) is in progress\n",
1899 mmc_hostname(host->mmc), __func__,
1900 mrq->cmd->opcode, host->curr.mrq->cmd->opcode);
1901
1902 /*
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301903 * Kick the software command timeout timer here.
1904 * Timer expires in 10 secs.
1905 */
1906 mod_timer(&host->req_tout_timer,
1907 (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
San Mehat9d2bd732009-09-22 16:44:22 -07001908
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301909 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301910 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301911 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
1912 mrq->cmd->opcode == 54) {
Pratibhasagar V1c11da62011-11-14 12:36:35 +05301913 if (!host->sdcc_version)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001914 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301915 else
1916 /*
1917 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
1918 * write operations using CMD53 and CMD54.
1919 * Setting this bit with CMD53 would
1920 * automatically triggers PROG_DONE interrupt
1921 * without the need of sending dummy CMD52.
1922 */
1923 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani758cf8c2011-11-13 11:59:55 +05301924 } else if (mrq->cmd->opcode == MMC_WRITE_BLOCK &&
1925 host->sdcc_version) {
1926 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001927 }
San Mehat9d2bd732009-09-22 16:44:22 -07001928 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301929
Pratibhasagar V00b94332011-10-18 14:57:27 +05301930 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301931 mrq->sbc->mrq = mrq;
1932 mrq->sbc->data = mrq->data;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301933 if (mrq->data->flags & MMC_DATA_WRITE) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301934 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301935 msmsdcc_start_command(host, mrq->sbc, 0);
1936 } else {
1937 msmsdcc_request_start(host, mrq);
1938 }
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301939 } else {
1940 msmsdcc_request_start(host, mrq);
1941 }
1942
San Mehat9d2bd732009-09-22 16:44:22 -07001943 spin_unlock_irqrestore(&host->lock, flags);
1944}
1945
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001946static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1947 int min_uV, int max_uV)
1948{
1949 int rc = 0;
1950
1951 if (vreg->set_voltage_sup) {
1952 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1953 if (rc) {
1954 pr_err("%s: regulator_set_voltage(%s) failed."
1955 " min_uV=%d, max_uV=%d, rc=%d\n",
1956 __func__, vreg->name, min_uV, max_uV, rc);
1957 }
1958 }
1959
1960 return rc;
1961}
1962
1963static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1964 int uA_load)
1965{
1966 int rc = 0;
1967
Krishna Kondafea60182011-11-01 16:01:34 -07001968 /* regulators that do not support regulator_set_voltage also
1969 do not support regulator_set_optimum_mode */
1970 if (vreg->set_voltage_sup) {
1971 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1972 if (rc < 0)
1973 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
1974 "uA_load=%d) failed. rc=%d\n", __func__,
1975 vreg->name, uA_load, rc);
1976 else
1977 /* regulator_set_optimum_mode() can return non zero
1978 * value even for success case.
1979 */
1980 rc = 0;
1981 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001982
1983 return rc;
1984}
1985
1986static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1987 struct device *dev)
1988{
1989 int rc = 0;
1990
1991 /* check if regulator is already initialized? */
1992 if (vreg->reg)
1993 goto out;
1994
1995 /* Get the regulator handle */
1996 vreg->reg = regulator_get(dev, vreg->name);
1997 if (IS_ERR(vreg->reg)) {
1998 rc = PTR_ERR(vreg->reg);
1999 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
2000 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002001 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002002 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002003
2004 if (regulator_count_voltages(vreg->reg) > 0)
2005 vreg->set_voltage_sup = 1;
2006
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002007out:
2008 return rc;
2009}
2010
2011static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
2012{
2013 if (vreg->reg)
2014 regulator_put(vreg->reg);
2015}
2016
2017/* This init function should be called only once for each SDCC slot */
2018static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
2019{
2020 int rc = 0;
2021 struct msm_mmc_slot_reg_data *curr_slot;
2022 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
2023 struct device *dev = mmc_dev(host->mmc);
2024
2025 curr_slot = host->plat->vreg_data;
2026 if (!curr_slot)
2027 goto out;
2028
2029 curr_vdd_reg = curr_slot->vdd_data;
2030 curr_vccq_reg = curr_slot->vccq_data;
2031 curr_vddp_reg = curr_slot->vddp_data;
2032
2033 if (is_init) {
2034 /*
2035 * Get the regulator handle from voltage regulator framework
2036 * and then try to set the voltage level for the regulator
2037 */
2038 if (curr_vdd_reg) {
2039 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
2040 if (rc)
2041 goto out;
2042 }
2043 if (curr_vccq_reg) {
2044 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
2045 if (rc)
2046 goto vdd_reg_deinit;
2047 }
2048 if (curr_vddp_reg) {
2049 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
2050 if (rc)
2051 goto vccq_reg_deinit;
2052 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002053 rc = msmsdcc_vreg_reset(host);
2054 if (rc)
2055 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
2056 host->pdev_id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002057 goto out;
2058 } else {
2059 /* Deregister all regulators from regulator framework */
2060 goto vddp_reg_deinit;
2061 }
2062vddp_reg_deinit:
2063 if (curr_vddp_reg)
2064 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
2065vccq_reg_deinit:
2066 if (curr_vccq_reg)
2067 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
2068vdd_reg_deinit:
2069 if (curr_vdd_reg)
2070 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2071out:
2072 return rc;
2073}
2074
2075static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2076{
2077 int rc = 0;
2078
Subhash Jadavanicc922692011-08-01 23:05:01 +05302079 /* Put regulator in HPM (high power mode) */
2080 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2081 if (rc < 0)
2082 goto out;
2083
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002084 if (!vreg->is_enabled) {
2085 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302086 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2087 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002088 if (rc)
2089 goto out;
2090
2091 rc = regulator_enable(vreg->reg);
2092 if (rc) {
2093 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2094 __func__, vreg->name, rc);
2095 goto out;
2096 }
2097 vreg->is_enabled = true;
2098 }
2099
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002100out:
2101 return rc;
2102}
2103
2104static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
2105{
2106 int rc = 0;
2107
2108 /* Never disable regulator marked as always_on */
2109 if (vreg->is_enabled && !vreg->always_on) {
2110 rc = regulator_disable(vreg->reg);
2111 if (rc) {
2112 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2113 __func__, vreg->name, rc);
2114 goto out;
2115 }
2116 vreg->is_enabled = false;
2117
2118 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2119 if (rc < 0)
2120 goto out;
2121
2122 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302123 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002124 if (rc)
2125 goto out;
2126 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
2127 /* Put always_on regulator in LPM (low power mode) */
2128 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2129 if (rc < 0)
2130 goto out;
2131 }
2132out:
2133 return rc;
2134}
2135
2136static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
2137{
2138 int rc = 0, i;
2139 struct msm_mmc_slot_reg_data *curr_slot;
2140 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
2141 struct msm_mmc_reg_data *vreg_table[3];
2142
2143 curr_slot = host->plat->vreg_data;
2144 if (!curr_slot)
2145 goto out;
2146
2147 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
2148 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
2149 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
2150
2151 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2152 if (vreg_table[i]) {
2153 if (enable)
2154 rc = msmsdcc_vreg_enable(vreg_table[i]);
2155 else
2156 rc = msmsdcc_vreg_disable(vreg_table[i]);
2157 if (rc)
2158 goto out;
2159 }
2160 }
2161out:
2162 return rc;
2163}
2164
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002165/*
2166 * Reset vreg by ensuring it is off during probe. A call
2167 * to enable vreg is needed to balance disable vreg
2168 */
2169static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2170{
2171 int rc;
2172
2173 rc = msmsdcc_setup_vreg(host, 1);
2174 if (rc)
2175 return rc;
2176 rc = msmsdcc_setup_vreg(host, 0);
2177 return rc;
2178}
2179
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302180static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002181{
2182 int rc = 0;
2183
2184 if (host->plat->vreg_data) {
2185 struct msm_mmc_reg_data *vddp_reg =
2186 host->plat->vreg_data->vddp_data;
2187
2188 if (vddp_reg && vddp_reg->is_enabled)
2189 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
2190 }
2191
2192 return rc;
2193}
2194
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302195static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
2196{
2197 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2198 int rc = 0;
2199
2200 if (curr_slot && curr_slot->vddp_data) {
2201 rc = msmsdcc_set_vddp_level(host,
2202 curr_slot->vddp_data->low_vol_level);
2203
2204 if (rc)
2205 pr_err("%s: %s: failed to change vddp level to %d",
2206 mmc_hostname(host->mmc), __func__,
2207 curr_slot->vddp_data->low_vol_level);
2208 }
2209
2210 return rc;
2211}
2212
2213static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
2214{
2215 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2216 int rc = 0;
2217
2218 if (curr_slot && curr_slot->vddp_data) {
2219 rc = msmsdcc_set_vddp_level(host,
2220 curr_slot->vddp_data->high_vol_level);
2221
2222 if (rc)
2223 pr_err("%s: %s: failed to change vddp level to %d",
2224 mmc_hostname(host->mmc), __func__,
2225 curr_slot->vddp_data->high_vol_level);
2226 }
2227
2228 return rc;
2229}
2230
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302231static inline int msmsdcc_set_vccq_vol(struct msmsdcc_host *host, int level)
2232{
2233 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2234 int rc = 0;
2235
2236 if (curr_slot && curr_slot->vccq_data) {
2237 rc = msmsdcc_vreg_set_voltage(curr_slot->vccq_data,
2238 level, level);
2239 if (rc)
2240 pr_err("%s: %s: failed to change vccq level to %d",
2241 mmc_hostname(host->mmc), __func__, level);
2242 }
2243
2244 return rc;
2245}
2246
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002247static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2248{
2249 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2250 return 1;
2251 return 0;
2252}
2253
Asutosh Dasf5298c32012-04-03 14:51:47 +05302254/*
2255 * Any function calling msmsdcc_setup_clocks must
2256 * acquire clk_mutex. May sleep.
2257 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002258static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
2259{
2260 if (enable) {
2261 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302262 clk_prepare_enable(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002263 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302264 clk_prepare_enable(host->pclk);
2265 clk_prepare_enable(host->clk);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302266 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302267 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002268 } else {
Subhash Jadavanidd432952012-03-28 11:25:56 +05302269 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302270 msmsdcc_delay(host);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302271 clk_disable_unprepare(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002272 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302273 clk_disable_unprepare(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002274 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302275 clk_disable_unprepare(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002276 }
2277}
2278
2279static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2280 unsigned int req_clk)
2281{
2282 unsigned int sel_clk = -1;
2283
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302284 if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
2285 sel_clk = msmsdcc_get_min_sup_clk_rate(host);
2286 goto out;
2287 }
2288
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002289 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2290 unsigned char cnt;
2291
2292 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2293 if (host->plat->sup_clk_table[cnt] > req_clk)
2294 break;
2295 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2296 sel_clk = host->plat->sup_clk_table[cnt];
2297 break;
2298 } else
2299 sel_clk = host->plat->sup_clk_table[cnt];
2300 }
2301 } else {
2302 if ((req_clk < host->plat->msmsdcc_fmax) &&
2303 (req_clk > host->plat->msmsdcc_fmid))
2304 sel_clk = host->plat->msmsdcc_fmid;
2305 else
2306 sel_clk = req_clk;
2307 }
2308
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302309out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002310 return sel_clk;
2311}
2312
2313static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2314 struct msmsdcc_host *host)
2315{
2316 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2317 return host->plat->sup_clk_table[0];
2318 else
2319 return host->plat->msmsdcc_fmin;
2320}
2321
2322static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2323 struct msmsdcc_host *host)
2324{
2325 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2326 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2327 else
2328 return host->plat->msmsdcc_fmax;
2329}
2330
2331static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302332{
2333 struct msm_mmc_gpio_data *curr;
2334 int i, rc = 0;
2335
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002336 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302337 for (i = 0; i < curr->size; i++) {
2338 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002339 if (curr->gpio[i].is_always_on &&
2340 curr->gpio[i].is_enabled)
2341 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302342 rc = gpio_request(curr->gpio[i].no,
2343 curr->gpio[i].name);
2344 if (rc) {
2345 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2346 mmc_hostname(host->mmc),
2347 curr->gpio[i].no,
2348 curr->gpio[i].name, rc);
2349 goto free_gpios;
2350 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002351 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302352 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002353 if (curr->gpio[i].is_always_on)
2354 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302355 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002356 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302357 }
2358 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002359 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302360
2361free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002362 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302363 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002364 curr->gpio[i].is_enabled = false;
2365 }
2366out:
2367 return rc;
2368}
2369
2370static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2371{
2372 struct msm_mmc_pad_data *curr;
2373 int i;
2374
2375 curr = host->plat->pin_data->pad_data;
2376 for (i = 0; i < curr->drv->size; i++) {
2377 if (enable)
2378 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2379 curr->drv->on[i].val);
2380 else
2381 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2382 curr->drv->off[i].val);
2383 }
2384
2385 for (i = 0; i < curr->pull->size; i++) {
2386 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002387 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002388 curr->pull->on[i].val);
2389 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002390 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002391 curr->pull->off[i].val);
2392 }
2393
2394 return 0;
2395}
2396
2397static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2398{
2399 int rc = 0;
2400
2401 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2402 return 0;
2403
2404 if (host->plat->pin_data->is_gpio)
2405 rc = msmsdcc_setup_gpio(host, enable);
2406 else
2407 rc = msmsdcc_setup_pad(host, enable);
2408
2409 if (!rc)
2410 host->plat->pin_data->cfg_sts = enable;
2411
2412 return rc;
2413}
2414
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302415static int msmsdcc_cfg_mpm_sdiowakeup(struct msmsdcc_host *host,
2416 unsigned mode)
2417{
2418 int ret = 0;
2419 unsigned int pin = host->plat->mpm_sdiowakeup_int;
2420
2421 if (!pin)
2422 return 0;
2423
2424 switch (mode) {
2425 case SDC_DAT1_DISABLE:
2426 ret = msm_mpm_enable_pin(pin, 0);
2427 break;
2428 case SDC_DAT1_ENABLE:
2429 ret = msm_mpm_set_pin_type(pin, IRQ_TYPE_LEVEL_LOW);
2430 ret = msm_mpm_enable_pin(pin, 1);
2431 break;
2432 case SDC_DAT1_ENWAKE:
2433 ret = msm_mpm_set_pin_wake(pin, 1);
2434 break;
2435 case SDC_DAT1_DISWAKE:
2436 ret = msm_mpm_set_pin_wake(pin, 0);
2437 break;
2438 default:
2439 ret = -EINVAL;
2440 break;
2441 }
2442
2443 return ret;
2444}
2445
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302446static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2447{
2448 u32 pwr = 0;
2449 int ret = 0;
2450 struct mmc_host *mmc = host->mmc;
2451
2452 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2453 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2454 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2455 ret = msmsdcc_setup_vreg(host, !!ios->vdd);
2456
2457 if (ret) {
2458 pr_err("%s: Failed to setup voltage regulators\n",
2459 mmc_hostname(host->mmc));
2460 goto out;
2461 }
2462
2463 switch (ios->power_mode) {
2464 case MMC_POWER_OFF:
2465 pwr = MCI_PWR_OFF;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302466 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302467 /*
2468 * As VDD pad rail is always on, set low voltage for VDD
2469 * pad rail when slot is unused (when card is not present
2470 * or during system suspend).
2471 */
2472 msmsdcc_set_vddp_low_vol(host);
2473 msmsdcc_setup_pins(host, false);
2474 break;
2475 case MMC_POWER_UP:
2476 /* writing PWR_UP bit is redundant */
2477 pwr = MCI_PWR_UP;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302478 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302479
2480 msmsdcc_set_vddp_high_vol(host);
2481 msmsdcc_setup_pins(host, true);
2482 break;
2483 case MMC_POWER_ON:
2484 pwr = MCI_PWR_ON;
2485 break;
2486 }
2487
2488out:
2489 return pwr;
2490}
2491
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002492static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2493{
2494 unsigned int wakeup_irq;
2495
2496 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2497 host->plat->sdiowakeup_irq :
2498 host->core_irqres->start;
2499
2500 if (!host->irq_wake_enabled) {
2501 enable_irq_wake(wakeup_irq);
2502 host->irq_wake_enabled = true;
2503 }
2504}
2505
2506static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2507{
2508 unsigned int wakeup_irq;
2509
2510 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2511 host->plat->sdiowakeup_irq :
2512 host->core_irqres->start;
2513
2514 if (host->irq_wake_enabled) {
2515 disable_irq_wake(wakeup_irq);
2516 host->irq_wake_enabled = false;
2517 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302518}
2519
San Mehat9d2bd732009-09-22 16:44:22 -07002520static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302521msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
2522{
2523 struct mmc_host *mmc = host->mmc;
2524
2525 /*
2526 * SDIO_AL clients has different mechanism of handling LPM through
2527 * sdio_al driver itself. The sdio wakeup interrupt is configured as
2528 * part of that. Here, we are interested only in clients like WLAN.
2529 */
2530 if (!(mmc->card && mmc_card_sdio(mmc->card))
2531 || host->plat->is_sdio_al_client)
2532 goto out;
2533
2534 if (!host->sdcc_suspended) {
2535 /*
2536 * When MSM is not in power collapse and we
2537 * are disabling clocks, enable bit 22 in MASK0
2538 * to handle asynchronous SDIO interrupts.
2539 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302540 if (enable_wakeup_irq) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302541 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302542 mb();
2543 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302544 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302545 msmsdcc_sync_reg_wr(host);
2546 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302547 goto out;
2548 } else if (!mmc_card_wake_sdio_irq(mmc)) {
2549 /*
2550 * Wakeup MSM only if SDIO function drivers set
2551 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
2552 */
2553 goto out;
2554 }
2555
2556 if (enable_wakeup_irq) {
2557 if (!host->plat->sdiowakeup_irq) {
2558 /*
2559 * When there is no gpio line that can be configured
2560 * as wakeup interrupt handle it by configuring
2561 * asynchronous sdio interrupts and DAT1 line.
2562 */
2563 writel_relaxed(MCI_SDIOINTMASK,
2564 host->base + MMCIMASK0);
2565 mb();
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302566 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302567 /* configure sdcc core interrupt as wakeup interrupt */
2568 msmsdcc_enable_irq_wake(host);
2569 } else {
2570 /* Let gpio line handle wakeup interrupt */
2571 writel_relaxed(0, host->base + MMCIMASK0);
2572 mb();
2573 if (host->sdio_wakeupirq_disabled) {
2574 host->sdio_wakeupirq_disabled = 0;
2575 /* configure gpio line as wakeup interrupt */
2576 msmsdcc_enable_irq_wake(host);
2577 enable_irq(host->plat->sdiowakeup_irq);
2578 }
2579 }
2580 } else {
2581 if (!host->plat->sdiowakeup_irq) {
2582 /*
2583 * We may not have cleared bit 22 in the interrupt
2584 * handler as the clocks might be off at that time.
2585 */
2586 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302587 msmsdcc_sync_reg_wr(host);
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302588 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302589 msmsdcc_disable_irq_wake(host);
2590 } else if (!host->sdio_wakeupirq_disabled) {
2591 disable_irq_nosync(host->plat->sdiowakeup_irq);
2592 msmsdcc_disable_irq_wake(host);
2593 host->sdio_wakeupirq_disabled = 1;
2594 }
2595 }
2596out:
2597 return;
2598}
2599
2600static void
San Mehat9d2bd732009-09-22 16:44:22 -07002601msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2602{
2603 struct msmsdcc_host *host = mmc_priv(mmc);
2604 u32 clk = 0, pwr = 0;
2605 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002606 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002607 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002608
Sahitya Tummala7a892482011-01-18 11:22:49 +05302609
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302610 /*
2611 * Disable SDCC core interrupt until set_ios is completed.
2612 * This avoids any race conditions with interrupt raised
2613 * when turning on/off the clocks. One possible
2614 * scenario is SDIO operational interrupt while the clock
2615 * is turned off.
Asutosh Dasf5298c32012-04-03 14:51:47 +05302616 * host->lock is being released intermittently below.
2617 * Thus, prevent concurrent access to host.
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302618 */
2619
Asutosh Dasf5298c32012-04-03 14:51:47 +05302620 mutex_lock(&host->clk_mutex);
2621 DBG(host, "ios->clock = %u\n", ios->clock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302622 spin_lock_irqsave(&host->lock, flags);
2623 if (!host->sdcc_irq_disabled) {
2624 spin_unlock_irqrestore(&host->lock, flags);
2625 disable_irq(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002626 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302627 host->sdcc_irq_disabled = 1;
2628 }
2629 spin_unlock_irqrestore(&host->lock, flags);
2630
2631 pwr = msmsdcc_setup_pwr(host, ios);
2632
2633 spin_lock_irqsave(&host->lock, flags);
2634 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002635 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302636 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002637 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302638 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002639 host->clks_on = 1;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302640 writel_relaxed(host->mci_irqenable,
2641 host->base + MMCIMASK0);
2642 mb();
2643 msmsdcc_cfg_sdio_wakeup(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002644 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002645
2646 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2647 /*
2648 * For DDR50 mode, controller needs clock rate to be
2649 * double than what is required on the SD card CLK pin.
2650 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302651 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002652 /*
2653 * Make sure that we don't double the clock if
2654 * doubled clock rate is already set
2655 */
2656 if (!host->ddr_doubled_clk_rate ||
2657 (host->ddr_doubled_clk_rate &&
2658 (host->ddr_doubled_clk_rate != ios->clock))) {
2659 host->ddr_doubled_clk_rate =
2660 msmsdcc_get_sup_clk_rate(
2661 host, (ios->clock * 2));
2662 clock = host->ddr_doubled_clk_rate;
2663 }
2664 } else {
2665 host->ddr_doubled_clk_rate = 0;
2666 }
2667
2668 if (clock != host->clk_rate) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302669 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002670 rc = clk_set_rate(host->clk, clock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302671 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002672 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302673 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002674 mmc_hostname(mmc), clock);
2675 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302676 host->reg_write_delay =
2677 (1 + ((3 * USEC_PER_SEC) /
2678 (host->clk_rate ? host->clk_rate :
2679 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002680 }
2681 /*
2682 * give atleast 2 MCLK cycles delay for clocks
2683 * and SDCC core to stabilize
2684 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302685 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002686 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002687 clk |= MCI_CLK_ENABLE;
2688 }
2689
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002690 if (ios->bus_width == MMC_BUS_WIDTH_8)
2691 clk |= MCI_CLK_WIDEBUS_8;
2692 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2693 clk |= MCI_CLK_WIDEBUS_4;
2694 else
2695 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002696
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002697 if (msmsdcc_is_pwrsave(host))
2698 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002699
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002700 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002701
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002702 host->tuning_needed = 0;
2703 /*
2704 * Select the controller timing mode according
2705 * to current bus speed mode
2706 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302707 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2708 (ios->timing == MMC_TIMING_MMC_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002709 clk |= (4 << 14);
2710 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302711 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002712 clk |= (3 << 14);
2713 } else {
2714 clk |= (2 << 14); /* feedback clock */
2715 }
2716
2717 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2718 clk |= (2 << 23);
2719
Subhash Jadavani00083572012-02-15 16:18:01 +05302720 /* Clear IO_PAD_PWR_SWITCH while powering off the card */
2721 if (!ios->vdd)
2722 host->io_pad_pwr_switch = 0;
2723
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002724 if (host->io_pad_pwr_switch)
2725 clk |= IO_PAD_PWR_SWITCH;
2726
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302727 /* Don't write into registers if clocks are disabled */
2728 if (host->clks_on) {
2729 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
2730 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302731 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002732 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302733 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
2734 host->pwr = pwr;
2735 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302736 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002737 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002738 }
2739
2740 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302741 msmsdcc_cfg_sdio_wakeup(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302742 spin_unlock_irqrestore(&host->lock, flags);
2743 /*
2744 * May get a wake-up interrupt the instant we disable the
2745 * clocks. This would disable the wake-up interrupt.
2746 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002747 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302748 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002749 host->clks_on = 0;
2750 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302751
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302752 if (host->tuning_in_progress)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302753 WARN(!host->clks_on,
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302754 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302755
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302756 /* Let interrupts be disabled if the host is powered off */
2757 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
2758 enable_irq(host->core_irqres->start);
2759 host->sdcc_irq_disabled = 0;
2760 }
2761
San Mehat4adbbcc2009-11-08 13:00:37 -08002762 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302763 mutex_unlock(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07002764}
2765
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002766int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2767{
2768 struct msmsdcc_host *host = mmc_priv(mmc);
2769 u32 clk;
2770
2771 clk = readl_relaxed(host->base + MMCICLOCK);
2772 pr_debug("Changing to pwr_save=%d", pwrsave);
2773 if (pwrsave && msmsdcc_is_pwrsave(host))
2774 clk |= MCI_CLK_PWRSAVE;
2775 else
2776 clk &= ~MCI_CLK_PWRSAVE;
2777 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302778 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002779
2780 return 0;
2781}
2782
2783static int msmsdcc_get_ro(struct mmc_host *mmc)
2784{
2785 int status = -ENOSYS;
2786 struct msmsdcc_host *host = mmc_priv(mmc);
2787
2788 if (host->plat->wpswitch) {
2789 status = host->plat->wpswitch(mmc_dev(mmc));
2790 } else if (host->plat->wpswitch_gpio) {
2791 status = gpio_request(host->plat->wpswitch_gpio,
2792 "SD_WP_Switch");
2793 if (status) {
2794 pr_err("%s: %s: Failed to request GPIO %d\n",
2795 mmc_hostname(mmc), __func__,
2796 host->plat->wpswitch_gpio);
2797 } else {
2798 status = gpio_direction_input(
2799 host->plat->wpswitch_gpio);
2800 if (!status) {
2801 /*
2802 * Wait for atleast 300ms as debounce
2803 * time for GPIO input to stabilize.
2804 */
2805 msleep(300);
2806 status = gpio_get_value_cansleep(
2807 host->plat->wpswitch_gpio);
2808 status ^= !host->plat->wpswitch_polarity;
2809 }
2810 gpio_free(host->plat->wpswitch_gpio);
2811 }
2812 }
2813
2814 if (status < 0)
2815 status = -ENOSYS;
2816 pr_debug("%s: Card read-only status %d\n", __func__, status);
2817
2818 return status;
2819}
2820
San Mehat9d2bd732009-09-22 16:44:22 -07002821static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2822{
2823 struct msmsdcc_host *host = mmc_priv(mmc);
2824 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002825
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302826 /*
2827 * We may come here with clocks turned off in that case don't
2828 * attempt to write into MASK0 register. While turning on the
2829 * clocks mci_irqenable will be written to MASK0 register.
2830 */
2831
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002832 if (enable) {
2833 spin_lock_irqsave(&host->lock, flags);
2834 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302835 if (host->clks_on) {
2836 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002837 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302838 mb();
2839 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002840 spin_unlock_irqrestore(&host->lock, flags);
2841 } else {
2842 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302843 if (host->clks_on) {
2844 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002845 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302846 mb();
2847 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002848 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002849}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002850
2851#ifdef CONFIG_PM_RUNTIME
subhashj245831e2012-04-30 18:46:17 +05302852static void msmsdcc_print_rpm_info(struct msmsdcc_host *host)
2853{
2854 struct device *dev = mmc_dev(host->mmc);
2855
2856 pr_info("%s: RPM: runtime_status=%d, usage_count=%d,"
2857 " is_suspended=%d, disable_depth=%d, runtime_error=%d,"
2858 " request_pending=%d, request=%d\n",
2859 mmc_hostname(host->mmc), dev->power.runtime_status,
2860 atomic_read(&dev->power.usage_count),
2861 dev->power.is_suspended, dev->power.disable_depth,
2862 dev->power.runtime_error, dev->power.request_pending,
2863 dev->power.request);
2864}
2865
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002866static int msmsdcc_enable(struct mmc_host *mmc)
2867{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002868 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002869 struct device *dev = mmc->parent;
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302870 struct msmsdcc_host *host = mmc_priv(mmc);
2871
2872 msmsdcc_pm_qos_update_latency(host, 1);
2873
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002874 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302875 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002876
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002877 if (host->sdcc_suspended && host->pending_resume &&
2878 !pm_runtime_suspended(dev)) {
2879 host->pending_resume = false;
2880 pm_runtime_get_noresume(dev);
2881 rc = msmsdcc_runtime_resume(dev);
2882 goto out;
2883 }
2884
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302885 if (dev->power.runtime_status == RPM_SUSPENDING) {
2886 if (mmc->suspend_task == current) {
2887 pm_runtime_get_noresume(dev);
2888 goto out;
2889 }
2890 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002891
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302892 rc = pm_runtime_get_sync(dev);
2893
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002894out:
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302895 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002896 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2897 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05302898 msmsdcc_print_rpm_info(host);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302899 return rc;
2900 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302901
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302902 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002903}
2904
2905static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2906{
2907 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302908 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002909
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302910 msmsdcc_pm_qos_update_latency(host, 0);
2911
2912 if (mmc->card && mmc_card_sdio(mmc->card))
2913 return 0;
2914
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302915 if (host->plat->disable_runtime_pm)
2916 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002917
2918 rc = pm_runtime_put_sync(mmc->parent);
2919
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002920 /*
2921 * Ignore -EAGAIN as that is not fatal, it means that
2922 * either runtime usage count is non-zero or the runtime
2923 * pm itself is disabled or not in proper state to process
2924 * idle notification.
2925 */
2926 if (rc < 0 && (rc != -EAGAIN)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002927 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2928 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05302929 msmsdcc_print_rpm_info(host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002930 return rc;
2931 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302932
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002933 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002934}
2935#else
subhashj245831e2012-04-30 18:46:17 +05302936static void msmsdcc_print_rpm_info(struct msmsdcc_host *host) {}
2937
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302938static int msmsdcc_enable(struct mmc_host *mmc)
2939{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002940 struct device *dev = mmc->parent;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302941 struct msmsdcc_host *host = mmc_priv(mmc);
2942 unsigned long flags;
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002943 int rc;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302944
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302945 msmsdcc_pm_qos_update_latency(host, 1);
2946
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002947 if (mmc->card && mmc_card_sdio(mmc->card))
2948 return 0;
2949
2950 if (host->sdcc_suspended && host->pending_resume) {
2951 host->pending_resume = false;
2952 rc = msmsdcc_runtime_resume(dev);
2953 goto out;
2954 }
2955
Asutosh Dasf5298c32012-04-03 14:51:47 +05302956 mutex_lock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302957 spin_lock_irqsave(&host->lock, flags);
2958 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302959 spin_unlock_irqrestore(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302960 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302961 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302962 host->clks_on = 1;
2963 }
2964 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302965 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302966
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002967out:
2968 if (rc < 0) {
2969 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2970 __func__, rc);
2971 return rc;
2972 }
2973
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302974 return 0;
2975}
2976
2977static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2978{
2979 struct msmsdcc_host *host = mmc_priv(mmc);
2980 unsigned long flags;
2981
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302982 msmsdcc_pm_qos_update_latency(host, 0);
2983
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302984 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302985 return 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302986
Asutosh Dasf5298c32012-04-03 14:51:47 +05302987 mutex_lock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302988 spin_lock_irqsave(&host->lock, flags);
2989 if (host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302990 spin_unlock_irqrestore(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302991 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302992 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302993 host->clks_on = 0;
2994 }
2995 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302996 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302997
2998 return 0;
2999}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003000#endif
3001
3002static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
3003 struct mmc_ios *ios)
3004{
3005 struct msmsdcc_host *host = mmc_priv(mmc);
3006 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303007 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003008
Subhash Jadavani00083572012-02-15 16:18:01 +05303009 spin_lock_irqsave(&host->lock, flags);
3010 host->io_pad_pwr_switch = 0;
3011 spin_unlock_irqrestore(&host->lock, flags);
3012
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303013 /*
3014 * For eMMC cards, VccQ voltage range must be changed
3015 * only if it operates in HS200 SDR 1.2V mode or in
3016 * DDR 1.2V mode.
3017 */
3018 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_120) {
3019 rc = msmsdcc_set_vccq_vol(host, 1200000);
3020 goto out;
3021 }
3022
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003023 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
3024 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303025 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003026 goto out;
3027 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
3028 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303029 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003030 goto out;
3031 }
San Mehat9d2bd732009-09-22 16:44:22 -07003032
3033 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003034 /*
3035 * If we are here means voltage switch from high voltage to
3036 * low voltage is required
3037 */
3038
3039 /*
3040 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
3041 * register until they become all zeros.
3042 */
3043 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303044 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003045 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
3046 mmc_hostname(mmc), __func__);
3047 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07003048 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003049
3050 /* Stop SD CLK output. */
3051 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3052 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303053 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003054 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003055
3056 /*
3057 * Switch VDDPX from high voltage to low voltage
3058 * to change the VDD of the SD IO pads.
3059 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303060 rc = msmsdcc_set_vddp_low_vol(host);
3061 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003062 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003063
3064 spin_lock_irqsave(&host->lock, flags);
3065 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3066 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303067 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003068 host->io_pad_pwr_switch = 1;
3069 spin_unlock_irqrestore(&host->lock, flags);
3070
3071 /* Wait 5 ms for the voltage regulater in the card to become stable. */
3072 usleep_range(5000, 5500);
3073
3074 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303075 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003076 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3077 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303078 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003079 spin_unlock_irqrestore(&host->lock, flags);
3080
3081 /*
3082 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
3083 * don't become all ones within 1 ms then a Voltage Switch
3084 * sequence has failed and a power cycle to the card is required.
3085 * Otherwise Voltage Switch sequence is completed successfully.
3086 */
3087 usleep_range(1000, 1500);
3088
3089 spin_lock_irqsave(&host->lock, flags);
3090 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
3091 != (0xF << 1)) {
3092 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
3093 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303094 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003095 goto out_unlock;
3096 }
3097
3098out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303099 /* Enable PWRSAVE */
3100 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3101 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303102 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003103 spin_unlock_irqrestore(&host->lock, flags);
3104out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303105 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003106}
3107
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303108static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003109{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003110 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003111
3112 /* Program the MCLK value to MCLK_FREQ bit field */
3113 if (host->clk_rate <= 112000000)
3114 mclk_freq = 0;
3115 else if (host->clk_rate <= 125000000)
3116 mclk_freq = 1;
3117 else if (host->clk_rate <= 137000000)
3118 mclk_freq = 2;
3119 else if (host->clk_rate <= 150000000)
3120 mclk_freq = 3;
3121 else if (host->clk_rate <= 162000000)
3122 mclk_freq = 4;
3123 else if (host->clk_rate <= 175000000)
3124 mclk_freq = 5;
3125 else if (host->clk_rate <= 187000000)
3126 mclk_freq = 6;
3127 else if (host->clk_rate <= 200000000)
3128 mclk_freq = 7;
3129
3130 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3131 & ~(7 << 24)) | (mclk_freq << 24)),
3132 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003133}
3134
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303135/* Initialize the DLL (Programmable Delay Line ) */
3136static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003137{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003138 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303139 unsigned long flags;
3140 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003141
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303142 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003143 /*
3144 * Make sure that clock is always enabled when DLL
3145 * tuning is in progress. Keeping PWRSAVE ON may
3146 * turn off the clock. So let's disable the PWRSAVE
3147 * here and re-enable it once tuning is completed.
3148 */
3149 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3150 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303151 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303152
3153 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3154 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3155 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3156
3157 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3158 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3159 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3160
3161 msmsdcc_cm_sdc4_dll_set_freq(host);
3162
3163 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3164 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3165 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3166
3167 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3168 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3169 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3170
3171 /* Set DLL_EN bit to 1. */
3172 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3173 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3174
3175 /* Set CK_OUT_EN bit to 1. */
3176 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3177 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3178
3179 wait_cnt = 50;
3180 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3181 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3182 /* max. wait for 50us sec for LOCK bit to be set */
3183 if (--wait_cnt == 0) {
3184 pr_err("%s: %s: DLL failed to LOCK\n",
3185 mmc_hostname(host->mmc), __func__);
3186 rc = -ETIMEDOUT;
3187 goto out;
3188 }
3189 /* wait for 1us before polling again */
3190 udelay(1);
3191 }
3192
3193out:
3194 /* re-enable PWRSAVE */
3195 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3196 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303197 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303198 spin_unlock_irqrestore(&host->lock, flags);
3199
3200 return rc;
3201}
3202
3203static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3204 u8 poll)
3205{
3206 int rc = 0;
3207 u32 wait_cnt = 50;
3208 u8 ck_out_en = 0;
3209
3210 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3211 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3212 MCI_CK_OUT_EN);
3213
3214 while (ck_out_en != poll) {
3215 if (--wait_cnt == 0) {
3216 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3217 mmc_hostname(host->mmc), __func__, poll);
3218 rc = -ETIMEDOUT;
3219 goto out;
3220 }
3221 udelay(1);
3222
3223 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3224 MCI_CK_OUT_EN);
3225 }
3226out:
3227 return rc;
3228}
3229
3230/*
3231 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3232 * calibration sequence. This function should be called before
3233 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3234 * commands (CMD17/CMD18).
3235 *
3236 * This function gets called when host spinlock acquired.
3237 */
3238static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3239{
3240 int rc = 0;
3241 u32 config;
3242
3243 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3244 config |= MCI_CDR_EN;
3245 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3246 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3247
3248 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3249 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3250 if (rc)
3251 goto err_out;
3252
3253 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3254 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3255 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3256
3257 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3258 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3259 if (rc)
3260 goto err_out;
3261
3262 goto out;
3263
3264err_out:
3265 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3266out:
3267 return rc;
3268}
3269
3270static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3271 u8 phase)
3272{
3273 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303274 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3275 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3276 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303277 unsigned long flags;
3278 u32 config;
3279
3280 spin_lock_irqsave(&host->lock, flags);
3281
3282 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3283 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3284 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3285 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3286
3287 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3288 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3289 if (rc)
3290 goto err_out;
3291
3292 /*
3293 * Write the selected DLL clock output phase (0 ... 15)
3294 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
3295 */
3296 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3297 & ~(0xF << 20))
3298 | (grey_coded_phase_table[phase] << 20)),
3299 host->base + MCI_DLL_CONFIG);
3300
3301 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3302 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3303 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3304
3305 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3306 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3307 if (rc)
3308 goto err_out;
3309
3310 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3311 config |= MCI_CDR_EN;
3312 config &= ~MCI_CDR_EXT_EN;
3313 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3314 goto out;
3315
3316err_out:
3317 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3318 mmc_hostname(host->mmc), __func__, phase);
3319out:
3320 spin_unlock_irqrestore(&host->lock, flags);
3321 return rc;
3322}
3323
3324/*
3325 * Find out the greatest range of consecuitive selected
3326 * DLL clock output phases that can be used as sampling
3327 * setting for SD3.0 UHS-I card read operation (in SDR104
3328 * timing mode) or for eMMC4.5 card read operation (in HS200
3329 * timing mode).
3330 * Select the 3/4 of the range and configure the DLL with the
3331 * selected DLL clock output phase.
3332*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303333static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303334 u8 *phase_table, u8 total_phases)
3335{
Subhash Jadavani6159c622012-03-15 19:05:55 +05303336 #define MAX_PHASES 16
Subhash Jadavani34187042012-03-02 10:59:49 +05303337 int ret;
Subhash Jadavani6159c622012-03-15 19:05:55 +05303338 u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
3339 u8 phases_per_row[MAX_PHASES] = {0};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303340 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303341 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3342 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303343
Subhash Jadavani6159c622012-03-15 19:05:55 +05303344 if (!total_phases || (total_phases > MAX_PHASES)) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303345 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3346 mmc_hostname(host->mmc), __func__, total_phases);
3347 return -EINVAL;
3348 }
3349
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303350 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303351 ranges[row_index][col_index] = phase_table[cnt];
3352 phases_per_row[row_index] += 1;
3353 col_index++;
3354
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303355 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303356 continue;
3357 /* check if next phase in phase_table is consecutive or not */
3358 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3359 row_index++;
3360 col_index = 0;
3361 }
3362 }
3363
Subhash Jadavani6159c622012-03-15 19:05:55 +05303364 if (row_index >= MAX_PHASES)
3365 return -EINVAL;
3366
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303367 /* Check if phase-0 is present in first valid window? */
3368 if (!ranges[0][0]) {
3369 phase_0_found = true;
3370 phase_0_raw_index = 0;
3371 /* Check if cycle exist between 2 valid windows */
3372 for (cnt = 1; cnt <= row_index; cnt++) {
3373 if (phases_per_row[cnt]) {
Subhash Jadavani6159c622012-03-15 19:05:55 +05303374 for (i = 0; i < phases_per_row[cnt]; i++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303375 if (ranges[cnt][i] == 15) {
3376 phase_15_found = true;
3377 phase_15_raw_index = cnt;
3378 break;
3379 }
3380 }
3381 }
3382 }
3383 }
3384
3385 /* If 2 valid windows form cycle then merge them as single window */
3386 if (phase_0_found && phase_15_found) {
3387 /* number of phases in raw where phase 0 is present */
3388 u8 phases_0 = phases_per_row[phase_0_raw_index];
3389 /* number of phases in raw where phase 15 is present */
3390 u8 phases_15 = phases_per_row[phase_15_raw_index];
3391
Subhash Jadavani6159c622012-03-15 19:05:55 +05303392 if (phases_0 + phases_15 >= MAX_PHASES)
3393 /*
3394 * If there are more than 1 phase windows then total
3395 * number of phases in both the windows should not be
3396 * more than or equal to MAX_PHASES.
3397 */
3398 return -EINVAL;
3399
3400 /* Merge 2 cyclic windows */
3401 i = phases_15;
3402 for (cnt = 0; cnt < phases_0; cnt++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303403 ranges[phase_15_raw_index][i] =
3404 ranges[phase_0_raw_index][cnt];
Subhash Jadavani6159c622012-03-15 19:05:55 +05303405 if (++i >= MAX_PHASES)
3406 break;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303407 }
Subhash Jadavani6159c622012-03-15 19:05:55 +05303408
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303409 phases_per_row[phase_0_raw_index] = 0;
3410 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
3411 }
3412
3413 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303414 if (phases_per_row[cnt] > curr_max) {
3415 curr_max = phases_per_row[cnt];
3416 selected_row_index = cnt;
3417 }
3418 }
3419
Subhash Jadavani6159c622012-03-15 19:05:55 +05303420 i = ((curr_max * 3) / 4);
3421 if (i)
3422 i--;
3423
Subhash Jadavani34187042012-03-02 10:59:49 +05303424 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303425
Subhash Jadavani6159c622012-03-15 19:05:55 +05303426 if (ret >= MAX_PHASES) {
3427 ret = -EINVAL;
3428 pr_err("%s: %s: invalid phase selected=%d\n",
3429 mmc_hostname(host->mmc), __func__, ret);
3430 }
3431
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303432 return ret;
3433}
3434
Girish K Sa3f41692012-02-29 12:00:09 +05303435static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303436{
3437 int rc = 0;
3438 struct msmsdcc_host *host = mmc_priv(mmc);
3439 unsigned long flags;
3440 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303441 const u32 *tuning_block_pattern = tuning_block_64;
3442 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303443
3444 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
3445
3446 /* Tuning is only required for SDR104 modes */
3447 if (!host->tuning_needed) {
3448 rc = 0;
3449 goto exit;
3450 }
3451
3452 spin_lock_irqsave(&host->lock, flags);
3453 WARN(!host->pwr, "SDCC power is turned off\n");
3454 WARN(!host->clks_on, "SDCC clocks are turned off\n");
3455 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
3456
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303457 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303458 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
3459 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
3460 tuning_block_pattern = tuning_block_128;
3461 size = sizeof(tuning_block_128);
3462 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303463 spin_unlock_irqrestore(&host->lock, flags);
3464
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003465 /* first of all reset the tuning block */
3466 rc = msmsdcc_init_cm_sdc4_dll(host);
3467 if (rc)
3468 goto out;
3469
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303470 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003471 if (!data_buf) {
3472 rc = -ENOMEM;
3473 goto out;
3474 }
3475
3476 phase = 0;
3477 do {
3478 struct mmc_command cmd = {0};
3479 struct mmc_data data = {0};
3480 struct mmc_request mrq = {
3481 .cmd = &cmd,
3482 .data = &data
3483 };
3484 struct scatterlist sg;
3485
3486 /* set the phase in delay line hw block */
3487 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3488 if (rc)
3489 goto kfree;
3490
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303491 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003492 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
3493
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303494 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003495 data.blocks = 1;
3496 data.flags = MMC_DATA_READ;
3497 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
3498
3499 data.sg = &sg;
3500 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303501 sg_init_one(&sg, data_buf, size);
3502 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003503 mmc_wait_for_req(mmc, &mrq);
3504
3505 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303506 !memcmp(data_buf, tuning_block_pattern, size)) {
3507 /* tuning is successful at this tuning point */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003508 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303509 pr_debug("%s: %s: found good phase = %d\n",
3510 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003511 }
3512 } while (++phase < 16);
3513
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003514 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303515 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303516 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05303517 if (rc < 0)
3518 goto kfree;
3519 else
3520 phase = (u8)rc;
3521
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003522 /*
3523 * Finally set the selected phase in delay
3524 * line hw block.
3525 */
3526 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3527 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303528 goto kfree;
3529 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
3530 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003531 } else {
3532 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303533 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003534 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303535 msmsdcc_dump_sdcc_state(host);
3536 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003537 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003538
3539kfree:
3540 kfree(data_buf);
3541out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303542 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303543 host->tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303544 spin_unlock_irqrestore(&host->lock, flags);
3545exit:
3546 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003547 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07003548}
3549
3550static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003551 .enable = msmsdcc_enable,
3552 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07003553 .request = msmsdcc_request,
3554 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003555 .get_ro = msmsdcc_get_ro,
San Mehat9d2bd732009-09-22 16:44:22 -07003556 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003557 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
3558 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07003559};
3560
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003561static unsigned int
3562msmsdcc_slot_status(struct msmsdcc_host *host)
3563{
3564 int status;
3565 unsigned int gpio_no = host->plat->status_gpio;
3566
3567 status = gpio_request(gpio_no, "SD_HW_Detect");
3568 if (status) {
3569 pr_err("%s: %s: Failed to request GPIO %d\n",
3570 mmc_hostname(host->mmc), __func__, gpio_no);
3571 } else {
3572 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003573 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08003574 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003575 if (host->plat->is_status_gpio_active_low)
3576 status = !status;
3577 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003578 gpio_free(gpio_no);
3579 }
3580 return status;
3581}
3582
San Mehat9d2bd732009-09-22 16:44:22 -07003583static void
3584msmsdcc_check_status(unsigned long data)
3585{
3586 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3587 unsigned int status;
3588
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003589 if (host->plat->status || host->plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08003590 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003591 status = host->plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08003592 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003593 status = msmsdcc_slot_status(host);
3594
Krishna Konda941604a2012-01-10 17:46:34 -08003595 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08003596
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003597 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08003598 if (host->plat->status)
3599 pr_info("%s: Slot status change detected "
3600 "(%d -> %d)\n",
3601 mmc_hostname(host->mmc),
3602 host->oldstat, status);
3603 else if (host->plat->is_status_gpio_active_low)
3604 pr_info("%s: Slot status change detected "
3605 "(%d -> %d) and the card detect GPIO"
3606 " is ACTIVE_LOW\n",
3607 mmc_hostname(host->mmc),
3608 host->oldstat, status);
3609 else
3610 pr_info("%s: Slot status change detected "
3611 "(%d -> %d) and the card detect GPIO"
3612 " is ACTIVE_HIGH\n",
3613 mmc_hostname(host->mmc),
3614 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07003615 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003616 }
3617 host->oldstat = status;
3618 } else {
3619 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07003620 }
San Mehat9d2bd732009-09-22 16:44:22 -07003621}
3622
3623static irqreturn_t
3624msmsdcc_platform_status_irq(int irq, void *dev_id)
3625{
3626 struct msmsdcc_host *host = dev_id;
3627
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003628 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07003629 msmsdcc_check_status((unsigned long) host);
3630 return IRQ_HANDLED;
3631}
3632
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003633static irqreturn_t
3634msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
3635{
3636 struct msmsdcc_host *host = dev_id;
3637
3638 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
3639 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303640 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003641 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303642 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003643 wake_lock(&host->sdio_wlock);
3644 msmsdcc_disable_irq_wake(host);
3645 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303646 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003647 }
3648 if (host->plat->is_sdio_al_client) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003649 wake_lock(&host->sdio_wlock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303650 mmc_signal_sdio_irq(host->mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003651 }
3652 spin_unlock(&host->lock);
3653
3654 return IRQ_HANDLED;
3655}
3656
San Mehat9d2bd732009-09-22 16:44:22 -07003657static void
3658msmsdcc_status_notify_cb(int card_present, void *dev_id)
3659{
3660 struct msmsdcc_host *host = dev_id;
3661
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003662 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07003663 card_present);
3664 msmsdcc_check_status((unsigned long) host);
3665}
3666
San Mehat9d2bd732009-09-22 16:44:22 -07003667static int
3668msmsdcc_init_dma(struct msmsdcc_host *host)
3669{
3670 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
3671 host->dma.host = host;
3672 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003673 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003674
3675 if (!host->dmares)
3676 return -ENODEV;
3677
3678 host->dma.nc = dma_alloc_coherent(NULL,
3679 sizeof(struct msmsdcc_nc_dmadata),
3680 &host->dma.nc_busaddr,
3681 GFP_KERNEL);
3682 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003683 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07003684 return -ENOMEM;
3685 }
3686 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
3687 host->dma.cmd_busaddr = host->dma.nc_busaddr;
3688 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
3689 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
3690 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07003691 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07003692
3693 return 0;
3694}
3695
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003696#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
3697/**
3698 * Allocate and Connect a SDCC peripheral's SPS endpoint
3699 *
3700 * This function allocates endpoint context and
3701 * connect it with memory endpoint by calling
3702 * appropriate SPS driver APIs.
3703 *
3704 * Also registers a SPS callback function with
3705 * SPS driver
3706 *
3707 * This function should only be called once typically
3708 * during driver probe.
3709 *
3710 * @host - Pointer to sdcc host structure
3711 * @ep - Pointer to sps endpoint data structure
3712 * @is_produce - 1 means Producer endpoint
3713 * 0 means Consumer endpoint
3714 *
3715 * @return - 0 if successful else negative value.
3716 *
3717 */
3718static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
3719 struct msmsdcc_sps_ep_conn_data *ep,
3720 bool is_producer)
3721{
3722 int rc = 0;
3723 struct sps_pipe *sps_pipe_handle;
3724 struct sps_connect *sps_config = &ep->config;
3725 struct sps_register_event *sps_event = &ep->event;
3726
3727 /* Allocate endpoint context */
3728 sps_pipe_handle = sps_alloc_endpoint();
3729 if (!sps_pipe_handle) {
3730 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
3731 mmc_hostname(host->mmc), is_producer);
3732 rc = -ENOMEM;
3733 goto out;
3734 }
3735
3736 /* Get default connection configuration for an endpoint */
3737 rc = sps_get_config(sps_pipe_handle, sps_config);
3738 if (rc) {
3739 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
3740 " rc=%d", mmc_hostname(host->mmc),
3741 (u32)sps_pipe_handle, rc);
3742 goto get_config_err;
3743 }
3744
3745 /* Modify the default connection configuration */
3746 if (is_producer) {
3747 /*
3748 * For SDCC producer transfer, source should be
3749 * SDCC peripheral where as destination should
3750 * be system memory.
3751 */
3752 sps_config->source = host->sps.bam_handle;
3753 sps_config->destination = SPS_DEV_HANDLE_MEM;
3754 /* Producer pipe will handle this connection */
3755 sps_config->mode = SPS_MODE_SRC;
3756 sps_config->options =
3757 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3758 } else {
3759 /*
3760 * For SDCC consumer transfer, source should be
3761 * system memory where as destination should
3762 * SDCC peripheral
3763 */
3764 sps_config->source = SPS_DEV_HANDLE_MEM;
3765 sps_config->destination = host->sps.bam_handle;
3766 sps_config->mode = SPS_MODE_DEST;
3767 sps_config->options =
3768 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3769 }
3770
3771 /* Producer pipe index */
3772 sps_config->src_pipe_index = host->sps.src_pipe_index;
3773 /* Consumer pipe index */
3774 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
3775 /*
3776 * This event thresold value is only significant for BAM-to-BAM
3777 * transfer. It's ignored for BAM-to-System mode transfer.
3778 */
3779 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05303780
3781 /* Allocate maximum descriptor fifo size */
3782 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
3783 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003784 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
3785 sps_config->desc.size,
3786 &sps_config->desc.phys_base,
3787 GFP_KERNEL);
3788
Pratibhasagar V00b94332011-10-18 14:57:27 +05303789 if (!sps_config->desc.base) {
3790 rc = -ENOMEM;
3791 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3792 , mmc_hostname(host->mmc));
3793 goto get_config_err;
3794 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003795 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3796
3797 /* Establish connection between peripheral and memory endpoint */
3798 rc = sps_connect(sps_pipe_handle, sps_config);
3799 if (rc) {
3800 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3801 " rc=%d", mmc_hostname(host->mmc),
3802 (u32)sps_pipe_handle, rc);
3803 goto sps_connect_err;
3804 }
3805
3806 sps_event->mode = SPS_TRIGGER_CALLBACK;
3807 sps_event->options = SPS_O_EOT;
3808 sps_event->callback = msmsdcc_sps_complete_cb;
3809 sps_event->xfer_done = NULL;
3810 sps_event->user = (void *)host;
3811
3812 /* Register callback event for EOT (End of transfer) event. */
3813 rc = sps_register_event(sps_pipe_handle, sps_event);
3814 if (rc) {
3815 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3816 " rc=%d", mmc_hostname(host->mmc),
3817 (u32)sps_pipe_handle, rc);
3818 goto reg_event_err;
3819 }
3820 /* Now save the sps pipe handle */
3821 ep->pipe_handle = sps_pipe_handle;
3822 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3823 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3824 __func__, is_producer ? "READ" : "WRITE",
3825 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3826 goto out;
3827
3828reg_event_err:
3829 sps_disconnect(sps_pipe_handle);
3830sps_connect_err:
3831 dma_free_coherent(mmc_dev(host->mmc),
3832 sps_config->desc.size,
3833 sps_config->desc.base,
3834 sps_config->desc.phys_base);
3835get_config_err:
3836 sps_free_endpoint(sps_pipe_handle);
3837out:
3838 return rc;
3839}
3840
3841/**
3842 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3843 *
3844 * This function disconnect endpoint and deallocates
3845 * endpoint context.
3846 *
3847 * This function should only be called once typically
3848 * during driver remove.
3849 *
3850 * @host - Pointer to sdcc host structure
3851 * @ep - Pointer to sps endpoint data structure
3852 *
3853 */
3854static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3855 struct msmsdcc_sps_ep_conn_data *ep)
3856{
3857 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3858 struct sps_connect *sps_config = &ep->config;
3859 struct sps_register_event *sps_event = &ep->event;
3860
3861 sps_event->xfer_done = NULL;
3862 sps_event->callback = NULL;
3863 sps_register_event(sps_pipe_handle, sps_event);
3864 sps_disconnect(sps_pipe_handle);
3865 dma_free_coherent(mmc_dev(host->mmc),
3866 sps_config->desc.size,
3867 sps_config->desc.base,
3868 sps_config->desc.phys_base);
3869 sps_free_endpoint(sps_pipe_handle);
3870}
3871
3872/**
3873 * Reset SDCC peripheral's SPS endpoint
3874 *
3875 * This function disconnects an endpoint.
3876 *
3877 * This function should be called for reseting
3878 * SPS endpoint when data transfer error is
3879 * encountered during data transfer. This
3880 * can be considered as soft reset to endpoint.
3881 *
3882 * This function should only be called if
3883 * msmsdcc_sps_init() is already called.
3884 *
3885 * @host - Pointer to sdcc host structure
3886 * @ep - Pointer to sps endpoint data structure
3887 *
3888 * @return - 0 if successful else negative value.
3889 */
3890static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3891 struct msmsdcc_sps_ep_conn_data *ep)
3892{
3893 int rc = 0;
3894 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3895
3896 rc = sps_disconnect(sps_pipe_handle);
3897 if (rc) {
3898 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3899 " rc=%d", mmc_hostname(host->mmc), __func__,
3900 (u32)sps_pipe_handle, rc);
3901 goto out;
3902 }
3903 out:
3904 return rc;
3905}
3906
3907/**
3908 * Restore SDCC peripheral's SPS endpoint
3909 *
3910 * This function connects an endpoint.
3911 *
3912 * This function should be called for restoring
3913 * SPS endpoint after data transfer error is
3914 * encountered during data transfer. This
3915 * can be considered as soft reset to endpoint.
3916 *
3917 * This function should only be called if
3918 * msmsdcc_sps_reset_ep() is called before.
3919 *
3920 * @host - Pointer to sdcc host structure
3921 * @ep - Pointer to sps endpoint data structure
3922 *
3923 * @return - 0 if successful else negative value.
3924 */
3925static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3926 struct msmsdcc_sps_ep_conn_data *ep)
3927{
3928 int rc = 0;
3929 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3930 struct sps_connect *sps_config = &ep->config;
3931 struct sps_register_event *sps_event = &ep->event;
3932
3933 /* Establish connection between peripheral and memory endpoint */
3934 rc = sps_connect(sps_pipe_handle, sps_config);
3935 if (rc) {
3936 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3937 " rc=%d", mmc_hostname(host->mmc), __func__,
3938 (u32)sps_pipe_handle, rc);
3939 goto out;
3940 }
3941
3942 /* Register callback event for EOT (End of transfer) event. */
3943 rc = sps_register_event(sps_pipe_handle, sps_event);
3944 if (rc) {
3945 pr_err("%s: %s: sps_register_event() failed!!!"
3946 " pipe_handle=0x%x, rc=%d",
3947 mmc_hostname(host->mmc), __func__,
3948 (u32)sps_pipe_handle, rc);
3949 goto reg_event_err;
3950 }
3951 goto out;
3952
3953reg_event_err:
3954 sps_disconnect(sps_pipe_handle);
3955out:
3956 return rc;
3957}
3958
3959/**
3960 * Initialize SPS HW connected with SDCC core
3961 *
3962 * This function register BAM HW resources with
3963 * SPS driver and then initialize 2 SPS endpoints
3964 *
3965 * This function should only be called once typically
3966 * during driver probe.
3967 *
3968 * @host - Pointer to sdcc host structure
3969 *
3970 * @return - 0 if successful else negative value.
3971 *
3972 */
3973static int msmsdcc_sps_init(struct msmsdcc_host *host)
3974{
3975 int rc = 0;
3976 struct sps_bam_props bam = {0};
3977
3978 host->bam_base = ioremap(host->bam_memres->start,
3979 resource_size(host->bam_memres));
3980 if (!host->bam_base) {
3981 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3982 " size=0x%x", mmc_hostname(host->mmc),
3983 host->bam_memres->start,
3984 (host->bam_memres->end -
3985 host->bam_memres->start));
3986 rc = -ENOMEM;
3987 goto out;
3988 }
3989
3990 bam.phys_addr = host->bam_memres->start;
3991 bam.virt_addr = host->bam_base;
3992 /*
3993 * This event thresold value is only significant for BAM-to-BAM
3994 * transfer. It's ignored for BAM-to-System mode transfer.
3995 */
3996 bam.event_threshold = 0x10; /* Pipe event threshold */
3997 /*
3998 * This threshold controls when the BAM publish
3999 * the descriptor size on the sideband interface.
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304000 * SPS HW will be used for data transfer size even
4001 * less than SDCC FIFO size. So let's set BAM summing
4002 * thresold to SPS_MIN_XFER_SIZE bytes.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004003 */
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304004 bam.summing_threshold = SPS_MIN_XFER_SIZE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004005 /* SPS driver wll handle the SDCC BAM IRQ */
4006 bam.irq = (u32)host->bam_irqres->start;
4007 bam.manage = SPS_BAM_MGR_LOCAL;
4008
4009 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
4010 (u32)bam.phys_addr);
4011 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
4012 (u32)bam.virt_addr);
4013
4014 /* Register SDCC Peripheral BAM device to SPS driver */
4015 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
4016 if (rc) {
4017 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
4018 mmc_hostname(host->mmc), rc);
4019 goto reg_bam_err;
4020 }
4021 pr_info("%s: BAM device registered. bam_handle=0x%x",
4022 mmc_hostname(host->mmc), host->sps.bam_handle);
4023
4024 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
4025 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
4026
4027 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
4028 SPS_PROD_PERIPHERAL);
4029 if (rc)
4030 goto sps_reset_err;
4031 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
4032 SPS_CONS_PERIPHERAL);
4033 if (rc)
4034 goto cons_conn_err;
4035
4036 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
4037 mmc_hostname(host->mmc),
4038 (unsigned long long)host->bam_memres->start,
4039 (unsigned int)host->bam_irqres->start);
4040 goto out;
4041
4042cons_conn_err:
4043 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4044sps_reset_err:
4045 sps_deregister_bam_device(host->sps.bam_handle);
4046reg_bam_err:
4047 iounmap(host->bam_base);
4048out:
4049 return rc;
4050}
4051
4052/**
4053 * De-initialize SPS HW connected with SDCC core
4054 *
4055 * This function deinitialize SPS endpoints and then
4056 * deregisters BAM resources from SPS driver.
4057 *
4058 * This function should only be called once typically
4059 * during driver remove.
4060 *
4061 * @host - Pointer to sdcc host structure
4062 *
4063 */
4064static void msmsdcc_sps_exit(struct msmsdcc_host *host)
4065{
4066 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
4067 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4068 sps_deregister_bam_device(host->sps.bam_handle);
4069 iounmap(host->bam_base);
4070}
4071#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
4072
4073static ssize_t
4074show_polling(struct device *dev, struct device_attribute *attr, char *buf)
4075{
4076 struct mmc_host *mmc = dev_get_drvdata(dev);
4077 struct msmsdcc_host *host = mmc_priv(mmc);
4078 int poll;
4079 unsigned long flags;
4080
4081 spin_lock_irqsave(&host->lock, flags);
4082 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
4083 spin_unlock_irqrestore(&host->lock, flags);
4084
4085 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
4086}
4087
4088static ssize_t
4089set_polling(struct device *dev, struct device_attribute *attr,
4090 const char *buf, size_t count)
4091{
4092 struct mmc_host *mmc = dev_get_drvdata(dev);
4093 struct msmsdcc_host *host = mmc_priv(mmc);
4094 int value;
4095 unsigned long flags;
4096
4097 sscanf(buf, "%d", &value);
4098
4099 spin_lock_irqsave(&host->lock, flags);
4100 if (value) {
4101 mmc->caps |= MMC_CAP_NEEDS_POLL;
4102 mmc_detect_change(host->mmc, 0);
4103 } else {
4104 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4105 }
4106#ifdef CONFIG_HAS_EARLYSUSPEND
4107 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
4108#endif
4109 spin_unlock_irqrestore(&host->lock, flags);
4110 return count;
4111}
4112
4113static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
4114 show_polling, set_polling);
4115static struct attribute *dev_attrs[] = {
4116 &dev_attr_polling.attr,
4117 NULL,
4118};
4119static struct attribute_group dev_attr_grp = {
4120 .attrs = dev_attrs,
4121};
4122
4123#ifdef CONFIG_HAS_EARLYSUSPEND
4124static void msmsdcc_early_suspend(struct early_suspend *h)
4125{
4126 struct msmsdcc_host *host =
4127 container_of(h, struct msmsdcc_host, early_suspend);
4128 unsigned long flags;
4129
4130 spin_lock_irqsave(&host->lock, flags);
4131 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
4132 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4133 spin_unlock_irqrestore(&host->lock, flags);
4134};
4135static void msmsdcc_late_resume(struct early_suspend *h)
4136{
4137 struct msmsdcc_host *host =
4138 container_of(h, struct msmsdcc_host, early_suspend);
4139 unsigned long flags;
4140
4141 if (host->polling_enabled) {
4142 spin_lock_irqsave(&host->lock, flags);
4143 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
4144 mmc_detect_change(host->mmc, 0);
4145 spin_unlock_irqrestore(&host->lock, flags);
4146 }
4147};
4148#endif
4149
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304150static void msmsdcc_print_regs(const char *name, void __iomem *base,
4151 u32 phys_base, unsigned int no_of_regs)
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304152{
4153 unsigned int i;
4154
4155 if (!base)
4156 return;
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304157
4158 pr_info("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
4159 " =====\n", name, phys_base, (u32)base);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304160 for (i = 0; i < no_of_regs; i = i + 4) {
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304161 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
4162 (u32)readl_relaxed(base + i*4),
4163 (u32)readl_relaxed(base + ((i+1)*4)),
4164 (u32)readl_relaxed(base + ((i+2)*4)),
4165 (u32)readl_relaxed(base + ((i+3)*4)));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304166 }
4167}
4168
4169static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
4170{
4171 /* Dump current state of SDCC clocks, power and irq */
4172 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304173 (host->pwr ? "ON" : "OFF"));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304174 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304175 mmc_hostname(host->mmc), (host->clks_on ? "ON" : "OFF"),
4176 (u32)clk_get_rate(host->clk));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304177 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
4178 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
4179
4180 /* Now dump SDCC registers. Don't print FIFO registers */
4181 if (host->clks_on)
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304182 msmsdcc_print_regs("SDCC-CORE", host->base,
4183 host->core_memres->start, 28);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304184
4185 if (host->curr.data) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304186 if (!msmsdcc_is_dma_possible(host, host->curr.data))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304187 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
4188 else if (host->is_dma_mode)
4189 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
4190 mmc_hostname(host->mmc), host->dma.busy,
4191 host->dma.channel, host->dma.crci);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304192 else if (host->is_sps_mode) {
subhashj245831e2012-04-30 18:46:17 +05304193 if (host->sps.busy && host->clks_on)
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304194 msmsdcc_print_regs("SDCC-DML", host->dml_base,
4195 host->dml_memres->start,
4196 16);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304197 pr_info("%s: SPS mode: busy=%d\n",
4198 mmc_hostname(host->mmc), host->sps.busy);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304199 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304200
4201 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
4202 mmc_hostname(host->mmc), host->curr.xfer_size,
4203 host->curr.data_xfered, host->curr.xfer_remain);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304204 }
4205
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304206 pr_info("%s: got_dataend=%d, prog_enable=%d,"
4207 " wait_for_auto_prog_done=%d, got_auto_prog_done=%d\n",
4208 mmc_hostname(host->mmc), host->curr.got_dataend,
4209 host->prog_enable, host->curr.wait_for_auto_prog_done,
4210 host->curr.got_auto_prog_done);
subhashj245831e2012-04-30 18:46:17 +05304211 msmsdcc_print_rpm_info(host);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304212}
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304213
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004214static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
4215{
4216 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4217 struct mmc_request *mrq;
4218 unsigned long flags;
4219
4220 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004221 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004222 pr_info("%s: %s: dummy CMD52 timeout\n",
4223 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004224 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004225 }
4226
4227 mrq = host->curr.mrq;
4228
4229 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304230 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
4231 mrq->cmd->opcode);
4232 msmsdcc_dump_sdcc_state(host);
4233
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004234 if (!mrq->cmd->error)
4235 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304236 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004237 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004238 if (mrq->data && !mrq->data->error)
4239 mrq->data->error = -ETIMEDOUT;
4240 host->curr.data_xfered = 0;
4241 if (host->dma.sg && host->is_dma_mode) {
4242 msm_dmov_stop_cmd(host->dma.channel,
4243 &host->dma.hdr, 0);
4244 } else if (host->sps.sg && host->is_sps_mode) {
4245 /* Stop current SPS transfer */
4246 msmsdcc_sps_exit_curr_xfer(host);
4247 } else {
4248 msmsdcc_reset_and_restore(host);
4249 msmsdcc_stop_data(host);
4250 if (mrq->data && mrq->data->stop)
4251 msmsdcc_start_command(host,
4252 mrq->data->stop, 0);
4253 else
4254 msmsdcc_request_end(host, mrq);
4255 }
4256 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304257 host->prog_enable = 0;
Subhash Jadavanied6b0e42012-03-07 16:36:27 +05304258 host->curr.wait_for_auto_prog_done = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004259 msmsdcc_reset_and_restore(host);
4260 msmsdcc_request_end(host, mrq);
4261 }
4262 }
4263 spin_unlock_irqrestore(&host->lock, flags);
4264}
4265
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304266static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
4267{
4268 int i, ret;
4269 struct mmc_platform_data *pdata;
4270 struct device_node *np = dev->of_node;
4271 u32 bus_width = 0;
4272 u32 *clk_table;
4273 int clk_table_len;
4274 u32 *sup_voltages;
4275 int sup_volt_len;
4276
4277 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
4278 if (!pdata) {
4279 dev_err(dev, "could not allocate memory for platform data\n");
4280 goto err;
4281 }
4282
4283 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
4284 if (bus_width == 8) {
4285 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
4286 } else if (bus_width == 4) {
4287 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
4288 } else {
4289 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
4290 pdata->mmc_bus_width = 0;
4291 }
4292
4293 if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
4294 size_t sz;
4295 sz = sup_volt_len / sizeof(*sup_voltages);
4296 if (sz > 0) {
4297 sup_voltages = devm_kzalloc(dev,
4298 sz * sizeof(*sup_voltages), GFP_KERNEL);
4299 if (!sup_voltages) {
4300 dev_err(dev, "No memory for supported voltage\n");
4301 goto err;
4302 }
4303
4304 ret = of_property_read_u32_array(np,
4305 "qcom,sdcc-sup-voltages", sup_voltages, sz);
4306 if (ret < 0) {
4307 dev_err(dev, "error while reading voltage"
4308 "ranges %d\n", ret);
4309 goto err;
4310 }
4311 } else {
4312 dev_err(dev, "No supported voltages\n");
4313 goto err;
4314 }
4315 for (i = 0; i < sz; i += 2) {
4316 u32 mask;
4317
4318 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
4319 sup_voltages[i + 1]);
4320 if (!mask)
4321 dev_err(dev, "Invalide voltage range %d\n", i);
4322 pdata->ocr_mask |= mask;
4323 }
4324 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
4325 } else {
4326 dev_err(dev, "Supported voltage range not specified\n");
4327 }
4328
4329 if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
4330 size_t sz;
4331 sz = clk_table_len / sizeof(*clk_table);
4332
4333 if (sz > 0) {
4334 clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
4335 GFP_KERNEL);
4336 if (!clk_table) {
4337 dev_err(dev, "No memory for clock table\n");
4338 goto err;
4339 }
4340
4341 ret = of_property_read_u32_array(np,
4342 "qcom,sdcc-clk-rates", clk_table, sz);
4343 if (ret < 0) {
4344 dev_err(dev, "error while reading clk"
4345 "table %d\n", ret);
4346 goto err;
4347 }
4348 } else {
4349 dev_err(dev, "clk_table not specified\n");
4350 goto err;
4351 }
4352 pdata->sup_clk_table = clk_table;
4353 pdata->sup_clk_cnt = sz;
4354 } else {
4355 dev_err(dev, "Supported clock rates not specified\n");
4356 }
4357
4358 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
4359 pdata->nonremovable = true;
4360 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
4361 pdata->disable_cmd23 = true;
4362
4363 return pdata;
4364err:
4365 return NULL;
4366}
4367
San Mehat9d2bd732009-09-22 16:44:22 -07004368static int
4369msmsdcc_probe(struct platform_device *pdev)
4370{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304371 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07004372 struct msmsdcc_host *host;
4373 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004374 unsigned long flags;
4375 struct resource *core_irqres = NULL;
4376 struct resource *bam_irqres = NULL;
4377 struct resource *core_memres = NULL;
4378 struct resource *dml_memres = NULL;
4379 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07004380 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07004381 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05304382 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004383 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07004384
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304385 if (pdev->dev.of_node) {
4386 plat = msmsdcc_populate_pdata(&pdev->dev);
4387 of_property_read_u32((&pdev->dev)->of_node,
4388 "cell-index", &pdev->id);
4389 } else {
4390 plat = pdev->dev.platform_data;
4391 }
4392
San Mehat9d2bd732009-09-22 16:44:22 -07004393 /* must have platform data */
4394 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004395 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004396 ret = -EINVAL;
4397 goto out;
4398 }
4399
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004400 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07004401 return -EINVAL;
4402
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304403 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
4404 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
4405 return -EINVAL;
4406 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004407
San Mehat9d2bd732009-09-22 16:44:22 -07004408 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004409 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004410 return -ENXIO;
4411 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304412 if (pdev->dev.of_node) {
4413 /*
4414 * Device tree iomem resources are only accessible by index.
4415 * index = 0 -> SDCC register interface
4416 * index = 1 -> DML register interface
4417 * index = 2 -> BAM register interface
4418 * IRQ resources:
4419 * index = 0 -> SDCC IRQ
4420 * index = 1 -> BAM IRQ
4421 */
4422 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
4423 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
4424 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
4425 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
4426 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
4427 } else {
4428 for (i = 0; i < pdev->num_resources; i++) {
4429 if (pdev->resource[i].flags & IORESOURCE_MEM) {
4430 if (!strncmp(pdev->resource[i].name,
4431 "sdcc_dml_addr",
4432 sizeof("sdcc_dml_addr")))
4433 dml_memres = &pdev->resource[i];
4434 else if (!strncmp(pdev->resource[i].name,
4435 "sdcc_bam_addr",
4436 sizeof("sdcc_bam_addr")))
4437 bam_memres = &pdev->resource[i];
4438 else
4439 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07004440
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304441 }
4442 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
4443 if (!strncmp(pdev->resource[i].name,
4444 "sdcc_bam_irq",
4445 sizeof("sdcc_bam_irq")))
4446 bam_irqres = &pdev->resource[i];
4447 else
4448 core_irqres = &pdev->resource[i];
4449 }
4450 if (pdev->resource[i].flags & IORESOURCE_DMA) {
4451 if (!strncmp(pdev->resource[i].name,
4452 "sdcc_dma_chnl",
4453 sizeof("sdcc_dma_chnl")))
4454 dmares = &pdev->resource[i];
4455 else if (!strncmp(pdev->resource[i].name,
4456 "sdcc_dma_crci",
4457 sizeof("sdcc_dma_crci")))
4458 dma_crci_res = &pdev->resource[i];
4459 }
Krishna Konda25786ec2011-07-25 16:21:36 -07004460 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004461 }
4462
4463 if (!core_irqres || !core_memres) {
4464 pr_err("%s: Invalid sdcc core resource\n", __func__);
4465 return -ENXIO;
4466 }
4467
4468 /*
4469 * Both BAM and DML memory resource should be preset.
4470 * BAM IRQ resource should also be present.
4471 */
4472 if ((bam_memres && !dml_memres) ||
4473 (!bam_memres && dml_memres) ||
4474 ((bam_memres && dml_memres) && !bam_irqres)) {
4475 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004476 return -ENXIO;
4477 }
4478
4479 /*
4480 * Setup our host structure
4481 */
San Mehat9d2bd732009-09-22 16:44:22 -07004482 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
4483 if (!mmc) {
4484 ret = -ENOMEM;
4485 goto out;
4486 }
4487
4488 host = mmc_priv(mmc);
4489 host->pdev_id = pdev->id;
4490 host->plat = plat;
4491 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08004492 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05304493
4494 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004495 host->is_sps_mode = 1;
4496 else if (dmares)
4497 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07004498
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004499 host->base = ioremap(core_memres->start,
4500 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07004501 if (!host->base) {
4502 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004503 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004504 }
4505
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004506 host->core_irqres = core_irqres;
4507 host->bam_irqres = bam_irqres;
4508 host->core_memres = core_memres;
4509 host->dml_memres = dml_memres;
4510 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07004511 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07004512 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07004513 spin_lock_init(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304514 mutex_init(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07004515
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004516#ifdef CONFIG_MMC_EMBEDDED_SDIO
4517 if (plat->embedded_sdio)
4518 mmc_set_embedded_sdio_data(mmc,
4519 &plat->embedded_sdio->cis,
4520 &plat->embedded_sdio->cccr,
4521 plat->embedded_sdio->funcs,
4522 plat->embedded_sdio->num_funcs);
4523#endif
4524
Sahitya Tummala62612cf2010-12-08 15:03:03 +05304525 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
4526 (unsigned long)host);
4527
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004528 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
4529 (unsigned long)host);
4530 if (host->is_dma_mode) {
4531 /* Setup DMA */
4532 ret = msmsdcc_init_dma(host);
4533 if (ret)
4534 goto ioremap_free;
4535 } else {
4536 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004537 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004538 }
4539
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004540 /*
4541 * Setup SDCC clock if derived from Dayatona
4542 * fabric core clock.
4543 */
4544 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07004545 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004546 if (!IS_ERR(host->dfab_pclk)) {
4547 /* Set the clock rate to 64MHz for max. performance */
4548 ret = clk_set_rate(host->dfab_pclk, 64000000);
4549 if (ret)
4550 goto dfab_pclk_put;
Asutosh Dasf5298c32012-04-03 14:51:47 +05304551 ret = clk_prepare_enable(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004552 if (ret)
4553 goto dfab_pclk_put;
4554 } else
4555 goto dma_free;
4556 }
4557
4558 /*
4559 * Setup main peripheral bus clock
4560 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004561 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004562 if (!IS_ERR(host->pclk)) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05304563 ret = clk_prepare_enable(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004564 if (ret)
4565 goto pclk_put;
4566
4567 host->pclk_rate = clk_get_rate(host->pclk);
4568 }
4569
4570 /*
4571 * Setup SDC MMC clock
4572 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004573 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07004574 if (IS_ERR(host->clk)) {
4575 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004576 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07004577 }
4578
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004579 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
4580 if (ret) {
4581 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
4582 goto clk_put;
4583 }
4584
Asutosh Dasf5298c32012-04-03 14:51:47 +05304585 ret = clk_prepare_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004586 if (ret)
4587 goto clk_put;
4588
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004589 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304590 if (!host->clk_rate)
4591 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304592
4593 /*
4594 * Lookup the Controller Version, to identify the supported features
4595 * Version number read as 0 would indicate SDCC3 or earlier versions
4596 */
4597 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
4598 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
4599 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304600 /*
4601 * Set the register write delay according to min. clock frequency
4602 * supported and update later when the host->clk_rate changes.
4603 */
4604 host->reg_write_delay =
4605 (1 + ((3 * USEC_PER_SEC) /
4606 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004607
4608 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05304609 /* Apply Hard reset to SDCC to put it in power on default state */
4610 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004611
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004612#define MSM_MMC_DEFAULT_CPUDMA_LATENCY 200 /* usecs */
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304613 /* pm qos request to prevent apps idle power collapse */
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004614 if (host->plat->cpu_dma_latency)
4615 host->cpu_dma_latency = host->plat->cpu_dma_latency;
4616 else
4617 host->cpu_dma_latency = MSM_MMC_DEFAULT_CPUDMA_LATENCY;
4618 pm_qos_add_request(&host->pm_qos_req_dma,
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304619 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
4620
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004621 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07004622 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004623 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07004624 goto clk_disable;
4625 }
4626
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004627
4628 /* Clocks has to be running before accessing SPS/DML HW blocks */
4629 if (host->is_sps_mode) {
4630 /* Initialize SPS */
4631 ret = msmsdcc_sps_init(host);
4632 if (ret)
4633 goto vreg_deinit;
4634 /* Initialize DML */
4635 ret = msmsdcc_dml_init(host);
4636 if (ret)
4637 goto sps_exit;
4638 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05304639 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07004640
San Mehat9d2bd732009-09-22 16:44:22 -07004641 /*
4642 * Setup MMC host structure
4643 */
4644 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004645 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
4646 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004647 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004648 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
4649 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07004650
San Mehat9d2bd732009-09-22 16:44:22 -07004651 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05304652 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304653
4654 /*
4655 * If we send the CMD23 before multi block write/read command
4656 * then we need not to send CMD12 at the end of the transfer.
4657 * If we don't send the CMD12 then only way to detect the PROG_DONE
4658 * status is to use the AUTO_PROG_DONE status provided by SDCC4
4659 * controller. So let's enable the CMD23 for SDCC4 only.
4660 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304661 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304662 mmc->caps |= MMC_CAP_CMD23;
4663
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004664 mmc->caps |= plat->uhs_caps;
4665 /*
4666 * XPC controls the maximum current in the default speed mode of SDXC
4667 * card. XPC=0 means 100mA (max.) but speed class is not supported.
4668 * XPC=1 means 150mA (max.) and speed class is supported.
4669 */
4670 if (plat->xpc_cap)
4671 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
4672 MMC_CAP_SET_XPC_180);
4673
Subhash Jadavani6bb34a82012-04-18 13:18:40 +05304674 mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304675 if (pdev->dev.of_node) {
4676 if (of_get_property((&pdev->dev)->of_node,
4677 "qcom,sdcc-hs200", NULL))
4678 mmc->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
4679 }
4680
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004681 if (plat->nonremovable)
4682 mmc->caps |= MMC_CAP_NONREMOVABLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004683 mmc->caps |= MMC_CAP_SDIO_IRQ;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004684
4685 if (plat->is_sdio_al_client)
4686 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07004687
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304688 mmc->max_segs = msmsdcc_get_nr_sg(host);
4689 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
4690 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07004691
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304692 mmc->max_req_size = MMC_MAX_REQ_SIZE;
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +05304693 mmc->max_seg_size = mmc->max_req_size;
San Mehat9d2bd732009-09-22 16:44:22 -07004694
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004695 writel_relaxed(0, host->base + MMCIMASK0);
4696 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05304697 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004698
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004699 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
4700 mb();
4701 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07004702
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004703 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
4704 DRIVER_NAME " (cmd)", host);
4705 if (ret)
4706 goto dml_exit;
4707
4708 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
4709 DRIVER_NAME " (pio)", host);
4710 if (ret)
4711 goto irq_free;
4712
4713 /*
4714 * Enable SDCC IRQ only when host is powered on. Otherwise, this
4715 * IRQ is un-necessarily being monitored by MPM (Modem power
4716 * management block) during idle-power collapse. The MPM will be
4717 * configured to monitor the DATA1 GPIO line with level-low trigger
4718 * and thus depending on the GPIO status, it prevents TCXO shutdown
4719 * during idle-power collapse.
4720 */
4721 disable_irq(core_irqres->start);
4722 host->sdcc_irq_disabled = 1;
4723
4724 if (plat->sdiowakeup_irq) {
4725 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4726 mmc_hostname(mmc));
4727 ret = request_irq(plat->sdiowakeup_irq,
4728 msmsdcc_platform_sdiowakeup_irq,
4729 IRQF_SHARED | IRQF_TRIGGER_LOW,
4730 DRIVER_NAME "sdiowakeup", host);
4731 if (ret) {
4732 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
4733 plat->sdiowakeup_irq, ret);
4734 goto pio_irq_free;
4735 } else {
4736 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304737 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004738 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304739 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004740 }
4741 spin_unlock_irqrestore(&host->lock, flags);
4742 }
4743 }
4744
Subhash Jadavanic9b85752012-04-13 11:16:49 +05304745 if (host->plat->mpm_sdiowakeup_int) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004746 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4747 mmc_hostname(mmc));
4748 }
4749
4750 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
4751 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004752 /*
4753 * Setup card detect change
4754 */
4755
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004756 if (plat->status || plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08004757 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004758 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08004759 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004760 host->oldstat = msmsdcc_slot_status(host);
Krishna Konda360aa422011-12-06 18:27:41 -08004761
Krishna Konda941604a2012-01-10 17:46:34 -08004762 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004763 }
San Mehat9d2bd732009-09-22 16:44:22 -07004764
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004765 if (plat->status_irq) {
4766 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07004767 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004768 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07004769 DRIVER_NAME " (slot)",
4770 host);
4771 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004772 pr_err("Unable to get slot IRQ %d (%d)\n",
4773 plat->status_irq, ret);
4774 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004775 }
4776 } else if (plat->register_status_notify) {
4777 plat->register_status_notify(msmsdcc_status_notify_cb, host);
4778 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004779 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07004780 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004781
4782 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004783
4784 ret = pm_runtime_set_active(&(pdev)->dev);
4785 if (ret < 0)
4786 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
4787 __func__, ret);
4788 /*
4789 * There is no notion of suspend/resume for SD/MMC/SDIO
4790 * cards. So host can be suspended/resumed with out
4791 * worrying about its children.
4792 */
4793 pm_suspend_ignore_children(&(pdev)->dev, true);
4794
4795 /*
4796 * MMC/SD/SDIO bus suspend/resume operations are defined
4797 * only for the slots that will be used for non-removable
4798 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
4799 * defined. Otherwise, they simply become card removal and
4800 * insertion events during suspend and resume respectively.
4801 * Hence, enable run-time PM only for slots for which bus
4802 * suspend/resume operations are defined.
4803 */
4804#ifdef CONFIG_MMC_UNSAFE_RESUME
4805 /*
4806 * If this capability is set, MMC core will enable/disable host
4807 * for every claim/release operation on a host. We use this
4808 * notification to increment/decrement runtime pm usage count.
4809 */
4810 mmc->caps |= MMC_CAP_DISABLE;
4811 pm_runtime_enable(&(pdev)->dev);
4812#else
4813 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
4814 mmc->caps |= MMC_CAP_DISABLE;
4815 pm_runtime_enable(&(pdev)->dev);
4816 }
4817#endif
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05304818#ifndef CONFIG_PM_RUNTIME
4819 mmc_set_disable_delay(mmc, MSM_MMC_DISABLE_TIMEOUT);
4820#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004821 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
4822 (unsigned long)host);
4823
San Mehat9d2bd732009-09-22 16:44:22 -07004824 mmc_add_host(mmc);
4825
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004826#ifdef CONFIG_HAS_EARLYSUSPEND
4827 host->early_suspend.suspend = msmsdcc_early_suspend;
4828 host->early_suspend.resume = msmsdcc_late_resume;
4829 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
4830 register_early_suspend(&host->early_suspend);
4831#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004832
Krishna Konda25786ec2011-07-25 16:21:36 -07004833 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
4834 " dmacrcri %d\n", mmc_hostname(mmc),
4835 (unsigned long long)core_memres->start,
4836 (unsigned int) core_irqres->start,
4837 (unsigned int) plat->status_irq, host->dma.channel,
4838 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004839
4840 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
4841 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
4842 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
4843 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
4844 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
4845 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
4846 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
4847 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
4848 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
4849 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
4850 host->eject);
4851 pr_info("%s: Power save feature enable = %d\n",
4852 mmc_hostname(mmc), msmsdcc_pwrsave);
4853
Krishna Konda25786ec2011-07-25 16:21:36 -07004854 if (host->is_dma_mode && host->dma.channel != -1
4855 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004856 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004857 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004858 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004859 mmc_hostname(mmc), host->dma.cmd_busaddr,
4860 host->dma.cmdptr_busaddr);
4861 } else if (host->is_sps_mode) {
4862 pr_info("%s: SPS-BAM data transfer mode available\n",
4863 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004864 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004865 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004866
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004867#if defined(CONFIG_DEBUG_FS)
4868 msmsdcc_dbg_createhost(host);
4869#endif
4870 if (!plat->status_irq) {
4871 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
4872 if (ret)
4873 goto platform_irq_free;
4874 }
San Mehat9d2bd732009-09-22 16:44:22 -07004875 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004876
4877 platform_irq_free:
4878 del_timer_sync(&host->req_tout_timer);
4879 pm_runtime_disable(&(pdev)->dev);
4880 pm_runtime_set_suspended(&(pdev)->dev);
4881
4882 if (plat->status_irq)
4883 free_irq(plat->status_irq, host);
4884 sdiowakeup_irq_free:
4885 wake_lock_destroy(&host->sdio_suspend_wlock);
4886 if (plat->sdiowakeup_irq)
4887 free_irq(plat->sdiowakeup_irq, host);
4888 pio_irq_free:
4889 if (plat->sdiowakeup_irq)
4890 wake_lock_destroy(&host->sdio_wlock);
4891 free_irq(core_irqres->start, host);
4892 irq_free:
4893 free_irq(core_irqres->start, host);
4894 dml_exit:
4895 if (host->is_sps_mode)
4896 msmsdcc_dml_exit(host);
4897 sps_exit:
4898 if (host->is_sps_mode)
4899 msmsdcc_sps_exit(host);
4900 vreg_deinit:
4901 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07004902 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004903 clk_disable(host->clk);
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004904 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304905 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07004906 clk_put:
4907 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004908 pclk_disable:
4909 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05304910 clk_disable_unprepare(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07004911 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004912 if (!IS_ERR(host->pclk))
4913 clk_put(host->pclk);
4914 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05304915 clk_disable_unprepare(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004916 dfab_pclk_put:
4917 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4918 clk_put(host->dfab_pclk);
4919 dma_free:
4920 if (host->is_dma_mode) {
4921 if (host->dmares)
4922 dma_free_coherent(NULL,
4923 sizeof(struct msmsdcc_nc_dmadata),
4924 host->dma.nc, host->dma.nc_busaddr);
4925 }
4926 ioremap_free:
4927 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07004928 host_free:
4929 mmc_free_host(mmc);
4930 out:
4931 return ret;
4932}
4933
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004934static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07004935{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004936 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4937 struct mmc_platform_data *plat;
4938 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004939
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004940 if (!mmc)
4941 return -ENXIO;
4942
4943 if (pm_runtime_suspended(&(pdev)->dev))
4944 pm_runtime_resume(&(pdev)->dev);
4945
4946 host = mmc_priv(mmc);
4947
4948 DBG(host, "Removing SDCC device = %d\n", pdev->id);
4949 plat = host->plat;
4950
4951 if (!plat->status_irq)
4952 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
4953
4954 del_timer_sync(&host->req_tout_timer);
4955 tasklet_kill(&host->dma_tlet);
4956 tasklet_kill(&host->sps.tlet);
4957 mmc_remove_host(mmc);
4958
4959 if (plat->status_irq)
4960 free_irq(plat->status_irq, host);
4961
4962 wake_lock_destroy(&host->sdio_suspend_wlock);
4963 if (plat->sdiowakeup_irq) {
4964 wake_lock_destroy(&host->sdio_wlock);
4965 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
4966 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07004967 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004968
4969 free_irq(host->core_irqres->start, host);
4970 free_irq(host->core_irqres->start, host);
4971
4972 clk_put(host->clk);
4973 if (!IS_ERR(host->pclk))
4974 clk_put(host->pclk);
4975 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4976 clk_put(host->dfab_pclk);
4977
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004978 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304979 pm_qos_remove_request(&host->pm_qos_req_dma);
4980
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004981 msmsdcc_vreg_init(host, false);
4982
4983 if (host->is_dma_mode) {
4984 if (host->dmares)
4985 dma_free_coherent(NULL,
4986 sizeof(struct msmsdcc_nc_dmadata),
4987 host->dma.nc, host->dma.nc_busaddr);
4988 }
4989
4990 if (host->is_sps_mode) {
4991 msmsdcc_dml_exit(host);
4992 msmsdcc_sps_exit(host);
4993 }
4994
4995 iounmap(host->base);
4996 mmc_free_host(mmc);
4997
4998#ifdef CONFIG_HAS_EARLYSUSPEND
4999 unregister_early_suspend(&host->early_suspend);
5000#endif
5001 pm_runtime_disable(&(pdev)->dev);
5002 pm_runtime_set_suspended(&(pdev)->dev);
5003
5004 return 0;
5005}
5006
5007#ifdef CONFIG_MSM_SDIO_AL
5008int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
5009{
5010 struct msmsdcc_host *host = mmc_priv(mmc);
5011 unsigned long flags;
5012
Asutosh Dasf5298c32012-04-03 14:51:47 +05305013 mutex_lock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005014 spin_lock_irqsave(&host->lock, flags);
5015 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
5016 enable ? "En" : "Dis");
5017
5018 if (enable) {
5019 if (!host->sdcc_irq_disabled) {
5020 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05305021 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005022 host->sdcc_irq_disabled = 1;
5023 }
5024
5025 if (host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305026 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005027 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305028 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005029 host->clks_on = 0;
5030 }
5031
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305032 if (host->plat->sdio_lpm_gpio_setup &&
5033 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005034 spin_unlock_irqrestore(&host->lock, flags);
5035 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
5036 spin_lock_irqsave(&host->lock, flags);
5037 host->sdio_gpio_lpm = 1;
5038 }
5039
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305040 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005041 msmsdcc_enable_irq_wake(host);
5042 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305043 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005044 }
5045 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305046 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005047 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305048 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005049 msmsdcc_disable_irq_wake(host);
5050 }
5051
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305052 if (host->plat->sdio_lpm_gpio_setup &&
5053 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005054 spin_unlock_irqrestore(&host->lock, flags);
5055 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
5056 spin_lock_irqsave(&host->lock, flags);
5057 host->sdio_gpio_lpm = 0;
5058 }
5059
5060 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305061 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005062 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305063 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005064 host->clks_on = 1;
5065 }
5066
5067 if (host->sdcc_irq_disabled) {
5068 writel_relaxed(host->mci_irqenable,
5069 host->base + MMCIMASK0);
5070 mb();
5071 enable_irq(host->core_irqres->start);
5072 host->sdcc_irq_disabled = 0;
5073 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005074 }
5075 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305076 mutex_unlock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005077 return 0;
5078}
5079#else
5080int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
5081{
5082 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07005083}
5084#endif
5085
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005086#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07005087static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005088msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07005089{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005090 struct mmc_host *mmc = dev_get_drvdata(dev);
5091 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07005092 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305093 unsigned long flags;
5094
San Mehat9d2bd732009-09-22 16:44:22 -07005095
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005096 if (host->plat->is_sdio_al_client)
5097 return 0;
Sahitya Tummala7661a452011-07-18 13:28:35 +05305098 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005099 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005100 host->sdcc_suspending = 1;
5101 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07005102
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005103 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005104 * MMC core thinks that host is disabled by now since
5105 * runtime suspend is scheduled after msmsdcc_disable()
5106 * is called. Thus, MMC core will try to enable the host
5107 * while suspending it. This results in a synchronous
5108 * runtime resume request while in runtime suspending
5109 * context and hence inorder to complete this resume
5110 * requet, it will wait for suspend to be complete,
5111 * but runtime suspend also can not proceed further
5112 * until the host is resumed. Thus, it leads to a hang.
5113 * Hence, increase the pm usage count before suspending
5114 * the host so that any resume requests after this will
5115 * simple become pm usage counter increment operations.
5116 */
5117 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05305118 /* If there is pending detect work abort runtime suspend */
5119 if (unlikely(work_busy(&mmc->detect.work)))
5120 rc = -EAGAIN;
5121 else
5122 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005123 pm_runtime_put_noidle(dev);
5124
5125 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305126 spin_lock_irqsave(&host->lock, flags);
5127 host->sdcc_suspended = true;
5128 spin_unlock_irqrestore(&host->lock, flags);
5129 if (mmc->card && mmc_card_sdio(mmc->card) &&
5130 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005131 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305132 * If SDIO function driver doesn't want
5133 * to power off the card, atleast turn off
5134 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005135 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305136 mmc_host_clk_hold(mmc);
5137 spin_lock_irqsave(&mmc->clk_lock, flags);
5138 mmc->clk_old = mmc->ios.clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005139 mmc->ios.clock = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305140 mmc->clk_gated = true;
5141 spin_unlock_irqrestore(&mmc->clk_lock, flags);
5142 mmc_set_ios(mmc);
5143 mmc_host_clk_release(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005144 }
5145 }
5146 host->sdcc_suspending = 0;
5147 mmc->suspend_task = NULL;
5148 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
5149 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005150 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05305151 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
San Mehat9d2bd732009-09-22 16:44:22 -07005152 return rc;
5153}
5154
5155static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005156msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07005157{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005158 struct mmc_host *mmc = dev_get_drvdata(dev);
5159 struct msmsdcc_host *host = mmc_priv(mmc);
5160 unsigned long flags;
5161
5162 if (host->plat->is_sdio_al_client)
5163 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07005164
Sahitya Tummala7661a452011-07-18 13:28:35 +05305165 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005166 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305167 if (mmc->card && mmc_card_sdio(mmc->card) &&
5168 mmc_card_keep_power(mmc)) {
5169 mmc_host_clk_hold(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305170 mmc->ios.clock = host->clk_rate;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305171 mmc_set_ios(mmc);
5172 mmc_host_clk_release(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305173 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005174
5175 mmc_resume_host(mmc);
5176
5177 /*
5178 * FIXME: Clearing of flags must be handled in clients
5179 * resume handler.
5180 */
5181 spin_lock_irqsave(&host->lock, flags);
5182 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305183 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005184 spin_unlock_irqrestore(&host->lock, flags);
5185
5186 /*
5187 * After resuming the host wait for sometime so that
5188 * the SDIO work will be processed.
5189 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305190 if (mmc->card && mmc_card_sdio(mmc->card)) {
Subhash Jadavanic9b85752012-04-13 11:16:49 +05305191 if ((host->plat->mpm_sdiowakeup_int ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005192 host->plat->sdiowakeup_irq) &&
5193 wake_lock_active(&host->sdio_wlock))
5194 wake_lock_timeout(&host->sdio_wlock, 1);
5195 }
5196
5197 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005198 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05305199 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005200 return 0;
5201}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005202
5203static int msmsdcc_runtime_idle(struct device *dev)
5204{
5205 struct mmc_host *mmc = dev_get_drvdata(dev);
5206 struct msmsdcc_host *host = mmc_priv(mmc);
5207
5208 if (host->plat->is_sdio_al_client)
5209 return 0;
5210
5211 /* Idle timeout is not configurable for now */
5212 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
5213
5214 return -EAGAIN;
5215}
5216
5217static int msmsdcc_pm_suspend(struct device *dev)
5218{
5219 struct mmc_host *mmc = dev_get_drvdata(dev);
5220 struct msmsdcc_host *host = mmc_priv(mmc);
5221 int rc = 0;
5222
5223 if (host->plat->is_sdio_al_client)
5224 return 0;
5225
5226
5227 if (host->plat->status_irq)
5228 disable_irq(host->plat->status_irq);
5229
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005230 if (!pm_runtime_suspended(dev))
5231 rc = msmsdcc_runtime_suspend(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005232
5233 return rc;
5234}
5235
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305236static int msmsdcc_suspend_noirq(struct device *dev)
5237{
5238 struct mmc_host *mmc = dev_get_drvdata(dev);
5239 struct msmsdcc_host *host = mmc_priv(mmc);
5240 int rc = 0;
5241
5242 /*
5243 * After platform suspend there may be active request
5244 * which might have enabled clocks. For example, in SDIO
5245 * case, ksdioirq thread might have scheduled after sdcc
5246 * suspend but before system freeze. In that case abort
5247 * suspend and retry instead of keeping the clocks on
5248 * during suspend and not allowing TCXO.
5249 */
5250
Asutosh Dasf5298c32012-04-03 14:51:47 +05305251 if (host->clks_on && !host->plat->is_sdio_al_client) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305252 pr_warn("%s: clocks are on after suspend, aborting system "
5253 "suspend\n", mmc_hostname(mmc));
5254 rc = -EAGAIN;
5255 }
5256
5257 return rc;
5258}
5259
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005260static int msmsdcc_pm_resume(struct device *dev)
5261{
5262 struct mmc_host *mmc = dev_get_drvdata(dev);
5263 struct msmsdcc_host *host = mmc_priv(mmc);
5264 int rc = 0;
5265
5266 if (host->plat->is_sdio_al_client)
5267 return 0;
5268
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005269 if (mmc->card && mmc_card_sdio(mmc->card))
Sahitya Tummalafb486372011-09-02 19:01:49 +05305270 rc = msmsdcc_runtime_resume(dev);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005271 else
5272 host->pending_resume = true;
5273
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005274 if (host->plat->status_irq) {
5275 msmsdcc_check_status((unsigned long)host);
5276 enable_irq(host->plat->status_irq);
5277 }
5278
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005279 return rc;
5280}
5281
Daniel Walker08ecfde2010-06-23 12:32:20 -07005282#else
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005283static int msmsdcc_runtime_suspend(struct device *dev)
5284{
5285 return 0;
5286}
5287static int msmsdcc_runtime_idle(struct device *dev)
5288{
5289 return 0;
5290}
5291static int msmsdcc_pm_suspend(struct device *dev)
5292{
5293 return 0;
5294}
5295static int msmsdcc_pm_resume(struct device *dev)
5296{
5297 return 0;
5298}
5299static int msmsdcc_suspend_noirq(struct device *dev)
5300{
5301 return 0;
5302}
5303static int msmsdcc_runtime_resume(struct device *dev)
5304{
5305 return 0;
5306}
Daniel Walker08ecfde2010-06-23 12:32:20 -07005307#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005308
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005309static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
5310 .runtime_suspend = msmsdcc_runtime_suspend,
5311 .runtime_resume = msmsdcc_runtime_resume,
5312 .runtime_idle = msmsdcc_runtime_idle,
5313 .suspend = msmsdcc_pm_suspend,
5314 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305315 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005316};
5317
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305318static const struct of_device_id msmsdcc_dt_match[] = {
5319 {.compatible = "qcom,msm-sdcc"},
5320
5321};
5322MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
5323
San Mehat9d2bd732009-09-22 16:44:22 -07005324static struct platform_driver msmsdcc_driver = {
5325 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005326 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07005327 .driver = {
5328 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005329 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305330 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07005331 },
5332};
5333
5334static int __init msmsdcc_init(void)
5335{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005336#if defined(CONFIG_DEBUG_FS)
5337 int ret = 0;
5338 ret = msmsdcc_dbg_init();
5339 if (ret) {
5340 pr_err("Failed to create debug fs dir \n");
5341 return ret;
5342 }
5343#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005344 return platform_driver_register(&msmsdcc_driver);
5345}
5346
5347static void __exit msmsdcc_exit(void)
5348{
5349 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005350
5351#if defined(CONFIG_DEBUG_FS)
5352 debugfs_remove(debugfs_file);
5353 debugfs_remove(debugfs_dir);
5354#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005355}
5356
5357module_init(msmsdcc_init);
5358module_exit(msmsdcc_exit);
5359
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005360MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07005361MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005362
5363#if defined(CONFIG_DEBUG_FS)
5364
5365static int
5366msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
5367{
5368 file->private_data = inode->i_private;
5369 return 0;
5370}
5371
5372static ssize_t
5373msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
5374 size_t count, loff_t *ppos)
5375{
5376 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08005377 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005378 int max, i;
5379
5380 i = 0;
5381 max = sizeof(buf) - 1;
5382
5383 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
5384 host->curr.cmd, host->curr.data);
5385 if (host->curr.cmd) {
5386 struct mmc_command *cmd = host->curr.cmd;
5387
5388 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
5389 cmd->opcode, cmd->arg, cmd->flags);
5390 }
5391 if (host->curr.data) {
5392 struct mmc_data *data = host->curr.data;
5393 i += scnprintf(buf + i, max - i,
5394 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
5395 data->timeout_ns, data->timeout_clks,
5396 data->blksz, data->blocks, data->error,
5397 data->flags);
5398 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
5399 host->curr.xfer_size, host->curr.xfer_remain,
5400 host->curr.data_xfered, host->dma.sg);
5401 }
5402
5403 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
5404}
5405
5406static const struct file_operations msmsdcc_dbg_state_ops = {
5407 .read = msmsdcc_dbg_state_read,
5408 .open = msmsdcc_dbg_state_open,
5409};
5410
5411static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
5412{
5413 if (debugfs_dir) {
5414 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
5415 0644, debugfs_dir, host,
5416 &msmsdcc_dbg_state_ops);
5417 }
5418}
5419
5420static int __init msmsdcc_dbg_init(void)
5421{
5422 int err;
5423
5424 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
5425 if (IS_ERR(debugfs_dir)) {
5426 err = PTR_ERR(debugfs_dir);
5427 debugfs_dir = NULL;
5428 return err;
5429 }
5430
5431 return 0;
5432}
5433#endif