blob: 3b115ab0396f2d86edaaa4d542b25ac64eb75b31 [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);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001853 unsigned long flags;
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 /*
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301907 * Kick the software command timeout timer here.
1908 * Timer expires in 10 secs.
1909 */
1910 mod_timer(&host->req_tout_timer,
1911 (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
San Mehat9d2bd732009-09-22 16:44:22 -07001912
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301913 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301914 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301915 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
1916 mrq->cmd->opcode == 54) {
Pratibhasagar V1c11da62011-11-14 12:36:35 +05301917 if (!host->sdcc_version)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001918 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301919 else
1920 /*
1921 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
1922 * write operations using CMD53 and CMD54.
1923 * Setting this bit with CMD53 would
1924 * automatically triggers PROG_DONE interrupt
1925 * without the need of sending dummy CMD52.
1926 */
1927 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani758cf8c2011-11-13 11:59:55 +05301928 } else if (mrq->cmd->opcode == MMC_WRITE_BLOCK &&
1929 host->sdcc_version) {
1930 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001931 }
San Mehat9d2bd732009-09-22 16:44:22 -07001932 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301933
Pratibhasagar V00b94332011-10-18 14:57:27 +05301934 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301935 mrq->sbc->mrq = mrq;
1936 mrq->sbc->data = mrq->data;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301937 if (mrq->data->flags & MMC_DATA_WRITE) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301938 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301939 msmsdcc_start_command(host, mrq->sbc, 0);
1940 } else {
1941 msmsdcc_request_start(host, mrq);
1942 }
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301943 } else {
1944 msmsdcc_request_start(host, mrq);
1945 }
1946
San Mehat9d2bd732009-09-22 16:44:22 -07001947 spin_unlock_irqrestore(&host->lock, flags);
1948}
1949
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001950static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1951 int min_uV, int max_uV)
1952{
1953 int rc = 0;
1954
1955 if (vreg->set_voltage_sup) {
1956 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1957 if (rc) {
1958 pr_err("%s: regulator_set_voltage(%s) failed."
1959 " min_uV=%d, max_uV=%d, rc=%d\n",
1960 __func__, vreg->name, min_uV, max_uV, rc);
1961 }
1962 }
1963
1964 return rc;
1965}
1966
1967static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1968 int uA_load)
1969{
1970 int rc = 0;
1971
Krishna Kondafea60182011-11-01 16:01:34 -07001972 /* regulators that do not support regulator_set_voltage also
1973 do not support regulator_set_optimum_mode */
1974 if (vreg->set_voltage_sup) {
1975 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1976 if (rc < 0)
1977 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
1978 "uA_load=%d) failed. rc=%d\n", __func__,
1979 vreg->name, uA_load, rc);
1980 else
1981 /* regulator_set_optimum_mode() can return non zero
1982 * value even for success case.
1983 */
1984 rc = 0;
1985 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001986
1987 return rc;
1988}
1989
1990static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1991 struct device *dev)
1992{
1993 int rc = 0;
1994
1995 /* check if regulator is already initialized? */
1996 if (vreg->reg)
1997 goto out;
1998
1999 /* Get the regulator handle */
2000 vreg->reg = regulator_get(dev, vreg->name);
2001 if (IS_ERR(vreg->reg)) {
2002 rc = PTR_ERR(vreg->reg);
2003 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
2004 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002005 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002006 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002007
2008 if (regulator_count_voltages(vreg->reg) > 0)
2009 vreg->set_voltage_sup = 1;
2010
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002011out:
2012 return rc;
2013}
2014
2015static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
2016{
2017 if (vreg->reg)
2018 regulator_put(vreg->reg);
2019}
2020
2021/* This init function should be called only once for each SDCC slot */
2022static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
2023{
2024 int rc = 0;
2025 struct msm_mmc_slot_reg_data *curr_slot;
2026 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
2027 struct device *dev = mmc_dev(host->mmc);
2028
2029 curr_slot = host->plat->vreg_data;
2030 if (!curr_slot)
2031 goto out;
2032
2033 curr_vdd_reg = curr_slot->vdd_data;
2034 curr_vccq_reg = curr_slot->vccq_data;
2035 curr_vddp_reg = curr_slot->vddp_data;
2036
2037 if (is_init) {
2038 /*
2039 * Get the regulator handle from voltage regulator framework
2040 * and then try to set the voltage level for the regulator
2041 */
2042 if (curr_vdd_reg) {
2043 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
2044 if (rc)
2045 goto out;
2046 }
2047 if (curr_vccq_reg) {
2048 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
2049 if (rc)
2050 goto vdd_reg_deinit;
2051 }
2052 if (curr_vddp_reg) {
2053 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
2054 if (rc)
2055 goto vccq_reg_deinit;
2056 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002057 rc = msmsdcc_vreg_reset(host);
2058 if (rc)
2059 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
2060 host->pdev_id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002061 goto out;
2062 } else {
2063 /* Deregister all regulators from regulator framework */
2064 goto vddp_reg_deinit;
2065 }
2066vddp_reg_deinit:
2067 if (curr_vddp_reg)
2068 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
2069vccq_reg_deinit:
2070 if (curr_vccq_reg)
2071 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
2072vdd_reg_deinit:
2073 if (curr_vdd_reg)
2074 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2075out:
2076 return rc;
2077}
2078
2079static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2080{
2081 int rc = 0;
2082
Subhash Jadavanicc922692011-08-01 23:05:01 +05302083 /* Put regulator in HPM (high power mode) */
2084 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2085 if (rc < 0)
2086 goto out;
2087
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002088 if (!vreg->is_enabled) {
2089 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302090 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2091 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002092 if (rc)
2093 goto out;
2094
2095 rc = regulator_enable(vreg->reg);
2096 if (rc) {
2097 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2098 __func__, vreg->name, rc);
2099 goto out;
2100 }
2101 vreg->is_enabled = true;
2102 }
2103
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002104out:
2105 return rc;
2106}
2107
2108static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
2109{
2110 int rc = 0;
2111
2112 /* Never disable regulator marked as always_on */
2113 if (vreg->is_enabled && !vreg->always_on) {
2114 rc = regulator_disable(vreg->reg);
2115 if (rc) {
2116 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2117 __func__, vreg->name, rc);
2118 goto out;
2119 }
2120 vreg->is_enabled = false;
2121
2122 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2123 if (rc < 0)
2124 goto out;
2125
2126 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302127 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002128 if (rc)
2129 goto out;
2130 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
2131 /* Put always_on regulator in LPM (low power mode) */
2132 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2133 if (rc < 0)
2134 goto out;
2135 }
2136out:
2137 return rc;
2138}
2139
2140static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
2141{
2142 int rc = 0, i;
2143 struct msm_mmc_slot_reg_data *curr_slot;
2144 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
2145 struct msm_mmc_reg_data *vreg_table[3];
2146
2147 curr_slot = host->plat->vreg_data;
2148 if (!curr_slot)
2149 goto out;
2150
2151 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
2152 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
2153 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
2154
2155 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2156 if (vreg_table[i]) {
2157 if (enable)
2158 rc = msmsdcc_vreg_enable(vreg_table[i]);
2159 else
2160 rc = msmsdcc_vreg_disable(vreg_table[i]);
2161 if (rc)
2162 goto out;
2163 }
2164 }
2165out:
2166 return rc;
2167}
2168
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002169/*
2170 * Reset vreg by ensuring it is off during probe. A call
2171 * to enable vreg is needed to balance disable vreg
2172 */
2173static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2174{
2175 int rc;
2176
2177 rc = msmsdcc_setup_vreg(host, 1);
2178 if (rc)
2179 return rc;
2180 rc = msmsdcc_setup_vreg(host, 0);
2181 return rc;
2182}
2183
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302184static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002185{
2186 int rc = 0;
2187
2188 if (host->plat->vreg_data) {
2189 struct msm_mmc_reg_data *vddp_reg =
2190 host->plat->vreg_data->vddp_data;
2191
2192 if (vddp_reg && vddp_reg->is_enabled)
2193 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
2194 }
2195
2196 return rc;
2197}
2198
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302199static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
2200{
2201 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2202 int rc = 0;
2203
2204 if (curr_slot && curr_slot->vddp_data) {
2205 rc = msmsdcc_set_vddp_level(host,
2206 curr_slot->vddp_data->low_vol_level);
2207
2208 if (rc)
2209 pr_err("%s: %s: failed to change vddp level to %d",
2210 mmc_hostname(host->mmc), __func__,
2211 curr_slot->vddp_data->low_vol_level);
2212 }
2213
2214 return rc;
2215}
2216
2217static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
2218{
2219 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2220 int rc = 0;
2221
2222 if (curr_slot && curr_slot->vddp_data) {
2223 rc = msmsdcc_set_vddp_level(host,
2224 curr_slot->vddp_data->high_vol_level);
2225
2226 if (rc)
2227 pr_err("%s: %s: failed to change vddp level to %d",
2228 mmc_hostname(host->mmc), __func__,
2229 curr_slot->vddp_data->high_vol_level);
2230 }
2231
2232 return rc;
2233}
2234
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302235static inline int msmsdcc_set_vccq_vol(struct msmsdcc_host *host, int level)
2236{
2237 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2238 int rc = 0;
2239
2240 if (curr_slot && curr_slot->vccq_data) {
2241 rc = msmsdcc_vreg_set_voltage(curr_slot->vccq_data,
2242 level, level);
2243 if (rc)
2244 pr_err("%s: %s: failed to change vccq level to %d",
2245 mmc_hostname(host->mmc), __func__, level);
2246 }
2247
2248 return rc;
2249}
2250
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002251static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2252{
2253 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2254 return 1;
2255 return 0;
2256}
2257
Asutosh Dasf5298c32012-04-03 14:51:47 +05302258/*
2259 * Any function calling msmsdcc_setup_clocks must
2260 * acquire clk_mutex. May sleep.
2261 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002262static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
2263{
2264 if (enable) {
2265 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302266 clk_prepare_enable(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002267 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302268 clk_prepare_enable(host->pclk);
2269 clk_prepare_enable(host->clk);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302270 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302271 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002272 } else {
Subhash Jadavanidd432952012-03-28 11:25:56 +05302273 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302274 msmsdcc_delay(host);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302275 clk_disable_unprepare(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002276 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302277 clk_disable_unprepare(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002278 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302279 clk_disable_unprepare(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002280 }
2281}
2282
2283static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2284 unsigned int req_clk)
2285{
2286 unsigned int sel_clk = -1;
2287
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302288 if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
2289 sel_clk = msmsdcc_get_min_sup_clk_rate(host);
2290 goto out;
2291 }
2292
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002293 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2294 unsigned char cnt;
2295
2296 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2297 if (host->plat->sup_clk_table[cnt] > req_clk)
2298 break;
2299 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2300 sel_clk = host->plat->sup_clk_table[cnt];
2301 break;
2302 } else
2303 sel_clk = host->plat->sup_clk_table[cnt];
2304 }
2305 } else {
2306 if ((req_clk < host->plat->msmsdcc_fmax) &&
2307 (req_clk > host->plat->msmsdcc_fmid))
2308 sel_clk = host->plat->msmsdcc_fmid;
2309 else
2310 sel_clk = req_clk;
2311 }
2312
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302313out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002314 return sel_clk;
2315}
2316
2317static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2318 struct msmsdcc_host *host)
2319{
2320 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2321 return host->plat->sup_clk_table[0];
2322 else
2323 return host->plat->msmsdcc_fmin;
2324}
2325
2326static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2327 struct msmsdcc_host *host)
2328{
2329 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2330 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2331 else
2332 return host->plat->msmsdcc_fmax;
2333}
2334
2335static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302336{
2337 struct msm_mmc_gpio_data *curr;
2338 int i, rc = 0;
2339
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002340 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302341 for (i = 0; i < curr->size; i++) {
2342 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002343 if (curr->gpio[i].is_always_on &&
2344 curr->gpio[i].is_enabled)
2345 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302346 rc = gpio_request(curr->gpio[i].no,
2347 curr->gpio[i].name);
2348 if (rc) {
2349 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2350 mmc_hostname(host->mmc),
2351 curr->gpio[i].no,
2352 curr->gpio[i].name, rc);
2353 goto free_gpios;
2354 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002355 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302356 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002357 if (curr->gpio[i].is_always_on)
2358 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302359 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002360 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302361 }
2362 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002363 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302364
2365free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002366 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302367 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002368 curr->gpio[i].is_enabled = false;
2369 }
2370out:
2371 return rc;
2372}
2373
2374static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2375{
2376 struct msm_mmc_pad_data *curr;
2377 int i;
2378
2379 curr = host->plat->pin_data->pad_data;
2380 for (i = 0; i < curr->drv->size; i++) {
2381 if (enable)
2382 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2383 curr->drv->on[i].val);
2384 else
2385 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2386 curr->drv->off[i].val);
2387 }
2388
2389 for (i = 0; i < curr->pull->size; i++) {
2390 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002391 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002392 curr->pull->on[i].val);
2393 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002394 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002395 curr->pull->off[i].val);
2396 }
2397
2398 return 0;
2399}
2400
2401static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2402{
2403 int rc = 0;
2404
2405 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2406 return 0;
2407
2408 if (host->plat->pin_data->is_gpio)
2409 rc = msmsdcc_setup_gpio(host, enable);
2410 else
2411 rc = msmsdcc_setup_pad(host, enable);
2412
2413 if (!rc)
2414 host->plat->pin_data->cfg_sts = enable;
2415
2416 return rc;
2417}
2418
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302419static int msmsdcc_cfg_mpm_sdiowakeup(struct msmsdcc_host *host,
2420 unsigned mode)
2421{
2422 int ret = 0;
2423 unsigned int pin = host->plat->mpm_sdiowakeup_int;
2424
2425 if (!pin)
2426 return 0;
2427
2428 switch (mode) {
2429 case SDC_DAT1_DISABLE:
2430 ret = msm_mpm_enable_pin(pin, 0);
2431 break;
2432 case SDC_DAT1_ENABLE:
2433 ret = msm_mpm_set_pin_type(pin, IRQ_TYPE_LEVEL_LOW);
2434 ret = msm_mpm_enable_pin(pin, 1);
2435 break;
2436 case SDC_DAT1_ENWAKE:
2437 ret = msm_mpm_set_pin_wake(pin, 1);
2438 break;
2439 case SDC_DAT1_DISWAKE:
2440 ret = msm_mpm_set_pin_wake(pin, 0);
2441 break;
2442 default:
2443 ret = -EINVAL;
2444 break;
2445 }
2446
2447 return ret;
2448}
2449
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302450static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2451{
2452 u32 pwr = 0;
2453 int ret = 0;
2454 struct mmc_host *mmc = host->mmc;
2455
2456 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2457 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2458 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2459 ret = msmsdcc_setup_vreg(host, !!ios->vdd);
2460
2461 if (ret) {
2462 pr_err("%s: Failed to setup voltage regulators\n",
2463 mmc_hostname(host->mmc));
2464 goto out;
2465 }
2466
2467 switch (ios->power_mode) {
2468 case MMC_POWER_OFF:
2469 pwr = MCI_PWR_OFF;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302470 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302471 /*
2472 * As VDD pad rail is always on, set low voltage for VDD
2473 * pad rail when slot is unused (when card is not present
2474 * or during system suspend).
2475 */
2476 msmsdcc_set_vddp_low_vol(host);
2477 msmsdcc_setup_pins(host, false);
2478 break;
2479 case MMC_POWER_UP:
2480 /* writing PWR_UP bit is redundant */
2481 pwr = MCI_PWR_UP;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302482 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302483
2484 msmsdcc_set_vddp_high_vol(host);
2485 msmsdcc_setup_pins(host, true);
2486 break;
2487 case MMC_POWER_ON:
2488 pwr = MCI_PWR_ON;
2489 break;
2490 }
2491
2492out:
2493 return pwr;
2494}
2495
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002496static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2497{
2498 unsigned int wakeup_irq;
2499
2500 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2501 host->plat->sdiowakeup_irq :
2502 host->core_irqres->start;
2503
2504 if (!host->irq_wake_enabled) {
2505 enable_irq_wake(wakeup_irq);
2506 host->irq_wake_enabled = true;
2507 }
2508}
2509
2510static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2511{
2512 unsigned int wakeup_irq;
2513
2514 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2515 host->plat->sdiowakeup_irq :
2516 host->core_irqres->start;
2517
2518 if (host->irq_wake_enabled) {
2519 disable_irq_wake(wakeup_irq);
2520 host->irq_wake_enabled = false;
2521 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302522}
2523
San Mehat9d2bd732009-09-22 16:44:22 -07002524static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302525msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
2526{
2527 struct mmc_host *mmc = host->mmc;
2528
2529 /*
2530 * SDIO_AL clients has different mechanism of handling LPM through
2531 * sdio_al driver itself. The sdio wakeup interrupt is configured as
2532 * part of that. Here, we are interested only in clients like WLAN.
2533 */
2534 if (!(mmc->card && mmc_card_sdio(mmc->card))
2535 || host->plat->is_sdio_al_client)
2536 goto out;
2537
2538 if (!host->sdcc_suspended) {
2539 /*
2540 * When MSM is not in power collapse and we
2541 * are disabling clocks, enable bit 22 in MASK0
2542 * to handle asynchronous SDIO interrupts.
2543 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302544 if (enable_wakeup_irq) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302545 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302546 mb();
2547 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302548 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302549 msmsdcc_sync_reg_wr(host);
2550 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302551 goto out;
2552 } else if (!mmc_card_wake_sdio_irq(mmc)) {
2553 /*
2554 * Wakeup MSM only if SDIO function drivers set
2555 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
2556 */
2557 goto out;
2558 }
2559
2560 if (enable_wakeup_irq) {
2561 if (!host->plat->sdiowakeup_irq) {
2562 /*
2563 * When there is no gpio line that can be configured
2564 * as wakeup interrupt handle it by configuring
2565 * asynchronous sdio interrupts and DAT1 line.
2566 */
2567 writel_relaxed(MCI_SDIOINTMASK,
2568 host->base + MMCIMASK0);
2569 mb();
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302570 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302571 /* configure sdcc core interrupt as wakeup interrupt */
2572 msmsdcc_enable_irq_wake(host);
2573 } else {
2574 /* Let gpio line handle wakeup interrupt */
2575 writel_relaxed(0, host->base + MMCIMASK0);
2576 mb();
2577 if (host->sdio_wakeupirq_disabled) {
2578 host->sdio_wakeupirq_disabled = 0;
2579 /* configure gpio line as wakeup interrupt */
2580 msmsdcc_enable_irq_wake(host);
2581 enable_irq(host->plat->sdiowakeup_irq);
2582 }
2583 }
2584 } else {
2585 if (!host->plat->sdiowakeup_irq) {
2586 /*
2587 * We may not have cleared bit 22 in the interrupt
2588 * handler as the clocks might be off at that time.
2589 */
2590 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302591 msmsdcc_sync_reg_wr(host);
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302592 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302593 msmsdcc_disable_irq_wake(host);
2594 } else if (!host->sdio_wakeupirq_disabled) {
2595 disable_irq_nosync(host->plat->sdiowakeup_irq);
2596 msmsdcc_disable_irq_wake(host);
2597 host->sdio_wakeupirq_disabled = 1;
2598 }
2599 }
2600out:
2601 return;
2602}
2603
2604static void
San Mehat9d2bd732009-09-22 16:44:22 -07002605msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2606{
2607 struct msmsdcc_host *host = mmc_priv(mmc);
2608 u32 clk = 0, pwr = 0;
2609 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002610 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002611 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002612
Sahitya Tummala7a892482011-01-18 11:22:49 +05302613
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302614 /*
2615 * Disable SDCC core interrupt until set_ios is completed.
2616 * This avoids any race conditions with interrupt raised
2617 * when turning on/off the clocks. One possible
2618 * scenario is SDIO operational interrupt while the clock
2619 * is turned off.
Asutosh Dasf5298c32012-04-03 14:51:47 +05302620 * host->lock is being released intermittently below.
2621 * Thus, prevent concurrent access to host.
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302622 */
2623
Asutosh Dasf5298c32012-04-03 14:51:47 +05302624 mutex_lock(&host->clk_mutex);
2625 DBG(host, "ios->clock = %u\n", ios->clock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302626 spin_lock_irqsave(&host->lock, flags);
2627 if (!host->sdcc_irq_disabled) {
2628 spin_unlock_irqrestore(&host->lock, flags);
2629 disable_irq(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002630 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302631 host->sdcc_irq_disabled = 1;
2632 }
2633 spin_unlock_irqrestore(&host->lock, flags);
2634
2635 pwr = msmsdcc_setup_pwr(host, ios);
2636
2637 spin_lock_irqsave(&host->lock, flags);
2638 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002639 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302640 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002641 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302642 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002643 host->clks_on = 1;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302644 writel_relaxed(host->mci_irqenable,
2645 host->base + MMCIMASK0);
2646 mb();
2647 msmsdcc_cfg_sdio_wakeup(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002648 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002649
2650 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2651 /*
2652 * For DDR50 mode, controller needs clock rate to be
2653 * double than what is required on the SD card CLK pin.
2654 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302655 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002656 /*
2657 * Make sure that we don't double the clock if
2658 * doubled clock rate is already set
2659 */
2660 if (!host->ddr_doubled_clk_rate ||
2661 (host->ddr_doubled_clk_rate &&
2662 (host->ddr_doubled_clk_rate != ios->clock))) {
2663 host->ddr_doubled_clk_rate =
2664 msmsdcc_get_sup_clk_rate(
2665 host, (ios->clock * 2));
2666 clock = host->ddr_doubled_clk_rate;
2667 }
2668 } else {
2669 host->ddr_doubled_clk_rate = 0;
2670 }
2671
2672 if (clock != host->clk_rate) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302673 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002674 rc = clk_set_rate(host->clk, clock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302675 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002676 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302677 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002678 mmc_hostname(mmc), clock);
2679 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302680 host->reg_write_delay =
2681 (1 + ((3 * USEC_PER_SEC) /
2682 (host->clk_rate ? host->clk_rate :
2683 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002684 }
2685 /*
2686 * give atleast 2 MCLK cycles delay for clocks
2687 * and SDCC core to stabilize
2688 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302689 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002690 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002691 clk |= MCI_CLK_ENABLE;
2692 }
2693
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002694 if (ios->bus_width == MMC_BUS_WIDTH_8)
2695 clk |= MCI_CLK_WIDEBUS_8;
2696 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2697 clk |= MCI_CLK_WIDEBUS_4;
2698 else
2699 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002700
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002701 if (msmsdcc_is_pwrsave(host))
2702 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002703
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002704 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002705
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002706 host->tuning_needed = 0;
2707 /*
2708 * Select the controller timing mode according
2709 * to current bus speed mode
2710 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302711 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2712 (ios->timing == MMC_TIMING_MMC_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002713 clk |= (4 << 14);
2714 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302715 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002716 clk |= (3 << 14);
2717 } else {
2718 clk |= (2 << 14); /* feedback clock */
2719 }
2720
2721 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2722 clk |= (2 << 23);
2723
Subhash Jadavani00083572012-02-15 16:18:01 +05302724 /* Clear IO_PAD_PWR_SWITCH while powering off the card */
2725 if (!ios->vdd)
2726 host->io_pad_pwr_switch = 0;
2727
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002728 if (host->io_pad_pwr_switch)
2729 clk |= IO_PAD_PWR_SWITCH;
2730
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302731 /* Don't write into registers if clocks are disabled */
2732 if (host->clks_on) {
2733 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
2734 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302735 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002736 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302737 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
2738 host->pwr = pwr;
2739 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302740 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002741 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002742 }
2743
2744 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302745 msmsdcc_cfg_sdio_wakeup(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302746 spin_unlock_irqrestore(&host->lock, flags);
2747 /*
2748 * May get a wake-up interrupt the instant we disable the
2749 * clocks. This would disable the wake-up interrupt.
2750 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002751 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302752 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002753 host->clks_on = 0;
2754 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302755
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302756 if (host->tuning_in_progress)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302757 WARN(!host->clks_on,
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302758 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302759
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302760 /* Let interrupts be disabled if the host is powered off */
2761 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
2762 enable_irq(host->core_irqres->start);
2763 host->sdcc_irq_disabled = 0;
2764 }
2765
San Mehat4adbbcc2009-11-08 13:00:37 -08002766 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302767 mutex_unlock(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07002768}
2769
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002770int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2771{
2772 struct msmsdcc_host *host = mmc_priv(mmc);
2773 u32 clk;
2774
2775 clk = readl_relaxed(host->base + MMCICLOCK);
2776 pr_debug("Changing to pwr_save=%d", pwrsave);
2777 if (pwrsave && msmsdcc_is_pwrsave(host))
2778 clk |= MCI_CLK_PWRSAVE;
2779 else
2780 clk &= ~MCI_CLK_PWRSAVE;
2781 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302782 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002783
2784 return 0;
2785}
2786
2787static int msmsdcc_get_ro(struct mmc_host *mmc)
2788{
2789 int status = -ENOSYS;
2790 struct msmsdcc_host *host = mmc_priv(mmc);
2791
2792 if (host->plat->wpswitch) {
2793 status = host->plat->wpswitch(mmc_dev(mmc));
2794 } else if (host->plat->wpswitch_gpio) {
2795 status = gpio_request(host->plat->wpswitch_gpio,
2796 "SD_WP_Switch");
2797 if (status) {
2798 pr_err("%s: %s: Failed to request GPIO %d\n",
2799 mmc_hostname(mmc), __func__,
2800 host->plat->wpswitch_gpio);
2801 } else {
2802 status = gpio_direction_input(
2803 host->plat->wpswitch_gpio);
2804 if (!status) {
2805 /*
2806 * Wait for atleast 300ms as debounce
2807 * time for GPIO input to stabilize.
2808 */
2809 msleep(300);
2810 status = gpio_get_value_cansleep(
2811 host->plat->wpswitch_gpio);
2812 status ^= !host->plat->wpswitch_polarity;
2813 }
2814 gpio_free(host->plat->wpswitch_gpio);
2815 }
2816 }
2817
2818 if (status < 0)
2819 status = -ENOSYS;
2820 pr_debug("%s: Card read-only status %d\n", __func__, status);
2821
2822 return status;
2823}
2824
San Mehat9d2bd732009-09-22 16:44:22 -07002825static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2826{
2827 struct msmsdcc_host *host = mmc_priv(mmc);
2828 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002829
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302830 /*
2831 * We may come here with clocks turned off in that case don't
2832 * attempt to write into MASK0 register. While turning on the
2833 * clocks mci_irqenable will be written to MASK0 register.
2834 */
2835
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002836 if (enable) {
2837 spin_lock_irqsave(&host->lock, flags);
2838 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302839 if (host->clks_on) {
2840 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002841 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302842 mb();
2843 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002844 spin_unlock_irqrestore(&host->lock, flags);
2845 } else {
2846 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302847 if (host->clks_on) {
2848 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002849 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302850 mb();
2851 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002852 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002853}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002854
2855#ifdef CONFIG_PM_RUNTIME
subhashj245831e2012-04-30 18:46:17 +05302856static void msmsdcc_print_rpm_info(struct msmsdcc_host *host)
2857{
2858 struct device *dev = mmc_dev(host->mmc);
2859
2860 pr_info("%s: RPM: runtime_status=%d, usage_count=%d,"
2861 " is_suspended=%d, disable_depth=%d, runtime_error=%d,"
2862 " request_pending=%d, request=%d\n",
2863 mmc_hostname(host->mmc), dev->power.runtime_status,
2864 atomic_read(&dev->power.usage_count),
2865 dev->power.is_suspended, dev->power.disable_depth,
2866 dev->power.runtime_error, dev->power.request_pending,
2867 dev->power.request);
2868}
2869
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002870static int msmsdcc_enable(struct mmc_host *mmc)
2871{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002872 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002873 struct device *dev = mmc->parent;
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302874 struct msmsdcc_host *host = mmc_priv(mmc);
2875
2876 msmsdcc_pm_qos_update_latency(host, 1);
2877
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002878 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302879 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002880
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002881 if (host->sdcc_suspended && host->pending_resume &&
2882 !pm_runtime_suspended(dev)) {
2883 host->pending_resume = false;
2884 pm_runtime_get_noresume(dev);
2885 rc = msmsdcc_runtime_resume(dev);
2886 goto out;
2887 }
2888
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302889 if (dev->power.runtime_status == RPM_SUSPENDING) {
2890 if (mmc->suspend_task == current) {
2891 pm_runtime_get_noresume(dev);
2892 goto out;
2893 }
2894 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002895
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302896 rc = pm_runtime_get_sync(dev);
2897
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002898out:
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302899 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002900 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2901 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05302902 msmsdcc_print_rpm_info(host);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302903 return rc;
2904 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302905
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302906 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002907}
2908
2909static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2910{
2911 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302912 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002913
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302914 msmsdcc_pm_qos_update_latency(host, 0);
2915
2916 if (mmc->card && mmc_card_sdio(mmc->card))
2917 return 0;
2918
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302919 if (host->plat->disable_runtime_pm)
2920 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002921
2922 rc = pm_runtime_put_sync(mmc->parent);
2923
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002924 /*
2925 * Ignore -EAGAIN as that is not fatal, it means that
2926 * either runtime usage count is non-zero or the runtime
2927 * pm itself is disabled or not in proper state to process
2928 * idle notification.
2929 */
2930 if (rc < 0 && (rc != -EAGAIN)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002931 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2932 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05302933 msmsdcc_print_rpm_info(host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002934 return rc;
2935 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302936
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002937 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002938}
2939#else
subhashj245831e2012-04-30 18:46:17 +05302940static void msmsdcc_print_rpm_info(struct msmsdcc_host *host) {}
2941
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302942static int msmsdcc_enable(struct mmc_host *mmc)
2943{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002944 struct device *dev = mmc->parent;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302945 struct msmsdcc_host *host = mmc_priv(mmc);
2946 unsigned long flags;
Sujit Reddy Thumma7f5051c2012-05-04 10:14:07 +05302947 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302948
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302949 msmsdcc_pm_qos_update_latency(host, 1);
2950
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002951 if (mmc->card && mmc_card_sdio(mmc->card))
2952 return 0;
2953
2954 if (host->sdcc_suspended && host->pending_resume) {
2955 host->pending_resume = false;
2956 rc = msmsdcc_runtime_resume(dev);
2957 goto out;
2958 }
2959
Asutosh Dasf5298c32012-04-03 14:51:47 +05302960 mutex_lock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302961 spin_lock_irqsave(&host->lock, flags);
2962 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302963 spin_unlock_irqrestore(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302964 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302965 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302966 host->clks_on = 1;
2967 }
2968 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302969 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302970
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002971out:
2972 if (rc < 0) {
2973 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2974 __func__, rc);
2975 return rc;
2976 }
2977
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302978 return 0;
2979}
2980
2981static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2982{
2983 struct msmsdcc_host *host = mmc_priv(mmc);
2984 unsigned long flags;
2985
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302986 msmsdcc_pm_qos_update_latency(host, 0);
2987
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302988 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302989 return 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302990
Asutosh Dasf5298c32012-04-03 14:51:47 +05302991 mutex_lock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302992 spin_lock_irqsave(&host->lock, flags);
2993 if (host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302994 spin_unlock_irqrestore(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302995 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302996 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302997 host->clks_on = 0;
2998 }
2999 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303000 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303001
3002 return 0;
3003}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003004#endif
3005
3006static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
3007 struct mmc_ios *ios)
3008{
3009 struct msmsdcc_host *host = mmc_priv(mmc);
3010 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303011 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003012
Subhash Jadavani00083572012-02-15 16:18:01 +05303013 spin_lock_irqsave(&host->lock, flags);
3014 host->io_pad_pwr_switch = 0;
3015 spin_unlock_irqrestore(&host->lock, flags);
3016
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303017 /*
3018 * For eMMC cards, VccQ voltage range must be changed
3019 * only if it operates in HS200 SDR 1.2V mode or in
3020 * DDR 1.2V mode.
3021 */
3022 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_120) {
3023 rc = msmsdcc_set_vccq_vol(host, 1200000);
3024 goto out;
3025 }
3026
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003027 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
3028 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303029 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003030 goto out;
3031 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
3032 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303033 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003034 goto out;
3035 }
San Mehat9d2bd732009-09-22 16:44:22 -07003036
3037 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003038 /*
3039 * If we are here means voltage switch from high voltage to
3040 * low voltage is required
3041 */
3042
3043 /*
3044 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
3045 * register until they become all zeros.
3046 */
3047 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303048 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003049 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
3050 mmc_hostname(mmc), __func__);
3051 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07003052 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003053
3054 /* Stop SD CLK output. */
3055 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3056 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303057 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003058 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003059
3060 /*
3061 * Switch VDDPX from high voltage to low voltage
3062 * to change the VDD of the SD IO pads.
3063 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303064 rc = msmsdcc_set_vddp_low_vol(host);
3065 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003066 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003067
3068 spin_lock_irqsave(&host->lock, flags);
3069 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3070 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303071 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003072 host->io_pad_pwr_switch = 1;
3073 spin_unlock_irqrestore(&host->lock, flags);
3074
3075 /* Wait 5 ms for the voltage regulater in the card to become stable. */
3076 usleep_range(5000, 5500);
3077
3078 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303079 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003080 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3081 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303082 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003083 spin_unlock_irqrestore(&host->lock, flags);
3084
3085 /*
3086 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
3087 * don't become all ones within 1 ms then a Voltage Switch
3088 * sequence has failed and a power cycle to the card is required.
3089 * Otherwise Voltage Switch sequence is completed successfully.
3090 */
3091 usleep_range(1000, 1500);
3092
3093 spin_lock_irqsave(&host->lock, flags);
3094 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
3095 != (0xF << 1)) {
3096 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
3097 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303098 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003099 goto out_unlock;
3100 }
3101
3102out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303103 /* Enable PWRSAVE */
3104 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3105 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303106 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003107 spin_unlock_irqrestore(&host->lock, flags);
3108out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303109 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003110}
3111
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303112static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003113{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003114 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003115
3116 /* Program the MCLK value to MCLK_FREQ bit field */
3117 if (host->clk_rate <= 112000000)
3118 mclk_freq = 0;
3119 else if (host->clk_rate <= 125000000)
3120 mclk_freq = 1;
3121 else if (host->clk_rate <= 137000000)
3122 mclk_freq = 2;
3123 else if (host->clk_rate <= 150000000)
3124 mclk_freq = 3;
3125 else if (host->clk_rate <= 162000000)
3126 mclk_freq = 4;
3127 else if (host->clk_rate <= 175000000)
3128 mclk_freq = 5;
3129 else if (host->clk_rate <= 187000000)
3130 mclk_freq = 6;
3131 else if (host->clk_rate <= 200000000)
3132 mclk_freq = 7;
3133
3134 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3135 & ~(7 << 24)) | (mclk_freq << 24)),
3136 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003137}
3138
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303139/* Initialize the DLL (Programmable Delay Line ) */
3140static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003141{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003142 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303143 unsigned long flags;
3144 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003145
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303146 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003147 /*
3148 * Make sure that clock is always enabled when DLL
3149 * tuning is in progress. Keeping PWRSAVE ON may
3150 * turn off the clock. So let's disable the PWRSAVE
3151 * here and re-enable it once tuning is completed.
3152 */
3153 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3154 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303155 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303156
3157 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3158 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3159 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3160
3161 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3162 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3163 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3164
3165 msmsdcc_cm_sdc4_dll_set_freq(host);
3166
3167 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3168 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3169 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3170
3171 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3172 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3173 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3174
3175 /* Set DLL_EN bit to 1. */
3176 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3177 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3178
3179 /* Set CK_OUT_EN bit to 1. */
3180 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3181 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3182
3183 wait_cnt = 50;
3184 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3185 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3186 /* max. wait for 50us sec for LOCK bit to be set */
3187 if (--wait_cnt == 0) {
3188 pr_err("%s: %s: DLL failed to LOCK\n",
3189 mmc_hostname(host->mmc), __func__);
3190 rc = -ETIMEDOUT;
3191 goto out;
3192 }
3193 /* wait for 1us before polling again */
3194 udelay(1);
3195 }
3196
3197out:
3198 /* re-enable PWRSAVE */
3199 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3200 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303201 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303202 spin_unlock_irqrestore(&host->lock, flags);
3203
3204 return rc;
3205}
3206
3207static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3208 u8 poll)
3209{
3210 int rc = 0;
3211 u32 wait_cnt = 50;
3212 u8 ck_out_en = 0;
3213
3214 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3215 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3216 MCI_CK_OUT_EN);
3217
3218 while (ck_out_en != poll) {
3219 if (--wait_cnt == 0) {
3220 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3221 mmc_hostname(host->mmc), __func__, poll);
3222 rc = -ETIMEDOUT;
3223 goto out;
3224 }
3225 udelay(1);
3226
3227 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3228 MCI_CK_OUT_EN);
3229 }
3230out:
3231 return rc;
3232}
3233
3234/*
3235 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3236 * calibration sequence. This function should be called before
3237 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3238 * commands (CMD17/CMD18).
3239 *
3240 * This function gets called when host spinlock acquired.
3241 */
3242static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3243{
3244 int rc = 0;
3245 u32 config;
3246
3247 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3248 config |= MCI_CDR_EN;
3249 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3250 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3251
3252 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3253 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3254 if (rc)
3255 goto err_out;
3256
3257 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3258 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3259 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3260
3261 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3262 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3263 if (rc)
3264 goto err_out;
3265
3266 goto out;
3267
3268err_out:
3269 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3270out:
3271 return rc;
3272}
3273
3274static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3275 u8 phase)
3276{
3277 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303278 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3279 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3280 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303281 unsigned long flags;
3282 u32 config;
3283
3284 spin_lock_irqsave(&host->lock, flags);
3285
3286 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3287 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3288 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3289 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3290
3291 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3292 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3293 if (rc)
3294 goto err_out;
3295
3296 /*
3297 * Write the selected DLL clock output phase (0 ... 15)
3298 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
3299 */
3300 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3301 & ~(0xF << 20))
3302 | (grey_coded_phase_table[phase] << 20)),
3303 host->base + MCI_DLL_CONFIG);
3304
3305 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3306 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3307 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3308
3309 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3310 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3311 if (rc)
3312 goto err_out;
3313
3314 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3315 config |= MCI_CDR_EN;
3316 config &= ~MCI_CDR_EXT_EN;
3317 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3318 goto out;
3319
3320err_out:
3321 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3322 mmc_hostname(host->mmc), __func__, phase);
3323out:
3324 spin_unlock_irqrestore(&host->lock, flags);
3325 return rc;
3326}
3327
3328/*
3329 * Find out the greatest range of consecuitive selected
3330 * DLL clock output phases that can be used as sampling
3331 * setting for SD3.0 UHS-I card read operation (in SDR104
3332 * timing mode) or for eMMC4.5 card read operation (in HS200
3333 * timing mode).
3334 * Select the 3/4 of the range and configure the DLL with the
3335 * selected DLL clock output phase.
3336*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303337static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303338 u8 *phase_table, u8 total_phases)
3339{
Subhash Jadavani6159c622012-03-15 19:05:55 +05303340 #define MAX_PHASES 16
Subhash Jadavani34187042012-03-02 10:59:49 +05303341 int ret;
Subhash Jadavani6159c622012-03-15 19:05:55 +05303342 u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
3343 u8 phases_per_row[MAX_PHASES] = {0};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303344 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303345 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3346 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303347
Subhash Jadavani6159c622012-03-15 19:05:55 +05303348 if (!total_phases || (total_phases > MAX_PHASES)) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303349 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3350 mmc_hostname(host->mmc), __func__, total_phases);
3351 return -EINVAL;
3352 }
3353
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303354 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303355 ranges[row_index][col_index] = phase_table[cnt];
3356 phases_per_row[row_index] += 1;
3357 col_index++;
3358
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303359 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303360 continue;
3361 /* check if next phase in phase_table is consecutive or not */
3362 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3363 row_index++;
3364 col_index = 0;
3365 }
3366 }
3367
Subhash Jadavani6159c622012-03-15 19:05:55 +05303368 if (row_index >= MAX_PHASES)
3369 return -EINVAL;
3370
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303371 /* Check if phase-0 is present in first valid window? */
3372 if (!ranges[0][0]) {
3373 phase_0_found = true;
3374 phase_0_raw_index = 0;
3375 /* Check if cycle exist between 2 valid windows */
3376 for (cnt = 1; cnt <= row_index; cnt++) {
3377 if (phases_per_row[cnt]) {
Subhash Jadavani6159c622012-03-15 19:05:55 +05303378 for (i = 0; i < phases_per_row[cnt]; i++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303379 if (ranges[cnt][i] == 15) {
3380 phase_15_found = true;
3381 phase_15_raw_index = cnt;
3382 break;
3383 }
3384 }
3385 }
3386 }
3387 }
3388
3389 /* If 2 valid windows form cycle then merge them as single window */
3390 if (phase_0_found && phase_15_found) {
3391 /* number of phases in raw where phase 0 is present */
3392 u8 phases_0 = phases_per_row[phase_0_raw_index];
3393 /* number of phases in raw where phase 15 is present */
3394 u8 phases_15 = phases_per_row[phase_15_raw_index];
3395
Subhash Jadavani6159c622012-03-15 19:05:55 +05303396 if (phases_0 + phases_15 >= MAX_PHASES)
3397 /*
3398 * If there are more than 1 phase windows then total
3399 * number of phases in both the windows should not be
3400 * more than or equal to MAX_PHASES.
3401 */
3402 return -EINVAL;
3403
3404 /* Merge 2 cyclic windows */
3405 i = phases_15;
3406 for (cnt = 0; cnt < phases_0; cnt++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303407 ranges[phase_15_raw_index][i] =
3408 ranges[phase_0_raw_index][cnt];
Subhash Jadavani6159c622012-03-15 19:05:55 +05303409 if (++i >= MAX_PHASES)
3410 break;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303411 }
Subhash Jadavani6159c622012-03-15 19:05:55 +05303412
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303413 phases_per_row[phase_0_raw_index] = 0;
3414 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
3415 }
3416
3417 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303418 if (phases_per_row[cnt] > curr_max) {
3419 curr_max = phases_per_row[cnt];
3420 selected_row_index = cnt;
3421 }
3422 }
3423
Subhash Jadavani6159c622012-03-15 19:05:55 +05303424 i = ((curr_max * 3) / 4);
3425 if (i)
3426 i--;
3427
Subhash Jadavani34187042012-03-02 10:59:49 +05303428 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303429
Subhash Jadavani6159c622012-03-15 19:05:55 +05303430 if (ret >= MAX_PHASES) {
3431 ret = -EINVAL;
3432 pr_err("%s: %s: invalid phase selected=%d\n",
3433 mmc_hostname(host->mmc), __func__, ret);
3434 }
3435
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303436 return ret;
3437}
3438
Girish K Sa3f41692012-02-29 12:00:09 +05303439static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303440{
3441 int rc = 0;
3442 struct msmsdcc_host *host = mmc_priv(mmc);
3443 unsigned long flags;
3444 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303445 const u32 *tuning_block_pattern = tuning_block_64;
3446 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303447
3448 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
3449
3450 /* Tuning is only required for SDR104 modes */
3451 if (!host->tuning_needed) {
3452 rc = 0;
3453 goto exit;
3454 }
3455
3456 spin_lock_irqsave(&host->lock, flags);
3457 WARN(!host->pwr, "SDCC power is turned off\n");
3458 WARN(!host->clks_on, "SDCC clocks are turned off\n");
3459 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
3460
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303461 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303462 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
3463 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
3464 tuning_block_pattern = tuning_block_128;
3465 size = sizeof(tuning_block_128);
3466 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303467 spin_unlock_irqrestore(&host->lock, flags);
3468
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003469 /* first of all reset the tuning block */
3470 rc = msmsdcc_init_cm_sdc4_dll(host);
3471 if (rc)
3472 goto out;
3473
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303474 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003475 if (!data_buf) {
3476 rc = -ENOMEM;
3477 goto out;
3478 }
3479
3480 phase = 0;
3481 do {
3482 struct mmc_command cmd = {0};
3483 struct mmc_data data = {0};
3484 struct mmc_request mrq = {
3485 .cmd = &cmd,
3486 .data = &data
3487 };
3488 struct scatterlist sg;
3489
3490 /* set the phase in delay line hw block */
3491 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3492 if (rc)
3493 goto kfree;
3494
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303495 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003496 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
3497
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303498 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003499 data.blocks = 1;
3500 data.flags = MMC_DATA_READ;
3501 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
3502
3503 data.sg = &sg;
3504 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303505 sg_init_one(&sg, data_buf, size);
3506 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003507 mmc_wait_for_req(mmc, &mrq);
3508
3509 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303510 !memcmp(data_buf, tuning_block_pattern, size)) {
3511 /* tuning is successful at this tuning point */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003512 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303513 pr_debug("%s: %s: found good phase = %d\n",
3514 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003515 }
3516 } while (++phase < 16);
3517
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003518 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303519 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303520 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05303521 if (rc < 0)
3522 goto kfree;
3523 else
3524 phase = (u8)rc;
3525
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003526 /*
3527 * Finally set the selected phase in delay
3528 * line hw block.
3529 */
3530 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3531 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303532 goto kfree;
3533 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
3534 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003535 } else {
3536 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303537 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003538 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303539 msmsdcc_dump_sdcc_state(host);
3540 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003541 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003542
3543kfree:
3544 kfree(data_buf);
3545out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303546 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303547 host->tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303548 spin_unlock_irqrestore(&host->lock, flags);
3549exit:
3550 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003551 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07003552}
3553
3554static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003555 .enable = msmsdcc_enable,
3556 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07003557 .request = msmsdcc_request,
3558 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003559 .get_ro = msmsdcc_get_ro,
San Mehat9d2bd732009-09-22 16:44:22 -07003560 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003561 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
3562 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07003563};
3564
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003565static unsigned int
3566msmsdcc_slot_status(struct msmsdcc_host *host)
3567{
3568 int status;
3569 unsigned int gpio_no = host->plat->status_gpio;
3570
3571 status = gpio_request(gpio_no, "SD_HW_Detect");
3572 if (status) {
3573 pr_err("%s: %s: Failed to request GPIO %d\n",
3574 mmc_hostname(host->mmc), __func__, gpio_no);
3575 } else {
3576 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003577 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08003578 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003579 if (host->plat->is_status_gpio_active_low)
3580 status = !status;
3581 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003582 gpio_free(gpio_no);
3583 }
3584 return status;
3585}
3586
San Mehat9d2bd732009-09-22 16:44:22 -07003587static void
3588msmsdcc_check_status(unsigned long data)
3589{
3590 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3591 unsigned int status;
3592
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003593 if (host->plat->status || host->plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08003594 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003595 status = host->plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08003596 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003597 status = msmsdcc_slot_status(host);
3598
Krishna Konda941604a2012-01-10 17:46:34 -08003599 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08003600
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003601 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08003602 if (host->plat->status)
3603 pr_info("%s: Slot status change detected "
3604 "(%d -> %d)\n",
3605 mmc_hostname(host->mmc),
3606 host->oldstat, status);
3607 else if (host->plat->is_status_gpio_active_low)
3608 pr_info("%s: Slot status change detected "
3609 "(%d -> %d) and the card detect GPIO"
3610 " is ACTIVE_LOW\n",
3611 mmc_hostname(host->mmc),
3612 host->oldstat, status);
3613 else
3614 pr_info("%s: Slot status change detected "
3615 "(%d -> %d) and the card detect GPIO"
3616 " is ACTIVE_HIGH\n",
3617 mmc_hostname(host->mmc),
3618 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07003619 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003620 }
3621 host->oldstat = status;
3622 } else {
3623 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07003624 }
San Mehat9d2bd732009-09-22 16:44:22 -07003625}
3626
3627static irqreturn_t
3628msmsdcc_platform_status_irq(int irq, void *dev_id)
3629{
3630 struct msmsdcc_host *host = dev_id;
3631
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003632 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07003633 msmsdcc_check_status((unsigned long) host);
3634 return IRQ_HANDLED;
3635}
3636
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003637static irqreturn_t
3638msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
3639{
3640 struct msmsdcc_host *host = dev_id;
3641
3642 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
3643 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303644 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003645 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303646 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003647 wake_lock(&host->sdio_wlock);
3648 msmsdcc_disable_irq_wake(host);
3649 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303650 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003651 }
3652 if (host->plat->is_sdio_al_client) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003653 wake_lock(&host->sdio_wlock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303654 mmc_signal_sdio_irq(host->mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003655 }
3656 spin_unlock(&host->lock);
3657
3658 return IRQ_HANDLED;
3659}
3660
San Mehat9d2bd732009-09-22 16:44:22 -07003661static void
3662msmsdcc_status_notify_cb(int card_present, void *dev_id)
3663{
3664 struct msmsdcc_host *host = dev_id;
3665
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003666 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07003667 card_present);
3668 msmsdcc_check_status((unsigned long) host);
3669}
3670
San Mehat9d2bd732009-09-22 16:44:22 -07003671static int
3672msmsdcc_init_dma(struct msmsdcc_host *host)
3673{
3674 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
3675 host->dma.host = host;
3676 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003677 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003678
3679 if (!host->dmares)
3680 return -ENODEV;
3681
3682 host->dma.nc = dma_alloc_coherent(NULL,
3683 sizeof(struct msmsdcc_nc_dmadata),
3684 &host->dma.nc_busaddr,
3685 GFP_KERNEL);
3686 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003687 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07003688 return -ENOMEM;
3689 }
3690 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
3691 host->dma.cmd_busaddr = host->dma.nc_busaddr;
3692 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
3693 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
3694 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07003695 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07003696
3697 return 0;
3698}
3699
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003700#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
3701/**
3702 * Allocate and Connect a SDCC peripheral's SPS endpoint
3703 *
3704 * This function allocates endpoint context and
3705 * connect it with memory endpoint by calling
3706 * appropriate SPS driver APIs.
3707 *
3708 * Also registers a SPS callback function with
3709 * SPS driver
3710 *
3711 * This function should only be called once typically
3712 * during driver probe.
3713 *
3714 * @host - Pointer to sdcc host structure
3715 * @ep - Pointer to sps endpoint data structure
3716 * @is_produce - 1 means Producer endpoint
3717 * 0 means Consumer endpoint
3718 *
3719 * @return - 0 if successful else negative value.
3720 *
3721 */
3722static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
3723 struct msmsdcc_sps_ep_conn_data *ep,
3724 bool is_producer)
3725{
3726 int rc = 0;
3727 struct sps_pipe *sps_pipe_handle;
3728 struct sps_connect *sps_config = &ep->config;
3729 struct sps_register_event *sps_event = &ep->event;
3730
3731 /* Allocate endpoint context */
3732 sps_pipe_handle = sps_alloc_endpoint();
3733 if (!sps_pipe_handle) {
3734 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
3735 mmc_hostname(host->mmc), is_producer);
3736 rc = -ENOMEM;
3737 goto out;
3738 }
3739
3740 /* Get default connection configuration for an endpoint */
3741 rc = sps_get_config(sps_pipe_handle, sps_config);
3742 if (rc) {
3743 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
3744 " rc=%d", mmc_hostname(host->mmc),
3745 (u32)sps_pipe_handle, rc);
3746 goto get_config_err;
3747 }
3748
3749 /* Modify the default connection configuration */
3750 if (is_producer) {
3751 /*
3752 * For SDCC producer transfer, source should be
3753 * SDCC peripheral where as destination should
3754 * be system memory.
3755 */
3756 sps_config->source = host->sps.bam_handle;
3757 sps_config->destination = SPS_DEV_HANDLE_MEM;
3758 /* Producer pipe will handle this connection */
3759 sps_config->mode = SPS_MODE_SRC;
3760 sps_config->options =
3761 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3762 } else {
3763 /*
3764 * For SDCC consumer transfer, source should be
3765 * system memory where as destination should
3766 * SDCC peripheral
3767 */
3768 sps_config->source = SPS_DEV_HANDLE_MEM;
3769 sps_config->destination = host->sps.bam_handle;
3770 sps_config->mode = SPS_MODE_DEST;
3771 sps_config->options =
3772 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3773 }
3774
3775 /* Producer pipe index */
3776 sps_config->src_pipe_index = host->sps.src_pipe_index;
3777 /* Consumer pipe index */
3778 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
3779 /*
3780 * This event thresold value is only significant for BAM-to-BAM
3781 * transfer. It's ignored for BAM-to-System mode transfer.
3782 */
3783 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05303784
3785 /* Allocate maximum descriptor fifo size */
3786 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
3787 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003788 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
3789 sps_config->desc.size,
3790 &sps_config->desc.phys_base,
3791 GFP_KERNEL);
3792
Pratibhasagar V00b94332011-10-18 14:57:27 +05303793 if (!sps_config->desc.base) {
3794 rc = -ENOMEM;
3795 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3796 , mmc_hostname(host->mmc));
3797 goto get_config_err;
3798 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003799 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3800
3801 /* Establish connection between peripheral and memory endpoint */
3802 rc = sps_connect(sps_pipe_handle, sps_config);
3803 if (rc) {
3804 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3805 " rc=%d", mmc_hostname(host->mmc),
3806 (u32)sps_pipe_handle, rc);
3807 goto sps_connect_err;
3808 }
3809
3810 sps_event->mode = SPS_TRIGGER_CALLBACK;
3811 sps_event->options = SPS_O_EOT;
3812 sps_event->callback = msmsdcc_sps_complete_cb;
3813 sps_event->xfer_done = NULL;
3814 sps_event->user = (void *)host;
3815
3816 /* Register callback event for EOT (End of transfer) event. */
3817 rc = sps_register_event(sps_pipe_handle, sps_event);
3818 if (rc) {
3819 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3820 " rc=%d", mmc_hostname(host->mmc),
3821 (u32)sps_pipe_handle, rc);
3822 goto reg_event_err;
3823 }
3824 /* Now save the sps pipe handle */
3825 ep->pipe_handle = sps_pipe_handle;
3826 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3827 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3828 __func__, is_producer ? "READ" : "WRITE",
3829 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3830 goto out;
3831
3832reg_event_err:
3833 sps_disconnect(sps_pipe_handle);
3834sps_connect_err:
3835 dma_free_coherent(mmc_dev(host->mmc),
3836 sps_config->desc.size,
3837 sps_config->desc.base,
3838 sps_config->desc.phys_base);
3839get_config_err:
3840 sps_free_endpoint(sps_pipe_handle);
3841out:
3842 return rc;
3843}
3844
3845/**
3846 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3847 *
3848 * This function disconnect endpoint and deallocates
3849 * endpoint context.
3850 *
3851 * This function should only be called once typically
3852 * during driver remove.
3853 *
3854 * @host - Pointer to sdcc host structure
3855 * @ep - Pointer to sps endpoint data structure
3856 *
3857 */
3858static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3859 struct msmsdcc_sps_ep_conn_data *ep)
3860{
3861 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3862 struct sps_connect *sps_config = &ep->config;
3863 struct sps_register_event *sps_event = &ep->event;
3864
3865 sps_event->xfer_done = NULL;
3866 sps_event->callback = NULL;
3867 sps_register_event(sps_pipe_handle, sps_event);
3868 sps_disconnect(sps_pipe_handle);
3869 dma_free_coherent(mmc_dev(host->mmc),
3870 sps_config->desc.size,
3871 sps_config->desc.base,
3872 sps_config->desc.phys_base);
3873 sps_free_endpoint(sps_pipe_handle);
3874}
3875
3876/**
3877 * Reset SDCC peripheral's SPS endpoint
3878 *
3879 * This function disconnects an endpoint.
3880 *
3881 * This function should be called for reseting
3882 * SPS endpoint when data transfer error is
3883 * encountered during data transfer. This
3884 * can be considered as soft reset to endpoint.
3885 *
3886 * This function should only be called if
3887 * msmsdcc_sps_init() is already called.
3888 *
3889 * @host - Pointer to sdcc host structure
3890 * @ep - Pointer to sps endpoint data structure
3891 *
3892 * @return - 0 if successful else negative value.
3893 */
3894static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3895 struct msmsdcc_sps_ep_conn_data *ep)
3896{
3897 int rc = 0;
3898 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3899
3900 rc = sps_disconnect(sps_pipe_handle);
3901 if (rc) {
3902 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3903 " rc=%d", mmc_hostname(host->mmc), __func__,
3904 (u32)sps_pipe_handle, rc);
3905 goto out;
3906 }
3907 out:
3908 return rc;
3909}
3910
3911/**
3912 * Restore SDCC peripheral's SPS endpoint
3913 *
3914 * This function connects an endpoint.
3915 *
3916 * This function should be called for restoring
3917 * SPS endpoint after data transfer error is
3918 * encountered during data transfer. This
3919 * can be considered as soft reset to endpoint.
3920 *
3921 * This function should only be called if
3922 * msmsdcc_sps_reset_ep() is called before.
3923 *
3924 * @host - Pointer to sdcc host structure
3925 * @ep - Pointer to sps endpoint data structure
3926 *
3927 * @return - 0 if successful else negative value.
3928 */
3929static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3930 struct msmsdcc_sps_ep_conn_data *ep)
3931{
3932 int rc = 0;
3933 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3934 struct sps_connect *sps_config = &ep->config;
3935 struct sps_register_event *sps_event = &ep->event;
3936
3937 /* Establish connection between peripheral and memory endpoint */
3938 rc = sps_connect(sps_pipe_handle, sps_config);
3939 if (rc) {
3940 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3941 " rc=%d", mmc_hostname(host->mmc), __func__,
3942 (u32)sps_pipe_handle, rc);
3943 goto out;
3944 }
3945
3946 /* Register callback event for EOT (End of transfer) event. */
3947 rc = sps_register_event(sps_pipe_handle, sps_event);
3948 if (rc) {
3949 pr_err("%s: %s: sps_register_event() failed!!!"
3950 " pipe_handle=0x%x, rc=%d",
3951 mmc_hostname(host->mmc), __func__,
3952 (u32)sps_pipe_handle, rc);
3953 goto reg_event_err;
3954 }
3955 goto out;
3956
3957reg_event_err:
3958 sps_disconnect(sps_pipe_handle);
3959out:
3960 return rc;
3961}
3962
3963/**
3964 * Initialize SPS HW connected with SDCC core
3965 *
3966 * This function register BAM HW resources with
3967 * SPS driver and then initialize 2 SPS endpoints
3968 *
3969 * This function should only be called once typically
3970 * during driver probe.
3971 *
3972 * @host - Pointer to sdcc host structure
3973 *
3974 * @return - 0 if successful else negative value.
3975 *
3976 */
3977static int msmsdcc_sps_init(struct msmsdcc_host *host)
3978{
3979 int rc = 0;
3980 struct sps_bam_props bam = {0};
3981
3982 host->bam_base = ioremap(host->bam_memres->start,
3983 resource_size(host->bam_memres));
3984 if (!host->bam_base) {
3985 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3986 " size=0x%x", mmc_hostname(host->mmc),
3987 host->bam_memres->start,
3988 (host->bam_memres->end -
3989 host->bam_memres->start));
3990 rc = -ENOMEM;
3991 goto out;
3992 }
3993
3994 bam.phys_addr = host->bam_memres->start;
3995 bam.virt_addr = host->bam_base;
3996 /*
3997 * This event thresold value is only significant for BAM-to-BAM
3998 * transfer. It's ignored for BAM-to-System mode transfer.
3999 */
4000 bam.event_threshold = 0x10; /* Pipe event threshold */
4001 /*
4002 * This threshold controls when the BAM publish
4003 * the descriptor size on the sideband interface.
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304004 * SPS HW will be used for data transfer size even
4005 * less than SDCC FIFO size. So let's set BAM summing
4006 * thresold to SPS_MIN_XFER_SIZE bytes.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004007 */
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304008 bam.summing_threshold = SPS_MIN_XFER_SIZE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004009 /* SPS driver wll handle the SDCC BAM IRQ */
4010 bam.irq = (u32)host->bam_irqres->start;
4011 bam.manage = SPS_BAM_MGR_LOCAL;
4012
4013 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
4014 (u32)bam.phys_addr);
4015 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
4016 (u32)bam.virt_addr);
4017
4018 /* Register SDCC Peripheral BAM device to SPS driver */
4019 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
4020 if (rc) {
4021 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
4022 mmc_hostname(host->mmc), rc);
4023 goto reg_bam_err;
4024 }
4025 pr_info("%s: BAM device registered. bam_handle=0x%x",
4026 mmc_hostname(host->mmc), host->sps.bam_handle);
4027
4028 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
4029 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
4030
4031 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
4032 SPS_PROD_PERIPHERAL);
4033 if (rc)
4034 goto sps_reset_err;
4035 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
4036 SPS_CONS_PERIPHERAL);
4037 if (rc)
4038 goto cons_conn_err;
4039
4040 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
4041 mmc_hostname(host->mmc),
4042 (unsigned long long)host->bam_memres->start,
4043 (unsigned int)host->bam_irqres->start);
4044 goto out;
4045
4046cons_conn_err:
4047 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4048sps_reset_err:
4049 sps_deregister_bam_device(host->sps.bam_handle);
4050reg_bam_err:
4051 iounmap(host->bam_base);
4052out:
4053 return rc;
4054}
4055
4056/**
4057 * De-initialize SPS HW connected with SDCC core
4058 *
4059 * This function deinitialize SPS endpoints and then
4060 * deregisters BAM resources from SPS driver.
4061 *
4062 * This function should only be called once typically
4063 * during driver remove.
4064 *
4065 * @host - Pointer to sdcc host structure
4066 *
4067 */
4068static void msmsdcc_sps_exit(struct msmsdcc_host *host)
4069{
4070 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
4071 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4072 sps_deregister_bam_device(host->sps.bam_handle);
4073 iounmap(host->bam_base);
4074}
4075#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
4076
4077static ssize_t
4078show_polling(struct device *dev, struct device_attribute *attr, char *buf)
4079{
4080 struct mmc_host *mmc = dev_get_drvdata(dev);
4081 struct msmsdcc_host *host = mmc_priv(mmc);
4082 int poll;
4083 unsigned long flags;
4084
4085 spin_lock_irqsave(&host->lock, flags);
4086 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
4087 spin_unlock_irqrestore(&host->lock, flags);
4088
4089 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
4090}
4091
4092static ssize_t
4093set_polling(struct device *dev, struct device_attribute *attr,
4094 const char *buf, size_t count)
4095{
4096 struct mmc_host *mmc = dev_get_drvdata(dev);
4097 struct msmsdcc_host *host = mmc_priv(mmc);
4098 int value;
4099 unsigned long flags;
4100
4101 sscanf(buf, "%d", &value);
4102
4103 spin_lock_irqsave(&host->lock, flags);
4104 if (value) {
4105 mmc->caps |= MMC_CAP_NEEDS_POLL;
4106 mmc_detect_change(host->mmc, 0);
4107 } else {
4108 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4109 }
4110#ifdef CONFIG_HAS_EARLYSUSPEND
4111 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
4112#endif
4113 spin_unlock_irqrestore(&host->lock, flags);
4114 return count;
4115}
4116
4117static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
4118 show_polling, set_polling);
4119static struct attribute *dev_attrs[] = {
4120 &dev_attr_polling.attr,
4121 NULL,
4122};
4123static struct attribute_group dev_attr_grp = {
4124 .attrs = dev_attrs,
4125};
4126
4127#ifdef CONFIG_HAS_EARLYSUSPEND
4128static void msmsdcc_early_suspend(struct early_suspend *h)
4129{
4130 struct msmsdcc_host *host =
4131 container_of(h, struct msmsdcc_host, early_suspend);
4132 unsigned long flags;
4133
4134 spin_lock_irqsave(&host->lock, flags);
4135 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
4136 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4137 spin_unlock_irqrestore(&host->lock, flags);
4138};
4139static void msmsdcc_late_resume(struct early_suspend *h)
4140{
4141 struct msmsdcc_host *host =
4142 container_of(h, struct msmsdcc_host, early_suspend);
4143 unsigned long flags;
4144
4145 if (host->polling_enabled) {
4146 spin_lock_irqsave(&host->lock, flags);
4147 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
4148 mmc_detect_change(host->mmc, 0);
4149 spin_unlock_irqrestore(&host->lock, flags);
4150 }
4151};
4152#endif
4153
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304154static void msmsdcc_print_regs(const char *name, void __iomem *base,
4155 u32 phys_base, unsigned int no_of_regs)
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304156{
4157 unsigned int i;
4158
4159 if (!base)
4160 return;
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304161
4162 pr_info("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
4163 " =====\n", name, phys_base, (u32)base);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304164 for (i = 0; i < no_of_regs; i = i + 4) {
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304165 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
4166 (u32)readl_relaxed(base + i*4),
4167 (u32)readl_relaxed(base + ((i+1)*4)),
4168 (u32)readl_relaxed(base + ((i+2)*4)),
4169 (u32)readl_relaxed(base + ((i+3)*4)));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304170 }
4171}
4172
4173static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
4174{
4175 /* Dump current state of SDCC clocks, power and irq */
4176 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304177 (host->pwr ? "ON" : "OFF"));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304178 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304179 mmc_hostname(host->mmc), (host->clks_on ? "ON" : "OFF"),
4180 (u32)clk_get_rate(host->clk));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304181 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
4182 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
4183
4184 /* Now dump SDCC registers. Don't print FIFO registers */
4185 if (host->clks_on)
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304186 msmsdcc_print_regs("SDCC-CORE", host->base,
4187 host->core_memres->start, 28);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304188
4189 if (host->curr.data) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304190 if (!msmsdcc_is_dma_possible(host, host->curr.data))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304191 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
4192 else if (host->is_dma_mode)
4193 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
4194 mmc_hostname(host->mmc), host->dma.busy,
4195 host->dma.channel, host->dma.crci);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304196 else if (host->is_sps_mode) {
subhashj245831e2012-04-30 18:46:17 +05304197 if (host->sps.busy && host->clks_on)
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304198 msmsdcc_print_regs("SDCC-DML", host->dml_base,
4199 host->dml_memres->start,
4200 16);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304201 pr_info("%s: SPS mode: busy=%d\n",
4202 mmc_hostname(host->mmc), host->sps.busy);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304203 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304204
4205 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
4206 mmc_hostname(host->mmc), host->curr.xfer_size,
4207 host->curr.data_xfered, host->curr.xfer_remain);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304208 }
4209
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304210 pr_info("%s: got_dataend=%d, prog_enable=%d,"
4211 " wait_for_auto_prog_done=%d, got_auto_prog_done=%d\n",
4212 mmc_hostname(host->mmc), host->curr.got_dataend,
4213 host->prog_enable, host->curr.wait_for_auto_prog_done,
4214 host->curr.got_auto_prog_done);
subhashj245831e2012-04-30 18:46:17 +05304215 msmsdcc_print_rpm_info(host);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304216}
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304217
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004218static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
4219{
4220 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4221 struct mmc_request *mrq;
4222 unsigned long flags;
4223
4224 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004225 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004226 pr_info("%s: %s: dummy CMD52 timeout\n",
4227 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004228 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004229 }
4230
4231 mrq = host->curr.mrq;
4232
4233 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304234 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
4235 mrq->cmd->opcode);
4236 msmsdcc_dump_sdcc_state(host);
4237
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004238 if (!mrq->cmd->error)
4239 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304240 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004241 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004242 if (mrq->data && !mrq->data->error)
4243 mrq->data->error = -ETIMEDOUT;
4244 host->curr.data_xfered = 0;
4245 if (host->dma.sg && host->is_dma_mode) {
4246 msm_dmov_stop_cmd(host->dma.channel,
4247 &host->dma.hdr, 0);
4248 } else if (host->sps.sg && host->is_sps_mode) {
4249 /* Stop current SPS transfer */
4250 msmsdcc_sps_exit_curr_xfer(host);
4251 } else {
4252 msmsdcc_reset_and_restore(host);
4253 msmsdcc_stop_data(host);
4254 if (mrq->data && mrq->data->stop)
4255 msmsdcc_start_command(host,
4256 mrq->data->stop, 0);
4257 else
4258 msmsdcc_request_end(host, mrq);
4259 }
4260 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304261 host->prog_enable = 0;
Subhash Jadavanied6b0e42012-03-07 16:36:27 +05304262 host->curr.wait_for_auto_prog_done = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004263 msmsdcc_reset_and_restore(host);
4264 msmsdcc_request_end(host, mrq);
4265 }
4266 }
4267 spin_unlock_irqrestore(&host->lock, flags);
4268}
4269
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304270static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
4271{
4272 int i, ret;
4273 struct mmc_platform_data *pdata;
4274 struct device_node *np = dev->of_node;
4275 u32 bus_width = 0;
4276 u32 *clk_table;
4277 int clk_table_len;
4278 u32 *sup_voltages;
4279 int sup_volt_len;
4280
4281 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
4282 if (!pdata) {
4283 dev_err(dev, "could not allocate memory for platform data\n");
4284 goto err;
4285 }
4286
4287 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
4288 if (bus_width == 8) {
4289 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
4290 } else if (bus_width == 4) {
4291 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
4292 } else {
4293 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
4294 pdata->mmc_bus_width = 0;
4295 }
4296
4297 if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
4298 size_t sz;
4299 sz = sup_volt_len / sizeof(*sup_voltages);
4300 if (sz > 0) {
4301 sup_voltages = devm_kzalloc(dev,
4302 sz * sizeof(*sup_voltages), GFP_KERNEL);
4303 if (!sup_voltages) {
4304 dev_err(dev, "No memory for supported voltage\n");
4305 goto err;
4306 }
4307
4308 ret = of_property_read_u32_array(np,
4309 "qcom,sdcc-sup-voltages", sup_voltages, sz);
4310 if (ret < 0) {
4311 dev_err(dev, "error while reading voltage"
4312 "ranges %d\n", ret);
4313 goto err;
4314 }
4315 } else {
4316 dev_err(dev, "No supported voltages\n");
4317 goto err;
4318 }
4319 for (i = 0; i < sz; i += 2) {
4320 u32 mask;
4321
4322 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
4323 sup_voltages[i + 1]);
4324 if (!mask)
4325 dev_err(dev, "Invalide voltage range %d\n", i);
4326 pdata->ocr_mask |= mask;
4327 }
4328 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
4329 } else {
4330 dev_err(dev, "Supported voltage range not specified\n");
4331 }
4332
4333 if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
4334 size_t sz;
4335 sz = clk_table_len / sizeof(*clk_table);
4336
4337 if (sz > 0) {
4338 clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
4339 GFP_KERNEL);
4340 if (!clk_table) {
4341 dev_err(dev, "No memory for clock table\n");
4342 goto err;
4343 }
4344
4345 ret = of_property_read_u32_array(np,
4346 "qcom,sdcc-clk-rates", clk_table, sz);
4347 if (ret < 0) {
4348 dev_err(dev, "error while reading clk"
4349 "table %d\n", ret);
4350 goto err;
4351 }
4352 } else {
4353 dev_err(dev, "clk_table not specified\n");
4354 goto err;
4355 }
4356 pdata->sup_clk_table = clk_table;
4357 pdata->sup_clk_cnt = sz;
4358 } else {
4359 dev_err(dev, "Supported clock rates not specified\n");
4360 }
4361
4362 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
4363 pdata->nonremovable = true;
4364 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
4365 pdata->disable_cmd23 = true;
4366
4367 return pdata;
4368err:
4369 return NULL;
4370}
4371
San Mehat9d2bd732009-09-22 16:44:22 -07004372static int
4373msmsdcc_probe(struct platform_device *pdev)
4374{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304375 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07004376 struct msmsdcc_host *host;
4377 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004378 unsigned long flags;
4379 struct resource *core_irqres = NULL;
4380 struct resource *bam_irqres = NULL;
4381 struct resource *core_memres = NULL;
4382 struct resource *dml_memres = NULL;
4383 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07004384 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07004385 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05304386 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004387 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07004388
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304389 if (pdev->dev.of_node) {
4390 plat = msmsdcc_populate_pdata(&pdev->dev);
4391 of_property_read_u32((&pdev->dev)->of_node,
4392 "cell-index", &pdev->id);
4393 } else {
4394 plat = pdev->dev.platform_data;
4395 }
4396
San Mehat9d2bd732009-09-22 16:44:22 -07004397 /* must have platform data */
4398 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004399 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004400 ret = -EINVAL;
4401 goto out;
4402 }
4403
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004404 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07004405 return -EINVAL;
4406
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304407 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
4408 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
4409 return -EINVAL;
4410 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004411
San Mehat9d2bd732009-09-22 16:44:22 -07004412 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004413 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004414 return -ENXIO;
4415 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304416 if (pdev->dev.of_node) {
4417 /*
4418 * Device tree iomem resources are only accessible by index.
4419 * index = 0 -> SDCC register interface
4420 * index = 1 -> DML register interface
4421 * index = 2 -> BAM register interface
4422 * IRQ resources:
4423 * index = 0 -> SDCC IRQ
4424 * index = 1 -> BAM IRQ
4425 */
4426 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
4427 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
4428 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
4429 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
4430 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
4431 } else {
4432 for (i = 0; i < pdev->num_resources; i++) {
4433 if (pdev->resource[i].flags & IORESOURCE_MEM) {
4434 if (!strncmp(pdev->resource[i].name,
4435 "sdcc_dml_addr",
4436 sizeof("sdcc_dml_addr")))
4437 dml_memres = &pdev->resource[i];
4438 else if (!strncmp(pdev->resource[i].name,
4439 "sdcc_bam_addr",
4440 sizeof("sdcc_bam_addr")))
4441 bam_memres = &pdev->resource[i];
4442 else
4443 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07004444
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304445 }
4446 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
4447 if (!strncmp(pdev->resource[i].name,
4448 "sdcc_bam_irq",
4449 sizeof("sdcc_bam_irq")))
4450 bam_irqres = &pdev->resource[i];
4451 else
4452 core_irqres = &pdev->resource[i];
4453 }
4454 if (pdev->resource[i].flags & IORESOURCE_DMA) {
4455 if (!strncmp(pdev->resource[i].name,
4456 "sdcc_dma_chnl",
4457 sizeof("sdcc_dma_chnl")))
4458 dmares = &pdev->resource[i];
4459 else if (!strncmp(pdev->resource[i].name,
4460 "sdcc_dma_crci",
4461 sizeof("sdcc_dma_crci")))
4462 dma_crci_res = &pdev->resource[i];
4463 }
Krishna Konda25786ec2011-07-25 16:21:36 -07004464 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004465 }
4466
4467 if (!core_irqres || !core_memres) {
4468 pr_err("%s: Invalid sdcc core resource\n", __func__);
4469 return -ENXIO;
4470 }
4471
4472 /*
4473 * Both BAM and DML memory resource should be preset.
4474 * BAM IRQ resource should also be present.
4475 */
4476 if ((bam_memres && !dml_memres) ||
4477 (!bam_memres && dml_memres) ||
4478 ((bam_memres && dml_memres) && !bam_irqres)) {
4479 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004480 return -ENXIO;
4481 }
4482
4483 /*
4484 * Setup our host structure
4485 */
San Mehat9d2bd732009-09-22 16:44:22 -07004486 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
4487 if (!mmc) {
4488 ret = -ENOMEM;
4489 goto out;
4490 }
4491
4492 host = mmc_priv(mmc);
4493 host->pdev_id = pdev->id;
4494 host->plat = plat;
4495 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08004496 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05304497
4498 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004499 host->is_sps_mode = 1;
4500 else if (dmares)
4501 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07004502
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004503 host->base = ioremap(core_memres->start,
4504 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07004505 if (!host->base) {
4506 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004507 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004508 }
4509
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004510 host->core_irqres = core_irqres;
4511 host->bam_irqres = bam_irqres;
4512 host->core_memres = core_memres;
4513 host->dml_memres = dml_memres;
4514 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07004515 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07004516 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07004517 spin_lock_init(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304518 mutex_init(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07004519
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004520#ifdef CONFIG_MMC_EMBEDDED_SDIO
4521 if (plat->embedded_sdio)
4522 mmc_set_embedded_sdio_data(mmc,
4523 &plat->embedded_sdio->cis,
4524 &plat->embedded_sdio->cccr,
4525 plat->embedded_sdio->funcs,
4526 plat->embedded_sdio->num_funcs);
4527#endif
4528
Sahitya Tummala62612cf2010-12-08 15:03:03 +05304529 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
4530 (unsigned long)host);
4531
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004532 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
4533 (unsigned long)host);
4534 if (host->is_dma_mode) {
4535 /* Setup DMA */
4536 ret = msmsdcc_init_dma(host);
4537 if (ret)
4538 goto ioremap_free;
4539 } else {
4540 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004541 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004542 }
4543
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004544 /*
4545 * Setup SDCC clock if derived from Dayatona
4546 * fabric core clock.
4547 */
4548 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07004549 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004550 if (!IS_ERR(host->dfab_pclk)) {
4551 /* Set the clock rate to 64MHz for max. performance */
4552 ret = clk_set_rate(host->dfab_pclk, 64000000);
4553 if (ret)
4554 goto dfab_pclk_put;
Asutosh Dasf5298c32012-04-03 14:51:47 +05304555 ret = clk_prepare_enable(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004556 if (ret)
4557 goto dfab_pclk_put;
4558 } else
4559 goto dma_free;
4560 }
4561
4562 /*
4563 * Setup main peripheral bus clock
4564 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004565 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004566 if (!IS_ERR(host->pclk)) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05304567 ret = clk_prepare_enable(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004568 if (ret)
4569 goto pclk_put;
4570
4571 host->pclk_rate = clk_get_rate(host->pclk);
4572 }
4573
4574 /*
4575 * Setup SDC MMC clock
4576 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004577 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07004578 if (IS_ERR(host->clk)) {
4579 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004580 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07004581 }
4582
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004583 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
4584 if (ret) {
4585 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
4586 goto clk_put;
4587 }
4588
Asutosh Dasf5298c32012-04-03 14:51:47 +05304589 ret = clk_prepare_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004590 if (ret)
4591 goto clk_put;
4592
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004593 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304594 if (!host->clk_rate)
4595 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304596
4597 /*
4598 * Lookup the Controller Version, to identify the supported features
4599 * Version number read as 0 would indicate SDCC3 or earlier versions
4600 */
4601 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
4602 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
4603 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304604 /*
4605 * Set the register write delay according to min. clock frequency
4606 * supported and update later when the host->clk_rate changes.
4607 */
4608 host->reg_write_delay =
4609 (1 + ((3 * USEC_PER_SEC) /
4610 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004611
4612 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05304613 /* Apply Hard reset to SDCC to put it in power on default state */
4614 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004615
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004616#define MSM_MMC_DEFAULT_CPUDMA_LATENCY 200 /* usecs */
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304617 /* pm qos request to prevent apps idle power collapse */
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004618 if (host->plat->cpu_dma_latency)
4619 host->cpu_dma_latency = host->plat->cpu_dma_latency;
4620 else
4621 host->cpu_dma_latency = MSM_MMC_DEFAULT_CPUDMA_LATENCY;
4622 pm_qos_add_request(&host->pm_qos_req_dma,
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304623 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
4624
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004625 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07004626 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004627 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07004628 goto clk_disable;
4629 }
4630
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004631
4632 /* Clocks has to be running before accessing SPS/DML HW blocks */
4633 if (host->is_sps_mode) {
4634 /* Initialize SPS */
4635 ret = msmsdcc_sps_init(host);
4636 if (ret)
4637 goto vreg_deinit;
4638 /* Initialize DML */
4639 ret = msmsdcc_dml_init(host);
4640 if (ret)
4641 goto sps_exit;
4642 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05304643 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07004644
San Mehat9d2bd732009-09-22 16:44:22 -07004645 /*
4646 * Setup MMC host structure
4647 */
4648 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004649 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
4650 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004651 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004652 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
4653 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07004654
San Mehat9d2bd732009-09-22 16:44:22 -07004655 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05304656 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304657
4658 /*
4659 * If we send the CMD23 before multi block write/read command
4660 * then we need not to send CMD12 at the end of the transfer.
4661 * If we don't send the CMD12 then only way to detect the PROG_DONE
4662 * status is to use the AUTO_PROG_DONE status provided by SDCC4
4663 * controller. So let's enable the CMD23 for SDCC4 only.
4664 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304665 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304666 mmc->caps |= MMC_CAP_CMD23;
4667
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004668 mmc->caps |= plat->uhs_caps;
4669 /*
4670 * XPC controls the maximum current in the default speed mode of SDXC
4671 * card. XPC=0 means 100mA (max.) but speed class is not supported.
4672 * XPC=1 means 150mA (max.) and speed class is supported.
4673 */
4674 if (plat->xpc_cap)
4675 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
4676 MMC_CAP_SET_XPC_180);
4677
Subhash Jadavani6bb34a82012-04-18 13:18:40 +05304678 mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304679 if (pdev->dev.of_node) {
4680 if (of_get_property((&pdev->dev)->of_node,
4681 "qcom,sdcc-hs200", NULL))
4682 mmc->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
4683 }
4684
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004685 if (plat->nonremovable)
4686 mmc->caps |= MMC_CAP_NONREMOVABLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004687 mmc->caps |= MMC_CAP_SDIO_IRQ;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004688
4689 if (plat->is_sdio_al_client)
4690 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07004691
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304692 mmc->max_segs = msmsdcc_get_nr_sg(host);
4693 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
4694 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07004695
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304696 mmc->max_req_size = MMC_MAX_REQ_SIZE;
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +05304697 mmc->max_seg_size = mmc->max_req_size;
San Mehat9d2bd732009-09-22 16:44:22 -07004698
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004699 writel_relaxed(0, host->base + MMCIMASK0);
4700 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05304701 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004702
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004703 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
4704 mb();
4705 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07004706
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004707 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
4708 DRIVER_NAME " (cmd)", host);
4709 if (ret)
4710 goto dml_exit;
4711
4712 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
4713 DRIVER_NAME " (pio)", host);
4714 if (ret)
4715 goto irq_free;
4716
4717 /*
4718 * Enable SDCC IRQ only when host is powered on. Otherwise, this
4719 * IRQ is un-necessarily being monitored by MPM (Modem power
4720 * management block) during idle-power collapse. The MPM will be
4721 * configured to monitor the DATA1 GPIO line with level-low trigger
4722 * and thus depending on the GPIO status, it prevents TCXO shutdown
4723 * during idle-power collapse.
4724 */
4725 disable_irq(core_irqres->start);
4726 host->sdcc_irq_disabled = 1;
4727
4728 if (plat->sdiowakeup_irq) {
4729 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4730 mmc_hostname(mmc));
4731 ret = request_irq(plat->sdiowakeup_irq,
4732 msmsdcc_platform_sdiowakeup_irq,
4733 IRQF_SHARED | IRQF_TRIGGER_LOW,
4734 DRIVER_NAME "sdiowakeup", host);
4735 if (ret) {
4736 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
4737 plat->sdiowakeup_irq, ret);
4738 goto pio_irq_free;
4739 } else {
4740 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304741 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004742 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304743 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004744 }
4745 spin_unlock_irqrestore(&host->lock, flags);
4746 }
4747 }
4748
Subhash Jadavanic9b85752012-04-13 11:16:49 +05304749 if (host->plat->mpm_sdiowakeup_int) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004750 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4751 mmc_hostname(mmc));
4752 }
4753
4754 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
4755 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004756 /*
4757 * Setup card detect change
4758 */
4759
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004760 if (plat->status || plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08004761 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004762 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08004763 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004764 host->oldstat = msmsdcc_slot_status(host);
Krishna Konda360aa422011-12-06 18:27:41 -08004765
Krishna Konda941604a2012-01-10 17:46:34 -08004766 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004767 }
San Mehat9d2bd732009-09-22 16:44:22 -07004768
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004769 if (plat->status_irq) {
4770 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07004771 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004772 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07004773 DRIVER_NAME " (slot)",
4774 host);
4775 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004776 pr_err("Unable to get slot IRQ %d (%d)\n",
4777 plat->status_irq, ret);
4778 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004779 }
4780 } else if (plat->register_status_notify) {
4781 plat->register_status_notify(msmsdcc_status_notify_cb, host);
4782 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004783 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07004784 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004785
4786 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004787
4788 ret = pm_runtime_set_active(&(pdev)->dev);
4789 if (ret < 0)
4790 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
4791 __func__, ret);
4792 /*
4793 * There is no notion of suspend/resume for SD/MMC/SDIO
4794 * cards. So host can be suspended/resumed with out
4795 * worrying about its children.
4796 */
4797 pm_suspend_ignore_children(&(pdev)->dev, true);
4798
4799 /*
4800 * MMC/SD/SDIO bus suspend/resume operations are defined
4801 * only for the slots that will be used for non-removable
4802 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
4803 * defined. Otherwise, they simply become card removal and
4804 * insertion events during suspend and resume respectively.
4805 * Hence, enable run-time PM only for slots for which bus
4806 * suspend/resume operations are defined.
4807 */
4808#ifdef CONFIG_MMC_UNSAFE_RESUME
4809 /*
4810 * If this capability is set, MMC core will enable/disable host
4811 * for every claim/release operation on a host. We use this
4812 * notification to increment/decrement runtime pm usage count.
4813 */
4814 mmc->caps |= MMC_CAP_DISABLE;
4815 pm_runtime_enable(&(pdev)->dev);
4816#else
4817 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
4818 mmc->caps |= MMC_CAP_DISABLE;
4819 pm_runtime_enable(&(pdev)->dev);
4820 }
4821#endif
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05304822#ifndef CONFIG_PM_RUNTIME
4823 mmc_set_disable_delay(mmc, MSM_MMC_DISABLE_TIMEOUT);
4824#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004825 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
4826 (unsigned long)host);
4827
San Mehat9d2bd732009-09-22 16:44:22 -07004828 mmc_add_host(mmc);
4829
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004830#ifdef CONFIG_HAS_EARLYSUSPEND
4831 host->early_suspend.suspend = msmsdcc_early_suspend;
4832 host->early_suspend.resume = msmsdcc_late_resume;
4833 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
4834 register_early_suspend(&host->early_suspend);
4835#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004836
Krishna Konda25786ec2011-07-25 16:21:36 -07004837 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
4838 " dmacrcri %d\n", mmc_hostname(mmc),
4839 (unsigned long long)core_memres->start,
4840 (unsigned int) core_irqres->start,
4841 (unsigned int) plat->status_irq, host->dma.channel,
4842 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004843
4844 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
4845 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
4846 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
4847 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
4848 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
4849 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
4850 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
4851 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
4852 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
4853 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
4854 host->eject);
4855 pr_info("%s: Power save feature enable = %d\n",
4856 mmc_hostname(mmc), msmsdcc_pwrsave);
4857
Krishna Konda25786ec2011-07-25 16:21:36 -07004858 if (host->is_dma_mode && host->dma.channel != -1
4859 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004860 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004861 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004862 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004863 mmc_hostname(mmc), host->dma.cmd_busaddr,
4864 host->dma.cmdptr_busaddr);
4865 } else if (host->is_sps_mode) {
4866 pr_info("%s: SPS-BAM data transfer mode available\n",
4867 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004868 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004869 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004870
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004871#if defined(CONFIG_DEBUG_FS)
4872 msmsdcc_dbg_createhost(host);
4873#endif
4874 if (!plat->status_irq) {
4875 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
4876 if (ret)
4877 goto platform_irq_free;
4878 }
San Mehat9d2bd732009-09-22 16:44:22 -07004879 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004880
4881 platform_irq_free:
4882 del_timer_sync(&host->req_tout_timer);
4883 pm_runtime_disable(&(pdev)->dev);
4884 pm_runtime_set_suspended(&(pdev)->dev);
4885
4886 if (plat->status_irq)
4887 free_irq(plat->status_irq, host);
4888 sdiowakeup_irq_free:
4889 wake_lock_destroy(&host->sdio_suspend_wlock);
4890 if (plat->sdiowakeup_irq)
4891 free_irq(plat->sdiowakeup_irq, host);
4892 pio_irq_free:
4893 if (plat->sdiowakeup_irq)
4894 wake_lock_destroy(&host->sdio_wlock);
4895 free_irq(core_irqres->start, host);
4896 irq_free:
4897 free_irq(core_irqres->start, host);
4898 dml_exit:
4899 if (host->is_sps_mode)
4900 msmsdcc_dml_exit(host);
4901 sps_exit:
4902 if (host->is_sps_mode)
4903 msmsdcc_sps_exit(host);
4904 vreg_deinit:
4905 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07004906 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004907 clk_disable(host->clk);
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004908 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304909 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07004910 clk_put:
4911 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004912 pclk_disable:
4913 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05304914 clk_disable_unprepare(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07004915 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004916 if (!IS_ERR(host->pclk))
4917 clk_put(host->pclk);
4918 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05304919 clk_disable_unprepare(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004920 dfab_pclk_put:
4921 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4922 clk_put(host->dfab_pclk);
4923 dma_free:
4924 if (host->is_dma_mode) {
4925 if (host->dmares)
4926 dma_free_coherent(NULL,
4927 sizeof(struct msmsdcc_nc_dmadata),
4928 host->dma.nc, host->dma.nc_busaddr);
4929 }
4930 ioremap_free:
4931 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07004932 host_free:
4933 mmc_free_host(mmc);
4934 out:
4935 return ret;
4936}
4937
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004938static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07004939{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004940 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4941 struct mmc_platform_data *plat;
4942 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004943
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004944 if (!mmc)
4945 return -ENXIO;
4946
4947 if (pm_runtime_suspended(&(pdev)->dev))
4948 pm_runtime_resume(&(pdev)->dev);
4949
4950 host = mmc_priv(mmc);
4951
4952 DBG(host, "Removing SDCC device = %d\n", pdev->id);
4953 plat = host->plat;
4954
4955 if (!plat->status_irq)
4956 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
4957
4958 del_timer_sync(&host->req_tout_timer);
4959 tasklet_kill(&host->dma_tlet);
4960 tasklet_kill(&host->sps.tlet);
4961 mmc_remove_host(mmc);
4962
4963 if (plat->status_irq)
4964 free_irq(plat->status_irq, host);
4965
4966 wake_lock_destroy(&host->sdio_suspend_wlock);
4967 if (plat->sdiowakeup_irq) {
4968 wake_lock_destroy(&host->sdio_wlock);
4969 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
4970 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07004971 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004972
4973 free_irq(host->core_irqres->start, host);
4974 free_irq(host->core_irqres->start, host);
4975
4976 clk_put(host->clk);
4977 if (!IS_ERR(host->pclk))
4978 clk_put(host->pclk);
4979 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4980 clk_put(host->dfab_pclk);
4981
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004982 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304983 pm_qos_remove_request(&host->pm_qos_req_dma);
4984
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004985 msmsdcc_vreg_init(host, false);
4986
4987 if (host->is_dma_mode) {
4988 if (host->dmares)
4989 dma_free_coherent(NULL,
4990 sizeof(struct msmsdcc_nc_dmadata),
4991 host->dma.nc, host->dma.nc_busaddr);
4992 }
4993
4994 if (host->is_sps_mode) {
4995 msmsdcc_dml_exit(host);
4996 msmsdcc_sps_exit(host);
4997 }
4998
4999 iounmap(host->base);
5000 mmc_free_host(mmc);
5001
5002#ifdef CONFIG_HAS_EARLYSUSPEND
5003 unregister_early_suspend(&host->early_suspend);
5004#endif
5005 pm_runtime_disable(&(pdev)->dev);
5006 pm_runtime_set_suspended(&(pdev)->dev);
5007
5008 return 0;
5009}
5010
5011#ifdef CONFIG_MSM_SDIO_AL
5012int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
5013{
5014 struct msmsdcc_host *host = mmc_priv(mmc);
5015 unsigned long flags;
5016
Asutosh Dasf5298c32012-04-03 14:51:47 +05305017 mutex_lock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005018 spin_lock_irqsave(&host->lock, flags);
5019 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
5020 enable ? "En" : "Dis");
5021
5022 if (enable) {
5023 if (!host->sdcc_irq_disabled) {
5024 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05305025 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005026 host->sdcc_irq_disabled = 1;
5027 }
5028
5029 if (host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305030 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005031 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305032 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005033 host->clks_on = 0;
5034 }
5035
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305036 if (host->plat->sdio_lpm_gpio_setup &&
5037 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005038 spin_unlock_irqrestore(&host->lock, flags);
5039 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
5040 spin_lock_irqsave(&host->lock, flags);
5041 host->sdio_gpio_lpm = 1;
5042 }
5043
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305044 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005045 msmsdcc_enable_irq_wake(host);
5046 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305047 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005048 }
5049 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305050 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005051 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305052 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005053 msmsdcc_disable_irq_wake(host);
5054 }
5055
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305056 if (host->plat->sdio_lpm_gpio_setup &&
5057 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005058 spin_unlock_irqrestore(&host->lock, flags);
5059 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
5060 spin_lock_irqsave(&host->lock, flags);
5061 host->sdio_gpio_lpm = 0;
5062 }
5063
5064 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305065 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005066 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305067 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005068 host->clks_on = 1;
5069 }
5070
5071 if (host->sdcc_irq_disabled) {
5072 writel_relaxed(host->mci_irqenable,
5073 host->base + MMCIMASK0);
5074 mb();
5075 enable_irq(host->core_irqres->start);
5076 host->sdcc_irq_disabled = 0;
5077 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005078 }
5079 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305080 mutex_unlock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005081 return 0;
5082}
5083#else
5084int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
5085{
5086 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07005087}
5088#endif
5089
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005090#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07005091static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005092msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07005093{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005094 struct mmc_host *mmc = dev_get_drvdata(dev);
5095 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07005096 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305097 unsigned long flags;
5098
San Mehat9d2bd732009-09-22 16:44:22 -07005099
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005100 if (host->plat->is_sdio_al_client)
5101 return 0;
Sahitya Tummala7661a452011-07-18 13:28:35 +05305102 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005103 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005104 host->sdcc_suspending = 1;
5105 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07005106
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005107 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005108 * MMC core thinks that host is disabled by now since
5109 * runtime suspend is scheduled after msmsdcc_disable()
5110 * is called. Thus, MMC core will try to enable the host
5111 * while suspending it. This results in a synchronous
5112 * runtime resume request while in runtime suspending
5113 * context and hence inorder to complete this resume
5114 * requet, it will wait for suspend to be complete,
5115 * but runtime suspend also can not proceed further
5116 * until the host is resumed. Thus, it leads to a hang.
5117 * Hence, increase the pm usage count before suspending
5118 * the host so that any resume requests after this will
5119 * simple become pm usage counter increment operations.
5120 */
5121 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05305122 /* If there is pending detect work abort runtime suspend */
5123 if (unlikely(work_busy(&mmc->detect.work)))
5124 rc = -EAGAIN;
5125 else
5126 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005127 pm_runtime_put_noidle(dev);
5128
5129 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305130 spin_lock_irqsave(&host->lock, flags);
5131 host->sdcc_suspended = true;
5132 spin_unlock_irqrestore(&host->lock, flags);
5133 if (mmc->card && mmc_card_sdio(mmc->card) &&
5134 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005135 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305136 * If SDIO function driver doesn't want
5137 * to power off the card, atleast turn off
5138 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005139 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305140 mmc_host_clk_hold(mmc);
5141 spin_lock_irqsave(&mmc->clk_lock, flags);
5142 mmc->clk_old = mmc->ios.clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005143 mmc->ios.clock = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305144 mmc->clk_gated = true;
5145 spin_unlock_irqrestore(&mmc->clk_lock, flags);
5146 mmc_set_ios(mmc);
5147 mmc_host_clk_release(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005148 }
5149 }
5150 host->sdcc_suspending = 0;
5151 mmc->suspend_task = NULL;
5152 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
5153 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005154 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05305155 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
San Mehat9d2bd732009-09-22 16:44:22 -07005156 return rc;
5157}
5158
5159static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005160msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07005161{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005162 struct mmc_host *mmc = dev_get_drvdata(dev);
5163 struct msmsdcc_host *host = mmc_priv(mmc);
5164 unsigned long flags;
5165
5166 if (host->plat->is_sdio_al_client)
5167 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07005168
Sahitya Tummala7661a452011-07-18 13:28:35 +05305169 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005170 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305171 if (mmc->card && mmc_card_sdio(mmc->card) &&
5172 mmc_card_keep_power(mmc)) {
5173 mmc_host_clk_hold(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305174 mmc->ios.clock = host->clk_rate;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305175 mmc_set_ios(mmc);
5176 mmc_host_clk_release(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305177 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005178
5179 mmc_resume_host(mmc);
5180
5181 /*
5182 * FIXME: Clearing of flags must be handled in clients
5183 * resume handler.
5184 */
5185 spin_lock_irqsave(&host->lock, flags);
5186 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305187 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005188 spin_unlock_irqrestore(&host->lock, flags);
5189
5190 /*
5191 * After resuming the host wait for sometime so that
5192 * the SDIO work will be processed.
5193 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305194 if (mmc->card && mmc_card_sdio(mmc->card)) {
Subhash Jadavanic9b85752012-04-13 11:16:49 +05305195 if ((host->plat->mpm_sdiowakeup_int ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005196 host->plat->sdiowakeup_irq) &&
5197 wake_lock_active(&host->sdio_wlock))
5198 wake_lock_timeout(&host->sdio_wlock, 1);
5199 }
5200
5201 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005202 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05305203 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005204 return 0;
5205}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005206
5207static int msmsdcc_runtime_idle(struct device *dev)
5208{
5209 struct mmc_host *mmc = dev_get_drvdata(dev);
5210 struct msmsdcc_host *host = mmc_priv(mmc);
5211
5212 if (host->plat->is_sdio_al_client)
5213 return 0;
5214
5215 /* Idle timeout is not configurable for now */
5216 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
5217
5218 return -EAGAIN;
5219}
5220
5221static int msmsdcc_pm_suspend(struct device *dev)
5222{
5223 struct mmc_host *mmc = dev_get_drvdata(dev);
5224 struct msmsdcc_host *host = mmc_priv(mmc);
5225 int rc = 0;
5226
5227 if (host->plat->is_sdio_al_client)
5228 return 0;
5229
5230
5231 if (host->plat->status_irq)
5232 disable_irq(host->plat->status_irq);
5233
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005234 if (!pm_runtime_suspended(dev))
5235 rc = msmsdcc_runtime_suspend(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005236
5237 return rc;
5238}
5239
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305240static int msmsdcc_suspend_noirq(struct device *dev)
5241{
5242 struct mmc_host *mmc = dev_get_drvdata(dev);
5243 struct msmsdcc_host *host = mmc_priv(mmc);
5244 int rc = 0;
5245
5246 /*
5247 * After platform suspend there may be active request
5248 * which might have enabled clocks. For example, in SDIO
5249 * case, ksdioirq thread might have scheduled after sdcc
5250 * suspend but before system freeze. In that case abort
5251 * suspend and retry instead of keeping the clocks on
5252 * during suspend and not allowing TCXO.
5253 */
5254
Asutosh Dasf5298c32012-04-03 14:51:47 +05305255 if (host->clks_on && !host->plat->is_sdio_al_client) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305256 pr_warn("%s: clocks are on after suspend, aborting system "
5257 "suspend\n", mmc_hostname(mmc));
5258 rc = -EAGAIN;
5259 }
5260
5261 return rc;
5262}
5263
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005264static int msmsdcc_pm_resume(struct device *dev)
5265{
5266 struct mmc_host *mmc = dev_get_drvdata(dev);
5267 struct msmsdcc_host *host = mmc_priv(mmc);
5268 int rc = 0;
5269
5270 if (host->plat->is_sdio_al_client)
5271 return 0;
5272
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005273 if (mmc->card && mmc_card_sdio(mmc->card))
Sahitya Tummalafb486372011-09-02 19:01:49 +05305274 rc = msmsdcc_runtime_resume(dev);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005275 else
5276 host->pending_resume = true;
5277
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005278 if (host->plat->status_irq) {
5279 msmsdcc_check_status((unsigned long)host);
5280 enable_irq(host->plat->status_irq);
5281 }
5282
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005283 return rc;
5284}
5285
Daniel Walker08ecfde2010-06-23 12:32:20 -07005286#else
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005287static int msmsdcc_runtime_suspend(struct device *dev)
5288{
5289 return 0;
5290}
5291static int msmsdcc_runtime_idle(struct device *dev)
5292{
5293 return 0;
5294}
5295static int msmsdcc_pm_suspend(struct device *dev)
5296{
5297 return 0;
5298}
5299static int msmsdcc_pm_resume(struct device *dev)
5300{
5301 return 0;
5302}
5303static int msmsdcc_suspend_noirq(struct device *dev)
5304{
5305 return 0;
5306}
5307static int msmsdcc_runtime_resume(struct device *dev)
5308{
5309 return 0;
5310}
Daniel Walker08ecfde2010-06-23 12:32:20 -07005311#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005312
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005313static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
5314 .runtime_suspend = msmsdcc_runtime_suspend,
5315 .runtime_resume = msmsdcc_runtime_resume,
5316 .runtime_idle = msmsdcc_runtime_idle,
5317 .suspend = msmsdcc_pm_suspend,
5318 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305319 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005320};
5321
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305322static const struct of_device_id msmsdcc_dt_match[] = {
5323 {.compatible = "qcom,msm-sdcc"},
5324
5325};
5326MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
5327
San Mehat9d2bd732009-09-22 16:44:22 -07005328static struct platform_driver msmsdcc_driver = {
5329 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005330 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07005331 .driver = {
5332 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005333 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305334 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07005335 },
5336};
5337
5338static int __init msmsdcc_init(void)
5339{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005340#if defined(CONFIG_DEBUG_FS)
5341 int ret = 0;
5342 ret = msmsdcc_dbg_init();
5343 if (ret) {
5344 pr_err("Failed to create debug fs dir \n");
5345 return ret;
5346 }
5347#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005348 return platform_driver_register(&msmsdcc_driver);
5349}
5350
5351static void __exit msmsdcc_exit(void)
5352{
5353 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005354
5355#if defined(CONFIG_DEBUG_FS)
5356 debugfs_remove(debugfs_file);
5357 debugfs_remove(debugfs_dir);
5358#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005359}
5360
5361module_init(msmsdcc_init);
5362module_exit(msmsdcc_exit);
5363
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005364MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07005365MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005366
5367#if defined(CONFIG_DEBUG_FS)
5368
5369static int
5370msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
5371{
5372 file->private_data = inode->i_private;
5373 return 0;
5374}
5375
5376static ssize_t
5377msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
5378 size_t count, loff_t *ppos)
5379{
5380 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08005381 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005382 int max, i;
5383
5384 i = 0;
5385 max = sizeof(buf) - 1;
5386
5387 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
5388 host->curr.cmd, host->curr.data);
5389 if (host->curr.cmd) {
5390 struct mmc_command *cmd = host->curr.cmd;
5391
5392 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
5393 cmd->opcode, cmd->arg, cmd->flags);
5394 }
5395 if (host->curr.data) {
5396 struct mmc_data *data = host->curr.data;
5397 i += scnprintf(buf + i, max - i,
5398 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
5399 data->timeout_ns, data->timeout_clks,
5400 data->blksz, data->blocks, data->error,
5401 data->flags);
5402 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
5403 host->curr.xfer_size, host->curr.xfer_remain,
5404 host->curr.data_xfered, host->dma.sg);
5405 }
5406
5407 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
5408}
5409
5410static const struct file_operations msmsdcc_dbg_state_ops = {
5411 .read = msmsdcc_dbg_state_read,
5412 .open = msmsdcc_dbg_state_open,
5413};
5414
5415static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
5416{
5417 if (debugfs_dir) {
5418 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
5419 0644, debugfs_dir, host,
5420 &msmsdcc_dbg_state_ops);
5421 }
5422}
5423
5424static int __init msmsdcc_dbg_init(void)
5425{
5426 int err;
5427
5428 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
5429 if (IS_ERR(debugfs_dir)) {
5430 err = PTR_ERR(debugfs_dir);
5431 debugfs_dir = NULL;
5432 return err;
5433 }
5434
5435 return 0;
5436}
5437#endif