blob: e45842948223efc1ecbc0f4c6c8a44d60b597970 [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;
subhashj8046ae12012-05-02 12:14:52 +05301560 if (mmc_resp_type(cmd))
1561 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1562 /*
1563 * Read rest of the response registers only if
1564 * long response is expected for this command
1565 */
1566 if (mmc_resp_type(cmd) & MMC_RSP_136) {
1567 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1568 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1569 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
1570 }
San Mehat9d2bd732009-09-22 16:44:22 -07001571
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001572 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301573 pr_debug("%s: CMD%d: Command timeout\n",
1574 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001575 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001576 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301577 !host->tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301578 pr_err("%s: CMD%d: Command CRC error\n",
1579 mmc_hostname(host->mmc), cmd->opcode);
1580 msmsdcc_dump_sdcc_state(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001581 cmd->error = -EILSEQ;
1582 }
1583
1584 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001585 if (host->curr.data && host->dma.sg &&
1586 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001587 msm_dmov_stop_cmd(host->dma.channel,
1588 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001589 else if (host->curr.data && host->sps.sg &&
1590 host->is_sps_mode){
1591 /* Stop current SPS transfer */
1592 msmsdcc_sps_exit_curr_xfer(host);
1593 }
San Mehat9d2bd732009-09-22 16:44:22 -07001594 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301595 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001596 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301597 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301598 } else { /* host->data == NULL */
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301599 if (!cmd->error && host->prog_enable) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301600 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001601 host->prog_enable = 0;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301602 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001603 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301604 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301605 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301606 host->prog_enable = 0;
Subhash Jadavanied6b0e42012-03-07 16:36:27 +05301607 host->curr.wait_for_auto_prog_done = 0;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001608 if (host->dummy_52_needed)
1609 host->dummy_52_needed = 0;
1610 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001611 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301612 msmsdcc_request_end(host, cmd->mrq);
1613 }
1614 }
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301615 } else if ((cmd == host->curr.mrq->sbc) && cmd->data) {
1616 if (cmd->data->flags & MMC_DATA_READ)
1617 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1618 else
1619 msmsdcc_request_start(host, host->curr.mrq);
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301620 } else if (cmd->data) {
1621 if (!(cmd->data->flags & MMC_DATA_READ))
1622 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001623 }
1624}
1625
San Mehat9d2bd732009-09-22 16:44:22 -07001626static irqreturn_t
1627msmsdcc_irq(int irq, void *dev_id)
1628{
1629 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001630 u32 status;
1631 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001632 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001633
1634 spin_lock(&host->lock);
1635
1636 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001637 struct mmc_command *cmd;
1638 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001639
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001640 if (timer) {
1641 timer = 0;
1642 msmsdcc_delay(host);
1643 }
San Mehat865c8062009-11-13 13:42:06 -08001644
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001645 if (!host->clks_on) {
1646 pr_debug("%s: %s: SDIO async irq received\n",
1647 mmc_hostname(host->mmc), __func__);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301648
1649 /*
1650 * Only async interrupt can come when clocks are off,
1651 * disable further interrupts and enable them when
1652 * clocks are on.
1653 */
1654 if (!host->sdcc_irq_disabled) {
1655 disable_irq_nosync(irq);
1656 host->sdcc_irq_disabled = 1;
1657 }
1658
1659 /*
1660 * If mmc_card_wake_sdio_irq() is set, mmc core layer
1661 * will take care of signaling sdio irq during
1662 * mmc_sdio_resume().
1663 */
1664 if (host->sdcc_suspended)
1665 /*
1666 * This is a wakeup interrupt so hold wakelock
1667 * until SDCC resume is handled.
1668 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001669 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301670 else
1671 mmc_signal_sdio_irq(host->mmc);
1672 ret = 1;
1673 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001674 }
1675
1676 status = readl_relaxed(host->base + MMCISTATUS);
1677
1678 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1679 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001680 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001681
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001682#if IRQ_DEBUG
1683 msmsdcc_print_status(host, "irq0-r", status);
1684#endif
1685 status &= readl_relaxed(host->base + MMCIMASK0);
1686 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301687 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301688 if (host->clk_rate <=
1689 msmsdcc_get_min_sup_clk_rate(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +05301690 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001691#if IRQ_DEBUG
1692 msmsdcc_print_status(host, "irq0-p", status);
1693#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001694
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001695 if (status & MCI_SDIOINTROPE) {
1696 if (host->sdcc_suspending)
1697 wake_lock(&host->sdio_suspend_wlock);
1698 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001699 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001700 data = host->curr.data;
1701
1702 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001703 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1704 MCI_CMDTIMEOUT)) {
1705 if (status & MCI_CMDTIMEOUT)
1706 pr_debug("%s: dummy CMD52 timeout\n",
1707 mmc_hostname(host->mmc));
1708 if (status & MCI_CMDCRCFAIL)
1709 pr_debug("%s: dummy CMD52 CRC failed\n",
1710 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001711 host->dummy_52_sent = 0;
1712 host->dummy_52_needed = 0;
1713 if (data) {
1714 msmsdcc_stop_data(host);
1715 msmsdcc_request_end(host, data->mrq);
1716 }
1717 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001718 spin_unlock(&host->lock);
1719 return IRQ_HANDLED;
1720 }
1721 break;
1722 }
1723
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001724 /*
1725 * Check for proper command response
1726 */
1727 cmd = host->curr.cmd;
1728 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1729 MCI_CMDTIMEOUT | MCI_PROGDONE |
1730 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1731 msmsdcc_do_cmdirq(host, status);
1732 }
1733
Sathish Ambley081d7842011-11-29 11:19:41 -08001734 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001735 /* Check for data errors */
1736 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1737 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1738 msmsdcc_data_err(host, data, status);
1739 host->curr.data_xfered = 0;
1740 if (host->dma.sg && host->is_dma_mode)
1741 msm_dmov_stop_cmd(host->dma.channel,
1742 &host->dma.hdr, 0);
1743 else if (host->sps.sg && host->is_sps_mode) {
1744 /* Stop current SPS transfer */
1745 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301746 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001747 msmsdcc_reset_and_restore(host);
1748 if (host->curr.data)
1749 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301750 if (!data->stop || (host->curr.mrq->sbc
1751 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001752 timer |=
1753 msmsdcc_request_end(host,
1754 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301755 else if ((host->curr.mrq->sbc
1756 && data->error) ||
1757 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001758 msmsdcc_start_command(host,
1759 data->stop,
1760 0);
1761 timer = 1;
1762 }
1763 }
1764 }
1765
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301766 /* Check for prog done */
1767 if (host->curr.wait_for_auto_prog_done &&
1768 (status & MCI_PROGDONE))
1769 host->curr.got_auto_prog_done = 1;
1770
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001771 /* Check for data done */
1772 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1773 host->curr.got_dataend = 1;
1774
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301775 if (host->curr.got_dataend &&
1776 (!host->curr.wait_for_auto_prog_done ||
1777 (host->curr.wait_for_auto_prog_done &&
1778 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001779 /*
1780 * If DMA is still in progress, we complete
1781 * via the completion handler
1782 */
1783 if (!host->dma.busy && !host->sps.busy) {
1784 /*
1785 * There appears to be an issue in the
1786 * controller where if you request a
1787 * small block transfer (< fifo size),
1788 * you may get your DATAEND/DATABLKEND
1789 * irq without the PIO data irq.
1790 *
1791 * Check to see if theres still data
1792 * to be read, and simulate a PIO irq.
1793 */
1794 if (data->flags & MMC_DATA_READ)
1795 msmsdcc_wait_for_rxdata(host,
1796 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001797 if (!data->error) {
1798 host->curr.data_xfered =
1799 host->curr.xfer_size;
1800 host->curr.xfer_remain -=
1801 host->curr.xfer_size;
1802 }
1803
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001804 if (!host->dummy_52_needed) {
1805 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301806 if (!data->stop ||
1807 (host->curr.mrq->sbc
1808 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001809 msmsdcc_request_end(
1810 host,
1811 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301812 else if ((host->curr.mrq->sbc
1813 && data->error) ||
1814 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001815 msmsdcc_start_command(
1816 host,
1817 data->stop, 0);
1818 timer = 1;
1819 }
1820 } else {
1821 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001822 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001823 &dummy52cmd,
1824 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001825 }
1826 }
1827 }
1828 }
1829
San Mehat9d2bd732009-09-22 16:44:22 -07001830 ret = 1;
1831 } while (status);
1832
1833 spin_unlock(&host->lock);
1834
San Mehat9d2bd732009-09-22 16:44:22 -07001835 return IRQ_RETVAL(ret);
1836}
1837
1838static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001839msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1840{
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301841 if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001842 /* Queue/read data, daisy-chain command when data starts */
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301843 if (mrq->sbc)
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301844 msmsdcc_start_data(host, mrq->data, mrq->sbc, 0);
1845 else
1846 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001847 } else {
1848 msmsdcc_start_command(host, mrq->cmd, 0);
1849 }
1850}
1851
1852static void
San Mehat9d2bd732009-09-22 16:44:22 -07001853msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1854{
1855 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001856 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001857
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001858 /*
1859 * Get the SDIO AL client out of LPM.
1860 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001861 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001862 if (host->plat->is_sdio_al_client)
1863 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001864
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301865 /* check if sps pipe reset is pending? */
1866 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1867 msmsdcc_sps_pipes_reset_and_restore(host);
1868 host->sps.pipe_reset_pending = false;
1869 }
1870
San Mehat9d2bd732009-09-22 16:44:22 -07001871 spin_lock_irqsave(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001872
1873 if (host->eject) {
1874 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1875 mrq->cmd->error = 0;
1876 mrq->data->bytes_xfered = mrq->data->blksz *
1877 mrq->data->blocks;
1878 } else
1879 mrq->cmd->error = -ENOMEDIUM;
1880
1881 spin_unlock_irqrestore(&host->lock, flags);
1882 mmc_request_done(mmc, mrq);
1883 return;
1884 }
1885
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301886 /*
subhashjf181c292012-05-02 13:07:40 +05301887 * Don't start the request if SDCC is not in proper state to handle it
1888 */
1889 if (!host->pwr || !host->clks_on || host->sdcc_irq_disabled) {
1890 WARN(1, "%s: %s: SDCC is in bad state. don't process"
1891 " new request (CMD%d)\n", mmc_hostname(host->mmc),
1892 __func__, mrq->cmd->opcode);
1893 msmsdcc_dump_sdcc_state(host);
1894 mrq->cmd->error = -EIO;
1895 if (mrq->data) {
1896 mrq->data->error = -EIO;
1897 mrq->data->bytes_xfered = 0;
1898 }
1899 spin_unlock_irqrestore(&host->lock, flags);
1900 mmc_request_done(mmc, mrq);
1901 return;
1902 }
1903
1904 WARN(host->curr.mrq, "%s: %s: New request (CMD%d) received while"
1905 " other request (CMD%d) is in progress\n",
1906 mmc_hostname(host->mmc), __func__,
1907 mrq->cmd->opcode, host->curr.mrq->cmd->opcode);
1908
1909 /*
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301910 * Kick the software command timeout timer here.
1911 * Timer expires in 10 secs.
1912 */
1913 mod_timer(&host->req_tout_timer,
1914 (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
San Mehat9d2bd732009-09-22 16:44:22 -07001915
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301916 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301917 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301918 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
1919 mrq->cmd->opcode == 54) {
Pratibhasagar V1c11da62011-11-14 12:36:35 +05301920 if (!host->sdcc_version)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001921 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301922 else
1923 /*
1924 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
1925 * write operations using CMD53 and CMD54.
1926 * Setting this bit with CMD53 would
1927 * automatically triggers PROG_DONE interrupt
1928 * without the need of sending dummy CMD52.
1929 */
1930 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani758cf8c2011-11-13 11:59:55 +05301931 } else if (mrq->cmd->opcode == MMC_WRITE_BLOCK &&
1932 host->sdcc_version) {
1933 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001934 }
San Mehat9d2bd732009-09-22 16:44:22 -07001935 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301936
Pratibhasagar V00b94332011-10-18 14:57:27 +05301937 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301938 mrq->sbc->mrq = mrq;
1939 mrq->sbc->data = mrq->data;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301940 if (mrq->data->flags & MMC_DATA_WRITE) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301941 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301942 msmsdcc_start_command(host, mrq->sbc, 0);
1943 } else {
1944 msmsdcc_request_start(host, mrq);
1945 }
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301946 } else {
1947 msmsdcc_request_start(host, mrq);
1948 }
1949
San Mehat9d2bd732009-09-22 16:44:22 -07001950 spin_unlock_irqrestore(&host->lock, flags);
1951}
1952
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001953static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1954 int min_uV, int max_uV)
1955{
1956 int rc = 0;
1957
1958 if (vreg->set_voltage_sup) {
1959 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1960 if (rc) {
1961 pr_err("%s: regulator_set_voltage(%s) failed."
1962 " min_uV=%d, max_uV=%d, rc=%d\n",
1963 __func__, vreg->name, min_uV, max_uV, rc);
1964 }
1965 }
1966
1967 return rc;
1968}
1969
1970static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1971 int uA_load)
1972{
1973 int rc = 0;
1974
Krishna Kondafea60182011-11-01 16:01:34 -07001975 /* regulators that do not support regulator_set_voltage also
1976 do not support regulator_set_optimum_mode */
1977 if (vreg->set_voltage_sup) {
1978 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1979 if (rc < 0)
1980 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
1981 "uA_load=%d) failed. rc=%d\n", __func__,
1982 vreg->name, uA_load, rc);
1983 else
1984 /* regulator_set_optimum_mode() can return non zero
1985 * value even for success case.
1986 */
1987 rc = 0;
1988 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001989
1990 return rc;
1991}
1992
1993static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1994 struct device *dev)
1995{
1996 int rc = 0;
1997
1998 /* check if regulator is already initialized? */
1999 if (vreg->reg)
2000 goto out;
2001
2002 /* Get the regulator handle */
2003 vreg->reg = regulator_get(dev, vreg->name);
2004 if (IS_ERR(vreg->reg)) {
2005 rc = PTR_ERR(vreg->reg);
2006 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
2007 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002008 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002009 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002010
2011 if (regulator_count_voltages(vreg->reg) > 0)
2012 vreg->set_voltage_sup = 1;
2013
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002014out:
2015 return rc;
2016}
2017
2018static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
2019{
2020 if (vreg->reg)
2021 regulator_put(vreg->reg);
2022}
2023
2024/* This init function should be called only once for each SDCC slot */
2025static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
2026{
2027 int rc = 0;
2028 struct msm_mmc_slot_reg_data *curr_slot;
2029 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
2030 struct device *dev = mmc_dev(host->mmc);
2031
2032 curr_slot = host->plat->vreg_data;
2033 if (!curr_slot)
2034 goto out;
2035
2036 curr_vdd_reg = curr_slot->vdd_data;
2037 curr_vccq_reg = curr_slot->vccq_data;
2038 curr_vddp_reg = curr_slot->vddp_data;
2039
2040 if (is_init) {
2041 /*
2042 * Get the regulator handle from voltage regulator framework
2043 * and then try to set the voltage level for the regulator
2044 */
2045 if (curr_vdd_reg) {
2046 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
2047 if (rc)
2048 goto out;
2049 }
2050 if (curr_vccq_reg) {
2051 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
2052 if (rc)
2053 goto vdd_reg_deinit;
2054 }
2055 if (curr_vddp_reg) {
2056 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
2057 if (rc)
2058 goto vccq_reg_deinit;
2059 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002060 rc = msmsdcc_vreg_reset(host);
2061 if (rc)
2062 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
2063 host->pdev_id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002064 goto out;
2065 } else {
2066 /* Deregister all regulators from regulator framework */
2067 goto vddp_reg_deinit;
2068 }
2069vddp_reg_deinit:
2070 if (curr_vddp_reg)
2071 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
2072vccq_reg_deinit:
2073 if (curr_vccq_reg)
2074 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
2075vdd_reg_deinit:
2076 if (curr_vdd_reg)
2077 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2078out:
2079 return rc;
2080}
2081
2082static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2083{
2084 int rc = 0;
2085
Subhash Jadavanicc922692011-08-01 23:05:01 +05302086 /* Put regulator in HPM (high power mode) */
2087 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2088 if (rc < 0)
2089 goto out;
2090
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002091 if (!vreg->is_enabled) {
2092 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302093 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2094 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002095 if (rc)
2096 goto out;
2097
2098 rc = regulator_enable(vreg->reg);
2099 if (rc) {
2100 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2101 __func__, vreg->name, rc);
2102 goto out;
2103 }
2104 vreg->is_enabled = true;
2105 }
2106
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002107out:
2108 return rc;
2109}
2110
2111static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
2112{
2113 int rc = 0;
2114
2115 /* Never disable regulator marked as always_on */
2116 if (vreg->is_enabled && !vreg->always_on) {
2117 rc = regulator_disable(vreg->reg);
2118 if (rc) {
2119 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2120 __func__, vreg->name, rc);
2121 goto out;
2122 }
2123 vreg->is_enabled = false;
2124
2125 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2126 if (rc < 0)
2127 goto out;
2128
2129 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302130 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002131 if (rc)
2132 goto out;
2133 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
2134 /* Put always_on regulator in LPM (low power mode) */
2135 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2136 if (rc < 0)
2137 goto out;
2138 }
2139out:
2140 return rc;
2141}
2142
2143static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
2144{
2145 int rc = 0, i;
2146 struct msm_mmc_slot_reg_data *curr_slot;
2147 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
2148 struct msm_mmc_reg_data *vreg_table[3];
2149
2150 curr_slot = host->plat->vreg_data;
2151 if (!curr_slot)
2152 goto out;
2153
2154 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
2155 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
2156 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
2157
2158 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2159 if (vreg_table[i]) {
2160 if (enable)
2161 rc = msmsdcc_vreg_enable(vreg_table[i]);
2162 else
2163 rc = msmsdcc_vreg_disable(vreg_table[i]);
2164 if (rc)
2165 goto out;
2166 }
2167 }
2168out:
2169 return rc;
2170}
2171
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002172/*
2173 * Reset vreg by ensuring it is off during probe. A call
2174 * to enable vreg is needed to balance disable vreg
2175 */
2176static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2177{
2178 int rc;
2179
2180 rc = msmsdcc_setup_vreg(host, 1);
2181 if (rc)
2182 return rc;
2183 rc = msmsdcc_setup_vreg(host, 0);
2184 return rc;
2185}
2186
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302187static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002188{
2189 int rc = 0;
2190
2191 if (host->plat->vreg_data) {
2192 struct msm_mmc_reg_data *vddp_reg =
2193 host->plat->vreg_data->vddp_data;
2194
2195 if (vddp_reg && vddp_reg->is_enabled)
2196 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
2197 }
2198
2199 return rc;
2200}
2201
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302202static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
2203{
2204 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2205 int rc = 0;
2206
2207 if (curr_slot && curr_slot->vddp_data) {
2208 rc = msmsdcc_set_vddp_level(host,
2209 curr_slot->vddp_data->low_vol_level);
2210
2211 if (rc)
2212 pr_err("%s: %s: failed to change vddp level to %d",
2213 mmc_hostname(host->mmc), __func__,
2214 curr_slot->vddp_data->low_vol_level);
2215 }
2216
2217 return rc;
2218}
2219
2220static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
2221{
2222 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2223 int rc = 0;
2224
2225 if (curr_slot && curr_slot->vddp_data) {
2226 rc = msmsdcc_set_vddp_level(host,
2227 curr_slot->vddp_data->high_vol_level);
2228
2229 if (rc)
2230 pr_err("%s: %s: failed to change vddp level to %d",
2231 mmc_hostname(host->mmc), __func__,
2232 curr_slot->vddp_data->high_vol_level);
2233 }
2234
2235 return rc;
2236}
2237
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302238static inline int msmsdcc_set_vccq_vol(struct msmsdcc_host *host, int level)
2239{
2240 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2241 int rc = 0;
2242
2243 if (curr_slot && curr_slot->vccq_data) {
2244 rc = msmsdcc_vreg_set_voltage(curr_slot->vccq_data,
2245 level, level);
2246 if (rc)
2247 pr_err("%s: %s: failed to change vccq level to %d",
2248 mmc_hostname(host->mmc), __func__, level);
2249 }
2250
2251 return rc;
2252}
2253
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002254static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2255{
2256 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2257 return 1;
2258 return 0;
2259}
2260
Asutosh Dasf5298c32012-04-03 14:51:47 +05302261/*
2262 * Any function calling msmsdcc_setup_clocks must
2263 * acquire clk_mutex. May sleep.
2264 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002265static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
2266{
2267 if (enable) {
2268 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302269 clk_prepare_enable(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002270 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302271 clk_prepare_enable(host->pclk);
2272 clk_prepare_enable(host->clk);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302273 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302274 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002275 } else {
Subhash Jadavanidd432952012-03-28 11:25:56 +05302276 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302277 msmsdcc_delay(host);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302278 clk_disable_unprepare(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002279 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302280 clk_disable_unprepare(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002281 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302282 clk_disable_unprepare(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002283 }
2284}
2285
2286static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2287 unsigned int req_clk)
2288{
2289 unsigned int sel_clk = -1;
2290
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302291 if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
2292 sel_clk = msmsdcc_get_min_sup_clk_rate(host);
2293 goto out;
2294 }
2295
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002296 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2297 unsigned char cnt;
2298
2299 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2300 if (host->plat->sup_clk_table[cnt] > req_clk)
2301 break;
2302 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2303 sel_clk = host->plat->sup_clk_table[cnt];
2304 break;
2305 } else
2306 sel_clk = host->plat->sup_clk_table[cnt];
2307 }
2308 } else {
2309 if ((req_clk < host->plat->msmsdcc_fmax) &&
2310 (req_clk > host->plat->msmsdcc_fmid))
2311 sel_clk = host->plat->msmsdcc_fmid;
2312 else
2313 sel_clk = req_clk;
2314 }
2315
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302316out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002317 return sel_clk;
2318}
2319
2320static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2321 struct msmsdcc_host *host)
2322{
2323 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2324 return host->plat->sup_clk_table[0];
2325 else
2326 return host->plat->msmsdcc_fmin;
2327}
2328
2329static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2330 struct msmsdcc_host *host)
2331{
2332 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2333 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2334 else
2335 return host->plat->msmsdcc_fmax;
2336}
2337
2338static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302339{
2340 struct msm_mmc_gpio_data *curr;
2341 int i, rc = 0;
2342
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002343 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302344 for (i = 0; i < curr->size; i++) {
2345 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002346 if (curr->gpio[i].is_always_on &&
2347 curr->gpio[i].is_enabled)
2348 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302349 rc = gpio_request(curr->gpio[i].no,
2350 curr->gpio[i].name);
2351 if (rc) {
2352 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2353 mmc_hostname(host->mmc),
2354 curr->gpio[i].no,
2355 curr->gpio[i].name, rc);
2356 goto free_gpios;
2357 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002358 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302359 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002360 if (curr->gpio[i].is_always_on)
2361 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302362 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002363 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302364 }
2365 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002366 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302367
2368free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002369 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302370 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002371 curr->gpio[i].is_enabled = false;
2372 }
2373out:
2374 return rc;
2375}
2376
2377static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2378{
2379 struct msm_mmc_pad_data *curr;
2380 int i;
2381
2382 curr = host->plat->pin_data->pad_data;
2383 for (i = 0; i < curr->drv->size; i++) {
2384 if (enable)
2385 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2386 curr->drv->on[i].val);
2387 else
2388 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2389 curr->drv->off[i].val);
2390 }
2391
2392 for (i = 0; i < curr->pull->size; i++) {
2393 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002394 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002395 curr->pull->on[i].val);
2396 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002397 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002398 curr->pull->off[i].val);
2399 }
2400
2401 return 0;
2402}
2403
2404static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2405{
2406 int rc = 0;
2407
2408 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2409 return 0;
2410
2411 if (host->plat->pin_data->is_gpio)
2412 rc = msmsdcc_setup_gpio(host, enable);
2413 else
2414 rc = msmsdcc_setup_pad(host, enable);
2415
2416 if (!rc)
2417 host->plat->pin_data->cfg_sts = enable;
2418
2419 return rc;
2420}
2421
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302422static int msmsdcc_cfg_mpm_sdiowakeup(struct msmsdcc_host *host,
2423 unsigned mode)
2424{
2425 int ret = 0;
2426 unsigned int pin = host->plat->mpm_sdiowakeup_int;
2427
2428 if (!pin)
2429 return 0;
2430
2431 switch (mode) {
2432 case SDC_DAT1_DISABLE:
2433 ret = msm_mpm_enable_pin(pin, 0);
2434 break;
2435 case SDC_DAT1_ENABLE:
2436 ret = msm_mpm_set_pin_type(pin, IRQ_TYPE_LEVEL_LOW);
2437 ret = msm_mpm_enable_pin(pin, 1);
2438 break;
2439 case SDC_DAT1_ENWAKE:
2440 ret = msm_mpm_set_pin_wake(pin, 1);
2441 break;
2442 case SDC_DAT1_DISWAKE:
2443 ret = msm_mpm_set_pin_wake(pin, 0);
2444 break;
2445 default:
2446 ret = -EINVAL;
2447 break;
2448 }
2449
2450 return ret;
2451}
2452
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302453static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2454{
2455 u32 pwr = 0;
2456 int ret = 0;
2457 struct mmc_host *mmc = host->mmc;
2458
2459 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2460 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2461 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2462 ret = msmsdcc_setup_vreg(host, !!ios->vdd);
2463
2464 if (ret) {
2465 pr_err("%s: Failed to setup voltage regulators\n",
2466 mmc_hostname(host->mmc));
2467 goto out;
2468 }
2469
2470 switch (ios->power_mode) {
2471 case MMC_POWER_OFF:
2472 pwr = MCI_PWR_OFF;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302473 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302474 /*
2475 * As VDD pad rail is always on, set low voltage for VDD
2476 * pad rail when slot is unused (when card is not present
2477 * or during system suspend).
2478 */
2479 msmsdcc_set_vddp_low_vol(host);
2480 msmsdcc_setup_pins(host, false);
2481 break;
2482 case MMC_POWER_UP:
2483 /* writing PWR_UP bit is redundant */
2484 pwr = MCI_PWR_UP;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302485 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302486
2487 msmsdcc_set_vddp_high_vol(host);
2488 msmsdcc_setup_pins(host, true);
2489 break;
2490 case MMC_POWER_ON:
2491 pwr = MCI_PWR_ON;
2492 break;
2493 }
2494
2495out:
2496 return pwr;
2497}
2498
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002499static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2500{
2501 unsigned int wakeup_irq;
2502
2503 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2504 host->plat->sdiowakeup_irq :
2505 host->core_irqres->start;
2506
2507 if (!host->irq_wake_enabled) {
2508 enable_irq_wake(wakeup_irq);
2509 host->irq_wake_enabled = true;
2510 }
2511}
2512
2513static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2514{
2515 unsigned int wakeup_irq;
2516
2517 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2518 host->plat->sdiowakeup_irq :
2519 host->core_irqres->start;
2520
2521 if (host->irq_wake_enabled) {
2522 disable_irq_wake(wakeup_irq);
2523 host->irq_wake_enabled = false;
2524 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302525}
2526
San Mehat9d2bd732009-09-22 16:44:22 -07002527static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302528msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
2529{
2530 struct mmc_host *mmc = host->mmc;
2531
2532 /*
2533 * SDIO_AL clients has different mechanism of handling LPM through
2534 * sdio_al driver itself. The sdio wakeup interrupt is configured as
2535 * part of that. Here, we are interested only in clients like WLAN.
2536 */
2537 if (!(mmc->card && mmc_card_sdio(mmc->card))
2538 || host->plat->is_sdio_al_client)
2539 goto out;
2540
2541 if (!host->sdcc_suspended) {
2542 /*
2543 * When MSM is not in power collapse and we
2544 * are disabling clocks, enable bit 22 in MASK0
2545 * to handle asynchronous SDIO interrupts.
2546 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302547 if (enable_wakeup_irq) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302548 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302549 mb();
2550 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302551 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302552 msmsdcc_sync_reg_wr(host);
2553 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302554 goto out;
2555 } else if (!mmc_card_wake_sdio_irq(mmc)) {
2556 /*
2557 * Wakeup MSM only if SDIO function drivers set
2558 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
2559 */
2560 goto out;
2561 }
2562
2563 if (enable_wakeup_irq) {
2564 if (!host->plat->sdiowakeup_irq) {
2565 /*
2566 * When there is no gpio line that can be configured
2567 * as wakeup interrupt handle it by configuring
2568 * asynchronous sdio interrupts and DAT1 line.
2569 */
2570 writel_relaxed(MCI_SDIOINTMASK,
2571 host->base + MMCIMASK0);
2572 mb();
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302573 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302574 /* configure sdcc core interrupt as wakeup interrupt */
2575 msmsdcc_enable_irq_wake(host);
2576 } else {
2577 /* Let gpio line handle wakeup interrupt */
2578 writel_relaxed(0, host->base + MMCIMASK0);
2579 mb();
2580 if (host->sdio_wakeupirq_disabled) {
2581 host->sdio_wakeupirq_disabled = 0;
2582 /* configure gpio line as wakeup interrupt */
2583 msmsdcc_enable_irq_wake(host);
2584 enable_irq(host->plat->sdiowakeup_irq);
2585 }
2586 }
2587 } else {
2588 if (!host->plat->sdiowakeup_irq) {
2589 /*
2590 * We may not have cleared bit 22 in the interrupt
2591 * handler as the clocks might be off at that time.
2592 */
2593 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302594 msmsdcc_sync_reg_wr(host);
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302595 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302596 msmsdcc_disable_irq_wake(host);
2597 } else if (!host->sdio_wakeupirq_disabled) {
2598 disable_irq_nosync(host->plat->sdiowakeup_irq);
2599 msmsdcc_disable_irq_wake(host);
2600 host->sdio_wakeupirq_disabled = 1;
2601 }
2602 }
2603out:
2604 return;
2605}
2606
2607static void
San Mehat9d2bd732009-09-22 16:44:22 -07002608msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2609{
2610 struct msmsdcc_host *host = mmc_priv(mmc);
2611 u32 clk = 0, pwr = 0;
2612 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002613 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002614 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002615
Sahitya Tummala7a892482011-01-18 11:22:49 +05302616
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302617 /*
2618 * Disable SDCC core interrupt until set_ios is completed.
2619 * This avoids any race conditions with interrupt raised
2620 * when turning on/off the clocks. One possible
2621 * scenario is SDIO operational interrupt while the clock
2622 * is turned off.
Asutosh Dasf5298c32012-04-03 14:51:47 +05302623 * host->lock is being released intermittently below.
2624 * Thus, prevent concurrent access to host.
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302625 */
2626
Asutosh Dasf5298c32012-04-03 14:51:47 +05302627 mutex_lock(&host->clk_mutex);
2628 DBG(host, "ios->clock = %u\n", ios->clock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302629 spin_lock_irqsave(&host->lock, flags);
2630 if (!host->sdcc_irq_disabled) {
2631 spin_unlock_irqrestore(&host->lock, flags);
2632 disable_irq(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002633 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302634 host->sdcc_irq_disabled = 1;
2635 }
2636 spin_unlock_irqrestore(&host->lock, flags);
2637
2638 pwr = msmsdcc_setup_pwr(host, ios);
2639
2640 spin_lock_irqsave(&host->lock, flags);
2641 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002642 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302643 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002644 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302645 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002646 host->clks_on = 1;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302647 writel_relaxed(host->mci_irqenable,
2648 host->base + MMCIMASK0);
2649 mb();
2650 msmsdcc_cfg_sdio_wakeup(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002651 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002652
2653 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2654 /*
2655 * For DDR50 mode, controller needs clock rate to be
2656 * double than what is required on the SD card CLK pin.
2657 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302658 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002659 /*
2660 * Make sure that we don't double the clock if
2661 * doubled clock rate is already set
2662 */
2663 if (!host->ddr_doubled_clk_rate ||
2664 (host->ddr_doubled_clk_rate &&
2665 (host->ddr_doubled_clk_rate != ios->clock))) {
2666 host->ddr_doubled_clk_rate =
2667 msmsdcc_get_sup_clk_rate(
2668 host, (ios->clock * 2));
2669 clock = host->ddr_doubled_clk_rate;
2670 }
2671 } else {
2672 host->ddr_doubled_clk_rate = 0;
2673 }
2674
2675 if (clock != host->clk_rate) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302676 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002677 rc = clk_set_rate(host->clk, clock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302678 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002679 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302680 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002681 mmc_hostname(mmc), clock);
2682 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302683 host->reg_write_delay =
2684 (1 + ((3 * USEC_PER_SEC) /
2685 (host->clk_rate ? host->clk_rate :
2686 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002687 }
2688 /*
2689 * give atleast 2 MCLK cycles delay for clocks
2690 * and SDCC core to stabilize
2691 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302692 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002693 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002694 clk |= MCI_CLK_ENABLE;
2695 }
2696
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002697 if (ios->bus_width == MMC_BUS_WIDTH_8)
2698 clk |= MCI_CLK_WIDEBUS_8;
2699 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2700 clk |= MCI_CLK_WIDEBUS_4;
2701 else
2702 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002703
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002704 if (msmsdcc_is_pwrsave(host))
2705 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002706
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002707 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002708
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002709 host->tuning_needed = 0;
2710 /*
2711 * Select the controller timing mode according
2712 * to current bus speed mode
2713 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302714 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2715 (ios->timing == MMC_TIMING_MMC_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002716 clk |= (4 << 14);
2717 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302718 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002719 clk |= (3 << 14);
2720 } else {
2721 clk |= (2 << 14); /* feedback clock */
2722 }
2723
2724 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2725 clk |= (2 << 23);
2726
Subhash Jadavani00083572012-02-15 16:18:01 +05302727 /* Clear IO_PAD_PWR_SWITCH while powering off the card */
2728 if (!ios->vdd)
2729 host->io_pad_pwr_switch = 0;
2730
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002731 if (host->io_pad_pwr_switch)
2732 clk |= IO_PAD_PWR_SWITCH;
2733
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302734 /* Don't write into registers if clocks are disabled */
2735 if (host->clks_on) {
2736 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
2737 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302738 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002739 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302740 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
2741 host->pwr = pwr;
2742 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302743 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002744 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002745 }
2746
2747 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302748 msmsdcc_cfg_sdio_wakeup(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302749 spin_unlock_irqrestore(&host->lock, flags);
2750 /*
2751 * May get a wake-up interrupt the instant we disable the
2752 * clocks. This would disable the wake-up interrupt.
2753 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002754 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302755 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002756 host->clks_on = 0;
2757 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302758
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302759 if (host->tuning_in_progress)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302760 WARN(!host->clks_on,
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302761 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302762
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302763 /* Let interrupts be disabled if the host is powered off */
2764 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
2765 enable_irq(host->core_irqres->start);
2766 host->sdcc_irq_disabled = 0;
2767 }
2768
San Mehat4adbbcc2009-11-08 13:00:37 -08002769 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302770 mutex_unlock(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07002771}
2772
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002773int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2774{
2775 struct msmsdcc_host *host = mmc_priv(mmc);
2776 u32 clk;
2777
2778 clk = readl_relaxed(host->base + MMCICLOCK);
2779 pr_debug("Changing to pwr_save=%d", pwrsave);
2780 if (pwrsave && msmsdcc_is_pwrsave(host))
2781 clk |= MCI_CLK_PWRSAVE;
2782 else
2783 clk &= ~MCI_CLK_PWRSAVE;
2784 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302785 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002786
2787 return 0;
2788}
2789
2790static int msmsdcc_get_ro(struct mmc_host *mmc)
2791{
2792 int status = -ENOSYS;
2793 struct msmsdcc_host *host = mmc_priv(mmc);
2794
2795 if (host->plat->wpswitch) {
2796 status = host->plat->wpswitch(mmc_dev(mmc));
2797 } else if (host->plat->wpswitch_gpio) {
2798 status = gpio_request(host->plat->wpswitch_gpio,
2799 "SD_WP_Switch");
2800 if (status) {
2801 pr_err("%s: %s: Failed to request GPIO %d\n",
2802 mmc_hostname(mmc), __func__,
2803 host->plat->wpswitch_gpio);
2804 } else {
2805 status = gpio_direction_input(
2806 host->plat->wpswitch_gpio);
2807 if (!status) {
2808 /*
2809 * Wait for atleast 300ms as debounce
2810 * time for GPIO input to stabilize.
2811 */
2812 msleep(300);
2813 status = gpio_get_value_cansleep(
2814 host->plat->wpswitch_gpio);
2815 status ^= !host->plat->wpswitch_polarity;
2816 }
2817 gpio_free(host->plat->wpswitch_gpio);
2818 }
2819 }
2820
2821 if (status < 0)
2822 status = -ENOSYS;
2823 pr_debug("%s: Card read-only status %d\n", __func__, status);
2824
2825 return status;
2826}
2827
San Mehat9d2bd732009-09-22 16:44:22 -07002828static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2829{
2830 struct msmsdcc_host *host = mmc_priv(mmc);
2831 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002832
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302833 /*
2834 * We may come here with clocks turned off in that case don't
2835 * attempt to write into MASK0 register. While turning on the
2836 * clocks mci_irqenable will be written to MASK0 register.
2837 */
2838
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002839 if (enable) {
2840 spin_lock_irqsave(&host->lock, flags);
2841 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302842 if (host->clks_on) {
2843 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002844 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302845 mb();
2846 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002847 spin_unlock_irqrestore(&host->lock, flags);
2848 } else {
2849 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302850 if (host->clks_on) {
2851 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002852 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302853 mb();
2854 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002855 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002856}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002857
2858#ifdef CONFIG_PM_RUNTIME
subhashj245831e2012-04-30 18:46:17 +05302859static void msmsdcc_print_rpm_info(struct msmsdcc_host *host)
2860{
2861 struct device *dev = mmc_dev(host->mmc);
2862
2863 pr_info("%s: RPM: runtime_status=%d, usage_count=%d,"
2864 " is_suspended=%d, disable_depth=%d, runtime_error=%d,"
2865 " request_pending=%d, request=%d\n",
2866 mmc_hostname(host->mmc), dev->power.runtime_status,
2867 atomic_read(&dev->power.usage_count),
2868 dev->power.is_suspended, dev->power.disable_depth,
2869 dev->power.runtime_error, dev->power.request_pending,
2870 dev->power.request);
2871}
2872
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002873static int msmsdcc_enable(struct mmc_host *mmc)
2874{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002875 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002876 struct device *dev = mmc->parent;
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302877 struct msmsdcc_host *host = mmc_priv(mmc);
2878
2879 msmsdcc_pm_qos_update_latency(host, 1);
2880
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002881 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302882 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002883
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002884 if (host->sdcc_suspended && host->pending_resume &&
2885 !pm_runtime_suspended(dev)) {
2886 host->pending_resume = false;
2887 pm_runtime_get_noresume(dev);
2888 rc = msmsdcc_runtime_resume(dev);
2889 goto out;
2890 }
2891
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302892 if (dev->power.runtime_status == RPM_SUSPENDING) {
2893 if (mmc->suspend_task == current) {
2894 pm_runtime_get_noresume(dev);
2895 goto out;
2896 }
2897 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002898
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302899 rc = pm_runtime_get_sync(dev);
2900
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002901out:
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302902 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002903 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2904 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05302905 msmsdcc_print_rpm_info(host);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302906 return rc;
2907 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302908
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302909 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002910}
2911
2912static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2913{
2914 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302915 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002916
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302917 msmsdcc_pm_qos_update_latency(host, 0);
2918
2919 if (mmc->card && mmc_card_sdio(mmc->card))
2920 return 0;
2921
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302922 if (host->plat->disable_runtime_pm)
2923 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002924
2925 rc = pm_runtime_put_sync(mmc->parent);
2926
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002927 /*
2928 * Ignore -EAGAIN as that is not fatal, it means that
2929 * either runtime usage count is non-zero or the runtime
2930 * pm itself is disabled or not in proper state to process
2931 * idle notification.
2932 */
2933 if (rc < 0 && (rc != -EAGAIN)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002934 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2935 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05302936 msmsdcc_print_rpm_info(host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002937 return rc;
2938 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302939
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002940 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002941}
2942#else
subhashj245831e2012-04-30 18:46:17 +05302943static void msmsdcc_print_rpm_info(struct msmsdcc_host *host) {}
2944
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302945static int msmsdcc_enable(struct mmc_host *mmc)
2946{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002947 struct device *dev = mmc->parent;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302948 struct msmsdcc_host *host = mmc_priv(mmc);
2949 unsigned long flags;
Sujit Reddy Thumma7f5051c2012-05-04 10:14:07 +05302950 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302951
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302952 msmsdcc_pm_qos_update_latency(host, 1);
2953
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002954 if (mmc->card && mmc_card_sdio(mmc->card))
2955 return 0;
2956
2957 if (host->sdcc_suspended && host->pending_resume) {
2958 host->pending_resume = false;
2959 rc = msmsdcc_runtime_resume(dev);
2960 goto out;
2961 }
2962
Asutosh Dasf5298c32012-04-03 14:51:47 +05302963 mutex_lock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302964 spin_lock_irqsave(&host->lock, flags);
2965 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302966 spin_unlock_irqrestore(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302967 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302968 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302969 host->clks_on = 1;
2970 }
2971 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302972 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302973
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002974out:
2975 if (rc < 0) {
2976 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2977 __func__, rc);
2978 return rc;
2979 }
2980
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302981 return 0;
2982}
2983
2984static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2985{
2986 struct msmsdcc_host *host = mmc_priv(mmc);
2987 unsigned long flags;
2988
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302989 msmsdcc_pm_qos_update_latency(host, 0);
2990
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302991 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302992 return 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302993
Asutosh Dasf5298c32012-04-03 14:51:47 +05302994 mutex_lock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302995 spin_lock_irqsave(&host->lock, flags);
2996 if (host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302997 spin_unlock_irqrestore(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302998 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302999 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303000 host->clks_on = 0;
3001 }
3002 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303003 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303004
3005 return 0;
3006}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003007#endif
3008
3009static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
3010 struct mmc_ios *ios)
3011{
3012 struct msmsdcc_host *host = mmc_priv(mmc);
3013 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303014 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003015
Subhash Jadavani00083572012-02-15 16:18:01 +05303016 spin_lock_irqsave(&host->lock, flags);
3017 host->io_pad_pwr_switch = 0;
3018 spin_unlock_irqrestore(&host->lock, flags);
3019
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303020 /*
3021 * For eMMC cards, VccQ voltage range must be changed
3022 * only if it operates in HS200 SDR 1.2V mode or in
3023 * DDR 1.2V mode.
3024 */
3025 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_120) {
3026 rc = msmsdcc_set_vccq_vol(host, 1200000);
3027 goto out;
3028 }
3029
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003030 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
3031 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303032 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003033 goto out;
3034 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
3035 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303036 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003037 goto out;
3038 }
San Mehat9d2bd732009-09-22 16:44:22 -07003039
3040 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003041 /*
3042 * If we are here means voltage switch from high voltage to
3043 * low voltage is required
3044 */
3045
3046 /*
3047 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
3048 * register until they become all zeros.
3049 */
3050 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303051 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003052 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
3053 mmc_hostname(mmc), __func__);
3054 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07003055 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003056
3057 /* Stop SD CLK output. */
3058 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3059 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303060 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003061 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003062
3063 /*
3064 * Switch VDDPX from high voltage to low voltage
3065 * to change the VDD of the SD IO pads.
3066 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303067 rc = msmsdcc_set_vddp_low_vol(host);
3068 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003069 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003070
3071 spin_lock_irqsave(&host->lock, flags);
3072 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3073 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303074 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003075 host->io_pad_pwr_switch = 1;
3076 spin_unlock_irqrestore(&host->lock, flags);
3077
3078 /* Wait 5 ms for the voltage regulater in the card to become stable. */
3079 usleep_range(5000, 5500);
3080
3081 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303082 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003083 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3084 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303085 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003086 spin_unlock_irqrestore(&host->lock, flags);
3087
3088 /*
3089 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
3090 * don't become all ones within 1 ms then a Voltage Switch
3091 * sequence has failed and a power cycle to the card is required.
3092 * Otherwise Voltage Switch sequence is completed successfully.
3093 */
3094 usleep_range(1000, 1500);
3095
3096 spin_lock_irqsave(&host->lock, flags);
3097 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
3098 != (0xF << 1)) {
3099 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
3100 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303101 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003102 goto out_unlock;
3103 }
3104
3105out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303106 /* Enable PWRSAVE */
3107 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3108 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303109 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003110 spin_unlock_irqrestore(&host->lock, flags);
3111out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303112 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003113}
3114
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303115static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003116{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003117 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003118
3119 /* Program the MCLK value to MCLK_FREQ bit field */
3120 if (host->clk_rate <= 112000000)
3121 mclk_freq = 0;
3122 else if (host->clk_rate <= 125000000)
3123 mclk_freq = 1;
3124 else if (host->clk_rate <= 137000000)
3125 mclk_freq = 2;
3126 else if (host->clk_rate <= 150000000)
3127 mclk_freq = 3;
3128 else if (host->clk_rate <= 162000000)
3129 mclk_freq = 4;
3130 else if (host->clk_rate <= 175000000)
3131 mclk_freq = 5;
3132 else if (host->clk_rate <= 187000000)
3133 mclk_freq = 6;
3134 else if (host->clk_rate <= 200000000)
3135 mclk_freq = 7;
3136
3137 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3138 & ~(7 << 24)) | (mclk_freq << 24)),
3139 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003140}
3141
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303142/* Initialize the DLL (Programmable Delay Line ) */
3143static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003144{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003145 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303146 unsigned long flags;
3147 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003148
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303149 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003150 /*
3151 * Make sure that clock is always enabled when DLL
3152 * tuning is in progress. Keeping PWRSAVE ON may
3153 * turn off the clock. So let's disable the PWRSAVE
3154 * here and re-enable it once tuning is completed.
3155 */
3156 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3157 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303158 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303159
3160 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3161 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3162 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3163
3164 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3165 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3166 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3167
3168 msmsdcc_cm_sdc4_dll_set_freq(host);
3169
3170 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3171 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3172 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3173
3174 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3175 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3176 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3177
3178 /* Set DLL_EN bit to 1. */
3179 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3180 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3181
3182 /* Set CK_OUT_EN bit to 1. */
3183 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3184 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3185
3186 wait_cnt = 50;
3187 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3188 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3189 /* max. wait for 50us sec for LOCK bit to be set */
3190 if (--wait_cnt == 0) {
3191 pr_err("%s: %s: DLL failed to LOCK\n",
3192 mmc_hostname(host->mmc), __func__);
3193 rc = -ETIMEDOUT;
3194 goto out;
3195 }
3196 /* wait for 1us before polling again */
3197 udelay(1);
3198 }
3199
3200out:
3201 /* re-enable PWRSAVE */
3202 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3203 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303204 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303205 spin_unlock_irqrestore(&host->lock, flags);
3206
3207 return rc;
3208}
3209
3210static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3211 u8 poll)
3212{
3213 int rc = 0;
3214 u32 wait_cnt = 50;
3215 u8 ck_out_en = 0;
3216
3217 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3218 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3219 MCI_CK_OUT_EN);
3220
3221 while (ck_out_en != poll) {
3222 if (--wait_cnt == 0) {
3223 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3224 mmc_hostname(host->mmc), __func__, poll);
3225 rc = -ETIMEDOUT;
3226 goto out;
3227 }
3228 udelay(1);
3229
3230 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3231 MCI_CK_OUT_EN);
3232 }
3233out:
3234 return rc;
3235}
3236
3237/*
3238 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3239 * calibration sequence. This function should be called before
3240 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3241 * commands (CMD17/CMD18).
3242 *
3243 * This function gets called when host spinlock acquired.
3244 */
3245static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3246{
3247 int rc = 0;
3248 u32 config;
3249
3250 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3251 config |= MCI_CDR_EN;
3252 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3253 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3254
3255 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3256 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3257 if (rc)
3258 goto err_out;
3259
3260 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3261 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3262 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3263
3264 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3265 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3266 if (rc)
3267 goto err_out;
3268
3269 goto out;
3270
3271err_out:
3272 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3273out:
3274 return rc;
3275}
3276
3277static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3278 u8 phase)
3279{
3280 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303281 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3282 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3283 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303284 unsigned long flags;
3285 u32 config;
3286
3287 spin_lock_irqsave(&host->lock, flags);
3288
3289 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3290 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3291 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3292 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3293
3294 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3295 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3296 if (rc)
3297 goto err_out;
3298
3299 /*
3300 * Write the selected DLL clock output phase (0 ... 15)
3301 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
3302 */
3303 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3304 & ~(0xF << 20))
3305 | (grey_coded_phase_table[phase] << 20)),
3306 host->base + MCI_DLL_CONFIG);
3307
3308 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3309 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3310 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3311
3312 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3313 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3314 if (rc)
3315 goto err_out;
3316
3317 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3318 config |= MCI_CDR_EN;
3319 config &= ~MCI_CDR_EXT_EN;
3320 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3321 goto out;
3322
3323err_out:
3324 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3325 mmc_hostname(host->mmc), __func__, phase);
3326out:
3327 spin_unlock_irqrestore(&host->lock, flags);
3328 return rc;
3329}
3330
3331/*
3332 * Find out the greatest range of consecuitive selected
3333 * DLL clock output phases that can be used as sampling
3334 * setting for SD3.0 UHS-I card read operation (in SDR104
3335 * timing mode) or for eMMC4.5 card read operation (in HS200
3336 * timing mode).
3337 * Select the 3/4 of the range and configure the DLL with the
3338 * selected DLL clock output phase.
3339*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303340static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303341 u8 *phase_table, u8 total_phases)
3342{
Subhash Jadavani6159c622012-03-15 19:05:55 +05303343 #define MAX_PHASES 16
Subhash Jadavani34187042012-03-02 10:59:49 +05303344 int ret;
Subhash Jadavani6159c622012-03-15 19:05:55 +05303345 u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
3346 u8 phases_per_row[MAX_PHASES] = {0};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303347 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303348 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3349 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303350
Subhash Jadavani6159c622012-03-15 19:05:55 +05303351 if (!total_phases || (total_phases > MAX_PHASES)) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303352 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3353 mmc_hostname(host->mmc), __func__, total_phases);
3354 return -EINVAL;
3355 }
3356
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303357 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303358 ranges[row_index][col_index] = phase_table[cnt];
3359 phases_per_row[row_index] += 1;
3360 col_index++;
3361
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303362 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303363 continue;
3364 /* check if next phase in phase_table is consecutive or not */
3365 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3366 row_index++;
3367 col_index = 0;
3368 }
3369 }
3370
Subhash Jadavani6159c622012-03-15 19:05:55 +05303371 if (row_index >= MAX_PHASES)
3372 return -EINVAL;
3373
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303374 /* Check if phase-0 is present in first valid window? */
3375 if (!ranges[0][0]) {
3376 phase_0_found = true;
3377 phase_0_raw_index = 0;
3378 /* Check if cycle exist between 2 valid windows */
3379 for (cnt = 1; cnt <= row_index; cnt++) {
3380 if (phases_per_row[cnt]) {
Subhash Jadavani6159c622012-03-15 19:05:55 +05303381 for (i = 0; i < phases_per_row[cnt]; i++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303382 if (ranges[cnt][i] == 15) {
3383 phase_15_found = true;
3384 phase_15_raw_index = cnt;
3385 break;
3386 }
3387 }
3388 }
3389 }
3390 }
3391
3392 /* If 2 valid windows form cycle then merge them as single window */
3393 if (phase_0_found && phase_15_found) {
3394 /* number of phases in raw where phase 0 is present */
3395 u8 phases_0 = phases_per_row[phase_0_raw_index];
3396 /* number of phases in raw where phase 15 is present */
3397 u8 phases_15 = phases_per_row[phase_15_raw_index];
3398
Subhash Jadavani6159c622012-03-15 19:05:55 +05303399 if (phases_0 + phases_15 >= MAX_PHASES)
3400 /*
3401 * If there are more than 1 phase windows then total
3402 * number of phases in both the windows should not be
3403 * more than or equal to MAX_PHASES.
3404 */
3405 return -EINVAL;
3406
3407 /* Merge 2 cyclic windows */
3408 i = phases_15;
3409 for (cnt = 0; cnt < phases_0; cnt++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303410 ranges[phase_15_raw_index][i] =
3411 ranges[phase_0_raw_index][cnt];
Subhash Jadavani6159c622012-03-15 19:05:55 +05303412 if (++i >= MAX_PHASES)
3413 break;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303414 }
Subhash Jadavani6159c622012-03-15 19:05:55 +05303415
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303416 phases_per_row[phase_0_raw_index] = 0;
3417 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
3418 }
3419
3420 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303421 if (phases_per_row[cnt] > curr_max) {
3422 curr_max = phases_per_row[cnt];
3423 selected_row_index = cnt;
3424 }
3425 }
3426
Subhash Jadavani6159c622012-03-15 19:05:55 +05303427 i = ((curr_max * 3) / 4);
3428 if (i)
3429 i--;
3430
Subhash Jadavani34187042012-03-02 10:59:49 +05303431 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303432
Subhash Jadavani6159c622012-03-15 19:05:55 +05303433 if (ret >= MAX_PHASES) {
3434 ret = -EINVAL;
3435 pr_err("%s: %s: invalid phase selected=%d\n",
3436 mmc_hostname(host->mmc), __func__, ret);
3437 }
3438
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303439 return ret;
3440}
3441
Girish K Sa3f41692012-02-29 12:00:09 +05303442static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303443{
3444 int rc = 0;
3445 struct msmsdcc_host *host = mmc_priv(mmc);
3446 unsigned long flags;
3447 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303448 const u32 *tuning_block_pattern = tuning_block_64;
3449 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303450
3451 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
3452
3453 /* Tuning is only required for SDR104 modes */
3454 if (!host->tuning_needed) {
3455 rc = 0;
3456 goto exit;
3457 }
3458
3459 spin_lock_irqsave(&host->lock, flags);
3460 WARN(!host->pwr, "SDCC power is turned off\n");
3461 WARN(!host->clks_on, "SDCC clocks are turned off\n");
3462 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
3463
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303464 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303465 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
3466 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
3467 tuning_block_pattern = tuning_block_128;
3468 size = sizeof(tuning_block_128);
3469 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303470 spin_unlock_irqrestore(&host->lock, flags);
3471
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003472 /* first of all reset the tuning block */
3473 rc = msmsdcc_init_cm_sdc4_dll(host);
3474 if (rc)
3475 goto out;
3476
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303477 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003478 if (!data_buf) {
3479 rc = -ENOMEM;
3480 goto out;
3481 }
3482
3483 phase = 0;
3484 do {
3485 struct mmc_command cmd = {0};
3486 struct mmc_data data = {0};
3487 struct mmc_request mrq = {
3488 .cmd = &cmd,
3489 .data = &data
3490 };
3491 struct scatterlist sg;
3492
3493 /* set the phase in delay line hw block */
3494 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3495 if (rc)
3496 goto kfree;
3497
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303498 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003499 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
3500
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303501 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003502 data.blocks = 1;
3503 data.flags = MMC_DATA_READ;
3504 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
3505
3506 data.sg = &sg;
3507 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303508 sg_init_one(&sg, data_buf, size);
3509 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003510 mmc_wait_for_req(mmc, &mrq);
3511
3512 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303513 !memcmp(data_buf, tuning_block_pattern, size)) {
3514 /* tuning is successful at this tuning point */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003515 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303516 pr_debug("%s: %s: found good phase = %d\n",
3517 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003518 }
3519 } while (++phase < 16);
3520
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003521 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303522 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303523 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05303524 if (rc < 0)
3525 goto kfree;
3526 else
3527 phase = (u8)rc;
3528
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003529 /*
3530 * Finally set the selected phase in delay
3531 * line hw block.
3532 */
3533 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3534 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303535 goto kfree;
3536 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
3537 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003538 } else {
3539 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303540 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003541 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303542 msmsdcc_dump_sdcc_state(host);
3543 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003544 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003545
3546kfree:
3547 kfree(data_buf);
3548out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303549 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303550 host->tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303551 spin_unlock_irqrestore(&host->lock, flags);
3552exit:
3553 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003554 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07003555}
3556
3557static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003558 .enable = msmsdcc_enable,
3559 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07003560 .request = msmsdcc_request,
3561 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003562 .get_ro = msmsdcc_get_ro,
San Mehat9d2bd732009-09-22 16:44:22 -07003563 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003564 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
3565 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07003566};
3567
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003568static unsigned int
3569msmsdcc_slot_status(struct msmsdcc_host *host)
3570{
3571 int status;
3572 unsigned int gpio_no = host->plat->status_gpio;
3573
3574 status = gpio_request(gpio_no, "SD_HW_Detect");
3575 if (status) {
3576 pr_err("%s: %s: Failed to request GPIO %d\n",
3577 mmc_hostname(host->mmc), __func__, gpio_no);
3578 } else {
3579 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003580 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08003581 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003582 if (host->plat->is_status_gpio_active_low)
3583 status = !status;
3584 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003585 gpio_free(gpio_no);
3586 }
3587 return status;
3588}
3589
San Mehat9d2bd732009-09-22 16:44:22 -07003590static void
3591msmsdcc_check_status(unsigned long data)
3592{
3593 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3594 unsigned int status;
3595
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003596 if (host->plat->status || host->plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08003597 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003598 status = host->plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08003599 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003600 status = msmsdcc_slot_status(host);
3601
Krishna Konda941604a2012-01-10 17:46:34 -08003602 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08003603
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003604 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08003605 if (host->plat->status)
3606 pr_info("%s: Slot status change detected "
3607 "(%d -> %d)\n",
3608 mmc_hostname(host->mmc),
3609 host->oldstat, status);
3610 else if (host->plat->is_status_gpio_active_low)
3611 pr_info("%s: Slot status change detected "
3612 "(%d -> %d) and the card detect GPIO"
3613 " is ACTIVE_LOW\n",
3614 mmc_hostname(host->mmc),
3615 host->oldstat, status);
3616 else
3617 pr_info("%s: Slot status change detected "
3618 "(%d -> %d) and the card detect GPIO"
3619 " is ACTIVE_HIGH\n",
3620 mmc_hostname(host->mmc),
3621 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07003622 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003623 }
3624 host->oldstat = status;
3625 } else {
3626 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07003627 }
San Mehat9d2bd732009-09-22 16:44:22 -07003628}
3629
3630static irqreturn_t
3631msmsdcc_platform_status_irq(int irq, void *dev_id)
3632{
3633 struct msmsdcc_host *host = dev_id;
3634
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003635 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07003636 msmsdcc_check_status((unsigned long) host);
3637 return IRQ_HANDLED;
3638}
3639
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003640static irqreturn_t
3641msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
3642{
3643 struct msmsdcc_host *host = dev_id;
3644
3645 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
3646 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303647 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003648 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303649 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003650 wake_lock(&host->sdio_wlock);
3651 msmsdcc_disable_irq_wake(host);
3652 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303653 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003654 }
3655 if (host->plat->is_sdio_al_client) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003656 wake_lock(&host->sdio_wlock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303657 mmc_signal_sdio_irq(host->mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003658 }
3659 spin_unlock(&host->lock);
3660
3661 return IRQ_HANDLED;
3662}
3663
San Mehat9d2bd732009-09-22 16:44:22 -07003664static void
3665msmsdcc_status_notify_cb(int card_present, void *dev_id)
3666{
3667 struct msmsdcc_host *host = dev_id;
3668
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003669 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07003670 card_present);
3671 msmsdcc_check_status((unsigned long) host);
3672}
3673
San Mehat9d2bd732009-09-22 16:44:22 -07003674static int
3675msmsdcc_init_dma(struct msmsdcc_host *host)
3676{
3677 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
3678 host->dma.host = host;
3679 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003680 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003681
3682 if (!host->dmares)
3683 return -ENODEV;
3684
3685 host->dma.nc = dma_alloc_coherent(NULL,
3686 sizeof(struct msmsdcc_nc_dmadata),
3687 &host->dma.nc_busaddr,
3688 GFP_KERNEL);
3689 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003690 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07003691 return -ENOMEM;
3692 }
3693 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
3694 host->dma.cmd_busaddr = host->dma.nc_busaddr;
3695 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
3696 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
3697 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07003698 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07003699
3700 return 0;
3701}
3702
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003703#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
3704/**
3705 * Allocate and Connect a SDCC peripheral's SPS endpoint
3706 *
3707 * This function allocates endpoint context and
3708 * connect it with memory endpoint by calling
3709 * appropriate SPS driver APIs.
3710 *
3711 * Also registers a SPS callback function with
3712 * SPS driver
3713 *
3714 * This function should only be called once typically
3715 * during driver probe.
3716 *
3717 * @host - Pointer to sdcc host structure
3718 * @ep - Pointer to sps endpoint data structure
3719 * @is_produce - 1 means Producer endpoint
3720 * 0 means Consumer endpoint
3721 *
3722 * @return - 0 if successful else negative value.
3723 *
3724 */
3725static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
3726 struct msmsdcc_sps_ep_conn_data *ep,
3727 bool is_producer)
3728{
3729 int rc = 0;
3730 struct sps_pipe *sps_pipe_handle;
3731 struct sps_connect *sps_config = &ep->config;
3732 struct sps_register_event *sps_event = &ep->event;
3733
3734 /* Allocate endpoint context */
3735 sps_pipe_handle = sps_alloc_endpoint();
3736 if (!sps_pipe_handle) {
3737 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
3738 mmc_hostname(host->mmc), is_producer);
3739 rc = -ENOMEM;
3740 goto out;
3741 }
3742
3743 /* Get default connection configuration for an endpoint */
3744 rc = sps_get_config(sps_pipe_handle, sps_config);
3745 if (rc) {
3746 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
3747 " rc=%d", mmc_hostname(host->mmc),
3748 (u32)sps_pipe_handle, rc);
3749 goto get_config_err;
3750 }
3751
3752 /* Modify the default connection configuration */
3753 if (is_producer) {
3754 /*
3755 * For SDCC producer transfer, source should be
3756 * SDCC peripheral where as destination should
3757 * be system memory.
3758 */
3759 sps_config->source = host->sps.bam_handle;
3760 sps_config->destination = SPS_DEV_HANDLE_MEM;
3761 /* Producer pipe will handle this connection */
3762 sps_config->mode = SPS_MODE_SRC;
3763 sps_config->options =
3764 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3765 } else {
3766 /*
3767 * For SDCC consumer transfer, source should be
3768 * system memory where as destination should
3769 * SDCC peripheral
3770 */
3771 sps_config->source = SPS_DEV_HANDLE_MEM;
3772 sps_config->destination = host->sps.bam_handle;
3773 sps_config->mode = SPS_MODE_DEST;
3774 sps_config->options =
3775 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3776 }
3777
3778 /* Producer pipe index */
3779 sps_config->src_pipe_index = host->sps.src_pipe_index;
3780 /* Consumer pipe index */
3781 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
3782 /*
3783 * This event thresold value is only significant for BAM-to-BAM
3784 * transfer. It's ignored for BAM-to-System mode transfer.
3785 */
3786 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05303787
3788 /* Allocate maximum descriptor fifo size */
3789 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
3790 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003791 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
3792 sps_config->desc.size,
3793 &sps_config->desc.phys_base,
3794 GFP_KERNEL);
3795
Pratibhasagar V00b94332011-10-18 14:57:27 +05303796 if (!sps_config->desc.base) {
3797 rc = -ENOMEM;
3798 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3799 , mmc_hostname(host->mmc));
3800 goto get_config_err;
3801 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003802 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3803
3804 /* Establish connection between peripheral and memory endpoint */
3805 rc = sps_connect(sps_pipe_handle, sps_config);
3806 if (rc) {
3807 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3808 " rc=%d", mmc_hostname(host->mmc),
3809 (u32)sps_pipe_handle, rc);
3810 goto sps_connect_err;
3811 }
3812
3813 sps_event->mode = SPS_TRIGGER_CALLBACK;
3814 sps_event->options = SPS_O_EOT;
3815 sps_event->callback = msmsdcc_sps_complete_cb;
3816 sps_event->xfer_done = NULL;
3817 sps_event->user = (void *)host;
3818
3819 /* Register callback event for EOT (End of transfer) event. */
3820 rc = sps_register_event(sps_pipe_handle, sps_event);
3821 if (rc) {
3822 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3823 " rc=%d", mmc_hostname(host->mmc),
3824 (u32)sps_pipe_handle, rc);
3825 goto reg_event_err;
3826 }
3827 /* Now save the sps pipe handle */
3828 ep->pipe_handle = sps_pipe_handle;
3829 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3830 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3831 __func__, is_producer ? "READ" : "WRITE",
3832 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3833 goto out;
3834
3835reg_event_err:
3836 sps_disconnect(sps_pipe_handle);
3837sps_connect_err:
3838 dma_free_coherent(mmc_dev(host->mmc),
3839 sps_config->desc.size,
3840 sps_config->desc.base,
3841 sps_config->desc.phys_base);
3842get_config_err:
3843 sps_free_endpoint(sps_pipe_handle);
3844out:
3845 return rc;
3846}
3847
3848/**
3849 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3850 *
3851 * This function disconnect endpoint and deallocates
3852 * endpoint context.
3853 *
3854 * This function should only be called once typically
3855 * during driver remove.
3856 *
3857 * @host - Pointer to sdcc host structure
3858 * @ep - Pointer to sps endpoint data structure
3859 *
3860 */
3861static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3862 struct msmsdcc_sps_ep_conn_data *ep)
3863{
3864 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3865 struct sps_connect *sps_config = &ep->config;
3866 struct sps_register_event *sps_event = &ep->event;
3867
3868 sps_event->xfer_done = NULL;
3869 sps_event->callback = NULL;
3870 sps_register_event(sps_pipe_handle, sps_event);
3871 sps_disconnect(sps_pipe_handle);
3872 dma_free_coherent(mmc_dev(host->mmc),
3873 sps_config->desc.size,
3874 sps_config->desc.base,
3875 sps_config->desc.phys_base);
3876 sps_free_endpoint(sps_pipe_handle);
3877}
3878
3879/**
3880 * Reset SDCC peripheral's SPS endpoint
3881 *
3882 * This function disconnects an endpoint.
3883 *
3884 * This function should be called for reseting
3885 * SPS endpoint when data transfer error is
3886 * encountered during data transfer. This
3887 * can be considered as soft reset to endpoint.
3888 *
3889 * This function should only be called if
3890 * msmsdcc_sps_init() is already called.
3891 *
3892 * @host - Pointer to sdcc host structure
3893 * @ep - Pointer to sps endpoint data structure
3894 *
3895 * @return - 0 if successful else negative value.
3896 */
3897static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3898 struct msmsdcc_sps_ep_conn_data *ep)
3899{
3900 int rc = 0;
3901 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3902
3903 rc = sps_disconnect(sps_pipe_handle);
3904 if (rc) {
3905 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3906 " rc=%d", mmc_hostname(host->mmc), __func__,
3907 (u32)sps_pipe_handle, rc);
3908 goto out;
3909 }
3910 out:
3911 return rc;
3912}
3913
3914/**
3915 * Restore SDCC peripheral's SPS endpoint
3916 *
3917 * This function connects an endpoint.
3918 *
3919 * This function should be called for restoring
3920 * SPS endpoint after data transfer error is
3921 * encountered during data transfer. This
3922 * can be considered as soft reset to endpoint.
3923 *
3924 * This function should only be called if
3925 * msmsdcc_sps_reset_ep() is called before.
3926 *
3927 * @host - Pointer to sdcc host structure
3928 * @ep - Pointer to sps endpoint data structure
3929 *
3930 * @return - 0 if successful else negative value.
3931 */
3932static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3933 struct msmsdcc_sps_ep_conn_data *ep)
3934{
3935 int rc = 0;
3936 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3937 struct sps_connect *sps_config = &ep->config;
3938 struct sps_register_event *sps_event = &ep->event;
3939
3940 /* Establish connection between peripheral and memory endpoint */
3941 rc = sps_connect(sps_pipe_handle, sps_config);
3942 if (rc) {
3943 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3944 " rc=%d", mmc_hostname(host->mmc), __func__,
3945 (u32)sps_pipe_handle, rc);
3946 goto out;
3947 }
3948
3949 /* Register callback event for EOT (End of transfer) event. */
3950 rc = sps_register_event(sps_pipe_handle, sps_event);
3951 if (rc) {
3952 pr_err("%s: %s: sps_register_event() failed!!!"
3953 " pipe_handle=0x%x, rc=%d",
3954 mmc_hostname(host->mmc), __func__,
3955 (u32)sps_pipe_handle, rc);
3956 goto reg_event_err;
3957 }
3958 goto out;
3959
3960reg_event_err:
3961 sps_disconnect(sps_pipe_handle);
3962out:
3963 return rc;
3964}
3965
3966/**
3967 * Initialize SPS HW connected with SDCC core
3968 *
3969 * This function register BAM HW resources with
3970 * SPS driver and then initialize 2 SPS endpoints
3971 *
3972 * This function should only be called once typically
3973 * during driver probe.
3974 *
3975 * @host - Pointer to sdcc host structure
3976 *
3977 * @return - 0 if successful else negative value.
3978 *
3979 */
3980static int msmsdcc_sps_init(struct msmsdcc_host *host)
3981{
3982 int rc = 0;
3983 struct sps_bam_props bam = {0};
3984
3985 host->bam_base = ioremap(host->bam_memres->start,
3986 resource_size(host->bam_memres));
3987 if (!host->bam_base) {
3988 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3989 " size=0x%x", mmc_hostname(host->mmc),
3990 host->bam_memres->start,
3991 (host->bam_memres->end -
3992 host->bam_memres->start));
3993 rc = -ENOMEM;
3994 goto out;
3995 }
3996
3997 bam.phys_addr = host->bam_memres->start;
3998 bam.virt_addr = host->bam_base;
3999 /*
4000 * This event thresold value is only significant for BAM-to-BAM
4001 * transfer. It's ignored for BAM-to-System mode transfer.
4002 */
4003 bam.event_threshold = 0x10; /* Pipe event threshold */
4004 /*
4005 * This threshold controls when the BAM publish
4006 * the descriptor size on the sideband interface.
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304007 * SPS HW will be used for data transfer size even
4008 * less than SDCC FIFO size. So let's set BAM summing
4009 * thresold to SPS_MIN_XFER_SIZE bytes.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004010 */
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304011 bam.summing_threshold = SPS_MIN_XFER_SIZE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004012 /* SPS driver wll handle the SDCC BAM IRQ */
4013 bam.irq = (u32)host->bam_irqres->start;
4014 bam.manage = SPS_BAM_MGR_LOCAL;
4015
4016 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
4017 (u32)bam.phys_addr);
4018 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
4019 (u32)bam.virt_addr);
4020
4021 /* Register SDCC Peripheral BAM device to SPS driver */
4022 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
4023 if (rc) {
4024 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
4025 mmc_hostname(host->mmc), rc);
4026 goto reg_bam_err;
4027 }
4028 pr_info("%s: BAM device registered. bam_handle=0x%x",
4029 mmc_hostname(host->mmc), host->sps.bam_handle);
4030
4031 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
4032 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
4033
4034 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
4035 SPS_PROD_PERIPHERAL);
4036 if (rc)
4037 goto sps_reset_err;
4038 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
4039 SPS_CONS_PERIPHERAL);
4040 if (rc)
4041 goto cons_conn_err;
4042
4043 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
4044 mmc_hostname(host->mmc),
4045 (unsigned long long)host->bam_memres->start,
4046 (unsigned int)host->bam_irqres->start);
4047 goto out;
4048
4049cons_conn_err:
4050 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4051sps_reset_err:
4052 sps_deregister_bam_device(host->sps.bam_handle);
4053reg_bam_err:
4054 iounmap(host->bam_base);
4055out:
4056 return rc;
4057}
4058
4059/**
4060 * De-initialize SPS HW connected with SDCC core
4061 *
4062 * This function deinitialize SPS endpoints and then
4063 * deregisters BAM resources from SPS driver.
4064 *
4065 * This function should only be called once typically
4066 * during driver remove.
4067 *
4068 * @host - Pointer to sdcc host structure
4069 *
4070 */
4071static void msmsdcc_sps_exit(struct msmsdcc_host *host)
4072{
4073 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
4074 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4075 sps_deregister_bam_device(host->sps.bam_handle);
4076 iounmap(host->bam_base);
4077}
4078#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
4079
4080static ssize_t
4081show_polling(struct device *dev, struct device_attribute *attr, char *buf)
4082{
4083 struct mmc_host *mmc = dev_get_drvdata(dev);
4084 struct msmsdcc_host *host = mmc_priv(mmc);
4085 int poll;
4086 unsigned long flags;
4087
4088 spin_lock_irqsave(&host->lock, flags);
4089 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
4090 spin_unlock_irqrestore(&host->lock, flags);
4091
4092 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
4093}
4094
4095static ssize_t
4096set_polling(struct device *dev, struct device_attribute *attr,
4097 const char *buf, size_t count)
4098{
4099 struct mmc_host *mmc = dev_get_drvdata(dev);
4100 struct msmsdcc_host *host = mmc_priv(mmc);
4101 int value;
4102 unsigned long flags;
4103
4104 sscanf(buf, "%d", &value);
4105
4106 spin_lock_irqsave(&host->lock, flags);
4107 if (value) {
4108 mmc->caps |= MMC_CAP_NEEDS_POLL;
4109 mmc_detect_change(host->mmc, 0);
4110 } else {
4111 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4112 }
4113#ifdef CONFIG_HAS_EARLYSUSPEND
4114 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
4115#endif
4116 spin_unlock_irqrestore(&host->lock, flags);
4117 return count;
4118}
4119
4120static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
4121 show_polling, set_polling);
4122static struct attribute *dev_attrs[] = {
4123 &dev_attr_polling.attr,
4124 NULL,
4125};
4126static struct attribute_group dev_attr_grp = {
4127 .attrs = dev_attrs,
4128};
4129
4130#ifdef CONFIG_HAS_EARLYSUSPEND
4131static void msmsdcc_early_suspend(struct early_suspend *h)
4132{
4133 struct msmsdcc_host *host =
4134 container_of(h, struct msmsdcc_host, early_suspend);
4135 unsigned long flags;
4136
4137 spin_lock_irqsave(&host->lock, flags);
4138 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
4139 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4140 spin_unlock_irqrestore(&host->lock, flags);
4141};
4142static void msmsdcc_late_resume(struct early_suspend *h)
4143{
4144 struct msmsdcc_host *host =
4145 container_of(h, struct msmsdcc_host, early_suspend);
4146 unsigned long flags;
4147
4148 if (host->polling_enabled) {
4149 spin_lock_irqsave(&host->lock, flags);
4150 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
4151 mmc_detect_change(host->mmc, 0);
4152 spin_unlock_irqrestore(&host->lock, flags);
4153 }
4154};
4155#endif
4156
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304157static void msmsdcc_print_regs(const char *name, void __iomem *base,
4158 u32 phys_base, unsigned int no_of_regs)
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304159{
4160 unsigned int i;
4161
4162 if (!base)
4163 return;
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304164
4165 pr_info("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
4166 " =====\n", name, phys_base, (u32)base);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304167 for (i = 0; i < no_of_regs; i = i + 4) {
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304168 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
4169 (u32)readl_relaxed(base + i*4),
4170 (u32)readl_relaxed(base + ((i+1)*4)),
4171 (u32)readl_relaxed(base + ((i+2)*4)),
4172 (u32)readl_relaxed(base + ((i+3)*4)));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304173 }
4174}
4175
4176static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
4177{
4178 /* Dump current state of SDCC clocks, power and irq */
4179 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304180 (host->pwr ? "ON" : "OFF"));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304181 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304182 mmc_hostname(host->mmc), (host->clks_on ? "ON" : "OFF"),
4183 (u32)clk_get_rate(host->clk));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304184 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
4185 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
4186
4187 /* Now dump SDCC registers. Don't print FIFO registers */
4188 if (host->clks_on)
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304189 msmsdcc_print_regs("SDCC-CORE", host->base,
4190 host->core_memres->start, 28);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304191
4192 if (host->curr.data) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304193 if (!msmsdcc_is_dma_possible(host, host->curr.data))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304194 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
4195 else if (host->is_dma_mode)
4196 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
4197 mmc_hostname(host->mmc), host->dma.busy,
4198 host->dma.channel, host->dma.crci);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304199 else if (host->is_sps_mode) {
subhashj245831e2012-04-30 18:46:17 +05304200 if (host->sps.busy && host->clks_on)
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304201 msmsdcc_print_regs("SDCC-DML", host->dml_base,
4202 host->dml_memres->start,
4203 16);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304204 pr_info("%s: SPS mode: busy=%d\n",
4205 mmc_hostname(host->mmc), host->sps.busy);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304206 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304207
4208 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
4209 mmc_hostname(host->mmc), host->curr.xfer_size,
4210 host->curr.data_xfered, host->curr.xfer_remain);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304211 }
4212
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304213 pr_info("%s: got_dataend=%d, prog_enable=%d,"
4214 " wait_for_auto_prog_done=%d, got_auto_prog_done=%d\n",
4215 mmc_hostname(host->mmc), host->curr.got_dataend,
4216 host->prog_enable, host->curr.wait_for_auto_prog_done,
4217 host->curr.got_auto_prog_done);
subhashj245831e2012-04-30 18:46:17 +05304218 msmsdcc_print_rpm_info(host);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304219}
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304220
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004221static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
4222{
4223 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4224 struct mmc_request *mrq;
4225 unsigned long flags;
4226
4227 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004228 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004229 pr_info("%s: %s: dummy CMD52 timeout\n",
4230 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004231 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004232 }
4233
4234 mrq = host->curr.mrq;
4235
4236 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304237 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
4238 mrq->cmd->opcode);
4239 msmsdcc_dump_sdcc_state(host);
4240
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004241 if (!mrq->cmd->error)
4242 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304243 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004244 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004245 if (mrq->data && !mrq->data->error)
4246 mrq->data->error = -ETIMEDOUT;
4247 host->curr.data_xfered = 0;
4248 if (host->dma.sg && host->is_dma_mode) {
4249 msm_dmov_stop_cmd(host->dma.channel,
4250 &host->dma.hdr, 0);
4251 } else if (host->sps.sg && host->is_sps_mode) {
4252 /* Stop current SPS transfer */
4253 msmsdcc_sps_exit_curr_xfer(host);
4254 } else {
4255 msmsdcc_reset_and_restore(host);
4256 msmsdcc_stop_data(host);
4257 if (mrq->data && mrq->data->stop)
4258 msmsdcc_start_command(host,
4259 mrq->data->stop, 0);
4260 else
4261 msmsdcc_request_end(host, mrq);
4262 }
4263 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304264 host->prog_enable = 0;
Subhash Jadavanied6b0e42012-03-07 16:36:27 +05304265 host->curr.wait_for_auto_prog_done = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004266 msmsdcc_reset_and_restore(host);
4267 msmsdcc_request_end(host, mrq);
4268 }
4269 }
4270 spin_unlock_irqrestore(&host->lock, flags);
4271}
4272
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304273static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
4274{
4275 int i, ret;
4276 struct mmc_platform_data *pdata;
4277 struct device_node *np = dev->of_node;
4278 u32 bus_width = 0;
4279 u32 *clk_table;
4280 int clk_table_len;
4281 u32 *sup_voltages;
4282 int sup_volt_len;
4283
4284 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
4285 if (!pdata) {
4286 dev_err(dev, "could not allocate memory for platform data\n");
4287 goto err;
4288 }
4289
4290 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
4291 if (bus_width == 8) {
4292 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
4293 } else if (bus_width == 4) {
4294 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
4295 } else {
4296 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
4297 pdata->mmc_bus_width = 0;
4298 }
4299
4300 if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
4301 size_t sz;
4302 sz = sup_volt_len / sizeof(*sup_voltages);
4303 if (sz > 0) {
4304 sup_voltages = devm_kzalloc(dev,
4305 sz * sizeof(*sup_voltages), GFP_KERNEL);
4306 if (!sup_voltages) {
4307 dev_err(dev, "No memory for supported voltage\n");
4308 goto err;
4309 }
4310
4311 ret = of_property_read_u32_array(np,
4312 "qcom,sdcc-sup-voltages", sup_voltages, sz);
4313 if (ret < 0) {
4314 dev_err(dev, "error while reading voltage"
4315 "ranges %d\n", ret);
4316 goto err;
4317 }
4318 } else {
4319 dev_err(dev, "No supported voltages\n");
4320 goto err;
4321 }
4322 for (i = 0; i < sz; i += 2) {
4323 u32 mask;
4324
4325 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
4326 sup_voltages[i + 1]);
4327 if (!mask)
4328 dev_err(dev, "Invalide voltage range %d\n", i);
4329 pdata->ocr_mask |= mask;
4330 }
4331 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
4332 } else {
4333 dev_err(dev, "Supported voltage range not specified\n");
4334 }
4335
4336 if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
4337 size_t sz;
4338 sz = clk_table_len / sizeof(*clk_table);
4339
4340 if (sz > 0) {
4341 clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
4342 GFP_KERNEL);
4343 if (!clk_table) {
4344 dev_err(dev, "No memory for clock table\n");
4345 goto err;
4346 }
4347
4348 ret = of_property_read_u32_array(np,
4349 "qcom,sdcc-clk-rates", clk_table, sz);
4350 if (ret < 0) {
4351 dev_err(dev, "error while reading clk"
4352 "table %d\n", ret);
4353 goto err;
4354 }
4355 } else {
4356 dev_err(dev, "clk_table not specified\n");
4357 goto err;
4358 }
4359 pdata->sup_clk_table = clk_table;
4360 pdata->sup_clk_cnt = sz;
4361 } else {
4362 dev_err(dev, "Supported clock rates not specified\n");
4363 }
4364
4365 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
4366 pdata->nonremovable = true;
4367 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
4368 pdata->disable_cmd23 = true;
4369
4370 return pdata;
4371err:
4372 return NULL;
4373}
4374
San Mehat9d2bd732009-09-22 16:44:22 -07004375static int
4376msmsdcc_probe(struct platform_device *pdev)
4377{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304378 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07004379 struct msmsdcc_host *host;
4380 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004381 unsigned long flags;
4382 struct resource *core_irqres = NULL;
4383 struct resource *bam_irqres = NULL;
4384 struct resource *core_memres = NULL;
4385 struct resource *dml_memres = NULL;
4386 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07004387 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07004388 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05304389 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004390 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07004391
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304392 if (pdev->dev.of_node) {
4393 plat = msmsdcc_populate_pdata(&pdev->dev);
4394 of_property_read_u32((&pdev->dev)->of_node,
4395 "cell-index", &pdev->id);
4396 } else {
4397 plat = pdev->dev.platform_data;
4398 }
4399
San Mehat9d2bd732009-09-22 16:44:22 -07004400 /* must have platform data */
4401 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004402 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004403 ret = -EINVAL;
4404 goto out;
4405 }
4406
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004407 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07004408 return -EINVAL;
4409
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304410 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
4411 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
4412 return -EINVAL;
4413 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004414
San Mehat9d2bd732009-09-22 16:44:22 -07004415 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004416 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004417 return -ENXIO;
4418 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304419 if (pdev->dev.of_node) {
4420 /*
4421 * Device tree iomem resources are only accessible by index.
4422 * index = 0 -> SDCC register interface
4423 * index = 1 -> DML register interface
4424 * index = 2 -> BAM register interface
4425 * IRQ resources:
4426 * index = 0 -> SDCC IRQ
4427 * index = 1 -> BAM IRQ
4428 */
4429 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
4430 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
4431 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
4432 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
4433 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
4434 } else {
4435 for (i = 0; i < pdev->num_resources; i++) {
4436 if (pdev->resource[i].flags & IORESOURCE_MEM) {
4437 if (!strncmp(pdev->resource[i].name,
4438 "sdcc_dml_addr",
4439 sizeof("sdcc_dml_addr")))
4440 dml_memres = &pdev->resource[i];
4441 else if (!strncmp(pdev->resource[i].name,
4442 "sdcc_bam_addr",
4443 sizeof("sdcc_bam_addr")))
4444 bam_memres = &pdev->resource[i];
4445 else
4446 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07004447
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304448 }
4449 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
4450 if (!strncmp(pdev->resource[i].name,
4451 "sdcc_bam_irq",
4452 sizeof("sdcc_bam_irq")))
4453 bam_irqres = &pdev->resource[i];
4454 else
4455 core_irqres = &pdev->resource[i];
4456 }
4457 if (pdev->resource[i].flags & IORESOURCE_DMA) {
4458 if (!strncmp(pdev->resource[i].name,
4459 "sdcc_dma_chnl",
4460 sizeof("sdcc_dma_chnl")))
4461 dmares = &pdev->resource[i];
4462 else if (!strncmp(pdev->resource[i].name,
4463 "sdcc_dma_crci",
4464 sizeof("sdcc_dma_crci")))
4465 dma_crci_res = &pdev->resource[i];
4466 }
Krishna Konda25786ec2011-07-25 16:21:36 -07004467 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004468 }
4469
4470 if (!core_irqres || !core_memres) {
4471 pr_err("%s: Invalid sdcc core resource\n", __func__);
4472 return -ENXIO;
4473 }
4474
4475 /*
4476 * Both BAM and DML memory resource should be preset.
4477 * BAM IRQ resource should also be present.
4478 */
4479 if ((bam_memres && !dml_memres) ||
4480 (!bam_memres && dml_memres) ||
4481 ((bam_memres && dml_memres) && !bam_irqres)) {
4482 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004483 return -ENXIO;
4484 }
4485
4486 /*
4487 * Setup our host structure
4488 */
San Mehat9d2bd732009-09-22 16:44:22 -07004489 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
4490 if (!mmc) {
4491 ret = -ENOMEM;
4492 goto out;
4493 }
4494
4495 host = mmc_priv(mmc);
4496 host->pdev_id = pdev->id;
4497 host->plat = plat;
4498 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08004499 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05304500
4501 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004502 host->is_sps_mode = 1;
4503 else if (dmares)
4504 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07004505
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004506 host->base = ioremap(core_memres->start,
4507 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07004508 if (!host->base) {
4509 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004510 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004511 }
4512
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004513 host->core_irqres = core_irqres;
4514 host->bam_irqres = bam_irqres;
4515 host->core_memres = core_memres;
4516 host->dml_memres = dml_memres;
4517 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07004518 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07004519 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07004520 spin_lock_init(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304521 mutex_init(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07004522
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004523#ifdef CONFIG_MMC_EMBEDDED_SDIO
4524 if (plat->embedded_sdio)
4525 mmc_set_embedded_sdio_data(mmc,
4526 &plat->embedded_sdio->cis,
4527 &plat->embedded_sdio->cccr,
4528 plat->embedded_sdio->funcs,
4529 plat->embedded_sdio->num_funcs);
4530#endif
4531
Sahitya Tummala62612cf2010-12-08 15:03:03 +05304532 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
4533 (unsigned long)host);
4534
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004535 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
4536 (unsigned long)host);
4537 if (host->is_dma_mode) {
4538 /* Setup DMA */
4539 ret = msmsdcc_init_dma(host);
4540 if (ret)
4541 goto ioremap_free;
4542 } else {
4543 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004544 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004545 }
4546
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004547 /*
4548 * Setup SDCC clock if derived from Dayatona
4549 * fabric core clock.
4550 */
4551 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07004552 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004553 if (!IS_ERR(host->dfab_pclk)) {
4554 /* Set the clock rate to 64MHz for max. performance */
4555 ret = clk_set_rate(host->dfab_pclk, 64000000);
4556 if (ret)
4557 goto dfab_pclk_put;
Asutosh Dasf5298c32012-04-03 14:51:47 +05304558 ret = clk_prepare_enable(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004559 if (ret)
4560 goto dfab_pclk_put;
4561 } else
4562 goto dma_free;
4563 }
4564
4565 /*
4566 * Setup main peripheral bus clock
4567 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004568 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004569 if (!IS_ERR(host->pclk)) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05304570 ret = clk_prepare_enable(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004571 if (ret)
4572 goto pclk_put;
4573
4574 host->pclk_rate = clk_get_rate(host->pclk);
4575 }
4576
4577 /*
4578 * Setup SDC MMC clock
4579 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004580 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07004581 if (IS_ERR(host->clk)) {
4582 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004583 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07004584 }
4585
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004586 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
4587 if (ret) {
4588 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
4589 goto clk_put;
4590 }
4591
Asutosh Dasf5298c32012-04-03 14:51:47 +05304592 ret = clk_prepare_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004593 if (ret)
4594 goto clk_put;
4595
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004596 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304597 if (!host->clk_rate)
4598 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304599
4600 /*
4601 * Lookup the Controller Version, to identify the supported features
4602 * Version number read as 0 would indicate SDCC3 or earlier versions
4603 */
4604 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
4605 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
4606 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304607 /*
4608 * Set the register write delay according to min. clock frequency
4609 * supported and update later when the host->clk_rate changes.
4610 */
4611 host->reg_write_delay =
4612 (1 + ((3 * USEC_PER_SEC) /
4613 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004614
4615 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05304616 /* Apply Hard reset to SDCC to put it in power on default state */
4617 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004618
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004619#define MSM_MMC_DEFAULT_CPUDMA_LATENCY 200 /* usecs */
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304620 /* pm qos request to prevent apps idle power collapse */
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004621 if (host->plat->cpu_dma_latency)
4622 host->cpu_dma_latency = host->plat->cpu_dma_latency;
4623 else
4624 host->cpu_dma_latency = MSM_MMC_DEFAULT_CPUDMA_LATENCY;
4625 pm_qos_add_request(&host->pm_qos_req_dma,
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304626 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
4627
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004628 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07004629 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004630 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07004631 goto clk_disable;
4632 }
4633
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004634
4635 /* Clocks has to be running before accessing SPS/DML HW blocks */
4636 if (host->is_sps_mode) {
4637 /* Initialize SPS */
4638 ret = msmsdcc_sps_init(host);
4639 if (ret)
4640 goto vreg_deinit;
4641 /* Initialize DML */
4642 ret = msmsdcc_dml_init(host);
4643 if (ret)
4644 goto sps_exit;
4645 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05304646 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07004647
San Mehat9d2bd732009-09-22 16:44:22 -07004648 /*
4649 * Setup MMC host structure
4650 */
4651 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004652 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
4653 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004654 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004655 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
4656 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07004657
San Mehat9d2bd732009-09-22 16:44:22 -07004658 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05304659 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304660
4661 /*
4662 * If we send the CMD23 before multi block write/read command
4663 * then we need not to send CMD12 at the end of the transfer.
4664 * If we don't send the CMD12 then only way to detect the PROG_DONE
4665 * status is to use the AUTO_PROG_DONE status provided by SDCC4
4666 * controller. So let's enable the CMD23 for SDCC4 only.
4667 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304668 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304669 mmc->caps |= MMC_CAP_CMD23;
4670
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004671 mmc->caps |= plat->uhs_caps;
4672 /*
4673 * XPC controls the maximum current in the default speed mode of SDXC
4674 * card. XPC=0 means 100mA (max.) but speed class is not supported.
4675 * XPC=1 means 150mA (max.) and speed class is supported.
4676 */
4677 if (plat->xpc_cap)
4678 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
4679 MMC_CAP_SET_XPC_180);
4680
Subhash Jadavani6bb34a82012-04-18 13:18:40 +05304681 mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304682 if (pdev->dev.of_node) {
4683 if (of_get_property((&pdev->dev)->of_node,
4684 "qcom,sdcc-hs200", NULL))
4685 mmc->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
4686 }
4687
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004688 if (plat->nonremovable)
4689 mmc->caps |= MMC_CAP_NONREMOVABLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004690 mmc->caps |= MMC_CAP_SDIO_IRQ;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004691
4692 if (plat->is_sdio_al_client)
4693 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07004694
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304695 mmc->max_segs = msmsdcc_get_nr_sg(host);
4696 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
4697 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07004698
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304699 mmc->max_req_size = MMC_MAX_REQ_SIZE;
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +05304700 mmc->max_seg_size = mmc->max_req_size;
San Mehat9d2bd732009-09-22 16:44:22 -07004701
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004702 writel_relaxed(0, host->base + MMCIMASK0);
4703 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05304704 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004705
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004706 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
4707 mb();
4708 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07004709
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004710 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
4711 DRIVER_NAME " (cmd)", host);
4712 if (ret)
4713 goto dml_exit;
4714
4715 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
4716 DRIVER_NAME " (pio)", host);
4717 if (ret)
4718 goto irq_free;
4719
4720 /*
4721 * Enable SDCC IRQ only when host is powered on. Otherwise, this
4722 * IRQ is un-necessarily being monitored by MPM (Modem power
4723 * management block) during idle-power collapse. The MPM will be
4724 * configured to monitor the DATA1 GPIO line with level-low trigger
4725 * and thus depending on the GPIO status, it prevents TCXO shutdown
4726 * during idle-power collapse.
4727 */
4728 disable_irq(core_irqres->start);
4729 host->sdcc_irq_disabled = 1;
4730
4731 if (plat->sdiowakeup_irq) {
4732 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4733 mmc_hostname(mmc));
4734 ret = request_irq(plat->sdiowakeup_irq,
4735 msmsdcc_platform_sdiowakeup_irq,
4736 IRQF_SHARED | IRQF_TRIGGER_LOW,
4737 DRIVER_NAME "sdiowakeup", host);
4738 if (ret) {
4739 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
4740 plat->sdiowakeup_irq, ret);
4741 goto pio_irq_free;
4742 } else {
4743 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304744 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004745 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304746 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004747 }
4748 spin_unlock_irqrestore(&host->lock, flags);
4749 }
4750 }
4751
Subhash Jadavanic9b85752012-04-13 11:16:49 +05304752 if (host->plat->mpm_sdiowakeup_int) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004753 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4754 mmc_hostname(mmc));
4755 }
4756
4757 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
4758 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004759 /*
4760 * Setup card detect change
4761 */
4762
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004763 if (plat->status || plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08004764 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004765 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08004766 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004767 host->oldstat = msmsdcc_slot_status(host);
Krishna Konda360aa422011-12-06 18:27:41 -08004768
Krishna Konda941604a2012-01-10 17:46:34 -08004769 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004770 }
San Mehat9d2bd732009-09-22 16:44:22 -07004771
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004772 if (plat->status_irq) {
4773 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07004774 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004775 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07004776 DRIVER_NAME " (slot)",
4777 host);
4778 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004779 pr_err("Unable to get slot IRQ %d (%d)\n",
4780 plat->status_irq, ret);
4781 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004782 }
4783 } else if (plat->register_status_notify) {
4784 plat->register_status_notify(msmsdcc_status_notify_cb, host);
4785 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004786 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07004787 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004788
4789 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004790
4791 ret = pm_runtime_set_active(&(pdev)->dev);
4792 if (ret < 0)
4793 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
4794 __func__, ret);
4795 /*
4796 * There is no notion of suspend/resume for SD/MMC/SDIO
4797 * cards. So host can be suspended/resumed with out
4798 * worrying about its children.
4799 */
4800 pm_suspend_ignore_children(&(pdev)->dev, true);
4801
4802 /*
4803 * MMC/SD/SDIO bus suspend/resume operations are defined
4804 * only for the slots that will be used for non-removable
4805 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
4806 * defined. Otherwise, they simply become card removal and
4807 * insertion events during suspend and resume respectively.
4808 * Hence, enable run-time PM only for slots for which bus
4809 * suspend/resume operations are defined.
4810 */
4811#ifdef CONFIG_MMC_UNSAFE_RESUME
4812 /*
4813 * If this capability is set, MMC core will enable/disable host
4814 * for every claim/release operation on a host. We use this
4815 * notification to increment/decrement runtime pm usage count.
4816 */
4817 mmc->caps |= MMC_CAP_DISABLE;
4818 pm_runtime_enable(&(pdev)->dev);
4819#else
4820 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
4821 mmc->caps |= MMC_CAP_DISABLE;
4822 pm_runtime_enable(&(pdev)->dev);
4823 }
4824#endif
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05304825#ifndef CONFIG_PM_RUNTIME
4826 mmc_set_disable_delay(mmc, MSM_MMC_DISABLE_TIMEOUT);
4827#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004828 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
4829 (unsigned long)host);
4830
San Mehat9d2bd732009-09-22 16:44:22 -07004831 mmc_add_host(mmc);
4832
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004833#ifdef CONFIG_HAS_EARLYSUSPEND
4834 host->early_suspend.suspend = msmsdcc_early_suspend;
4835 host->early_suspend.resume = msmsdcc_late_resume;
4836 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
4837 register_early_suspend(&host->early_suspend);
4838#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004839
Krishna Konda25786ec2011-07-25 16:21:36 -07004840 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
4841 " dmacrcri %d\n", mmc_hostname(mmc),
4842 (unsigned long long)core_memres->start,
4843 (unsigned int) core_irqres->start,
4844 (unsigned int) plat->status_irq, host->dma.channel,
4845 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004846
4847 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
4848 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
4849 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
4850 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
4851 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
4852 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
4853 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
4854 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
4855 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
4856 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
4857 host->eject);
4858 pr_info("%s: Power save feature enable = %d\n",
4859 mmc_hostname(mmc), msmsdcc_pwrsave);
4860
Krishna Konda25786ec2011-07-25 16:21:36 -07004861 if (host->is_dma_mode && host->dma.channel != -1
4862 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004863 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004864 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004865 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004866 mmc_hostname(mmc), host->dma.cmd_busaddr,
4867 host->dma.cmdptr_busaddr);
4868 } else if (host->is_sps_mode) {
4869 pr_info("%s: SPS-BAM data transfer mode available\n",
4870 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004871 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004872 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004873
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004874#if defined(CONFIG_DEBUG_FS)
4875 msmsdcc_dbg_createhost(host);
4876#endif
4877 if (!plat->status_irq) {
4878 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
4879 if (ret)
4880 goto platform_irq_free;
4881 }
San Mehat9d2bd732009-09-22 16:44:22 -07004882 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004883
4884 platform_irq_free:
4885 del_timer_sync(&host->req_tout_timer);
4886 pm_runtime_disable(&(pdev)->dev);
4887 pm_runtime_set_suspended(&(pdev)->dev);
4888
4889 if (plat->status_irq)
4890 free_irq(plat->status_irq, host);
4891 sdiowakeup_irq_free:
4892 wake_lock_destroy(&host->sdio_suspend_wlock);
4893 if (plat->sdiowakeup_irq)
4894 free_irq(plat->sdiowakeup_irq, host);
4895 pio_irq_free:
4896 if (plat->sdiowakeup_irq)
4897 wake_lock_destroy(&host->sdio_wlock);
4898 free_irq(core_irqres->start, host);
4899 irq_free:
4900 free_irq(core_irqres->start, host);
4901 dml_exit:
4902 if (host->is_sps_mode)
4903 msmsdcc_dml_exit(host);
4904 sps_exit:
4905 if (host->is_sps_mode)
4906 msmsdcc_sps_exit(host);
4907 vreg_deinit:
4908 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07004909 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004910 clk_disable(host->clk);
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004911 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304912 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07004913 clk_put:
4914 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004915 pclk_disable:
4916 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05304917 clk_disable_unprepare(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07004918 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004919 if (!IS_ERR(host->pclk))
4920 clk_put(host->pclk);
4921 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05304922 clk_disable_unprepare(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004923 dfab_pclk_put:
4924 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4925 clk_put(host->dfab_pclk);
4926 dma_free:
4927 if (host->is_dma_mode) {
4928 if (host->dmares)
4929 dma_free_coherent(NULL,
4930 sizeof(struct msmsdcc_nc_dmadata),
4931 host->dma.nc, host->dma.nc_busaddr);
4932 }
4933 ioremap_free:
4934 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07004935 host_free:
4936 mmc_free_host(mmc);
4937 out:
4938 return ret;
4939}
4940
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004941static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07004942{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004943 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4944 struct mmc_platform_data *plat;
4945 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004946
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004947 if (!mmc)
4948 return -ENXIO;
4949
4950 if (pm_runtime_suspended(&(pdev)->dev))
4951 pm_runtime_resume(&(pdev)->dev);
4952
4953 host = mmc_priv(mmc);
4954
4955 DBG(host, "Removing SDCC device = %d\n", pdev->id);
4956 plat = host->plat;
4957
4958 if (!plat->status_irq)
4959 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
4960
4961 del_timer_sync(&host->req_tout_timer);
4962 tasklet_kill(&host->dma_tlet);
4963 tasklet_kill(&host->sps.tlet);
4964 mmc_remove_host(mmc);
4965
4966 if (plat->status_irq)
4967 free_irq(plat->status_irq, host);
4968
4969 wake_lock_destroy(&host->sdio_suspend_wlock);
4970 if (plat->sdiowakeup_irq) {
4971 wake_lock_destroy(&host->sdio_wlock);
4972 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
4973 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07004974 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004975
4976 free_irq(host->core_irqres->start, host);
4977 free_irq(host->core_irqres->start, host);
4978
4979 clk_put(host->clk);
4980 if (!IS_ERR(host->pclk))
4981 clk_put(host->pclk);
4982 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4983 clk_put(host->dfab_pclk);
4984
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004985 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304986 pm_qos_remove_request(&host->pm_qos_req_dma);
4987
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004988 msmsdcc_vreg_init(host, false);
4989
4990 if (host->is_dma_mode) {
4991 if (host->dmares)
4992 dma_free_coherent(NULL,
4993 sizeof(struct msmsdcc_nc_dmadata),
4994 host->dma.nc, host->dma.nc_busaddr);
4995 }
4996
4997 if (host->is_sps_mode) {
4998 msmsdcc_dml_exit(host);
4999 msmsdcc_sps_exit(host);
5000 }
5001
5002 iounmap(host->base);
5003 mmc_free_host(mmc);
5004
5005#ifdef CONFIG_HAS_EARLYSUSPEND
5006 unregister_early_suspend(&host->early_suspend);
5007#endif
5008 pm_runtime_disable(&(pdev)->dev);
5009 pm_runtime_set_suspended(&(pdev)->dev);
5010
5011 return 0;
5012}
5013
5014#ifdef CONFIG_MSM_SDIO_AL
5015int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
5016{
5017 struct msmsdcc_host *host = mmc_priv(mmc);
5018 unsigned long flags;
5019
Asutosh Dasf5298c32012-04-03 14:51:47 +05305020 mutex_lock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005021 spin_lock_irqsave(&host->lock, flags);
5022 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
5023 enable ? "En" : "Dis");
5024
5025 if (enable) {
5026 if (!host->sdcc_irq_disabled) {
5027 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05305028 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005029 host->sdcc_irq_disabled = 1;
5030 }
5031
5032 if (host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305033 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005034 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305035 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005036 host->clks_on = 0;
5037 }
5038
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305039 if (host->plat->sdio_lpm_gpio_setup &&
5040 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005041 spin_unlock_irqrestore(&host->lock, flags);
5042 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
5043 spin_lock_irqsave(&host->lock, flags);
5044 host->sdio_gpio_lpm = 1;
5045 }
5046
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305047 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005048 msmsdcc_enable_irq_wake(host);
5049 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305050 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005051 }
5052 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305053 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005054 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305055 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005056 msmsdcc_disable_irq_wake(host);
5057 }
5058
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305059 if (host->plat->sdio_lpm_gpio_setup &&
5060 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005061 spin_unlock_irqrestore(&host->lock, flags);
5062 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
5063 spin_lock_irqsave(&host->lock, flags);
5064 host->sdio_gpio_lpm = 0;
5065 }
5066
5067 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305068 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005069 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305070 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005071 host->clks_on = 1;
5072 }
5073
5074 if (host->sdcc_irq_disabled) {
5075 writel_relaxed(host->mci_irqenable,
5076 host->base + MMCIMASK0);
5077 mb();
5078 enable_irq(host->core_irqres->start);
5079 host->sdcc_irq_disabled = 0;
5080 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005081 }
5082 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305083 mutex_unlock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005084 return 0;
5085}
5086#else
5087int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
5088{
5089 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07005090}
5091#endif
5092
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005093#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07005094static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005095msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07005096{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005097 struct mmc_host *mmc = dev_get_drvdata(dev);
5098 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07005099 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305100 unsigned long flags;
5101
San Mehat9d2bd732009-09-22 16:44:22 -07005102
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005103 if (host->plat->is_sdio_al_client)
5104 return 0;
Sahitya Tummala7661a452011-07-18 13:28:35 +05305105 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005106 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005107 host->sdcc_suspending = 1;
5108 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07005109
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005110 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005111 * MMC core thinks that host is disabled by now since
5112 * runtime suspend is scheduled after msmsdcc_disable()
5113 * is called. Thus, MMC core will try to enable the host
5114 * while suspending it. This results in a synchronous
5115 * runtime resume request while in runtime suspending
5116 * context and hence inorder to complete this resume
5117 * requet, it will wait for suspend to be complete,
5118 * but runtime suspend also can not proceed further
5119 * until the host is resumed. Thus, it leads to a hang.
5120 * Hence, increase the pm usage count before suspending
5121 * the host so that any resume requests after this will
5122 * simple become pm usage counter increment operations.
5123 */
5124 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05305125 /* If there is pending detect work abort runtime suspend */
5126 if (unlikely(work_busy(&mmc->detect.work)))
5127 rc = -EAGAIN;
5128 else
5129 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005130 pm_runtime_put_noidle(dev);
5131
5132 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305133 spin_lock_irqsave(&host->lock, flags);
5134 host->sdcc_suspended = true;
5135 spin_unlock_irqrestore(&host->lock, flags);
5136 if (mmc->card && mmc_card_sdio(mmc->card) &&
5137 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005138 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305139 * If SDIO function driver doesn't want
5140 * to power off the card, atleast turn off
5141 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005142 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305143 mmc_host_clk_hold(mmc);
5144 spin_lock_irqsave(&mmc->clk_lock, flags);
5145 mmc->clk_old = mmc->ios.clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005146 mmc->ios.clock = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305147 mmc->clk_gated = true;
5148 spin_unlock_irqrestore(&mmc->clk_lock, flags);
5149 mmc_set_ios(mmc);
5150 mmc_host_clk_release(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005151 }
5152 }
5153 host->sdcc_suspending = 0;
5154 mmc->suspend_task = NULL;
5155 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
5156 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005157 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05305158 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
San Mehat9d2bd732009-09-22 16:44:22 -07005159 return rc;
5160}
5161
5162static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005163msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07005164{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005165 struct mmc_host *mmc = dev_get_drvdata(dev);
5166 struct msmsdcc_host *host = mmc_priv(mmc);
5167 unsigned long flags;
5168
5169 if (host->plat->is_sdio_al_client)
5170 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07005171
Sahitya Tummala7661a452011-07-18 13:28:35 +05305172 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005173 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305174 if (mmc->card && mmc_card_sdio(mmc->card) &&
5175 mmc_card_keep_power(mmc)) {
5176 mmc_host_clk_hold(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305177 mmc->ios.clock = host->clk_rate;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305178 mmc_set_ios(mmc);
5179 mmc_host_clk_release(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305180 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005181
5182 mmc_resume_host(mmc);
5183
5184 /*
5185 * FIXME: Clearing of flags must be handled in clients
5186 * resume handler.
5187 */
5188 spin_lock_irqsave(&host->lock, flags);
5189 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305190 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005191 spin_unlock_irqrestore(&host->lock, flags);
5192
5193 /*
5194 * After resuming the host wait for sometime so that
5195 * the SDIO work will be processed.
5196 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305197 if (mmc->card && mmc_card_sdio(mmc->card)) {
Subhash Jadavanic9b85752012-04-13 11:16:49 +05305198 if ((host->plat->mpm_sdiowakeup_int ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005199 host->plat->sdiowakeup_irq) &&
5200 wake_lock_active(&host->sdio_wlock))
5201 wake_lock_timeout(&host->sdio_wlock, 1);
5202 }
5203
5204 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005205 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05305206 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005207 return 0;
5208}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005209
5210static int msmsdcc_runtime_idle(struct device *dev)
5211{
5212 struct mmc_host *mmc = dev_get_drvdata(dev);
5213 struct msmsdcc_host *host = mmc_priv(mmc);
5214
5215 if (host->plat->is_sdio_al_client)
5216 return 0;
5217
5218 /* Idle timeout is not configurable for now */
5219 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
5220
5221 return -EAGAIN;
5222}
5223
5224static int msmsdcc_pm_suspend(struct device *dev)
5225{
5226 struct mmc_host *mmc = dev_get_drvdata(dev);
5227 struct msmsdcc_host *host = mmc_priv(mmc);
5228 int rc = 0;
5229
5230 if (host->plat->is_sdio_al_client)
5231 return 0;
5232
5233
5234 if (host->plat->status_irq)
5235 disable_irq(host->plat->status_irq);
5236
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005237 if (!pm_runtime_suspended(dev))
5238 rc = msmsdcc_runtime_suspend(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005239
5240 return rc;
5241}
5242
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305243static int msmsdcc_suspend_noirq(struct device *dev)
5244{
5245 struct mmc_host *mmc = dev_get_drvdata(dev);
5246 struct msmsdcc_host *host = mmc_priv(mmc);
5247 int rc = 0;
5248
5249 /*
5250 * After platform suspend there may be active request
5251 * which might have enabled clocks. For example, in SDIO
5252 * case, ksdioirq thread might have scheduled after sdcc
5253 * suspend but before system freeze. In that case abort
5254 * suspend and retry instead of keeping the clocks on
5255 * during suspend and not allowing TCXO.
5256 */
5257
Asutosh Dasf5298c32012-04-03 14:51:47 +05305258 if (host->clks_on && !host->plat->is_sdio_al_client) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305259 pr_warn("%s: clocks are on after suspend, aborting system "
5260 "suspend\n", mmc_hostname(mmc));
5261 rc = -EAGAIN;
5262 }
5263
5264 return rc;
5265}
5266
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005267static int msmsdcc_pm_resume(struct device *dev)
5268{
5269 struct mmc_host *mmc = dev_get_drvdata(dev);
5270 struct msmsdcc_host *host = mmc_priv(mmc);
5271 int rc = 0;
5272
5273 if (host->plat->is_sdio_al_client)
5274 return 0;
5275
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005276 if (mmc->card && mmc_card_sdio(mmc->card))
Sahitya Tummalafb486372011-09-02 19:01:49 +05305277 rc = msmsdcc_runtime_resume(dev);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005278 else
5279 host->pending_resume = true;
5280
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005281 if (host->plat->status_irq) {
5282 msmsdcc_check_status((unsigned long)host);
5283 enable_irq(host->plat->status_irq);
5284 }
5285
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005286 return rc;
5287}
5288
Daniel Walker08ecfde2010-06-23 12:32:20 -07005289#else
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005290static int msmsdcc_runtime_suspend(struct device *dev)
5291{
5292 return 0;
5293}
5294static int msmsdcc_runtime_idle(struct device *dev)
5295{
5296 return 0;
5297}
5298static int msmsdcc_pm_suspend(struct device *dev)
5299{
5300 return 0;
5301}
5302static int msmsdcc_pm_resume(struct device *dev)
5303{
5304 return 0;
5305}
5306static int msmsdcc_suspend_noirq(struct device *dev)
5307{
5308 return 0;
5309}
5310static int msmsdcc_runtime_resume(struct device *dev)
5311{
5312 return 0;
5313}
Daniel Walker08ecfde2010-06-23 12:32:20 -07005314#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005315
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005316static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
5317 .runtime_suspend = msmsdcc_runtime_suspend,
5318 .runtime_resume = msmsdcc_runtime_resume,
5319 .runtime_idle = msmsdcc_runtime_idle,
5320 .suspend = msmsdcc_pm_suspend,
5321 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305322 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005323};
5324
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305325static const struct of_device_id msmsdcc_dt_match[] = {
5326 {.compatible = "qcom,msm-sdcc"},
5327
5328};
5329MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
5330
San Mehat9d2bd732009-09-22 16:44:22 -07005331static struct platform_driver msmsdcc_driver = {
5332 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005333 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07005334 .driver = {
5335 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005336 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305337 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07005338 },
5339};
5340
5341static int __init msmsdcc_init(void)
5342{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005343#if defined(CONFIG_DEBUG_FS)
5344 int ret = 0;
5345 ret = msmsdcc_dbg_init();
5346 if (ret) {
5347 pr_err("Failed to create debug fs dir \n");
5348 return ret;
5349 }
5350#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005351 return platform_driver_register(&msmsdcc_driver);
5352}
5353
5354static void __exit msmsdcc_exit(void)
5355{
5356 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005357
5358#if defined(CONFIG_DEBUG_FS)
5359 debugfs_remove(debugfs_file);
5360 debugfs_remove(debugfs_dir);
5361#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005362}
5363
5364module_init(msmsdcc_init);
5365module_exit(msmsdcc_exit);
5366
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005367MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07005368MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005369
5370#if defined(CONFIG_DEBUG_FS)
5371
5372static int
5373msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
5374{
5375 file->private_data = inode->i_private;
5376 return 0;
5377}
5378
5379static ssize_t
5380msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
5381 size_t count, loff_t *ppos)
5382{
5383 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08005384 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005385 int max, i;
5386
5387 i = 0;
5388 max = sizeof(buf) - 1;
5389
5390 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
5391 host->curr.cmd, host->curr.data);
5392 if (host->curr.cmd) {
5393 struct mmc_command *cmd = host->curr.cmd;
5394
5395 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
5396 cmd->opcode, cmd->arg, cmd->flags);
5397 }
5398 if (host->curr.data) {
5399 struct mmc_data *data = host->curr.data;
5400 i += scnprintf(buf + i, max - i,
5401 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
5402 data->timeout_ns, data->timeout_clks,
5403 data->blksz, data->blocks, data->error,
5404 data->flags);
5405 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
5406 host->curr.xfer_size, host->curr.xfer_remain,
5407 host->curr.data_xfered, host->dma.sg);
5408 }
5409
5410 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
5411}
5412
5413static const struct file_operations msmsdcc_dbg_state_ops = {
5414 .read = msmsdcc_dbg_state_read,
5415 .open = msmsdcc_dbg_state_open,
5416};
5417
5418static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
5419{
5420 if (debugfs_dir) {
5421 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
5422 0644, debugfs_dir, host,
5423 &msmsdcc_dbg_state_ops);
5424 }
5425}
5426
5427static int __init msmsdcc_dbg_init(void)
5428{
5429 int err;
5430
5431 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
5432 if (IS_ERR(debugfs_dir)) {
5433 err = PTR_ERR(debugfs_dir);
5434 debugfs_dir = NULL;
5435 return err;
5436 }
5437
5438 return 0;
5439}
5440#endif