blob: 0d6c5f104c6c8c1b9a4da57ca9581d5136c49bcb [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
Asutosh Das05049132012-05-09 12:38:15 +05301024 /* DAT_CMD bit should be set for all ADTC */
1025 if (mmc_cmd_type(cmd) == MMC_CMD_ADTC)
San Mehat56a8b5b2009-11-21 12:29:46 -08001026 *c |= MCI_CSPM_DATCMD;
1027
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001028 /* Check if AUTO CMD19 is required or not? */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301029 if (host->tuning_needed &&
1030 !(host->mmc->ios.timing == MMC_TIMING_MMC_HS200)) {
1031
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301032 /*
1033 * For open ended block read operation (without CMD23),
1034 * AUTO_CMD19 bit should be set while sending the READ command.
1035 * For close ended block read operation (with CMD23),
1036 * AUTO_CMD19 bit should be set while sending CMD23.
1037 */
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301038 if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
1039 host->curr.mrq->cmd->opcode ==
1040 MMC_READ_MULTIPLE_BLOCK) ||
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301041 (!host->curr.mrq->sbc &&
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301042 (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
1043 cmd->opcode == MMC_READ_MULTIPLE_BLOCK))) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301044 msmsdcc_enable_cdr_cm_sdc4_dll(host);
1045 *c |= MCI_CSPM_AUTO_CMD19;
1046 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001047 }
1048
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05301049 /* Clear CDR_EN bit for write operations */
1050 if (host->tuning_needed && cmd->mrq->data &&
1051 (cmd->mrq->data->flags & MMC_DATA_WRITE))
1052 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) &
1053 ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
1054
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301055 if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301056 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001057 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301058 }
1059
San Mehat56a8b5b2009-11-21 12:29:46 -08001060 if (cmd == cmd->mrq->stop)
1061 *c |= MCI_CSPM_MCIABORT;
1062
San Mehat56a8b5b2009-11-21 12:29:46 -08001063 if (host->curr.cmd != NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001064 pr_err("%s: Overlapping command requests\n",
1065 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -08001066 }
1067 host->curr.cmd = cmd;
1068}
1069
1070static void
1071msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1072 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001073{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301074 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001075 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001076 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001077 unsigned int pio_irqmask = 0;
1078
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301079 BUG_ON(!data->sg);
1080 BUG_ON(!data->sg_len);
1081
San Mehat9d2bd732009-09-22 16:44:22 -07001082 host->curr.data = data;
1083 host->curr.xfer_size = data->blksz * data->blocks;
1084 host->curr.xfer_remain = host->curr.xfer_size;
1085 host->curr.data_xfered = 0;
1086 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301087 host->curr.got_auto_prog_done = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001088
San Mehat9d2bd732009-09-22 16:44:22 -07001089 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1090
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301091 if (host->curr.wait_for_auto_prog_done)
1092 datactrl |= MCI_AUTO_PROG_DONE;
1093
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05301094 if (msmsdcc_is_dma_possible(host, data)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001095 if (host->is_dma_mode && !msmsdcc_config_dma(host, data)) {
1096 datactrl |= MCI_DPSM_DMAENABLE;
1097 } else if (host->is_sps_mode) {
1098 if (!msmsdcc_is_dml_busy(host)) {
1099 if (!msmsdcc_sps_start_xfer(host, data)) {
1100 /* Now kick start DML transfer */
1101 mb();
1102 msmsdcc_dml_start_xfer(host, data);
1103 datactrl |= MCI_DPSM_DMAENABLE;
1104 host->sps.busy = 1;
1105 }
1106 } else {
1107 /*
1108 * Can't proceed with new transfer as
1109 * previous trasnfer is already in progress.
1110 * There is no point of going into PIO mode
1111 * as well. Is this a time to do kernel panic?
1112 */
1113 pr_err("%s: %s: DML HW is busy!!!"
1114 " Can't perform new SPS transfers"
1115 " now\n", mmc_hostname(host->mmc),
1116 __func__);
1117 }
1118 }
1119 }
1120
1121 /* Is data transfer in PIO mode required? */
1122 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001123 if (data->flags & MMC_DATA_READ) {
1124 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1125 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1126 pio_irqmask |= MCI_RXDATAAVLBLMASK;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001127 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001128 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1129 MCI_TXFIFOEMPTYMASK;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001130
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001131 msmsdcc_sg_start(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001132 }
1133
1134 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301135 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
San Mehat9d2bd732009-09-22 16:44:22 -07001136
San Mehat56a8b5b2009-11-21 12:29:46 -08001137 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001138 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001139 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -07001140
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001141 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
1142 /* Use ADM (Application Data Mover) HW for Data transfer */
1143 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001144 host->cmd_timeout = timeout;
1145 host->cmd_pio_irqmask = pio_irqmask;
1146 host->cmd_datactrl = datactrl;
1147 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001148
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001149 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1150 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001151 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001152
1153 if (cmd) {
1154 msmsdcc_start_command_deferred(host, cmd, &c);
1155 host->cmd_c = c;
1156 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001157 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1158 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1159 host->base + MMCIMASK0);
1160 mb();
1161 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001162 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001163 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001164 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001165
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001166 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001167
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001168 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1169 (~(MCI_IRQ_PIO))) | pio_irqmask,
1170 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001171 writel_relaxed(datactrl, base + MMCIDATACTRL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001172
1173 if (cmd) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05301174 /* Delay between data/command */
1175 msmsdcc_sync_reg_wr(host);
San Mehat56a8b5b2009-11-21 12:29:46 -08001176 /* Daisy-chain the command if requested */
1177 msmsdcc_start_command(host, cmd, c);
Subhash Jadavanidd432952012-03-28 11:25:56 +05301178 } else {
1179 /*
1180 * We don't need delay after writing to DATA_CTRL
1181 * register if we are not writing to CMD register
1182 * immediately after this. As we already have delay
1183 * before sending the command, we just need mb() here.
1184 */
1185 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001186 }
San Mehat9d2bd732009-09-22 16:44:22 -07001187 }
1188}
1189
1190static void
1191msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1192{
San Mehat56a8b5b2009-11-21 12:29:46 -08001193 msmsdcc_start_command_deferred(host, cmd, &c);
1194 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001195}
1196
1197static void
1198msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1199 unsigned int status)
1200{
1201 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001202 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
Subhash Jadavanib30c9822012-03-27 18:03:16 +05301203 || data->mrq->cmd->opcode == MMC_BUS_TEST_R
1204 || data->mrq->cmd->opcode ==
1205 MMC_SEND_TUNING_BLOCK_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001206 pr_err("%s: Data CRC error\n",
1207 mmc_hostname(host->mmc));
1208 pr_err("%s: opcode 0x%.8x\n", __func__,
1209 data->mrq->cmd->opcode);
1210 pr_err("%s: blksz %d, blocks %d\n", __func__,
1211 data->blksz, data->blocks);
1212 data->error = -EILSEQ;
1213 }
San Mehat9d2bd732009-09-22 16:44:22 -07001214 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001215 /* CRC is optional for the bus test commands, not all
1216 * cards respond back with CRC. However controller
1217 * waits for the CRC and times out. Hence ignore the
1218 * data timeouts during the Bustest.
1219 */
1220 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1221 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301222 pr_err("%s: CMD%d: Data timeout\n",
1223 mmc_hostname(host->mmc),
1224 data->mrq->cmd->opcode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001225 data->error = -ETIMEDOUT;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301226 msmsdcc_dump_sdcc_state(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001227 }
San Mehat9d2bd732009-09-22 16:44:22 -07001228 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001229 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001230 data->error = -EIO;
1231 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001232 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001233 data->error = -EIO;
1234 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001235 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001236 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001237 data->error = -EIO;
1238 }
San Mehat9d2bd732009-09-22 16:44:22 -07001239
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001240 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001241 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001242 host->dummy_52_needed = 0;
1243}
San Mehat9d2bd732009-09-22 16:44:22 -07001244
1245static int
1246msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1247{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001248 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001249 uint32_t *ptr = (uint32_t *) buffer;
1250 int count = 0;
1251
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301252 if (remain % 4)
1253 remain = ((remain >> 2) + 1) << 2;
1254
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001255 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1256
1257 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001258 ptr++;
1259 count += sizeof(uint32_t);
1260
1261 remain -= sizeof(uint32_t);
1262 if (remain == 0)
1263 break;
1264 }
1265 return count;
1266}
1267
1268static int
1269msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001270 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001271{
1272 void __iomem *base = host->base;
1273 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001274 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001275
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001276 while (readl_relaxed(base + MMCISTATUS) &
1277 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1278 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001279
San Mehat9d2bd732009-09-22 16:44:22 -07001280 count = min(remain, maxcnt);
1281
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301282 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1283 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001284 ptr += count;
1285 remain -= count;
1286
1287 if (remain == 0)
1288 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001289 }
1290 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001291
1292 return ptr - buffer;
1293}
1294
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001295/*
1296 * Copy up to a word (4 bytes) between a scatterlist
1297 * and a temporary bounce buffer when the word lies across
1298 * two pages. The temporary buffer can then be read to/
1299 * written from the FIFO once.
1300 */
1301static void _msmsdcc_sg_consume_word(struct msmsdcc_host *host)
1302{
1303 struct msmsdcc_pio_data *pio = &host->pio;
1304 unsigned int bytes_avail;
1305
1306 if (host->curr.data->flags & MMC_DATA_READ)
1307 memcpy(pio->sg_miter.addr, pio->bounce_buf,
1308 pio->bounce_buf_len);
1309 else
1310 memcpy(pio->bounce_buf, pio->sg_miter.addr,
1311 pio->bounce_buf_len);
1312
1313 while (pio->bounce_buf_len != 4) {
1314 if (!sg_miter_next(&pio->sg_miter))
1315 break;
1316 bytes_avail = min_t(unsigned int, pio->sg_miter.length,
1317 4 - pio->bounce_buf_len);
1318 if (host->curr.data->flags & MMC_DATA_READ)
1319 memcpy(pio->sg_miter.addr,
1320 &pio->bounce_buf[pio->bounce_buf_len],
1321 bytes_avail);
1322 else
1323 memcpy(&pio->bounce_buf[pio->bounce_buf_len],
1324 pio->sg_miter.addr, bytes_avail);
1325
1326 pio->sg_miter.consumed = bytes_avail;
1327 pio->bounce_buf_len += bytes_avail;
1328 }
1329}
1330
1331/*
1332 * Use sg_miter_next to return as many 4-byte aligned
1333 * chunks as possible, using a temporary 4 byte buffer
1334 * for alignment if necessary
1335 */
1336static int msmsdcc_sg_next(struct msmsdcc_host *host, char **buf, int *len)
1337{
1338 struct msmsdcc_pio_data *pio = &host->pio;
1339 unsigned int length, rlength;
1340 char *buffer;
1341
1342 if (!sg_miter_next(&pio->sg_miter))
1343 return 0;
1344
1345 buffer = pio->sg_miter.addr;
1346 length = pio->sg_miter.length;
1347
1348 if (length < host->curr.xfer_remain) {
1349 rlength = round_down(length, 4);
1350 if (rlength) {
1351 /*
1352 * We have a 4-byte aligned chunk.
1353 * The rounding will be reflected by
1354 * a call to msmsdcc_sg_consumed
1355 */
1356 length = rlength;
1357 goto sg_next_end;
1358 }
1359 /*
1360 * We have a length less than 4 bytes. Check to
1361 * see if more buffer is available, and combine
1362 * to make 4 bytes if possible.
1363 */
1364 pio->bounce_buf_len = length;
1365 memset(pio->bounce_buf, 0, 4);
1366
1367 /*
1368 * On a read, get 4 bytes from FIFO, and distribute
1369 * (4-bouce_buf_len) bytes into consecutive
1370 * sgl buffers when msmsdcc_sg_consumed is called
1371 */
1372 if (host->curr.data->flags & MMC_DATA_READ) {
1373 buffer = pio->bounce_buf;
1374 length = 4;
1375 goto sg_next_end;
1376 } else {
1377 _msmsdcc_sg_consume_word(host);
1378 buffer = pio->bounce_buf;
1379 length = pio->bounce_buf_len;
1380 }
1381 }
1382
1383sg_next_end:
1384 *buf = buffer;
1385 *len = length;
1386 return 1;
1387}
1388
1389/*
1390 * Update sg_miter.consumed based on how many bytes were
1391 * consumed. If the bounce buffer was used to read from FIFO,
1392 * redistribute into sgls.
1393 */
1394static void msmsdcc_sg_consumed(struct msmsdcc_host *host,
1395 unsigned int length)
1396{
1397 struct msmsdcc_pio_data *pio = &host->pio;
1398
1399 if (host->curr.data->flags & MMC_DATA_READ) {
1400 if (length > pio->sg_miter.consumed)
1401 /*
1402 * consumed 4 bytes, but sgl
1403 * describes < 4 bytes
1404 */
1405 _msmsdcc_sg_consume_word(host);
1406 else
1407 pio->sg_miter.consumed = length;
1408 } else
1409 if (length < pio->sg_miter.consumed)
1410 pio->sg_miter.consumed = length;
1411}
1412
1413static void msmsdcc_sg_start(struct msmsdcc_host *host)
1414{
1415 unsigned int sg_miter_flags = SG_MITER_ATOMIC;
1416
1417 host->pio.bounce_buf_len = 0;
1418
1419 if (host->curr.data->flags & MMC_DATA_READ)
1420 sg_miter_flags |= SG_MITER_TO_SG;
1421 else
1422 sg_miter_flags |= SG_MITER_FROM_SG;
1423
1424 sg_miter_start(&host->pio.sg_miter, host->curr.data->sg,
1425 host->curr.data->sg_len, sg_miter_flags);
1426}
1427
1428static void msmsdcc_sg_stop(struct msmsdcc_host *host)
1429{
1430 sg_miter_stop(&host->pio.sg_miter);
1431}
1432
San Mehat1cd22962010-02-03 12:59:29 -08001433static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001434msmsdcc_pio_irq(int irq, void *dev_id)
1435{
1436 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001437 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001438 uint32_t status;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001439 unsigned long flags;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001440 unsigned int remain;
1441 char *buffer;
San Mehat9d2bd732009-09-22 16:44:22 -07001442
Murali Palnati36448a42011-09-02 15:06:18 +05301443 spin_lock(&host->lock);
1444
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001445 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001446
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001447 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301448 (MCI_IRQ_PIO)) == 0) {
1449 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001450 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301451 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001452#if IRQ_DEBUG
1453 msmsdcc_print_status(host, "irq1-r", status);
1454#endif
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001455 local_irq_save(flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001456
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001457 do {
1458 unsigned int len;
San Mehat9d2bd732009-09-22 16:44:22 -07001459
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001460 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1461 | MCI_RXDATAAVLBL)))
1462 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001463
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001464 if (!msmsdcc_sg_next(host, &buffer, &remain))
1465 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001466
San Mehat9d2bd732009-09-22 16:44:22 -07001467 len = 0;
1468 if (status & MCI_RXACTIVE)
1469 len = msmsdcc_pio_read(host, buffer, remain);
1470 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001471 len = msmsdcc_pio_write(host, buffer, remain);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001472
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301473 /* len might have aligned to 32bits above */
1474 if (len > remain)
1475 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001476
San Mehat9d2bd732009-09-22 16:44:22 -07001477 host->curr.xfer_remain -= len;
1478 host->curr.data_xfered += len;
1479 remain -= len;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001480 msmsdcc_sg_consumed(host, len);
San Mehat9d2bd732009-09-22 16:44:22 -07001481
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001482 if (remain) /* Done with this page? */
1483 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001484
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001485 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001486 } while (1);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001487
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001488 msmsdcc_sg_stop(host);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001489 local_irq_restore(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001490
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001491 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1492 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1493 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1494 host->base + MMCIMASK0);
1495 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301496 /*
1497 * back to back write to MASK0 register don't need
1498 * synchronization delay.
1499 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001500 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1501 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1502 }
1503 mb();
1504 } else if (!host->curr.xfer_remain) {
1505 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1506 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1507 mb();
1508 }
San Mehat9d2bd732009-09-22 16:44:22 -07001509
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001510 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001511
1512 return IRQ_HANDLED;
1513}
1514
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001515static void
1516msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1517
1518static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1519 struct mmc_data *data)
1520{
1521 u32 loop_cnt = 0;
1522
1523 /*
1524 * For read commands with data less than fifo size, it is possible to
1525 * get DATAEND first and RXDATA_AVAIL might be set later because of
1526 * synchronization delay through the asynchronous RX FIFO. Thus, for
1527 * such cases, even after DATAEND interrupt is received software
1528 * should poll for RXDATA_AVAIL until the requested data is read out
1529 * of FIFO. This change is needed to get around this abnormal but
1530 * sometimes expected behavior of SDCC3 controller.
1531 *
1532 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1533 * after the data is loaded into RX FIFO. This would amount to less
1534 * than a microsecond and thus looping for 1000 times is good enough
1535 * for that delay.
1536 */
1537 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1538 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1539 spin_unlock(&host->lock);
1540 msmsdcc_pio_irq(1, host);
1541 spin_lock(&host->lock);
1542 }
1543 }
1544 if (loop_cnt == 1000) {
1545 pr_info("%s: Timed out while polling for Rx Data\n",
1546 mmc_hostname(host->mmc));
1547 data->error = -ETIMEDOUT;
1548 msmsdcc_reset_and_restore(host);
1549 }
1550}
1551
San Mehat9d2bd732009-09-22 16:44:22 -07001552static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1553{
1554 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001555
1556 host->curr.cmd = NULL;
subhashj8046ae12012-05-02 12:14:52 +05301557 if (mmc_resp_type(cmd))
1558 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1559 /*
1560 * Read rest of the response registers only if
1561 * long response is expected for this command
1562 */
1563 if (mmc_resp_type(cmd) & MMC_RSP_136) {
1564 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1565 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1566 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
1567 }
San Mehat9d2bd732009-09-22 16:44:22 -07001568
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001569 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301570 pr_debug("%s: CMD%d: Command timeout\n",
1571 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001572 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001573 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301574 !host->tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301575 pr_err("%s: CMD%d: Command CRC error\n",
1576 mmc_hostname(host->mmc), cmd->opcode);
1577 msmsdcc_dump_sdcc_state(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001578 cmd->error = -EILSEQ;
1579 }
1580
1581 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001582 if (host->curr.data && host->dma.sg &&
1583 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001584 msm_dmov_stop_cmd(host->dma.channel,
1585 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001586 else if (host->curr.data && host->sps.sg &&
1587 host->is_sps_mode){
1588 /* Stop current SPS transfer */
1589 msmsdcc_sps_exit_curr_xfer(host);
1590 }
San Mehat9d2bd732009-09-22 16:44:22 -07001591 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301592 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001593 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301594 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301595 } else { /* host->data == NULL */
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301596 if (!cmd->error && host->prog_enable) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301597 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001598 host->prog_enable = 0;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301599 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001600 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301601 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301602 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301603 host->prog_enable = 0;
Subhash Jadavanied6b0e42012-03-07 16:36:27 +05301604 host->curr.wait_for_auto_prog_done = 0;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001605 if (host->dummy_52_needed)
1606 host->dummy_52_needed = 0;
1607 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001608 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301609 msmsdcc_request_end(host, cmd->mrq);
1610 }
1611 }
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301612 } else if ((cmd == host->curr.mrq->sbc) && cmd->data) {
1613 if (cmd->data->flags & MMC_DATA_READ)
1614 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1615 else
1616 msmsdcc_request_start(host, host->curr.mrq);
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301617 } else if (cmd->data) {
1618 if (!(cmd->data->flags & MMC_DATA_READ))
1619 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001620 }
1621}
1622
San Mehat9d2bd732009-09-22 16:44:22 -07001623static irqreturn_t
1624msmsdcc_irq(int irq, void *dev_id)
1625{
1626 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001627 u32 status;
1628 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001629 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001630
1631 spin_lock(&host->lock);
1632
1633 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001634 struct mmc_command *cmd;
1635 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001636
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001637 if (timer) {
1638 timer = 0;
1639 msmsdcc_delay(host);
1640 }
San Mehat865c8062009-11-13 13:42:06 -08001641
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001642 if (!host->clks_on) {
1643 pr_debug("%s: %s: SDIO async irq received\n",
1644 mmc_hostname(host->mmc), __func__);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301645
1646 /*
1647 * Only async interrupt can come when clocks are off,
1648 * disable further interrupts and enable them when
1649 * clocks are on.
1650 */
1651 if (!host->sdcc_irq_disabled) {
1652 disable_irq_nosync(irq);
1653 host->sdcc_irq_disabled = 1;
1654 }
1655
1656 /*
1657 * If mmc_card_wake_sdio_irq() is set, mmc core layer
1658 * will take care of signaling sdio irq during
1659 * mmc_sdio_resume().
1660 */
1661 if (host->sdcc_suspended)
1662 /*
1663 * This is a wakeup interrupt so hold wakelock
1664 * until SDCC resume is handled.
1665 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001666 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301667 else
1668 mmc_signal_sdio_irq(host->mmc);
1669 ret = 1;
1670 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001671 }
1672
1673 status = readl_relaxed(host->base + MMCISTATUS);
1674
1675 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1676 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001677 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001678
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001679#if IRQ_DEBUG
1680 msmsdcc_print_status(host, "irq0-r", status);
1681#endif
1682 status &= readl_relaxed(host->base + MMCIMASK0);
1683 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301684 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301685 if (host->clk_rate <=
1686 msmsdcc_get_min_sup_clk_rate(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +05301687 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001688#if IRQ_DEBUG
1689 msmsdcc_print_status(host, "irq0-p", status);
1690#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001691
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001692 if (status & MCI_SDIOINTROPE) {
1693 if (host->sdcc_suspending)
1694 wake_lock(&host->sdio_suspend_wlock);
1695 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001696 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001697 data = host->curr.data;
1698
1699 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001700 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1701 MCI_CMDTIMEOUT)) {
1702 if (status & MCI_CMDTIMEOUT)
1703 pr_debug("%s: dummy CMD52 timeout\n",
1704 mmc_hostname(host->mmc));
1705 if (status & MCI_CMDCRCFAIL)
1706 pr_debug("%s: dummy CMD52 CRC failed\n",
1707 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001708 host->dummy_52_sent = 0;
1709 host->dummy_52_needed = 0;
1710 if (data) {
1711 msmsdcc_stop_data(host);
1712 msmsdcc_request_end(host, data->mrq);
1713 }
1714 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001715 spin_unlock(&host->lock);
1716 return IRQ_HANDLED;
1717 }
1718 break;
1719 }
1720
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001721 /*
1722 * Check for proper command response
1723 */
1724 cmd = host->curr.cmd;
1725 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1726 MCI_CMDTIMEOUT | MCI_PROGDONE |
1727 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1728 msmsdcc_do_cmdirq(host, status);
1729 }
1730
Sathish Ambley081d7842011-11-29 11:19:41 -08001731 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001732 /* Check for data errors */
1733 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1734 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1735 msmsdcc_data_err(host, data, status);
1736 host->curr.data_xfered = 0;
1737 if (host->dma.sg && host->is_dma_mode)
1738 msm_dmov_stop_cmd(host->dma.channel,
1739 &host->dma.hdr, 0);
1740 else if (host->sps.sg && host->is_sps_mode) {
1741 /* Stop current SPS transfer */
1742 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301743 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001744 msmsdcc_reset_and_restore(host);
1745 if (host->curr.data)
1746 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301747 if (!data->stop || (host->curr.mrq->sbc
1748 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001749 timer |=
1750 msmsdcc_request_end(host,
1751 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301752 else if ((host->curr.mrq->sbc
1753 && data->error) ||
1754 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001755 msmsdcc_start_command(host,
1756 data->stop,
1757 0);
1758 timer = 1;
1759 }
1760 }
1761 }
1762
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301763 /* Check for prog done */
1764 if (host->curr.wait_for_auto_prog_done &&
1765 (status & MCI_PROGDONE))
1766 host->curr.got_auto_prog_done = 1;
1767
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001768 /* Check for data done */
1769 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1770 host->curr.got_dataend = 1;
1771
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301772 if (host->curr.got_dataend &&
1773 (!host->curr.wait_for_auto_prog_done ||
1774 (host->curr.wait_for_auto_prog_done &&
1775 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001776 /*
1777 * If DMA is still in progress, we complete
1778 * via the completion handler
1779 */
1780 if (!host->dma.busy && !host->sps.busy) {
1781 /*
1782 * There appears to be an issue in the
1783 * controller where if you request a
1784 * small block transfer (< fifo size),
1785 * you may get your DATAEND/DATABLKEND
1786 * irq without the PIO data irq.
1787 *
1788 * Check to see if theres still data
1789 * to be read, and simulate a PIO irq.
1790 */
1791 if (data->flags & MMC_DATA_READ)
1792 msmsdcc_wait_for_rxdata(host,
1793 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001794 if (!data->error) {
1795 host->curr.data_xfered =
1796 host->curr.xfer_size;
1797 host->curr.xfer_remain -=
1798 host->curr.xfer_size;
1799 }
1800
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001801 if (!host->dummy_52_needed) {
1802 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301803 if (!data->stop ||
1804 (host->curr.mrq->sbc
1805 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001806 msmsdcc_request_end(
1807 host,
1808 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301809 else if ((host->curr.mrq->sbc
1810 && data->error) ||
1811 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001812 msmsdcc_start_command(
1813 host,
1814 data->stop, 0);
1815 timer = 1;
1816 }
1817 } else {
1818 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001819 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001820 &dummy52cmd,
1821 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001822 }
1823 }
1824 }
1825 }
1826
San Mehat9d2bd732009-09-22 16:44:22 -07001827 ret = 1;
1828 } while (status);
1829
1830 spin_unlock(&host->lock);
1831
San Mehat9d2bd732009-09-22 16:44:22 -07001832 return IRQ_RETVAL(ret);
1833}
1834
1835static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001836msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1837{
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301838 if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001839 /* Queue/read data, daisy-chain command when data starts */
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301840 if (mrq->sbc)
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301841 msmsdcc_start_data(host, mrq->data, mrq->sbc, 0);
1842 else
1843 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001844 } else {
1845 msmsdcc_start_command(host, mrq->cmd, 0);
1846 }
1847}
1848
1849static void
San Mehat9d2bd732009-09-22 16:44:22 -07001850msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1851{
1852 struct msmsdcc_host *host = mmc_priv(mmc);
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05301853 unsigned long flags, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001854
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001855 /*
1856 * Get the SDIO AL client out of LPM.
1857 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001858 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001859 if (host->plat->is_sdio_al_client)
1860 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001861
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301862 /* check if sps pipe reset is pending? */
1863 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1864 msmsdcc_sps_pipes_reset_and_restore(host);
1865 host->sps.pipe_reset_pending = false;
1866 }
1867
San Mehat9d2bd732009-09-22 16:44:22 -07001868 spin_lock_irqsave(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001869
1870 if (host->eject) {
1871 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1872 mrq->cmd->error = 0;
1873 mrq->data->bytes_xfered = mrq->data->blksz *
1874 mrq->data->blocks;
1875 } else
1876 mrq->cmd->error = -ENOMEDIUM;
1877
1878 spin_unlock_irqrestore(&host->lock, flags);
1879 mmc_request_done(mmc, mrq);
1880 return;
1881 }
1882
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301883 /*
subhashjf181c292012-05-02 13:07:40 +05301884 * Don't start the request if SDCC is not in proper state to handle it
1885 */
1886 if (!host->pwr || !host->clks_on || host->sdcc_irq_disabled) {
1887 WARN(1, "%s: %s: SDCC is in bad state. don't process"
1888 " new request (CMD%d)\n", mmc_hostname(host->mmc),
1889 __func__, mrq->cmd->opcode);
1890 msmsdcc_dump_sdcc_state(host);
1891 mrq->cmd->error = -EIO;
1892 if (mrq->data) {
1893 mrq->data->error = -EIO;
1894 mrq->data->bytes_xfered = 0;
1895 }
1896 spin_unlock_irqrestore(&host->lock, flags);
1897 mmc_request_done(mmc, mrq);
1898 return;
1899 }
1900
1901 WARN(host->curr.mrq, "%s: %s: New request (CMD%d) received while"
1902 " other request (CMD%d) is in progress\n",
1903 mmc_hostname(host->mmc), __func__,
1904 mrq->cmd->opcode, host->curr.mrq->cmd->opcode);
1905
1906 /*
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05301907 * Set timeout value to 10 secs (or more in case of buggy cards)
1908 */
1909 if ((mmc->card) && (mmc->card->quirks & MMC_QUIRK_INAND_DATA_TIMEOUT))
1910 timeout = 20000;
1911 else
1912 timeout = MSM_MMC_REQ_TIMEOUT;
1913 /*
1914 * Kick the software request timeout timer here with the timeout
1915 * value identified above
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301916 */
1917 mod_timer(&host->req_tout_timer,
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05301918 (jiffies + msecs_to_jiffies(timeout)));
San Mehat9d2bd732009-09-22 16:44:22 -07001919
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301920 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301921 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301922 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
1923 mrq->cmd->opcode == 54) {
Pratibhasagar V1c11da62011-11-14 12:36:35 +05301924 if (!host->sdcc_version)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001925 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301926 else
1927 /*
1928 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
1929 * write operations using CMD53 and CMD54.
1930 * Setting this bit with CMD53 would
1931 * automatically triggers PROG_DONE interrupt
1932 * without the need of sending dummy CMD52.
1933 */
1934 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani758cf8c2011-11-13 11:59:55 +05301935 } else if (mrq->cmd->opcode == MMC_WRITE_BLOCK &&
1936 host->sdcc_version) {
1937 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001938 }
San Mehat9d2bd732009-09-22 16:44:22 -07001939 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301940
Pratibhasagar V00b94332011-10-18 14:57:27 +05301941 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301942 mrq->sbc->mrq = mrq;
1943 mrq->sbc->data = mrq->data;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301944 if (mrq->data->flags & MMC_DATA_WRITE) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301945 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301946 msmsdcc_start_command(host, mrq->sbc, 0);
1947 } else {
1948 msmsdcc_request_start(host, mrq);
1949 }
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301950 } else {
1951 msmsdcc_request_start(host, mrq);
1952 }
1953
San Mehat9d2bd732009-09-22 16:44:22 -07001954 spin_unlock_irqrestore(&host->lock, flags);
1955}
1956
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001957static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1958 int min_uV, int max_uV)
1959{
1960 int rc = 0;
1961
1962 if (vreg->set_voltage_sup) {
1963 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1964 if (rc) {
1965 pr_err("%s: regulator_set_voltage(%s) failed."
1966 " min_uV=%d, max_uV=%d, rc=%d\n",
1967 __func__, vreg->name, min_uV, max_uV, rc);
1968 }
1969 }
1970
1971 return rc;
1972}
1973
1974static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1975 int uA_load)
1976{
1977 int rc = 0;
1978
Krishna Kondafea60182011-11-01 16:01:34 -07001979 /* regulators that do not support regulator_set_voltage also
1980 do not support regulator_set_optimum_mode */
1981 if (vreg->set_voltage_sup) {
1982 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1983 if (rc < 0)
1984 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
1985 "uA_load=%d) failed. rc=%d\n", __func__,
1986 vreg->name, uA_load, rc);
1987 else
1988 /* regulator_set_optimum_mode() can return non zero
1989 * value even for success case.
1990 */
1991 rc = 0;
1992 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001993
1994 return rc;
1995}
1996
1997static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1998 struct device *dev)
1999{
2000 int rc = 0;
2001
2002 /* check if regulator is already initialized? */
2003 if (vreg->reg)
2004 goto out;
2005
2006 /* Get the regulator handle */
2007 vreg->reg = regulator_get(dev, vreg->name);
2008 if (IS_ERR(vreg->reg)) {
2009 rc = PTR_ERR(vreg->reg);
2010 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
2011 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002012 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002013 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002014
2015 if (regulator_count_voltages(vreg->reg) > 0)
2016 vreg->set_voltage_sup = 1;
2017
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002018out:
2019 return rc;
2020}
2021
2022static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
2023{
2024 if (vreg->reg)
2025 regulator_put(vreg->reg);
2026}
2027
2028/* This init function should be called only once for each SDCC slot */
2029static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
2030{
2031 int rc = 0;
2032 struct msm_mmc_slot_reg_data *curr_slot;
2033 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
2034 struct device *dev = mmc_dev(host->mmc);
2035
2036 curr_slot = host->plat->vreg_data;
2037 if (!curr_slot)
2038 goto out;
2039
2040 curr_vdd_reg = curr_slot->vdd_data;
2041 curr_vccq_reg = curr_slot->vccq_data;
2042 curr_vddp_reg = curr_slot->vddp_data;
2043
2044 if (is_init) {
2045 /*
2046 * Get the regulator handle from voltage regulator framework
2047 * and then try to set the voltage level for the regulator
2048 */
2049 if (curr_vdd_reg) {
2050 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
2051 if (rc)
2052 goto out;
2053 }
2054 if (curr_vccq_reg) {
2055 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
2056 if (rc)
2057 goto vdd_reg_deinit;
2058 }
2059 if (curr_vddp_reg) {
2060 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
2061 if (rc)
2062 goto vccq_reg_deinit;
2063 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002064 rc = msmsdcc_vreg_reset(host);
2065 if (rc)
2066 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
2067 host->pdev_id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002068 goto out;
2069 } else {
2070 /* Deregister all regulators from regulator framework */
2071 goto vddp_reg_deinit;
2072 }
2073vddp_reg_deinit:
2074 if (curr_vddp_reg)
2075 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
2076vccq_reg_deinit:
2077 if (curr_vccq_reg)
2078 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
2079vdd_reg_deinit:
2080 if (curr_vdd_reg)
2081 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2082out:
2083 return rc;
2084}
2085
2086static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2087{
2088 int rc = 0;
2089
Subhash Jadavanicc922692011-08-01 23:05:01 +05302090 /* Put regulator in HPM (high power mode) */
2091 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2092 if (rc < 0)
2093 goto out;
2094
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002095 if (!vreg->is_enabled) {
2096 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302097 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2098 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002099 if (rc)
2100 goto out;
2101
2102 rc = regulator_enable(vreg->reg);
2103 if (rc) {
2104 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2105 __func__, vreg->name, rc);
2106 goto out;
2107 }
2108 vreg->is_enabled = true;
2109 }
2110
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002111out:
2112 return rc;
2113}
2114
2115static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
2116{
2117 int rc = 0;
2118
2119 /* Never disable regulator marked as always_on */
2120 if (vreg->is_enabled && !vreg->always_on) {
2121 rc = regulator_disable(vreg->reg);
2122 if (rc) {
2123 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2124 __func__, vreg->name, rc);
2125 goto out;
2126 }
2127 vreg->is_enabled = false;
2128
2129 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2130 if (rc < 0)
2131 goto out;
2132
2133 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302134 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002135 if (rc)
2136 goto out;
2137 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
2138 /* Put always_on regulator in LPM (low power mode) */
2139 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2140 if (rc < 0)
2141 goto out;
2142 }
2143out:
2144 return rc;
2145}
2146
2147static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
2148{
2149 int rc = 0, i;
2150 struct msm_mmc_slot_reg_data *curr_slot;
2151 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
2152 struct msm_mmc_reg_data *vreg_table[3];
2153
2154 curr_slot = host->plat->vreg_data;
2155 if (!curr_slot)
2156 goto out;
2157
2158 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
2159 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
2160 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
2161
2162 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2163 if (vreg_table[i]) {
2164 if (enable)
2165 rc = msmsdcc_vreg_enable(vreg_table[i]);
2166 else
2167 rc = msmsdcc_vreg_disable(vreg_table[i]);
2168 if (rc)
2169 goto out;
2170 }
2171 }
2172out:
2173 return rc;
2174}
2175
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002176/*
2177 * Reset vreg by ensuring it is off during probe. A call
2178 * to enable vreg is needed to balance disable vreg
2179 */
2180static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2181{
2182 int rc;
2183
2184 rc = msmsdcc_setup_vreg(host, 1);
2185 if (rc)
2186 return rc;
2187 rc = msmsdcc_setup_vreg(host, 0);
2188 return rc;
2189}
2190
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302191static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002192{
2193 int rc = 0;
2194
2195 if (host->plat->vreg_data) {
2196 struct msm_mmc_reg_data *vddp_reg =
2197 host->plat->vreg_data->vddp_data;
2198
2199 if (vddp_reg && vddp_reg->is_enabled)
2200 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
2201 }
2202
2203 return rc;
2204}
2205
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302206static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
2207{
2208 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2209 int rc = 0;
2210
2211 if (curr_slot && curr_slot->vddp_data) {
2212 rc = msmsdcc_set_vddp_level(host,
2213 curr_slot->vddp_data->low_vol_level);
2214
2215 if (rc)
2216 pr_err("%s: %s: failed to change vddp level to %d",
2217 mmc_hostname(host->mmc), __func__,
2218 curr_slot->vddp_data->low_vol_level);
2219 }
2220
2221 return rc;
2222}
2223
2224static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
2225{
2226 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2227 int rc = 0;
2228
2229 if (curr_slot && curr_slot->vddp_data) {
2230 rc = msmsdcc_set_vddp_level(host,
2231 curr_slot->vddp_data->high_vol_level);
2232
2233 if (rc)
2234 pr_err("%s: %s: failed to change vddp level to %d",
2235 mmc_hostname(host->mmc), __func__,
2236 curr_slot->vddp_data->high_vol_level);
2237 }
2238
2239 return rc;
2240}
2241
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302242static inline int msmsdcc_set_vccq_vol(struct msmsdcc_host *host, int level)
2243{
2244 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2245 int rc = 0;
2246
2247 if (curr_slot && curr_slot->vccq_data) {
2248 rc = msmsdcc_vreg_set_voltage(curr_slot->vccq_data,
2249 level, level);
2250 if (rc)
2251 pr_err("%s: %s: failed to change vccq level to %d",
2252 mmc_hostname(host->mmc), __func__, level);
2253 }
2254
2255 return rc;
2256}
2257
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002258static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2259{
2260 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2261 return 1;
2262 return 0;
2263}
2264
Asutosh Dasf5298c32012-04-03 14:51:47 +05302265/*
2266 * Any function calling msmsdcc_setup_clocks must
2267 * acquire clk_mutex. May sleep.
2268 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002269static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
2270{
2271 if (enable) {
2272 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302273 clk_prepare_enable(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002274 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302275 clk_prepare_enable(host->pclk);
2276 clk_prepare_enable(host->clk);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302277 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302278 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002279 } else {
Subhash Jadavanidd432952012-03-28 11:25:56 +05302280 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302281 msmsdcc_delay(host);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302282 clk_disable_unprepare(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002283 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302284 clk_disable_unprepare(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002285 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302286 clk_disable_unprepare(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002287 }
2288}
2289
2290static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2291 unsigned int req_clk)
2292{
2293 unsigned int sel_clk = -1;
2294
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302295 if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
2296 sel_clk = msmsdcc_get_min_sup_clk_rate(host);
2297 goto out;
2298 }
2299
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002300 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2301 unsigned char cnt;
2302
2303 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2304 if (host->plat->sup_clk_table[cnt] > req_clk)
2305 break;
2306 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2307 sel_clk = host->plat->sup_clk_table[cnt];
2308 break;
2309 } else
2310 sel_clk = host->plat->sup_clk_table[cnt];
2311 }
2312 } else {
2313 if ((req_clk < host->plat->msmsdcc_fmax) &&
2314 (req_clk > host->plat->msmsdcc_fmid))
2315 sel_clk = host->plat->msmsdcc_fmid;
2316 else
2317 sel_clk = req_clk;
2318 }
2319
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302320out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002321 return sel_clk;
2322}
2323
2324static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2325 struct msmsdcc_host *host)
2326{
2327 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2328 return host->plat->sup_clk_table[0];
2329 else
2330 return host->plat->msmsdcc_fmin;
2331}
2332
2333static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2334 struct msmsdcc_host *host)
2335{
2336 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2337 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2338 else
2339 return host->plat->msmsdcc_fmax;
2340}
2341
2342static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302343{
2344 struct msm_mmc_gpio_data *curr;
2345 int i, rc = 0;
2346
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002347 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302348 for (i = 0; i < curr->size; i++) {
2349 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002350 if (curr->gpio[i].is_always_on &&
2351 curr->gpio[i].is_enabled)
2352 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302353 rc = gpio_request(curr->gpio[i].no,
2354 curr->gpio[i].name);
2355 if (rc) {
2356 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2357 mmc_hostname(host->mmc),
2358 curr->gpio[i].no,
2359 curr->gpio[i].name, rc);
2360 goto free_gpios;
2361 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002362 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302363 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002364 if (curr->gpio[i].is_always_on)
2365 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302366 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002367 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302368 }
2369 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002370 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302371
2372free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002373 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302374 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002375 curr->gpio[i].is_enabled = false;
2376 }
2377out:
2378 return rc;
2379}
2380
2381static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2382{
2383 struct msm_mmc_pad_data *curr;
2384 int i;
2385
2386 curr = host->plat->pin_data->pad_data;
2387 for (i = 0; i < curr->drv->size; i++) {
2388 if (enable)
2389 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2390 curr->drv->on[i].val);
2391 else
2392 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2393 curr->drv->off[i].val);
2394 }
2395
2396 for (i = 0; i < curr->pull->size; i++) {
2397 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002398 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002399 curr->pull->on[i].val);
2400 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002401 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002402 curr->pull->off[i].val);
2403 }
2404
2405 return 0;
2406}
2407
2408static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2409{
2410 int rc = 0;
2411
2412 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2413 return 0;
2414
2415 if (host->plat->pin_data->is_gpio)
2416 rc = msmsdcc_setup_gpio(host, enable);
2417 else
2418 rc = msmsdcc_setup_pad(host, enable);
2419
2420 if (!rc)
2421 host->plat->pin_data->cfg_sts = enable;
2422
2423 return rc;
2424}
2425
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302426static int msmsdcc_cfg_mpm_sdiowakeup(struct msmsdcc_host *host,
2427 unsigned mode)
2428{
2429 int ret = 0;
2430 unsigned int pin = host->plat->mpm_sdiowakeup_int;
2431
2432 if (!pin)
2433 return 0;
2434
2435 switch (mode) {
2436 case SDC_DAT1_DISABLE:
2437 ret = msm_mpm_enable_pin(pin, 0);
2438 break;
2439 case SDC_DAT1_ENABLE:
2440 ret = msm_mpm_set_pin_type(pin, IRQ_TYPE_LEVEL_LOW);
2441 ret = msm_mpm_enable_pin(pin, 1);
2442 break;
2443 case SDC_DAT1_ENWAKE:
2444 ret = msm_mpm_set_pin_wake(pin, 1);
2445 break;
2446 case SDC_DAT1_DISWAKE:
2447 ret = msm_mpm_set_pin_wake(pin, 0);
2448 break;
2449 default:
2450 ret = -EINVAL;
2451 break;
2452 }
2453
2454 return ret;
2455}
2456
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302457static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2458{
2459 u32 pwr = 0;
2460 int ret = 0;
2461 struct mmc_host *mmc = host->mmc;
2462
2463 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2464 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2465 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2466 ret = msmsdcc_setup_vreg(host, !!ios->vdd);
2467
2468 if (ret) {
2469 pr_err("%s: Failed to setup voltage regulators\n",
2470 mmc_hostname(host->mmc));
2471 goto out;
2472 }
2473
2474 switch (ios->power_mode) {
2475 case MMC_POWER_OFF:
2476 pwr = MCI_PWR_OFF;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302477 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302478 /*
2479 * As VDD pad rail is always on, set low voltage for VDD
2480 * pad rail when slot is unused (when card is not present
2481 * or during system suspend).
2482 */
2483 msmsdcc_set_vddp_low_vol(host);
2484 msmsdcc_setup_pins(host, false);
2485 break;
2486 case MMC_POWER_UP:
2487 /* writing PWR_UP bit is redundant */
2488 pwr = MCI_PWR_UP;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302489 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302490
2491 msmsdcc_set_vddp_high_vol(host);
2492 msmsdcc_setup_pins(host, true);
2493 break;
2494 case MMC_POWER_ON:
2495 pwr = MCI_PWR_ON;
2496 break;
2497 }
2498
2499out:
2500 return pwr;
2501}
2502
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002503static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2504{
2505 unsigned int wakeup_irq;
2506
2507 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2508 host->plat->sdiowakeup_irq :
2509 host->core_irqres->start;
2510
2511 if (!host->irq_wake_enabled) {
2512 enable_irq_wake(wakeup_irq);
2513 host->irq_wake_enabled = true;
2514 }
2515}
2516
2517static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2518{
2519 unsigned int wakeup_irq;
2520
2521 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2522 host->plat->sdiowakeup_irq :
2523 host->core_irqres->start;
2524
2525 if (host->irq_wake_enabled) {
2526 disable_irq_wake(wakeup_irq);
2527 host->irq_wake_enabled = false;
2528 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302529}
2530
San Mehat9d2bd732009-09-22 16:44:22 -07002531static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302532msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
2533{
2534 struct mmc_host *mmc = host->mmc;
2535
2536 /*
2537 * SDIO_AL clients has different mechanism of handling LPM through
2538 * sdio_al driver itself. The sdio wakeup interrupt is configured as
2539 * part of that. Here, we are interested only in clients like WLAN.
2540 */
2541 if (!(mmc->card && mmc_card_sdio(mmc->card))
2542 || host->plat->is_sdio_al_client)
2543 goto out;
2544
2545 if (!host->sdcc_suspended) {
2546 /*
2547 * When MSM is not in power collapse and we
2548 * are disabling clocks, enable bit 22 in MASK0
2549 * to handle asynchronous SDIO interrupts.
2550 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302551 if (enable_wakeup_irq) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302552 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302553 mb();
2554 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302555 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302556 msmsdcc_sync_reg_wr(host);
2557 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302558 goto out;
2559 } else if (!mmc_card_wake_sdio_irq(mmc)) {
2560 /*
2561 * Wakeup MSM only if SDIO function drivers set
2562 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
2563 */
2564 goto out;
2565 }
2566
2567 if (enable_wakeup_irq) {
2568 if (!host->plat->sdiowakeup_irq) {
2569 /*
2570 * When there is no gpio line that can be configured
2571 * as wakeup interrupt handle it by configuring
2572 * asynchronous sdio interrupts and DAT1 line.
2573 */
2574 writel_relaxed(MCI_SDIOINTMASK,
2575 host->base + MMCIMASK0);
2576 mb();
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302577 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302578 /* configure sdcc core interrupt as wakeup interrupt */
2579 msmsdcc_enable_irq_wake(host);
2580 } else {
2581 /* Let gpio line handle wakeup interrupt */
2582 writel_relaxed(0, host->base + MMCIMASK0);
2583 mb();
2584 if (host->sdio_wakeupirq_disabled) {
2585 host->sdio_wakeupirq_disabled = 0;
2586 /* configure gpio line as wakeup interrupt */
2587 msmsdcc_enable_irq_wake(host);
2588 enable_irq(host->plat->sdiowakeup_irq);
2589 }
2590 }
2591 } else {
2592 if (!host->plat->sdiowakeup_irq) {
2593 /*
2594 * We may not have cleared bit 22 in the interrupt
2595 * handler as the clocks might be off at that time.
2596 */
2597 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302598 msmsdcc_sync_reg_wr(host);
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302599 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302600 msmsdcc_disable_irq_wake(host);
2601 } else if (!host->sdio_wakeupirq_disabled) {
2602 disable_irq_nosync(host->plat->sdiowakeup_irq);
2603 msmsdcc_disable_irq_wake(host);
2604 host->sdio_wakeupirq_disabled = 1;
2605 }
2606 }
2607out:
2608 return;
2609}
2610
2611static void
San Mehat9d2bd732009-09-22 16:44:22 -07002612msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2613{
2614 struct msmsdcc_host *host = mmc_priv(mmc);
2615 u32 clk = 0, pwr = 0;
2616 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002617 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002618 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002619
Sahitya Tummala7a892482011-01-18 11:22:49 +05302620
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302621 /*
2622 * Disable SDCC core interrupt until set_ios is completed.
2623 * This avoids any race conditions with interrupt raised
2624 * when turning on/off the clocks. One possible
2625 * scenario is SDIO operational interrupt while the clock
2626 * is turned off.
Asutosh Dasf5298c32012-04-03 14:51:47 +05302627 * host->lock is being released intermittently below.
2628 * Thus, prevent concurrent access to host.
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302629 */
2630
Asutosh Dasf5298c32012-04-03 14:51:47 +05302631 mutex_lock(&host->clk_mutex);
2632 DBG(host, "ios->clock = %u\n", ios->clock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302633 spin_lock_irqsave(&host->lock, flags);
2634 if (!host->sdcc_irq_disabled) {
2635 spin_unlock_irqrestore(&host->lock, flags);
2636 disable_irq(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002637 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302638 host->sdcc_irq_disabled = 1;
2639 }
2640 spin_unlock_irqrestore(&host->lock, flags);
2641
2642 pwr = msmsdcc_setup_pwr(host, ios);
2643
2644 spin_lock_irqsave(&host->lock, flags);
2645 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002646 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302647 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002648 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302649 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002650 host->clks_on = 1;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302651 writel_relaxed(host->mci_irqenable,
2652 host->base + MMCIMASK0);
2653 mb();
2654 msmsdcc_cfg_sdio_wakeup(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002655 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002656
2657 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2658 /*
2659 * For DDR50 mode, controller needs clock rate to be
2660 * double than what is required on the SD card CLK pin.
2661 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302662 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002663 /*
2664 * Make sure that we don't double the clock if
2665 * doubled clock rate is already set
2666 */
2667 if (!host->ddr_doubled_clk_rate ||
2668 (host->ddr_doubled_clk_rate &&
2669 (host->ddr_doubled_clk_rate != ios->clock))) {
2670 host->ddr_doubled_clk_rate =
2671 msmsdcc_get_sup_clk_rate(
2672 host, (ios->clock * 2));
2673 clock = host->ddr_doubled_clk_rate;
2674 }
2675 } else {
2676 host->ddr_doubled_clk_rate = 0;
2677 }
2678
2679 if (clock != host->clk_rate) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302680 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002681 rc = clk_set_rate(host->clk, clock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302682 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002683 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302684 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002685 mmc_hostname(mmc), clock);
2686 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302687 host->reg_write_delay =
2688 (1 + ((3 * USEC_PER_SEC) /
2689 (host->clk_rate ? host->clk_rate :
2690 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002691 }
2692 /*
2693 * give atleast 2 MCLK cycles delay for clocks
2694 * and SDCC core to stabilize
2695 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302696 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002697 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002698 clk |= MCI_CLK_ENABLE;
2699 }
2700
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002701 if (ios->bus_width == MMC_BUS_WIDTH_8)
2702 clk |= MCI_CLK_WIDEBUS_8;
2703 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2704 clk |= MCI_CLK_WIDEBUS_4;
2705 else
2706 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002707
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002708 if (msmsdcc_is_pwrsave(host))
2709 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002710
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002711 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002712
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002713 host->tuning_needed = 0;
2714 /*
2715 * Select the controller timing mode according
2716 * to current bus speed mode
2717 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302718 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2719 (ios->timing == MMC_TIMING_MMC_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002720 clk |= (4 << 14);
2721 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302722 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002723 clk |= (3 << 14);
2724 } else {
2725 clk |= (2 << 14); /* feedback clock */
2726 }
2727
2728 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2729 clk |= (2 << 23);
2730
Subhash Jadavani00083572012-02-15 16:18:01 +05302731 /* Clear IO_PAD_PWR_SWITCH while powering off the card */
2732 if (!ios->vdd)
2733 host->io_pad_pwr_switch = 0;
2734
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002735 if (host->io_pad_pwr_switch)
2736 clk |= IO_PAD_PWR_SWITCH;
2737
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302738 /* Don't write into registers if clocks are disabled */
2739 if (host->clks_on) {
2740 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
2741 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302742 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002743 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302744 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
2745 host->pwr = pwr;
2746 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302747 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002748 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002749 }
2750
2751 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302752 msmsdcc_cfg_sdio_wakeup(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302753 spin_unlock_irqrestore(&host->lock, flags);
2754 /*
2755 * May get a wake-up interrupt the instant we disable the
2756 * clocks. This would disable the wake-up interrupt.
2757 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002758 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302759 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002760 host->clks_on = 0;
2761 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302762
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302763 if (host->tuning_in_progress)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302764 WARN(!host->clks_on,
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302765 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302766
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302767 /* Let interrupts be disabled if the host is powered off */
2768 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
2769 enable_irq(host->core_irqres->start);
2770 host->sdcc_irq_disabled = 0;
2771 }
2772
San Mehat4adbbcc2009-11-08 13:00:37 -08002773 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302774 mutex_unlock(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07002775}
2776
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002777int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2778{
2779 struct msmsdcc_host *host = mmc_priv(mmc);
2780 u32 clk;
2781
2782 clk = readl_relaxed(host->base + MMCICLOCK);
2783 pr_debug("Changing to pwr_save=%d", pwrsave);
2784 if (pwrsave && msmsdcc_is_pwrsave(host))
2785 clk |= MCI_CLK_PWRSAVE;
2786 else
2787 clk &= ~MCI_CLK_PWRSAVE;
2788 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302789 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002790
2791 return 0;
2792}
2793
2794static int msmsdcc_get_ro(struct mmc_host *mmc)
2795{
2796 int status = -ENOSYS;
2797 struct msmsdcc_host *host = mmc_priv(mmc);
2798
2799 if (host->plat->wpswitch) {
2800 status = host->plat->wpswitch(mmc_dev(mmc));
2801 } else if (host->plat->wpswitch_gpio) {
2802 status = gpio_request(host->plat->wpswitch_gpio,
2803 "SD_WP_Switch");
2804 if (status) {
2805 pr_err("%s: %s: Failed to request GPIO %d\n",
2806 mmc_hostname(mmc), __func__,
2807 host->plat->wpswitch_gpio);
2808 } else {
2809 status = gpio_direction_input(
2810 host->plat->wpswitch_gpio);
2811 if (!status) {
2812 /*
2813 * Wait for atleast 300ms as debounce
2814 * time for GPIO input to stabilize.
2815 */
2816 msleep(300);
2817 status = gpio_get_value_cansleep(
2818 host->plat->wpswitch_gpio);
2819 status ^= !host->plat->wpswitch_polarity;
2820 }
2821 gpio_free(host->plat->wpswitch_gpio);
2822 }
2823 }
2824
2825 if (status < 0)
2826 status = -ENOSYS;
2827 pr_debug("%s: Card read-only status %d\n", __func__, status);
2828
2829 return status;
2830}
2831
San Mehat9d2bd732009-09-22 16:44:22 -07002832static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2833{
2834 struct msmsdcc_host *host = mmc_priv(mmc);
2835 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002836
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302837 /*
2838 * We may come here with clocks turned off in that case don't
2839 * attempt to write into MASK0 register. While turning on the
2840 * clocks mci_irqenable will be written to MASK0 register.
2841 */
2842
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002843 if (enable) {
2844 spin_lock_irqsave(&host->lock, flags);
2845 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302846 if (host->clks_on) {
2847 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002848 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302849 mb();
2850 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002851 spin_unlock_irqrestore(&host->lock, flags);
2852 } else {
2853 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302854 if (host->clks_on) {
2855 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002856 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302857 mb();
2858 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002859 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002860}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002861
2862#ifdef CONFIG_PM_RUNTIME
subhashj245831e2012-04-30 18:46:17 +05302863static void msmsdcc_print_rpm_info(struct msmsdcc_host *host)
2864{
2865 struct device *dev = mmc_dev(host->mmc);
2866
2867 pr_info("%s: RPM: runtime_status=%d, usage_count=%d,"
2868 " is_suspended=%d, disable_depth=%d, runtime_error=%d,"
2869 " request_pending=%d, request=%d\n",
2870 mmc_hostname(host->mmc), dev->power.runtime_status,
2871 atomic_read(&dev->power.usage_count),
2872 dev->power.is_suspended, dev->power.disable_depth,
2873 dev->power.runtime_error, dev->power.request_pending,
2874 dev->power.request);
2875}
2876
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002877static int msmsdcc_enable(struct mmc_host *mmc)
2878{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002879 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002880 struct device *dev = mmc->parent;
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302881 struct msmsdcc_host *host = mmc_priv(mmc);
2882
2883 msmsdcc_pm_qos_update_latency(host, 1);
2884
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002885 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302886 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002887
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002888 if (host->sdcc_suspended && host->pending_resume &&
2889 !pm_runtime_suspended(dev)) {
2890 host->pending_resume = false;
2891 pm_runtime_get_noresume(dev);
2892 rc = msmsdcc_runtime_resume(dev);
2893 goto out;
2894 }
2895
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302896 if (dev->power.runtime_status == RPM_SUSPENDING) {
2897 if (mmc->suspend_task == current) {
2898 pm_runtime_get_noresume(dev);
2899 goto out;
2900 }
2901 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002902
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302903 rc = pm_runtime_get_sync(dev);
2904
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002905out:
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302906 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002907 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2908 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05302909 msmsdcc_print_rpm_info(host);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302910 return rc;
2911 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302912
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302913 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002914}
2915
2916static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2917{
2918 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302919 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002920
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302921 msmsdcc_pm_qos_update_latency(host, 0);
2922
2923 if (mmc->card && mmc_card_sdio(mmc->card))
2924 return 0;
2925
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302926 if (host->plat->disable_runtime_pm)
2927 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002928
2929 rc = pm_runtime_put_sync(mmc->parent);
2930
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002931 /*
2932 * Ignore -EAGAIN as that is not fatal, it means that
2933 * either runtime usage count is non-zero or the runtime
2934 * pm itself is disabled or not in proper state to process
2935 * idle notification.
2936 */
2937 if (rc < 0 && (rc != -EAGAIN)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002938 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2939 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05302940 msmsdcc_print_rpm_info(host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002941 return rc;
2942 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302943
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002944 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002945}
2946#else
subhashj245831e2012-04-30 18:46:17 +05302947static void msmsdcc_print_rpm_info(struct msmsdcc_host *host) {}
2948
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302949static int msmsdcc_enable(struct mmc_host *mmc)
2950{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002951 struct device *dev = mmc->parent;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302952 struct msmsdcc_host *host = mmc_priv(mmc);
2953 unsigned long flags;
Sujit Reddy Thumma7f5051c2012-05-04 10:14:07 +05302954 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302955
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302956 msmsdcc_pm_qos_update_latency(host, 1);
2957
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002958 if (mmc->card && mmc_card_sdio(mmc->card))
2959 return 0;
2960
2961 if (host->sdcc_suspended && host->pending_resume) {
2962 host->pending_resume = false;
2963 rc = msmsdcc_runtime_resume(dev);
2964 goto out;
2965 }
2966
Asutosh Dasf5298c32012-04-03 14:51:47 +05302967 mutex_lock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302968 spin_lock_irqsave(&host->lock, flags);
2969 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302970 spin_unlock_irqrestore(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302971 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302972 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302973 host->clks_on = 1;
2974 }
2975 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302976 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302977
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002978out:
2979 if (rc < 0) {
2980 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2981 __func__, rc);
2982 return rc;
2983 }
2984
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302985 return 0;
2986}
2987
2988static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2989{
2990 struct msmsdcc_host *host = mmc_priv(mmc);
2991 unsigned long flags;
2992
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302993 msmsdcc_pm_qos_update_latency(host, 0);
2994
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302995 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302996 return 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302997
Asutosh Dasf5298c32012-04-03 14:51:47 +05302998 mutex_lock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302999 spin_lock_irqsave(&host->lock, flags);
3000 if (host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05303001 spin_unlock_irqrestore(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303002 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303003 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303004 host->clks_on = 0;
3005 }
3006 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303007 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303008
3009 return 0;
3010}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003011#endif
3012
3013static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
3014 struct mmc_ios *ios)
3015{
3016 struct msmsdcc_host *host = mmc_priv(mmc);
3017 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303018 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003019
Subhash Jadavani00083572012-02-15 16:18:01 +05303020 spin_lock_irqsave(&host->lock, flags);
3021 host->io_pad_pwr_switch = 0;
3022 spin_unlock_irqrestore(&host->lock, flags);
3023
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303024 /*
3025 * For eMMC cards, VccQ voltage range must be changed
3026 * only if it operates in HS200 SDR 1.2V mode or in
3027 * DDR 1.2V mode.
3028 */
3029 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_120) {
3030 rc = msmsdcc_set_vccq_vol(host, 1200000);
3031 goto out;
3032 }
3033
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003034 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
3035 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303036 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003037 goto out;
3038 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
3039 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303040 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003041 goto out;
3042 }
San Mehat9d2bd732009-09-22 16:44:22 -07003043
3044 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003045 /*
3046 * If we are here means voltage switch from high voltage to
3047 * low voltage is required
3048 */
3049
3050 /*
3051 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
3052 * register until they become all zeros.
3053 */
3054 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303055 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003056 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
3057 mmc_hostname(mmc), __func__);
3058 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07003059 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003060
3061 /* Stop SD CLK output. */
3062 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3063 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303064 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003065 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003066
3067 /*
3068 * Switch VDDPX from high voltage to low voltage
3069 * to change the VDD of the SD IO pads.
3070 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303071 rc = msmsdcc_set_vddp_low_vol(host);
3072 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003073 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003074
3075 spin_lock_irqsave(&host->lock, flags);
3076 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3077 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303078 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003079 host->io_pad_pwr_switch = 1;
3080 spin_unlock_irqrestore(&host->lock, flags);
3081
3082 /* Wait 5 ms for the voltage regulater in the card to become stable. */
3083 usleep_range(5000, 5500);
3084
3085 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303086 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003087 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3088 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303089 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003090 spin_unlock_irqrestore(&host->lock, flags);
3091
3092 /*
3093 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
3094 * don't become all ones within 1 ms then a Voltage Switch
3095 * sequence has failed and a power cycle to the card is required.
3096 * Otherwise Voltage Switch sequence is completed successfully.
3097 */
3098 usleep_range(1000, 1500);
3099
3100 spin_lock_irqsave(&host->lock, flags);
3101 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
3102 != (0xF << 1)) {
3103 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
3104 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303105 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003106 goto out_unlock;
3107 }
3108
3109out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303110 /* Enable PWRSAVE */
3111 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3112 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303113 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003114 spin_unlock_irqrestore(&host->lock, flags);
3115out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303116 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003117}
3118
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303119static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003120{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003121 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003122
3123 /* Program the MCLK value to MCLK_FREQ bit field */
3124 if (host->clk_rate <= 112000000)
3125 mclk_freq = 0;
3126 else if (host->clk_rate <= 125000000)
3127 mclk_freq = 1;
3128 else if (host->clk_rate <= 137000000)
3129 mclk_freq = 2;
3130 else if (host->clk_rate <= 150000000)
3131 mclk_freq = 3;
3132 else if (host->clk_rate <= 162000000)
3133 mclk_freq = 4;
3134 else if (host->clk_rate <= 175000000)
3135 mclk_freq = 5;
3136 else if (host->clk_rate <= 187000000)
3137 mclk_freq = 6;
3138 else if (host->clk_rate <= 200000000)
3139 mclk_freq = 7;
3140
3141 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3142 & ~(7 << 24)) | (mclk_freq << 24)),
3143 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003144}
3145
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303146/* Initialize the DLL (Programmable Delay Line ) */
3147static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003148{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003149 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303150 unsigned long flags;
3151 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003152
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303153 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003154 /*
3155 * Make sure that clock is always enabled when DLL
3156 * tuning is in progress. Keeping PWRSAVE ON may
3157 * turn off the clock. So let's disable the PWRSAVE
3158 * here and re-enable it once tuning is completed.
3159 */
3160 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3161 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303162 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303163
3164 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3165 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3166 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3167
3168 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3169 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3170 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3171
3172 msmsdcc_cm_sdc4_dll_set_freq(host);
3173
3174 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3175 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3176 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3177
3178 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3179 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3180 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3181
3182 /* Set DLL_EN bit to 1. */
3183 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3184 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3185
3186 /* Set CK_OUT_EN bit to 1. */
3187 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3188 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3189
3190 wait_cnt = 50;
3191 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3192 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3193 /* max. wait for 50us sec for LOCK bit to be set */
3194 if (--wait_cnt == 0) {
3195 pr_err("%s: %s: DLL failed to LOCK\n",
3196 mmc_hostname(host->mmc), __func__);
3197 rc = -ETIMEDOUT;
3198 goto out;
3199 }
3200 /* wait for 1us before polling again */
3201 udelay(1);
3202 }
3203
3204out:
3205 /* re-enable PWRSAVE */
3206 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3207 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303208 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303209 spin_unlock_irqrestore(&host->lock, flags);
3210
3211 return rc;
3212}
3213
3214static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3215 u8 poll)
3216{
3217 int rc = 0;
3218 u32 wait_cnt = 50;
3219 u8 ck_out_en = 0;
3220
3221 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3222 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3223 MCI_CK_OUT_EN);
3224
3225 while (ck_out_en != poll) {
3226 if (--wait_cnt == 0) {
3227 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3228 mmc_hostname(host->mmc), __func__, poll);
3229 rc = -ETIMEDOUT;
3230 goto out;
3231 }
3232 udelay(1);
3233
3234 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3235 MCI_CK_OUT_EN);
3236 }
3237out:
3238 return rc;
3239}
3240
3241/*
3242 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3243 * calibration sequence. This function should be called before
3244 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3245 * commands (CMD17/CMD18).
3246 *
3247 * This function gets called when host spinlock acquired.
3248 */
3249static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3250{
3251 int rc = 0;
3252 u32 config;
3253
3254 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3255 config |= MCI_CDR_EN;
3256 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3257 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3258
3259 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3260 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3261 if (rc)
3262 goto err_out;
3263
3264 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3265 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3266 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3267
3268 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3269 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3270 if (rc)
3271 goto err_out;
3272
3273 goto out;
3274
3275err_out:
3276 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3277out:
3278 return rc;
3279}
3280
3281static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3282 u8 phase)
3283{
3284 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303285 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3286 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3287 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303288 unsigned long flags;
3289 u32 config;
3290
3291 spin_lock_irqsave(&host->lock, flags);
3292
3293 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3294 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3295 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3296 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3297
3298 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3299 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3300 if (rc)
3301 goto err_out;
3302
3303 /*
3304 * Write the selected DLL clock output phase (0 ... 15)
3305 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
3306 */
3307 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3308 & ~(0xF << 20))
3309 | (grey_coded_phase_table[phase] << 20)),
3310 host->base + MCI_DLL_CONFIG);
3311
3312 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3313 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3314 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3315
3316 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3317 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3318 if (rc)
3319 goto err_out;
3320
3321 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3322 config |= MCI_CDR_EN;
3323 config &= ~MCI_CDR_EXT_EN;
3324 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3325 goto out;
3326
3327err_out:
3328 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3329 mmc_hostname(host->mmc), __func__, phase);
3330out:
3331 spin_unlock_irqrestore(&host->lock, flags);
3332 return rc;
3333}
3334
3335/*
3336 * Find out the greatest range of consecuitive selected
3337 * DLL clock output phases that can be used as sampling
3338 * setting for SD3.0 UHS-I card read operation (in SDR104
3339 * timing mode) or for eMMC4.5 card read operation (in HS200
3340 * timing mode).
3341 * Select the 3/4 of the range and configure the DLL with the
3342 * selected DLL clock output phase.
3343*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303344static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303345 u8 *phase_table, u8 total_phases)
3346{
Subhash Jadavani6159c622012-03-15 19:05:55 +05303347 #define MAX_PHASES 16
Subhash Jadavani34187042012-03-02 10:59:49 +05303348 int ret;
Subhash Jadavani6159c622012-03-15 19:05:55 +05303349 u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
3350 u8 phases_per_row[MAX_PHASES] = {0};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303351 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303352 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3353 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303354
Subhash Jadavani6159c622012-03-15 19:05:55 +05303355 if (!total_phases || (total_phases > MAX_PHASES)) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303356 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3357 mmc_hostname(host->mmc), __func__, total_phases);
3358 return -EINVAL;
3359 }
3360
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303361 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303362 ranges[row_index][col_index] = phase_table[cnt];
3363 phases_per_row[row_index] += 1;
3364 col_index++;
3365
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303366 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303367 continue;
3368 /* check if next phase in phase_table is consecutive or not */
3369 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3370 row_index++;
3371 col_index = 0;
3372 }
3373 }
3374
Subhash Jadavani6159c622012-03-15 19:05:55 +05303375 if (row_index >= MAX_PHASES)
3376 return -EINVAL;
3377
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303378 /* Check if phase-0 is present in first valid window? */
3379 if (!ranges[0][0]) {
3380 phase_0_found = true;
3381 phase_0_raw_index = 0;
3382 /* Check if cycle exist between 2 valid windows */
3383 for (cnt = 1; cnt <= row_index; cnt++) {
3384 if (phases_per_row[cnt]) {
Subhash Jadavani6159c622012-03-15 19:05:55 +05303385 for (i = 0; i < phases_per_row[cnt]; i++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303386 if (ranges[cnt][i] == 15) {
3387 phase_15_found = true;
3388 phase_15_raw_index = cnt;
3389 break;
3390 }
3391 }
3392 }
3393 }
3394 }
3395
3396 /* If 2 valid windows form cycle then merge them as single window */
3397 if (phase_0_found && phase_15_found) {
3398 /* number of phases in raw where phase 0 is present */
3399 u8 phases_0 = phases_per_row[phase_0_raw_index];
3400 /* number of phases in raw where phase 15 is present */
3401 u8 phases_15 = phases_per_row[phase_15_raw_index];
3402
Subhash Jadavani6159c622012-03-15 19:05:55 +05303403 if (phases_0 + phases_15 >= MAX_PHASES)
3404 /*
3405 * If there are more than 1 phase windows then total
3406 * number of phases in both the windows should not be
3407 * more than or equal to MAX_PHASES.
3408 */
3409 return -EINVAL;
3410
3411 /* Merge 2 cyclic windows */
3412 i = phases_15;
3413 for (cnt = 0; cnt < phases_0; cnt++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303414 ranges[phase_15_raw_index][i] =
3415 ranges[phase_0_raw_index][cnt];
Subhash Jadavani6159c622012-03-15 19:05:55 +05303416 if (++i >= MAX_PHASES)
3417 break;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303418 }
Subhash Jadavani6159c622012-03-15 19:05:55 +05303419
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303420 phases_per_row[phase_0_raw_index] = 0;
3421 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
3422 }
3423
3424 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303425 if (phases_per_row[cnt] > curr_max) {
3426 curr_max = phases_per_row[cnt];
3427 selected_row_index = cnt;
3428 }
3429 }
3430
Subhash Jadavani6159c622012-03-15 19:05:55 +05303431 i = ((curr_max * 3) / 4);
3432 if (i)
3433 i--;
3434
Subhash Jadavani34187042012-03-02 10:59:49 +05303435 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303436
Subhash Jadavani6159c622012-03-15 19:05:55 +05303437 if (ret >= MAX_PHASES) {
3438 ret = -EINVAL;
3439 pr_err("%s: %s: invalid phase selected=%d\n",
3440 mmc_hostname(host->mmc), __func__, ret);
3441 }
3442
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303443 return ret;
3444}
3445
Girish K Sa3f41692012-02-29 12:00:09 +05303446static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303447{
3448 int rc = 0;
3449 struct msmsdcc_host *host = mmc_priv(mmc);
3450 unsigned long flags;
3451 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303452 const u32 *tuning_block_pattern = tuning_block_64;
3453 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303454
3455 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
3456
3457 /* Tuning is only required for SDR104 modes */
3458 if (!host->tuning_needed) {
3459 rc = 0;
3460 goto exit;
3461 }
3462
3463 spin_lock_irqsave(&host->lock, flags);
3464 WARN(!host->pwr, "SDCC power is turned off\n");
3465 WARN(!host->clks_on, "SDCC clocks are turned off\n");
3466 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
3467
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303468 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303469 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
3470 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
3471 tuning_block_pattern = tuning_block_128;
3472 size = sizeof(tuning_block_128);
3473 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303474 spin_unlock_irqrestore(&host->lock, flags);
3475
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003476 /* first of all reset the tuning block */
3477 rc = msmsdcc_init_cm_sdc4_dll(host);
3478 if (rc)
3479 goto out;
3480
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303481 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003482 if (!data_buf) {
3483 rc = -ENOMEM;
3484 goto out;
3485 }
3486
3487 phase = 0;
3488 do {
3489 struct mmc_command cmd = {0};
3490 struct mmc_data data = {0};
3491 struct mmc_request mrq = {
3492 .cmd = &cmd,
3493 .data = &data
3494 };
3495 struct scatterlist sg;
3496
3497 /* set the phase in delay line hw block */
3498 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3499 if (rc)
3500 goto kfree;
3501
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303502 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003503 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
3504
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303505 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003506 data.blocks = 1;
3507 data.flags = MMC_DATA_READ;
3508 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
3509
3510 data.sg = &sg;
3511 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303512 sg_init_one(&sg, data_buf, size);
3513 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003514 mmc_wait_for_req(mmc, &mrq);
3515
3516 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303517 !memcmp(data_buf, tuning_block_pattern, size)) {
3518 /* tuning is successful at this tuning point */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003519 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303520 pr_debug("%s: %s: found good phase = %d\n",
3521 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003522 }
3523 } while (++phase < 16);
3524
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003525 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303526 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303527 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05303528 if (rc < 0)
3529 goto kfree;
3530 else
3531 phase = (u8)rc;
3532
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003533 /*
3534 * Finally set the selected phase in delay
3535 * line hw block.
3536 */
3537 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3538 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303539 goto kfree;
3540 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
3541 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003542 } else {
3543 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303544 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003545 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303546 msmsdcc_dump_sdcc_state(host);
3547 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003548 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003549
3550kfree:
3551 kfree(data_buf);
3552out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303553 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303554 host->tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303555 spin_unlock_irqrestore(&host->lock, flags);
3556exit:
3557 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003558 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07003559}
3560
3561static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003562 .enable = msmsdcc_enable,
3563 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07003564 .request = msmsdcc_request,
3565 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003566 .get_ro = msmsdcc_get_ro,
San Mehat9d2bd732009-09-22 16:44:22 -07003567 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003568 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
3569 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07003570};
3571
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003572static unsigned int
3573msmsdcc_slot_status(struct msmsdcc_host *host)
3574{
3575 int status;
3576 unsigned int gpio_no = host->plat->status_gpio;
3577
3578 status = gpio_request(gpio_no, "SD_HW_Detect");
3579 if (status) {
3580 pr_err("%s: %s: Failed to request GPIO %d\n",
3581 mmc_hostname(host->mmc), __func__, gpio_no);
3582 } else {
3583 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003584 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08003585 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003586 if (host->plat->is_status_gpio_active_low)
3587 status = !status;
3588 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003589 gpio_free(gpio_no);
3590 }
3591 return status;
3592}
3593
San Mehat9d2bd732009-09-22 16:44:22 -07003594static void
3595msmsdcc_check_status(unsigned long data)
3596{
3597 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3598 unsigned int status;
3599
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003600 if (host->plat->status || host->plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08003601 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003602 status = host->plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08003603 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003604 status = msmsdcc_slot_status(host);
3605
Krishna Konda941604a2012-01-10 17:46:34 -08003606 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08003607
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003608 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08003609 if (host->plat->status)
3610 pr_info("%s: Slot status change detected "
3611 "(%d -> %d)\n",
3612 mmc_hostname(host->mmc),
3613 host->oldstat, status);
3614 else if (host->plat->is_status_gpio_active_low)
3615 pr_info("%s: Slot status change detected "
3616 "(%d -> %d) and the card detect GPIO"
3617 " is ACTIVE_LOW\n",
3618 mmc_hostname(host->mmc),
3619 host->oldstat, status);
3620 else
3621 pr_info("%s: Slot status change detected "
3622 "(%d -> %d) and the card detect GPIO"
3623 " is ACTIVE_HIGH\n",
3624 mmc_hostname(host->mmc),
3625 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07003626 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003627 }
3628 host->oldstat = status;
3629 } else {
3630 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07003631 }
San Mehat9d2bd732009-09-22 16:44:22 -07003632}
3633
3634static irqreturn_t
3635msmsdcc_platform_status_irq(int irq, void *dev_id)
3636{
3637 struct msmsdcc_host *host = dev_id;
3638
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003639 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07003640 msmsdcc_check_status((unsigned long) host);
3641 return IRQ_HANDLED;
3642}
3643
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003644static irqreturn_t
3645msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
3646{
3647 struct msmsdcc_host *host = dev_id;
3648
3649 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
3650 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303651 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003652 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303653 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003654 wake_lock(&host->sdio_wlock);
3655 msmsdcc_disable_irq_wake(host);
3656 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303657 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003658 }
3659 if (host->plat->is_sdio_al_client) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003660 wake_lock(&host->sdio_wlock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303661 mmc_signal_sdio_irq(host->mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003662 }
3663 spin_unlock(&host->lock);
3664
3665 return IRQ_HANDLED;
3666}
3667
San Mehat9d2bd732009-09-22 16:44:22 -07003668static void
3669msmsdcc_status_notify_cb(int card_present, void *dev_id)
3670{
3671 struct msmsdcc_host *host = dev_id;
3672
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003673 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07003674 card_present);
3675 msmsdcc_check_status((unsigned long) host);
3676}
3677
San Mehat9d2bd732009-09-22 16:44:22 -07003678static int
3679msmsdcc_init_dma(struct msmsdcc_host *host)
3680{
3681 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
3682 host->dma.host = host;
3683 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003684 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003685
3686 if (!host->dmares)
3687 return -ENODEV;
3688
3689 host->dma.nc = dma_alloc_coherent(NULL,
3690 sizeof(struct msmsdcc_nc_dmadata),
3691 &host->dma.nc_busaddr,
3692 GFP_KERNEL);
3693 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003694 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07003695 return -ENOMEM;
3696 }
3697 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
3698 host->dma.cmd_busaddr = host->dma.nc_busaddr;
3699 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
3700 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
3701 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07003702 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07003703
3704 return 0;
3705}
3706
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003707#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
3708/**
3709 * Allocate and Connect a SDCC peripheral's SPS endpoint
3710 *
3711 * This function allocates endpoint context and
3712 * connect it with memory endpoint by calling
3713 * appropriate SPS driver APIs.
3714 *
3715 * Also registers a SPS callback function with
3716 * SPS driver
3717 *
3718 * This function should only be called once typically
3719 * during driver probe.
3720 *
3721 * @host - Pointer to sdcc host structure
3722 * @ep - Pointer to sps endpoint data structure
3723 * @is_produce - 1 means Producer endpoint
3724 * 0 means Consumer endpoint
3725 *
3726 * @return - 0 if successful else negative value.
3727 *
3728 */
3729static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
3730 struct msmsdcc_sps_ep_conn_data *ep,
3731 bool is_producer)
3732{
3733 int rc = 0;
3734 struct sps_pipe *sps_pipe_handle;
3735 struct sps_connect *sps_config = &ep->config;
3736 struct sps_register_event *sps_event = &ep->event;
3737
3738 /* Allocate endpoint context */
3739 sps_pipe_handle = sps_alloc_endpoint();
3740 if (!sps_pipe_handle) {
3741 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
3742 mmc_hostname(host->mmc), is_producer);
3743 rc = -ENOMEM;
3744 goto out;
3745 }
3746
3747 /* Get default connection configuration for an endpoint */
3748 rc = sps_get_config(sps_pipe_handle, sps_config);
3749 if (rc) {
3750 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
3751 " rc=%d", mmc_hostname(host->mmc),
3752 (u32)sps_pipe_handle, rc);
3753 goto get_config_err;
3754 }
3755
3756 /* Modify the default connection configuration */
3757 if (is_producer) {
3758 /*
3759 * For SDCC producer transfer, source should be
3760 * SDCC peripheral where as destination should
3761 * be system memory.
3762 */
3763 sps_config->source = host->sps.bam_handle;
3764 sps_config->destination = SPS_DEV_HANDLE_MEM;
3765 /* Producer pipe will handle this connection */
3766 sps_config->mode = SPS_MODE_SRC;
3767 sps_config->options =
3768 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3769 } else {
3770 /*
3771 * For SDCC consumer transfer, source should be
3772 * system memory where as destination should
3773 * SDCC peripheral
3774 */
3775 sps_config->source = SPS_DEV_HANDLE_MEM;
3776 sps_config->destination = host->sps.bam_handle;
3777 sps_config->mode = SPS_MODE_DEST;
3778 sps_config->options =
3779 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3780 }
3781
3782 /* Producer pipe index */
3783 sps_config->src_pipe_index = host->sps.src_pipe_index;
3784 /* Consumer pipe index */
3785 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
3786 /*
3787 * This event thresold value is only significant for BAM-to-BAM
3788 * transfer. It's ignored for BAM-to-System mode transfer.
3789 */
3790 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05303791
3792 /* Allocate maximum descriptor fifo size */
3793 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
3794 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003795 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
3796 sps_config->desc.size,
3797 &sps_config->desc.phys_base,
3798 GFP_KERNEL);
3799
Pratibhasagar V00b94332011-10-18 14:57:27 +05303800 if (!sps_config->desc.base) {
3801 rc = -ENOMEM;
3802 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3803 , mmc_hostname(host->mmc));
3804 goto get_config_err;
3805 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003806 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3807
3808 /* Establish connection between peripheral and memory endpoint */
3809 rc = sps_connect(sps_pipe_handle, sps_config);
3810 if (rc) {
3811 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3812 " rc=%d", mmc_hostname(host->mmc),
3813 (u32)sps_pipe_handle, rc);
3814 goto sps_connect_err;
3815 }
3816
3817 sps_event->mode = SPS_TRIGGER_CALLBACK;
3818 sps_event->options = SPS_O_EOT;
3819 sps_event->callback = msmsdcc_sps_complete_cb;
3820 sps_event->xfer_done = NULL;
3821 sps_event->user = (void *)host;
3822
3823 /* Register callback event for EOT (End of transfer) event. */
3824 rc = sps_register_event(sps_pipe_handle, sps_event);
3825 if (rc) {
3826 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3827 " rc=%d", mmc_hostname(host->mmc),
3828 (u32)sps_pipe_handle, rc);
3829 goto reg_event_err;
3830 }
3831 /* Now save the sps pipe handle */
3832 ep->pipe_handle = sps_pipe_handle;
3833 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3834 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3835 __func__, is_producer ? "READ" : "WRITE",
3836 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3837 goto out;
3838
3839reg_event_err:
3840 sps_disconnect(sps_pipe_handle);
3841sps_connect_err:
3842 dma_free_coherent(mmc_dev(host->mmc),
3843 sps_config->desc.size,
3844 sps_config->desc.base,
3845 sps_config->desc.phys_base);
3846get_config_err:
3847 sps_free_endpoint(sps_pipe_handle);
3848out:
3849 return rc;
3850}
3851
3852/**
3853 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3854 *
3855 * This function disconnect endpoint and deallocates
3856 * endpoint context.
3857 *
3858 * This function should only be called once typically
3859 * during driver remove.
3860 *
3861 * @host - Pointer to sdcc host structure
3862 * @ep - Pointer to sps endpoint data structure
3863 *
3864 */
3865static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3866 struct msmsdcc_sps_ep_conn_data *ep)
3867{
3868 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3869 struct sps_connect *sps_config = &ep->config;
3870 struct sps_register_event *sps_event = &ep->event;
3871
3872 sps_event->xfer_done = NULL;
3873 sps_event->callback = NULL;
3874 sps_register_event(sps_pipe_handle, sps_event);
3875 sps_disconnect(sps_pipe_handle);
3876 dma_free_coherent(mmc_dev(host->mmc),
3877 sps_config->desc.size,
3878 sps_config->desc.base,
3879 sps_config->desc.phys_base);
3880 sps_free_endpoint(sps_pipe_handle);
3881}
3882
3883/**
3884 * Reset SDCC peripheral's SPS endpoint
3885 *
3886 * This function disconnects an endpoint.
3887 *
3888 * This function should be called for reseting
3889 * SPS endpoint when data transfer error is
3890 * encountered during data transfer. This
3891 * can be considered as soft reset to endpoint.
3892 *
3893 * This function should only be called if
3894 * msmsdcc_sps_init() is already called.
3895 *
3896 * @host - Pointer to sdcc host structure
3897 * @ep - Pointer to sps endpoint data structure
3898 *
3899 * @return - 0 if successful else negative value.
3900 */
3901static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3902 struct msmsdcc_sps_ep_conn_data *ep)
3903{
3904 int rc = 0;
3905 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3906
3907 rc = sps_disconnect(sps_pipe_handle);
3908 if (rc) {
3909 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3910 " rc=%d", mmc_hostname(host->mmc), __func__,
3911 (u32)sps_pipe_handle, rc);
3912 goto out;
3913 }
3914 out:
3915 return rc;
3916}
3917
3918/**
3919 * Restore SDCC peripheral's SPS endpoint
3920 *
3921 * This function connects an endpoint.
3922 *
3923 * This function should be called for restoring
3924 * SPS endpoint after data transfer error is
3925 * encountered during data transfer. This
3926 * can be considered as soft reset to endpoint.
3927 *
3928 * This function should only be called if
3929 * msmsdcc_sps_reset_ep() is called before.
3930 *
3931 * @host - Pointer to sdcc host structure
3932 * @ep - Pointer to sps endpoint data structure
3933 *
3934 * @return - 0 if successful else negative value.
3935 */
3936static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3937 struct msmsdcc_sps_ep_conn_data *ep)
3938{
3939 int rc = 0;
3940 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3941 struct sps_connect *sps_config = &ep->config;
3942 struct sps_register_event *sps_event = &ep->event;
3943
3944 /* Establish connection between peripheral and memory endpoint */
3945 rc = sps_connect(sps_pipe_handle, sps_config);
3946 if (rc) {
3947 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3948 " rc=%d", mmc_hostname(host->mmc), __func__,
3949 (u32)sps_pipe_handle, rc);
3950 goto out;
3951 }
3952
3953 /* Register callback event for EOT (End of transfer) event. */
3954 rc = sps_register_event(sps_pipe_handle, sps_event);
3955 if (rc) {
3956 pr_err("%s: %s: sps_register_event() failed!!!"
3957 " pipe_handle=0x%x, rc=%d",
3958 mmc_hostname(host->mmc), __func__,
3959 (u32)sps_pipe_handle, rc);
3960 goto reg_event_err;
3961 }
3962 goto out;
3963
3964reg_event_err:
3965 sps_disconnect(sps_pipe_handle);
3966out:
3967 return rc;
3968}
3969
3970/**
3971 * Initialize SPS HW connected with SDCC core
3972 *
3973 * This function register BAM HW resources with
3974 * SPS driver and then initialize 2 SPS endpoints
3975 *
3976 * This function should only be called once typically
3977 * during driver probe.
3978 *
3979 * @host - Pointer to sdcc host structure
3980 *
3981 * @return - 0 if successful else negative value.
3982 *
3983 */
3984static int msmsdcc_sps_init(struct msmsdcc_host *host)
3985{
3986 int rc = 0;
3987 struct sps_bam_props bam = {0};
3988
3989 host->bam_base = ioremap(host->bam_memres->start,
3990 resource_size(host->bam_memres));
3991 if (!host->bam_base) {
3992 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3993 " size=0x%x", mmc_hostname(host->mmc),
3994 host->bam_memres->start,
3995 (host->bam_memres->end -
3996 host->bam_memres->start));
3997 rc = -ENOMEM;
3998 goto out;
3999 }
4000
4001 bam.phys_addr = host->bam_memres->start;
4002 bam.virt_addr = host->bam_base;
4003 /*
4004 * This event thresold value is only significant for BAM-to-BAM
4005 * transfer. It's ignored for BAM-to-System mode transfer.
4006 */
4007 bam.event_threshold = 0x10; /* Pipe event threshold */
4008 /*
4009 * This threshold controls when the BAM publish
4010 * the descriptor size on the sideband interface.
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304011 * SPS HW will be used for data transfer size even
4012 * less than SDCC FIFO size. So let's set BAM summing
4013 * thresold to SPS_MIN_XFER_SIZE bytes.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004014 */
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304015 bam.summing_threshold = SPS_MIN_XFER_SIZE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004016 /* SPS driver wll handle the SDCC BAM IRQ */
4017 bam.irq = (u32)host->bam_irqres->start;
4018 bam.manage = SPS_BAM_MGR_LOCAL;
4019
4020 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
4021 (u32)bam.phys_addr);
4022 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
4023 (u32)bam.virt_addr);
4024
4025 /* Register SDCC Peripheral BAM device to SPS driver */
4026 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
4027 if (rc) {
4028 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
4029 mmc_hostname(host->mmc), rc);
4030 goto reg_bam_err;
4031 }
4032 pr_info("%s: BAM device registered. bam_handle=0x%x",
4033 mmc_hostname(host->mmc), host->sps.bam_handle);
4034
4035 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
4036 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
4037
4038 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
4039 SPS_PROD_PERIPHERAL);
4040 if (rc)
4041 goto sps_reset_err;
4042 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
4043 SPS_CONS_PERIPHERAL);
4044 if (rc)
4045 goto cons_conn_err;
4046
4047 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
4048 mmc_hostname(host->mmc),
4049 (unsigned long long)host->bam_memres->start,
4050 (unsigned int)host->bam_irqres->start);
4051 goto out;
4052
4053cons_conn_err:
4054 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4055sps_reset_err:
4056 sps_deregister_bam_device(host->sps.bam_handle);
4057reg_bam_err:
4058 iounmap(host->bam_base);
4059out:
4060 return rc;
4061}
4062
4063/**
4064 * De-initialize SPS HW connected with SDCC core
4065 *
4066 * This function deinitialize SPS endpoints and then
4067 * deregisters BAM resources from SPS driver.
4068 *
4069 * This function should only be called once typically
4070 * during driver remove.
4071 *
4072 * @host - Pointer to sdcc host structure
4073 *
4074 */
4075static void msmsdcc_sps_exit(struct msmsdcc_host *host)
4076{
4077 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
4078 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4079 sps_deregister_bam_device(host->sps.bam_handle);
4080 iounmap(host->bam_base);
4081}
4082#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
4083
4084static ssize_t
4085show_polling(struct device *dev, struct device_attribute *attr, char *buf)
4086{
4087 struct mmc_host *mmc = dev_get_drvdata(dev);
4088 struct msmsdcc_host *host = mmc_priv(mmc);
4089 int poll;
4090 unsigned long flags;
4091
4092 spin_lock_irqsave(&host->lock, flags);
4093 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
4094 spin_unlock_irqrestore(&host->lock, flags);
4095
4096 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
4097}
4098
4099static ssize_t
4100set_polling(struct device *dev, struct device_attribute *attr,
4101 const char *buf, size_t count)
4102{
4103 struct mmc_host *mmc = dev_get_drvdata(dev);
4104 struct msmsdcc_host *host = mmc_priv(mmc);
4105 int value;
4106 unsigned long flags;
4107
4108 sscanf(buf, "%d", &value);
4109
4110 spin_lock_irqsave(&host->lock, flags);
4111 if (value) {
4112 mmc->caps |= MMC_CAP_NEEDS_POLL;
4113 mmc_detect_change(host->mmc, 0);
4114 } else {
4115 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4116 }
4117#ifdef CONFIG_HAS_EARLYSUSPEND
4118 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
4119#endif
4120 spin_unlock_irqrestore(&host->lock, flags);
4121 return count;
4122}
4123
4124static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
4125 show_polling, set_polling);
4126static struct attribute *dev_attrs[] = {
4127 &dev_attr_polling.attr,
4128 NULL,
4129};
4130static struct attribute_group dev_attr_grp = {
4131 .attrs = dev_attrs,
4132};
4133
4134#ifdef CONFIG_HAS_EARLYSUSPEND
4135static void msmsdcc_early_suspend(struct early_suspend *h)
4136{
4137 struct msmsdcc_host *host =
4138 container_of(h, struct msmsdcc_host, early_suspend);
4139 unsigned long flags;
4140
4141 spin_lock_irqsave(&host->lock, flags);
4142 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
4143 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4144 spin_unlock_irqrestore(&host->lock, flags);
4145};
4146static void msmsdcc_late_resume(struct early_suspend *h)
4147{
4148 struct msmsdcc_host *host =
4149 container_of(h, struct msmsdcc_host, early_suspend);
4150 unsigned long flags;
4151
4152 if (host->polling_enabled) {
4153 spin_lock_irqsave(&host->lock, flags);
4154 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
4155 mmc_detect_change(host->mmc, 0);
4156 spin_unlock_irqrestore(&host->lock, flags);
4157 }
4158};
4159#endif
4160
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304161static void msmsdcc_print_regs(const char *name, void __iomem *base,
4162 u32 phys_base, unsigned int no_of_regs)
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304163{
4164 unsigned int i;
4165
4166 if (!base)
4167 return;
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304168
4169 pr_info("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
4170 " =====\n", name, phys_base, (u32)base);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304171 for (i = 0; i < no_of_regs; i = i + 4) {
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304172 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
4173 (u32)readl_relaxed(base + i*4),
4174 (u32)readl_relaxed(base + ((i+1)*4)),
4175 (u32)readl_relaxed(base + ((i+2)*4)),
4176 (u32)readl_relaxed(base + ((i+3)*4)));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304177 }
4178}
4179
4180static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
4181{
4182 /* Dump current state of SDCC clocks, power and irq */
4183 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304184 (host->pwr ? "ON" : "OFF"));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304185 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304186 mmc_hostname(host->mmc), (host->clks_on ? "ON" : "OFF"),
4187 (u32)clk_get_rate(host->clk));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304188 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
4189 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
4190
4191 /* Now dump SDCC registers. Don't print FIFO registers */
4192 if (host->clks_on)
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304193 msmsdcc_print_regs("SDCC-CORE", host->base,
4194 host->core_memres->start, 28);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304195
4196 if (host->curr.data) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304197 if (!msmsdcc_is_dma_possible(host, host->curr.data))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304198 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
4199 else if (host->is_dma_mode)
4200 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
4201 mmc_hostname(host->mmc), host->dma.busy,
4202 host->dma.channel, host->dma.crci);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304203 else if (host->is_sps_mode) {
subhashj245831e2012-04-30 18:46:17 +05304204 if (host->sps.busy && host->clks_on)
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304205 msmsdcc_print_regs("SDCC-DML", host->dml_base,
4206 host->dml_memres->start,
4207 16);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304208 pr_info("%s: SPS mode: busy=%d\n",
4209 mmc_hostname(host->mmc), host->sps.busy);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304210 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304211
4212 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
4213 mmc_hostname(host->mmc), host->curr.xfer_size,
4214 host->curr.data_xfered, host->curr.xfer_remain);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304215 }
4216
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304217 pr_info("%s: got_dataend=%d, prog_enable=%d,"
4218 " wait_for_auto_prog_done=%d, got_auto_prog_done=%d\n",
4219 mmc_hostname(host->mmc), host->curr.got_dataend,
4220 host->prog_enable, host->curr.wait_for_auto_prog_done,
4221 host->curr.got_auto_prog_done);
subhashj245831e2012-04-30 18:46:17 +05304222 msmsdcc_print_rpm_info(host);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304223}
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304224
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004225static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
4226{
4227 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4228 struct mmc_request *mrq;
4229 unsigned long flags;
4230
4231 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004232 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004233 pr_info("%s: %s: dummy CMD52 timeout\n",
4234 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004235 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004236 }
4237
4238 mrq = host->curr.mrq;
4239
4240 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304241 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
4242 mrq->cmd->opcode);
4243 msmsdcc_dump_sdcc_state(host);
4244
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004245 if (!mrq->cmd->error)
4246 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304247 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004248 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004249 if (mrq->data && !mrq->data->error)
4250 mrq->data->error = -ETIMEDOUT;
4251 host->curr.data_xfered = 0;
4252 if (host->dma.sg && host->is_dma_mode) {
4253 msm_dmov_stop_cmd(host->dma.channel,
4254 &host->dma.hdr, 0);
4255 } else if (host->sps.sg && host->is_sps_mode) {
4256 /* Stop current SPS transfer */
4257 msmsdcc_sps_exit_curr_xfer(host);
4258 } else {
4259 msmsdcc_reset_and_restore(host);
4260 msmsdcc_stop_data(host);
4261 if (mrq->data && mrq->data->stop)
4262 msmsdcc_start_command(host,
4263 mrq->data->stop, 0);
4264 else
4265 msmsdcc_request_end(host, mrq);
4266 }
4267 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304268 host->prog_enable = 0;
Subhash Jadavanied6b0e42012-03-07 16:36:27 +05304269 host->curr.wait_for_auto_prog_done = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004270 msmsdcc_reset_and_restore(host);
4271 msmsdcc_request_end(host, mrq);
4272 }
4273 }
4274 spin_unlock_irqrestore(&host->lock, flags);
4275}
4276
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304277static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
4278{
4279 int i, ret;
4280 struct mmc_platform_data *pdata;
4281 struct device_node *np = dev->of_node;
4282 u32 bus_width = 0;
4283 u32 *clk_table;
4284 int clk_table_len;
4285 u32 *sup_voltages;
4286 int sup_volt_len;
4287
4288 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
4289 if (!pdata) {
4290 dev_err(dev, "could not allocate memory for platform data\n");
4291 goto err;
4292 }
4293
4294 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
4295 if (bus_width == 8) {
4296 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
4297 } else if (bus_width == 4) {
4298 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
4299 } else {
4300 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
4301 pdata->mmc_bus_width = 0;
4302 }
4303
4304 if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
4305 size_t sz;
4306 sz = sup_volt_len / sizeof(*sup_voltages);
4307 if (sz > 0) {
4308 sup_voltages = devm_kzalloc(dev,
4309 sz * sizeof(*sup_voltages), GFP_KERNEL);
4310 if (!sup_voltages) {
4311 dev_err(dev, "No memory for supported voltage\n");
4312 goto err;
4313 }
4314
4315 ret = of_property_read_u32_array(np,
4316 "qcom,sdcc-sup-voltages", sup_voltages, sz);
4317 if (ret < 0) {
4318 dev_err(dev, "error while reading voltage"
4319 "ranges %d\n", ret);
4320 goto err;
4321 }
4322 } else {
4323 dev_err(dev, "No supported voltages\n");
4324 goto err;
4325 }
4326 for (i = 0; i < sz; i += 2) {
4327 u32 mask;
4328
4329 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
4330 sup_voltages[i + 1]);
4331 if (!mask)
4332 dev_err(dev, "Invalide voltage range %d\n", i);
4333 pdata->ocr_mask |= mask;
4334 }
4335 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
4336 } else {
4337 dev_err(dev, "Supported voltage range not specified\n");
4338 }
4339
4340 if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
4341 size_t sz;
4342 sz = clk_table_len / sizeof(*clk_table);
4343
4344 if (sz > 0) {
4345 clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
4346 GFP_KERNEL);
4347 if (!clk_table) {
4348 dev_err(dev, "No memory for clock table\n");
4349 goto err;
4350 }
4351
4352 ret = of_property_read_u32_array(np,
4353 "qcom,sdcc-clk-rates", clk_table, sz);
4354 if (ret < 0) {
4355 dev_err(dev, "error while reading clk"
4356 "table %d\n", ret);
4357 goto err;
4358 }
4359 } else {
4360 dev_err(dev, "clk_table not specified\n");
4361 goto err;
4362 }
4363 pdata->sup_clk_table = clk_table;
4364 pdata->sup_clk_cnt = sz;
4365 } else {
4366 dev_err(dev, "Supported clock rates not specified\n");
4367 }
4368
4369 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
4370 pdata->nonremovable = true;
4371 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
4372 pdata->disable_cmd23 = true;
4373
4374 return pdata;
4375err:
4376 return NULL;
4377}
4378
San Mehat9d2bd732009-09-22 16:44:22 -07004379static int
4380msmsdcc_probe(struct platform_device *pdev)
4381{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304382 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07004383 struct msmsdcc_host *host;
4384 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004385 unsigned long flags;
4386 struct resource *core_irqres = NULL;
4387 struct resource *bam_irqres = NULL;
4388 struct resource *core_memres = NULL;
4389 struct resource *dml_memres = NULL;
4390 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07004391 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07004392 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05304393 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004394 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07004395
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304396 if (pdev->dev.of_node) {
4397 plat = msmsdcc_populate_pdata(&pdev->dev);
4398 of_property_read_u32((&pdev->dev)->of_node,
4399 "cell-index", &pdev->id);
4400 } else {
4401 plat = pdev->dev.platform_data;
4402 }
4403
San Mehat9d2bd732009-09-22 16:44:22 -07004404 /* must have platform data */
4405 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004406 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004407 ret = -EINVAL;
4408 goto out;
4409 }
4410
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004411 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07004412 return -EINVAL;
4413
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304414 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
4415 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
4416 return -EINVAL;
4417 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004418
San Mehat9d2bd732009-09-22 16:44:22 -07004419 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004420 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004421 return -ENXIO;
4422 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304423 if (pdev->dev.of_node) {
4424 /*
4425 * Device tree iomem resources are only accessible by index.
4426 * index = 0 -> SDCC register interface
4427 * index = 1 -> DML register interface
4428 * index = 2 -> BAM register interface
4429 * IRQ resources:
4430 * index = 0 -> SDCC IRQ
4431 * index = 1 -> BAM IRQ
4432 */
4433 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
4434 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
4435 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
4436 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
4437 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
4438 } else {
4439 for (i = 0; i < pdev->num_resources; i++) {
4440 if (pdev->resource[i].flags & IORESOURCE_MEM) {
4441 if (!strncmp(pdev->resource[i].name,
4442 "sdcc_dml_addr",
4443 sizeof("sdcc_dml_addr")))
4444 dml_memres = &pdev->resource[i];
4445 else if (!strncmp(pdev->resource[i].name,
4446 "sdcc_bam_addr",
4447 sizeof("sdcc_bam_addr")))
4448 bam_memres = &pdev->resource[i];
4449 else
4450 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07004451
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304452 }
4453 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
4454 if (!strncmp(pdev->resource[i].name,
4455 "sdcc_bam_irq",
4456 sizeof("sdcc_bam_irq")))
4457 bam_irqres = &pdev->resource[i];
4458 else
4459 core_irqres = &pdev->resource[i];
4460 }
4461 if (pdev->resource[i].flags & IORESOURCE_DMA) {
4462 if (!strncmp(pdev->resource[i].name,
4463 "sdcc_dma_chnl",
4464 sizeof("sdcc_dma_chnl")))
4465 dmares = &pdev->resource[i];
4466 else if (!strncmp(pdev->resource[i].name,
4467 "sdcc_dma_crci",
4468 sizeof("sdcc_dma_crci")))
4469 dma_crci_res = &pdev->resource[i];
4470 }
Krishna Konda25786ec2011-07-25 16:21:36 -07004471 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004472 }
4473
4474 if (!core_irqres || !core_memres) {
4475 pr_err("%s: Invalid sdcc core resource\n", __func__);
4476 return -ENXIO;
4477 }
4478
4479 /*
4480 * Both BAM and DML memory resource should be preset.
4481 * BAM IRQ resource should also be present.
4482 */
4483 if ((bam_memres && !dml_memres) ||
4484 (!bam_memres && dml_memres) ||
4485 ((bam_memres && dml_memres) && !bam_irqres)) {
4486 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004487 return -ENXIO;
4488 }
4489
4490 /*
4491 * Setup our host structure
4492 */
San Mehat9d2bd732009-09-22 16:44:22 -07004493 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
4494 if (!mmc) {
4495 ret = -ENOMEM;
4496 goto out;
4497 }
4498
4499 host = mmc_priv(mmc);
4500 host->pdev_id = pdev->id;
4501 host->plat = plat;
4502 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08004503 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05304504
4505 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004506 host->is_sps_mode = 1;
4507 else if (dmares)
4508 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07004509
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004510 host->base = ioremap(core_memres->start,
4511 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07004512 if (!host->base) {
4513 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004514 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004515 }
4516
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004517 host->core_irqres = core_irqres;
4518 host->bam_irqres = bam_irqres;
4519 host->core_memres = core_memres;
4520 host->dml_memres = dml_memres;
4521 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07004522 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07004523 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07004524 spin_lock_init(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304525 mutex_init(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07004526
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004527#ifdef CONFIG_MMC_EMBEDDED_SDIO
4528 if (plat->embedded_sdio)
4529 mmc_set_embedded_sdio_data(mmc,
4530 &plat->embedded_sdio->cis,
4531 &plat->embedded_sdio->cccr,
4532 plat->embedded_sdio->funcs,
4533 plat->embedded_sdio->num_funcs);
4534#endif
4535
Sahitya Tummala62612cf2010-12-08 15:03:03 +05304536 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
4537 (unsigned long)host);
4538
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004539 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
4540 (unsigned long)host);
4541 if (host->is_dma_mode) {
4542 /* Setup DMA */
4543 ret = msmsdcc_init_dma(host);
4544 if (ret)
4545 goto ioremap_free;
4546 } else {
4547 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004548 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004549 }
4550
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004551 /*
4552 * Setup SDCC clock if derived from Dayatona
4553 * fabric core clock.
4554 */
4555 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07004556 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004557 if (!IS_ERR(host->dfab_pclk)) {
4558 /* Set the clock rate to 64MHz for max. performance */
4559 ret = clk_set_rate(host->dfab_pclk, 64000000);
4560 if (ret)
4561 goto dfab_pclk_put;
Asutosh Dasf5298c32012-04-03 14:51:47 +05304562 ret = clk_prepare_enable(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004563 if (ret)
4564 goto dfab_pclk_put;
4565 } else
4566 goto dma_free;
4567 }
4568
4569 /*
4570 * Setup main peripheral bus clock
4571 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004572 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004573 if (!IS_ERR(host->pclk)) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05304574 ret = clk_prepare_enable(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004575 if (ret)
4576 goto pclk_put;
4577
4578 host->pclk_rate = clk_get_rate(host->pclk);
4579 }
4580
4581 /*
4582 * Setup SDC MMC clock
4583 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004584 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07004585 if (IS_ERR(host->clk)) {
4586 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004587 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07004588 }
4589
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004590 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
4591 if (ret) {
4592 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
4593 goto clk_put;
4594 }
4595
Asutosh Dasf5298c32012-04-03 14:51:47 +05304596 ret = clk_prepare_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004597 if (ret)
4598 goto clk_put;
4599
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004600 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304601 if (!host->clk_rate)
4602 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304603
4604 /*
4605 * Lookup the Controller Version, to identify the supported features
4606 * Version number read as 0 would indicate SDCC3 or earlier versions
4607 */
4608 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
4609 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
4610 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304611 /*
4612 * Set the register write delay according to min. clock frequency
4613 * supported and update later when the host->clk_rate changes.
4614 */
4615 host->reg_write_delay =
4616 (1 + ((3 * USEC_PER_SEC) /
4617 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004618
4619 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05304620 /* Apply Hard reset to SDCC to put it in power on default state */
4621 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004622
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004623#define MSM_MMC_DEFAULT_CPUDMA_LATENCY 200 /* usecs */
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304624 /* pm qos request to prevent apps idle power collapse */
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004625 if (host->plat->cpu_dma_latency)
4626 host->cpu_dma_latency = host->plat->cpu_dma_latency;
4627 else
4628 host->cpu_dma_latency = MSM_MMC_DEFAULT_CPUDMA_LATENCY;
4629 pm_qos_add_request(&host->pm_qos_req_dma,
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304630 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
4631
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004632 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07004633 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004634 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07004635 goto clk_disable;
4636 }
4637
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004638
4639 /* Clocks has to be running before accessing SPS/DML HW blocks */
4640 if (host->is_sps_mode) {
4641 /* Initialize SPS */
4642 ret = msmsdcc_sps_init(host);
4643 if (ret)
4644 goto vreg_deinit;
4645 /* Initialize DML */
4646 ret = msmsdcc_dml_init(host);
4647 if (ret)
4648 goto sps_exit;
4649 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05304650 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07004651
San Mehat9d2bd732009-09-22 16:44:22 -07004652 /*
4653 * Setup MMC host structure
4654 */
4655 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004656 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
4657 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004658 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004659 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
4660 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07004661
San Mehat9d2bd732009-09-22 16:44:22 -07004662 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05304663 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304664
4665 /*
4666 * If we send the CMD23 before multi block write/read command
4667 * then we need not to send CMD12 at the end of the transfer.
4668 * If we don't send the CMD12 then only way to detect the PROG_DONE
4669 * status is to use the AUTO_PROG_DONE status provided by SDCC4
4670 * controller. So let's enable the CMD23 for SDCC4 only.
4671 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304672 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304673 mmc->caps |= MMC_CAP_CMD23;
4674
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004675 mmc->caps |= plat->uhs_caps;
4676 /*
4677 * XPC controls the maximum current in the default speed mode of SDXC
4678 * card. XPC=0 means 100mA (max.) but speed class is not supported.
4679 * XPC=1 means 150mA (max.) and speed class is supported.
4680 */
4681 if (plat->xpc_cap)
4682 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
4683 MMC_CAP_SET_XPC_180);
4684
Subhash Jadavani6bb34a82012-04-18 13:18:40 +05304685 mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304686 if (pdev->dev.of_node) {
4687 if (of_get_property((&pdev->dev)->of_node,
4688 "qcom,sdcc-hs200", NULL))
4689 mmc->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
4690 }
4691
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004692 if (plat->nonremovable)
4693 mmc->caps |= MMC_CAP_NONREMOVABLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004694 mmc->caps |= MMC_CAP_SDIO_IRQ;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004695
4696 if (plat->is_sdio_al_client)
4697 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07004698
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304699 mmc->max_segs = msmsdcc_get_nr_sg(host);
4700 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
4701 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07004702
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304703 mmc->max_req_size = MMC_MAX_REQ_SIZE;
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +05304704 mmc->max_seg_size = mmc->max_req_size;
San Mehat9d2bd732009-09-22 16:44:22 -07004705
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004706 writel_relaxed(0, host->base + MMCIMASK0);
4707 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05304708 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004709
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004710 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
4711 mb();
4712 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07004713
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004714 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
4715 DRIVER_NAME " (cmd)", host);
4716 if (ret)
4717 goto dml_exit;
4718
4719 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
4720 DRIVER_NAME " (pio)", host);
4721 if (ret)
4722 goto irq_free;
4723
4724 /*
4725 * Enable SDCC IRQ only when host is powered on. Otherwise, this
4726 * IRQ is un-necessarily being monitored by MPM (Modem power
4727 * management block) during idle-power collapse. The MPM will be
4728 * configured to monitor the DATA1 GPIO line with level-low trigger
4729 * and thus depending on the GPIO status, it prevents TCXO shutdown
4730 * during idle-power collapse.
4731 */
4732 disable_irq(core_irqres->start);
4733 host->sdcc_irq_disabled = 1;
4734
4735 if (plat->sdiowakeup_irq) {
4736 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4737 mmc_hostname(mmc));
4738 ret = request_irq(plat->sdiowakeup_irq,
4739 msmsdcc_platform_sdiowakeup_irq,
4740 IRQF_SHARED | IRQF_TRIGGER_LOW,
4741 DRIVER_NAME "sdiowakeup", host);
4742 if (ret) {
4743 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
4744 plat->sdiowakeup_irq, ret);
4745 goto pio_irq_free;
4746 } else {
4747 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304748 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004749 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304750 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004751 }
4752 spin_unlock_irqrestore(&host->lock, flags);
4753 }
4754 }
4755
Subhash Jadavanic9b85752012-04-13 11:16:49 +05304756 if (host->plat->mpm_sdiowakeup_int) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004757 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4758 mmc_hostname(mmc));
4759 }
4760
4761 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
4762 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004763 /*
4764 * Setup card detect change
4765 */
4766
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004767 if (plat->status || plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08004768 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004769 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08004770 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004771 host->oldstat = msmsdcc_slot_status(host);
Krishna Konda360aa422011-12-06 18:27:41 -08004772
Krishna Konda941604a2012-01-10 17:46:34 -08004773 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004774 }
San Mehat9d2bd732009-09-22 16:44:22 -07004775
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004776 if (plat->status_irq) {
4777 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07004778 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004779 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07004780 DRIVER_NAME " (slot)",
4781 host);
4782 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004783 pr_err("Unable to get slot IRQ %d (%d)\n",
4784 plat->status_irq, ret);
4785 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004786 }
4787 } else if (plat->register_status_notify) {
4788 plat->register_status_notify(msmsdcc_status_notify_cb, host);
4789 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004790 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07004791 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004792
4793 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004794
4795 ret = pm_runtime_set_active(&(pdev)->dev);
4796 if (ret < 0)
4797 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
4798 __func__, ret);
4799 /*
4800 * There is no notion of suspend/resume for SD/MMC/SDIO
4801 * cards. So host can be suspended/resumed with out
4802 * worrying about its children.
4803 */
4804 pm_suspend_ignore_children(&(pdev)->dev, true);
4805
4806 /*
4807 * MMC/SD/SDIO bus suspend/resume operations are defined
4808 * only for the slots that will be used for non-removable
4809 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
4810 * defined. Otherwise, they simply become card removal and
4811 * insertion events during suspend and resume respectively.
4812 * Hence, enable run-time PM only for slots for which bus
4813 * suspend/resume operations are defined.
4814 */
4815#ifdef CONFIG_MMC_UNSAFE_RESUME
4816 /*
4817 * If this capability is set, MMC core will enable/disable host
4818 * for every claim/release operation on a host. We use this
4819 * notification to increment/decrement runtime pm usage count.
4820 */
4821 mmc->caps |= MMC_CAP_DISABLE;
4822 pm_runtime_enable(&(pdev)->dev);
4823#else
4824 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
4825 mmc->caps |= MMC_CAP_DISABLE;
4826 pm_runtime_enable(&(pdev)->dev);
4827 }
4828#endif
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05304829#ifndef CONFIG_PM_RUNTIME
4830 mmc_set_disable_delay(mmc, MSM_MMC_DISABLE_TIMEOUT);
4831#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004832 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
4833 (unsigned long)host);
4834
San Mehat9d2bd732009-09-22 16:44:22 -07004835 mmc_add_host(mmc);
4836
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004837#ifdef CONFIG_HAS_EARLYSUSPEND
4838 host->early_suspend.suspend = msmsdcc_early_suspend;
4839 host->early_suspend.resume = msmsdcc_late_resume;
4840 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
4841 register_early_suspend(&host->early_suspend);
4842#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004843
Krishna Konda25786ec2011-07-25 16:21:36 -07004844 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
4845 " dmacrcri %d\n", mmc_hostname(mmc),
4846 (unsigned long long)core_memres->start,
4847 (unsigned int) core_irqres->start,
4848 (unsigned int) plat->status_irq, host->dma.channel,
4849 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004850
4851 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
4852 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
4853 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
4854 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
4855 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
4856 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
4857 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
4858 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
4859 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
4860 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
4861 host->eject);
4862 pr_info("%s: Power save feature enable = %d\n",
4863 mmc_hostname(mmc), msmsdcc_pwrsave);
4864
Krishna Konda25786ec2011-07-25 16:21:36 -07004865 if (host->is_dma_mode && host->dma.channel != -1
4866 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004867 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004868 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004869 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004870 mmc_hostname(mmc), host->dma.cmd_busaddr,
4871 host->dma.cmdptr_busaddr);
4872 } else if (host->is_sps_mode) {
4873 pr_info("%s: SPS-BAM data transfer mode available\n",
4874 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004875 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004876 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004877
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004878#if defined(CONFIG_DEBUG_FS)
4879 msmsdcc_dbg_createhost(host);
4880#endif
4881 if (!plat->status_irq) {
4882 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
4883 if (ret)
4884 goto platform_irq_free;
4885 }
San Mehat9d2bd732009-09-22 16:44:22 -07004886 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004887
4888 platform_irq_free:
4889 del_timer_sync(&host->req_tout_timer);
4890 pm_runtime_disable(&(pdev)->dev);
4891 pm_runtime_set_suspended(&(pdev)->dev);
4892
4893 if (plat->status_irq)
4894 free_irq(plat->status_irq, host);
4895 sdiowakeup_irq_free:
4896 wake_lock_destroy(&host->sdio_suspend_wlock);
4897 if (plat->sdiowakeup_irq)
4898 free_irq(plat->sdiowakeup_irq, host);
4899 pio_irq_free:
4900 if (plat->sdiowakeup_irq)
4901 wake_lock_destroy(&host->sdio_wlock);
4902 free_irq(core_irqres->start, host);
4903 irq_free:
4904 free_irq(core_irqres->start, host);
4905 dml_exit:
4906 if (host->is_sps_mode)
4907 msmsdcc_dml_exit(host);
4908 sps_exit:
4909 if (host->is_sps_mode)
4910 msmsdcc_sps_exit(host);
4911 vreg_deinit:
4912 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07004913 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004914 clk_disable(host->clk);
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004915 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304916 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07004917 clk_put:
4918 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004919 pclk_disable:
4920 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05304921 clk_disable_unprepare(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07004922 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004923 if (!IS_ERR(host->pclk))
4924 clk_put(host->pclk);
4925 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05304926 clk_disable_unprepare(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004927 dfab_pclk_put:
4928 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4929 clk_put(host->dfab_pclk);
4930 dma_free:
4931 if (host->is_dma_mode) {
4932 if (host->dmares)
4933 dma_free_coherent(NULL,
4934 sizeof(struct msmsdcc_nc_dmadata),
4935 host->dma.nc, host->dma.nc_busaddr);
4936 }
4937 ioremap_free:
4938 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07004939 host_free:
4940 mmc_free_host(mmc);
4941 out:
4942 return ret;
4943}
4944
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004945static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07004946{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004947 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4948 struct mmc_platform_data *plat;
4949 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004950
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004951 if (!mmc)
4952 return -ENXIO;
4953
4954 if (pm_runtime_suspended(&(pdev)->dev))
4955 pm_runtime_resume(&(pdev)->dev);
4956
4957 host = mmc_priv(mmc);
4958
4959 DBG(host, "Removing SDCC device = %d\n", pdev->id);
4960 plat = host->plat;
4961
4962 if (!plat->status_irq)
4963 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
4964
4965 del_timer_sync(&host->req_tout_timer);
4966 tasklet_kill(&host->dma_tlet);
4967 tasklet_kill(&host->sps.tlet);
4968 mmc_remove_host(mmc);
4969
4970 if (plat->status_irq)
4971 free_irq(plat->status_irq, host);
4972
4973 wake_lock_destroy(&host->sdio_suspend_wlock);
4974 if (plat->sdiowakeup_irq) {
4975 wake_lock_destroy(&host->sdio_wlock);
4976 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
4977 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07004978 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004979
4980 free_irq(host->core_irqres->start, host);
4981 free_irq(host->core_irqres->start, host);
4982
4983 clk_put(host->clk);
4984 if (!IS_ERR(host->pclk))
4985 clk_put(host->pclk);
4986 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4987 clk_put(host->dfab_pclk);
4988
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004989 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304990 pm_qos_remove_request(&host->pm_qos_req_dma);
4991
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004992 msmsdcc_vreg_init(host, false);
4993
4994 if (host->is_dma_mode) {
4995 if (host->dmares)
4996 dma_free_coherent(NULL,
4997 sizeof(struct msmsdcc_nc_dmadata),
4998 host->dma.nc, host->dma.nc_busaddr);
4999 }
5000
5001 if (host->is_sps_mode) {
5002 msmsdcc_dml_exit(host);
5003 msmsdcc_sps_exit(host);
5004 }
5005
5006 iounmap(host->base);
5007 mmc_free_host(mmc);
5008
5009#ifdef CONFIG_HAS_EARLYSUSPEND
5010 unregister_early_suspend(&host->early_suspend);
5011#endif
5012 pm_runtime_disable(&(pdev)->dev);
5013 pm_runtime_set_suspended(&(pdev)->dev);
5014
5015 return 0;
5016}
5017
5018#ifdef CONFIG_MSM_SDIO_AL
5019int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
5020{
5021 struct msmsdcc_host *host = mmc_priv(mmc);
5022 unsigned long flags;
5023
Asutosh Dasf5298c32012-04-03 14:51:47 +05305024 mutex_lock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005025 spin_lock_irqsave(&host->lock, flags);
5026 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
5027 enable ? "En" : "Dis");
5028
5029 if (enable) {
5030 if (!host->sdcc_irq_disabled) {
5031 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05305032 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005033 host->sdcc_irq_disabled = 1;
5034 }
5035
5036 if (host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305037 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005038 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305039 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005040 host->clks_on = 0;
5041 }
5042
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305043 if (host->plat->sdio_lpm_gpio_setup &&
5044 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005045 spin_unlock_irqrestore(&host->lock, flags);
5046 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
5047 spin_lock_irqsave(&host->lock, flags);
5048 host->sdio_gpio_lpm = 1;
5049 }
5050
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305051 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005052 msmsdcc_enable_irq_wake(host);
5053 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305054 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005055 }
5056 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305057 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005058 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305059 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005060 msmsdcc_disable_irq_wake(host);
5061 }
5062
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305063 if (host->plat->sdio_lpm_gpio_setup &&
5064 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005065 spin_unlock_irqrestore(&host->lock, flags);
5066 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
5067 spin_lock_irqsave(&host->lock, flags);
5068 host->sdio_gpio_lpm = 0;
5069 }
5070
5071 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305072 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005073 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305074 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005075 host->clks_on = 1;
5076 }
5077
5078 if (host->sdcc_irq_disabled) {
5079 writel_relaxed(host->mci_irqenable,
5080 host->base + MMCIMASK0);
5081 mb();
5082 enable_irq(host->core_irqres->start);
5083 host->sdcc_irq_disabled = 0;
5084 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005085 }
5086 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305087 mutex_unlock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005088 return 0;
5089}
5090#else
5091int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
5092{
5093 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07005094}
5095#endif
5096
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005097#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07005098static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005099msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07005100{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005101 struct mmc_host *mmc = dev_get_drvdata(dev);
5102 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07005103 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305104 unsigned long flags;
5105
San Mehat9d2bd732009-09-22 16:44:22 -07005106
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005107 if (host->plat->is_sdio_al_client)
5108 return 0;
Sahitya Tummala7661a452011-07-18 13:28:35 +05305109 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005110 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005111 host->sdcc_suspending = 1;
5112 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07005113
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005114 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005115 * MMC core thinks that host is disabled by now since
5116 * runtime suspend is scheduled after msmsdcc_disable()
5117 * is called. Thus, MMC core will try to enable the host
5118 * while suspending it. This results in a synchronous
5119 * runtime resume request while in runtime suspending
5120 * context and hence inorder to complete this resume
5121 * requet, it will wait for suspend to be complete,
5122 * but runtime suspend also can not proceed further
5123 * until the host is resumed. Thus, it leads to a hang.
5124 * Hence, increase the pm usage count before suspending
5125 * the host so that any resume requests after this will
5126 * simple become pm usage counter increment operations.
5127 */
5128 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05305129 /* If there is pending detect work abort runtime suspend */
5130 if (unlikely(work_busy(&mmc->detect.work)))
5131 rc = -EAGAIN;
5132 else
5133 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005134 pm_runtime_put_noidle(dev);
5135
5136 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305137 spin_lock_irqsave(&host->lock, flags);
5138 host->sdcc_suspended = true;
5139 spin_unlock_irqrestore(&host->lock, flags);
5140 if (mmc->card && mmc_card_sdio(mmc->card) &&
5141 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005142 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305143 * If SDIO function driver doesn't want
5144 * to power off the card, atleast turn off
5145 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005146 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305147 mmc_host_clk_hold(mmc);
5148 spin_lock_irqsave(&mmc->clk_lock, flags);
5149 mmc->clk_old = mmc->ios.clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005150 mmc->ios.clock = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305151 mmc->clk_gated = true;
5152 spin_unlock_irqrestore(&mmc->clk_lock, flags);
5153 mmc_set_ios(mmc);
5154 mmc_host_clk_release(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005155 }
5156 }
5157 host->sdcc_suspending = 0;
5158 mmc->suspend_task = NULL;
5159 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
5160 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005161 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05305162 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
San Mehat9d2bd732009-09-22 16:44:22 -07005163 return rc;
5164}
5165
5166static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005167msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07005168{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005169 struct mmc_host *mmc = dev_get_drvdata(dev);
5170 struct msmsdcc_host *host = mmc_priv(mmc);
5171 unsigned long flags;
5172
5173 if (host->plat->is_sdio_al_client)
5174 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07005175
Sahitya Tummala7661a452011-07-18 13:28:35 +05305176 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005177 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305178 if (mmc->card && mmc_card_sdio(mmc->card) &&
5179 mmc_card_keep_power(mmc)) {
5180 mmc_host_clk_hold(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305181 mmc->ios.clock = host->clk_rate;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305182 mmc_set_ios(mmc);
5183 mmc_host_clk_release(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305184 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005185
5186 mmc_resume_host(mmc);
5187
5188 /*
5189 * FIXME: Clearing of flags must be handled in clients
5190 * resume handler.
5191 */
5192 spin_lock_irqsave(&host->lock, flags);
5193 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305194 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005195 spin_unlock_irqrestore(&host->lock, flags);
5196
5197 /*
5198 * After resuming the host wait for sometime so that
5199 * the SDIO work will be processed.
5200 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305201 if (mmc->card && mmc_card_sdio(mmc->card)) {
Subhash Jadavanic9b85752012-04-13 11:16:49 +05305202 if ((host->plat->mpm_sdiowakeup_int ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005203 host->plat->sdiowakeup_irq) &&
5204 wake_lock_active(&host->sdio_wlock))
5205 wake_lock_timeout(&host->sdio_wlock, 1);
5206 }
5207
5208 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005209 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05305210 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005211 return 0;
5212}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005213
5214static int msmsdcc_runtime_idle(struct device *dev)
5215{
5216 struct mmc_host *mmc = dev_get_drvdata(dev);
5217 struct msmsdcc_host *host = mmc_priv(mmc);
5218
5219 if (host->plat->is_sdio_al_client)
5220 return 0;
5221
5222 /* Idle timeout is not configurable for now */
5223 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
5224
5225 return -EAGAIN;
5226}
5227
5228static int msmsdcc_pm_suspend(struct device *dev)
5229{
5230 struct mmc_host *mmc = dev_get_drvdata(dev);
5231 struct msmsdcc_host *host = mmc_priv(mmc);
5232 int rc = 0;
5233
5234 if (host->plat->is_sdio_al_client)
5235 return 0;
5236
5237
5238 if (host->plat->status_irq)
5239 disable_irq(host->plat->status_irq);
5240
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005241 if (!pm_runtime_suspended(dev))
5242 rc = msmsdcc_runtime_suspend(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005243
5244 return rc;
5245}
5246
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305247static int msmsdcc_suspend_noirq(struct device *dev)
5248{
5249 struct mmc_host *mmc = dev_get_drvdata(dev);
5250 struct msmsdcc_host *host = mmc_priv(mmc);
5251 int rc = 0;
5252
5253 /*
5254 * After platform suspend there may be active request
5255 * which might have enabled clocks. For example, in SDIO
5256 * case, ksdioirq thread might have scheduled after sdcc
5257 * suspend but before system freeze. In that case abort
5258 * suspend and retry instead of keeping the clocks on
5259 * during suspend and not allowing TCXO.
5260 */
5261
Asutosh Dasf5298c32012-04-03 14:51:47 +05305262 if (host->clks_on && !host->plat->is_sdio_al_client) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305263 pr_warn("%s: clocks are on after suspend, aborting system "
5264 "suspend\n", mmc_hostname(mmc));
5265 rc = -EAGAIN;
5266 }
5267
5268 return rc;
5269}
5270
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005271static int msmsdcc_pm_resume(struct device *dev)
5272{
5273 struct mmc_host *mmc = dev_get_drvdata(dev);
5274 struct msmsdcc_host *host = mmc_priv(mmc);
5275 int rc = 0;
5276
5277 if (host->plat->is_sdio_al_client)
5278 return 0;
5279
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005280 if (mmc->card && mmc_card_sdio(mmc->card))
Sahitya Tummalafb486372011-09-02 19:01:49 +05305281 rc = msmsdcc_runtime_resume(dev);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005282 else
5283 host->pending_resume = true;
5284
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005285 if (host->plat->status_irq) {
5286 msmsdcc_check_status((unsigned long)host);
5287 enable_irq(host->plat->status_irq);
5288 }
5289
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005290 return rc;
5291}
5292
Daniel Walker08ecfde2010-06-23 12:32:20 -07005293#else
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005294static int msmsdcc_runtime_suspend(struct device *dev)
5295{
5296 return 0;
5297}
5298static int msmsdcc_runtime_idle(struct device *dev)
5299{
5300 return 0;
5301}
5302static int msmsdcc_pm_suspend(struct device *dev)
5303{
5304 return 0;
5305}
5306static int msmsdcc_pm_resume(struct device *dev)
5307{
5308 return 0;
5309}
5310static int msmsdcc_suspend_noirq(struct device *dev)
5311{
5312 return 0;
5313}
5314static int msmsdcc_runtime_resume(struct device *dev)
5315{
5316 return 0;
5317}
Daniel Walker08ecfde2010-06-23 12:32:20 -07005318#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005319
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005320static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
5321 .runtime_suspend = msmsdcc_runtime_suspend,
5322 .runtime_resume = msmsdcc_runtime_resume,
5323 .runtime_idle = msmsdcc_runtime_idle,
5324 .suspend = msmsdcc_pm_suspend,
5325 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305326 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005327};
5328
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305329static const struct of_device_id msmsdcc_dt_match[] = {
5330 {.compatible = "qcom,msm-sdcc"},
5331
5332};
5333MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
5334
San Mehat9d2bd732009-09-22 16:44:22 -07005335static struct platform_driver msmsdcc_driver = {
5336 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005337 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07005338 .driver = {
5339 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005340 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305341 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07005342 },
5343};
5344
5345static int __init msmsdcc_init(void)
5346{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005347#if defined(CONFIG_DEBUG_FS)
5348 int ret = 0;
5349 ret = msmsdcc_dbg_init();
5350 if (ret) {
5351 pr_err("Failed to create debug fs dir \n");
5352 return ret;
5353 }
5354#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005355 return platform_driver_register(&msmsdcc_driver);
5356}
5357
5358static void __exit msmsdcc_exit(void)
5359{
5360 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005361
5362#if defined(CONFIG_DEBUG_FS)
5363 debugfs_remove(debugfs_file);
5364 debugfs_remove(debugfs_dir);
5365#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005366}
5367
5368module_init(msmsdcc_init);
5369module_exit(msmsdcc_exit);
5370
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005371MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07005372MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005373
5374#if defined(CONFIG_DEBUG_FS)
5375
5376static int
5377msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
5378{
5379 file->private_data = inode->i_private;
5380 return 0;
5381}
5382
5383static ssize_t
5384msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
5385 size_t count, loff_t *ppos)
5386{
5387 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08005388 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005389 int max, i;
5390
5391 i = 0;
5392 max = sizeof(buf) - 1;
5393
5394 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
5395 host->curr.cmd, host->curr.data);
5396 if (host->curr.cmd) {
5397 struct mmc_command *cmd = host->curr.cmd;
5398
5399 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
5400 cmd->opcode, cmd->arg, cmd->flags);
5401 }
5402 if (host->curr.data) {
5403 struct mmc_data *data = host->curr.data;
5404 i += scnprintf(buf + i, max - i,
5405 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
5406 data->timeout_ns, data->timeout_clks,
5407 data->blksz, data->blocks, data->error,
5408 data->flags);
5409 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
5410 host->curr.xfer_size, host->curr.xfer_remain,
5411 host->curr.data_xfered, host->dma.sg);
5412 }
5413
5414 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
5415}
5416
5417static const struct file_operations msmsdcc_dbg_state_ops = {
5418 .read = msmsdcc_dbg_state_read,
5419 .open = msmsdcc_dbg_state_open,
5420};
5421
5422static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
5423{
5424 if (debugfs_dir) {
5425 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
5426 0644, debugfs_dir, host,
5427 &msmsdcc_dbg_state_ops);
5428 }
5429}
5430
5431static int __init msmsdcc_dbg_init(void)
5432{
5433 int err;
5434
5435 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
5436 if (IS_ERR(debugfs_dir)) {
5437 err = PTR_ERR(debugfs_dir);
5438 debugfs_dir = NULL;
5439 return err;
5440 }
5441
5442 return 0;
5443}
5444#endif