blob: b46bee64e3ee28ec9ba47fce509ceb39f0673f02 [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.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006 * Copyright (c) 2009-2011, 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>
San Mehat9d2bd732009-09-22 16:44:22 -070046
47#include <asm/cacheflush.h>
48#include <asm/div64.h>
49#include <asm/sizes.h>
50
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070051#include <asm/mach/mmc.h>
San Mehat9d2bd732009-09-22 16:44:22 -070052#include <mach/msm_iomap.h>
Sahitya Tummalab08bb352010-12-08 15:03:05 +053053#include <mach/clk.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070054#include <mach/dma.h>
55#include <mach/htc_pwrsink.h>
56#include <mach/sdio_al.h>
San Mehat9d2bd732009-09-22 16:44:22 -070057
San Mehat9d2bd732009-09-22 16:44:22 -070058#include "msm_sdcc.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070059#include "msm_sdcc_dml.h"
San Mehat9d2bd732009-09-22 16:44:22 -070060
61#define DRIVER_NAME "msm-sdcc"
62
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070063#define DBG(host, fmt, args...) \
64 pr_debug("%s: %s: " fmt "\n", mmc_hostname(host->mmc), __func__ , args)
65
66#define IRQ_DEBUG 0
67#define SPS_SDCC_PRODUCER_PIPE_INDEX 1
68#define SPS_SDCC_CONSUMER_PIPE_INDEX 2
69#define SPS_CONS_PERIPHERAL 0
70#define SPS_PROD_PERIPHERAL 1
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070071
72#if defined(CONFIG_DEBUG_FS)
73static void msmsdcc_dbg_createhost(struct msmsdcc_host *);
74static struct dentry *debugfs_dir;
75static struct dentry *debugfs_file;
76static int msmsdcc_dbg_init(void);
77#endif
78
Subhash Jadavani8766e352011-11-30 11:30:32 +053079static u64 dma_mask = DMA_BIT_MASK(32);
San Mehat9d2bd732009-09-22 16:44:22 -070080static unsigned int msmsdcc_pwrsave = 1;
San Mehat9d2bd732009-09-22 16:44:22 -070081
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070082static struct mmc_command dummy52cmd;
83static struct mmc_request dummy52mrq = {
84 .cmd = &dummy52cmd,
85 .data = NULL,
86 .stop = NULL,
87};
88static struct mmc_command dummy52cmd = {
89 .opcode = SD_IO_RW_DIRECT,
90 .flags = MMC_RSP_PRESENT,
91 .data = NULL,
92 .mrq = &dummy52mrq,
93};
94/*
95 * An array holding the Tuning pattern to compare with when
96 * executing a tuning cycle.
97 */
98static const u32 cmd19_tuning_block[16] = {
99 0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
100 0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
101 0xF0FFF0FF, 0x3CCCFC0F, 0xCFCC33CC, 0xEEFFEFFF,
102 0xFDFFFDFF, 0xFFBFFFDF, 0xFFF7FFBB, 0xDE7B7FF7
103};
San Mehat865c8062009-11-13 13:42:06 -0800104
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700105#if IRQ_DEBUG == 1
106static char *irq_status_bits[] = { "cmdcrcfail", "datcrcfail", "cmdtimeout",
107 "dattimeout", "txunderrun", "rxoverrun",
108 "cmdrespend", "cmdsent", "dataend", NULL,
109 "datablkend", "cmdactive", "txactive",
110 "rxactive", "txhalfempty", "rxhalffull",
111 "txfifofull", "rxfifofull", "txfifoempty",
112 "rxfifoempty", "txdataavlbl", "rxdataavlbl",
113 "sdiointr", "progdone", "atacmdcompl",
114 "sdiointrope", "ccstimeout", NULL, NULL,
115 NULL, NULL, NULL };
116
117static void
118msmsdcc_print_status(struct msmsdcc_host *host, char *hdr, uint32_t status)
San Mehat865c8062009-11-13 13:42:06 -0800119{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700120 int i;
San Mehat8b1c2ba2009-11-16 10:17:30 -0800121
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700122 pr_debug("%s-%s ", mmc_hostname(host->mmc), hdr);
123 for (i = 0; i < 32; i++) {
124 if (status & (1 << i))
125 pr_debug("%s ", irq_status_bits[i]);
San Mehat865c8062009-11-13 13:42:06 -0800126 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700127 pr_debug("\n");
San Mehatc7fc9372009-11-22 17:19:07 -0800128}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700129#endif
San Mehat865c8062009-11-13 13:42:06 -0800130
San Mehat9d2bd732009-09-22 16:44:22 -0700131static void
132msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
133 u32 c);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530134static inline void msmsdcc_delay(struct msmsdcc_host *host);
135
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530136static inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
137{
138 unsigned short ret = NR_SG;
139
140 if (host->is_sps_mode) {
141 if (NR_SG > MAX_NR_SG_SPS)
142 ret = MAX_NR_SG_SPS;
143 } else { /* DMA or PIO mode */
144 if (NR_SG > MAX_NR_SG_DMA_PIO)
145 ret = MAX_NR_SG_DMA_PIO;
146 }
147
148 return ret;
149}
150
151static inline unsigned int msmsdcc_get_max_seg_size(struct msmsdcc_host *host)
152{
153 unsigned int max_seg_size;
154
155 /*
156 * SPS BAM has limitation of max. number of descriptors.
157 * max. # of descriptors = SPS_MAX_DESCS
158 * each descriptor can point to SPS_MAX_DESC_SIZE (16KB)
159 * So (nr_sg * max_seg_size) should be limited to the
160 * max. size that all of the descriptors can point to.
161 * i.e., (nr_sg * max_seg_size) = (SPS_MAX_DESCS * SPS_MAX_DESC_SIZE).
162 */
163 if (host->is_sps_mode) {
164 max_seg_size = (SPS_MAX_DESCS * SPS_MAX_DESC_SIZE) /
165 msmsdcc_get_nr_sg(host);
166 } else { /* DMA or PIO mode */
167 max_seg_size = MMC_MAX_REQ_SIZE;
168 }
169
170 return max_seg_size;
171}
San Mehat9d2bd732009-09-22 16:44:22 -0700172
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700173#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
174static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
175 struct msmsdcc_sps_ep_conn_data *ep);
176static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
177 struct msmsdcc_sps_ep_conn_data *ep);
178#else
179static inline int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
180 struct msmsdcc_sps_ep_conn_data *ep,
181 bool is_producer) { return 0; }
182static inline void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
183 struct msmsdcc_sps_ep_conn_data *ep) { }
184static inline int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
185 struct msmsdcc_sps_ep_conn_data *ep)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530186{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700187 return 0;
188}
189static inline int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
190 struct msmsdcc_sps_ep_conn_data *ep)
191{
192 return 0;
193}
194static inline int msmsdcc_sps_init(struct msmsdcc_host *host) { return 0; }
195static inline void msmsdcc_sps_exit(struct msmsdcc_host *host) {}
196#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530197
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700198/**
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530199 * Apply soft reset to all SDCC BAM pipes
200 *
201 * This function applies soft reset to SDCC BAM pipe.
202 *
203 * This function should be called to recover from error
204 * conditions encountered during CMD/DATA tranfsers with card.
205 *
206 * @host - Pointer to driver's host structure
207 *
208 */
209static void msmsdcc_sps_pipes_reset_and_restore(struct msmsdcc_host *host)
210{
211 int rc;
212
213 /* Reset all SDCC BAM pipes */
214 rc = msmsdcc_sps_reset_ep(host, &host->sps.prod);
215 if (rc)
216 pr_err("%s:msmsdcc_sps_reset_ep(prod) error=%d\n",
217 mmc_hostname(host->mmc), rc);
218 rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
219 if (rc)
220 pr_err("%s:msmsdcc_sps_reset_ep(cons) error=%d\n",
221 mmc_hostname(host->mmc), rc);
222
223 /* Restore all BAM pipes connections */
224 rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
225 if (rc)
226 pr_err("%s:msmsdcc_sps_restore_ep(prod) error=%d\n",
227 mmc_hostname(host->mmc), rc);
228 rc = msmsdcc_sps_restore_ep(host, &host->sps.cons);
229 if (rc)
230 pr_err("%s:msmsdcc_sps_restore_ep(cons) error=%d\n",
231 mmc_hostname(host->mmc), rc);
232}
233
234/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700235 * Apply soft reset
236 *
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530237 * This function applies soft reset to SDCC core and DML core.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700238 *
239 * This function should be called to recover from error
240 * conditions encountered with CMD/DATA tranfsers with card.
241 *
242 * Soft reset should only be used with SDCC controller v4.
243 *
244 * @host - Pointer to driver's host structure
245 *
246 */
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530247static void msmsdcc_soft_reset(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700248{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700249 /*
250 * Reset SDCC controller's DPSM (data path state machine
251 * and CPSM (command path state machine).
252 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700253 writel_relaxed(0, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530254 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700255 writel_relaxed(0, host->base + MMCIDATACTRL);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530256 msmsdcc_delay(host);
257}
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530258
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530259static void msmsdcc_hard_reset(struct msmsdcc_host *host)
260{
261 int ret;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530262
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530263 /* Reset the controller */
264 ret = clk_reset(host->clk, CLK_RESET_ASSERT);
265 if (ret)
266 pr_err("%s: Clock assert failed at %u Hz"
267 " with err %d\n", mmc_hostname(host->mmc),
268 host->clk_rate, ret);
269
270 ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
271 if (ret)
272 pr_err("%s: Clock deassert failed at %u Hz"
273 " with err %d\n", mmc_hostname(host->mmc),
274 host->clk_rate, ret);
275
276 /* Give some delay for clock reset to propogate to controller */
277 msmsdcc_delay(host);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530278}
279
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700280static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
281{
Pratibhasagar V1c11da62011-11-14 12:36:35 +0530282 if (host->sdcc_version) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530283 if (host->is_sps_mode) {
284 /* Reset DML first */
285 msmsdcc_dml_reset(host);
286 /*
287 * delay the SPS pipe reset in thread context as
288 * sps_connect/sps_disconnect APIs can be called
289 * only from non-atomic context.
290 */
291 host->sps.pipe_reset_pending = true;
292 }
293 mb();
294 msmsdcc_soft_reset(host);
295
296 pr_debug("%s: Applied soft reset to Controller\n",
297 mmc_hostname(host->mmc));
298
299 if (host->is_sps_mode)
300 msmsdcc_dml_init(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700301 } else {
302 /* Give Clock reset (hard reset) to controller */
303 u32 mci_clk = 0;
304 u32 mci_mask0 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700305
306 /* Save the controller state */
307 mci_clk = readl_relaxed(host->base + MMCICLOCK);
308 mci_mask0 = readl_relaxed(host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700309 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700310
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530311 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700312 pr_debug("%s: Controller has been reinitialized\n",
313 mmc_hostname(host->mmc));
314
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700315 /* Restore the contoller state */
316 writel_relaxed(host->pwr, host->base + MMCIPOWER);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530317 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700318 writel_relaxed(mci_clk, host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530319 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700320 writel_relaxed(mci_mask0, host->base + MMCIMASK0);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530321 mb(); /* no delay required after writing to MASK0 register */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700322 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530323
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700324 if (host->dummy_52_needed)
325 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700326}
327
328static int
San Mehat9d2bd732009-09-22 16:44:22 -0700329msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
330{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700331 int retval = 0;
332
San Mehat9d2bd732009-09-22 16:44:22 -0700333 BUG_ON(host->curr.data);
334
335 host->curr.mrq = NULL;
336 host->curr.cmd = NULL;
337
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700338 del_timer(&host->req_tout_timer);
339
San Mehat9d2bd732009-09-22 16:44:22 -0700340 if (mrq->data)
341 mrq->data->bytes_xfered = host->curr.data_xfered;
342 if (mrq->cmd->error == -ETIMEDOUT)
343 mdelay(5);
344
345 /*
346 * Need to drop the host lock here; mmc_request_done may call
347 * back into the driver...
348 */
349 spin_unlock(&host->lock);
350 mmc_request_done(host->mmc, mrq);
351 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700352
353 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700354}
355
356static void
357msmsdcc_stop_data(struct msmsdcc_host *host)
358{
San Mehat9d2bd732009-09-22 16:44:22 -0700359 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530360 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530361 host->curr.wait_for_auto_prog_done = 0;
362 host->curr.got_auto_prog_done = 0;
Krishna Konda3f5d48f2011-07-27 10:47:31 -0700363 writel_relaxed(readl_relaxed(host->base + MMCIDATACTRL) &
364 (~(MCI_DPSM_ENABLE)), host->base + MMCIDATACTRL);
Krishna Konda3e5c4d02011-07-11 16:31:45 -0700365 msmsdcc_delay(host); /* Allow the DPSM to be reset */
San Mehat9d2bd732009-09-22 16:44:22 -0700366}
367
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700368static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700369{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700370 return host->core_memres->start + MMCIFIFO;
371}
372
373static inline unsigned int msmsdcc_get_min_sup_clk_rate(
374 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530375
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700376static inline void msmsdcc_delay(struct msmsdcc_host *host)
377{
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530378 ktime_t start, diff;
379
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700380 mb();
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +0530381 udelay(host->reg_write_delay);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530382
Pratibhasagar V1c11da62011-11-14 12:36:35 +0530383 if (host->sdcc_version &&
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530384 (readl_relaxed(host->base + MCI_STATUS2) &
385 MCI_MCLK_REG_WR_ACTIVE)) {
386 start = ktime_get();
387 while (readl_relaxed(host->base + MCI_STATUS2) &
388 MCI_MCLK_REG_WR_ACTIVE) {
389 diff = ktime_sub(ktime_get(), start);
390 /* poll for max. 1 ms */
391 if (ktime_to_us(diff) > 1000) {
392 pr_warning("%s: previous reg. write is"
393 " still active\n",
394 mmc_hostname(host->mmc));
395 break;
396 }
397 }
398 }
San Mehat9d2bd732009-09-22 16:44:22 -0700399}
400
San Mehat56a8b5b2009-11-21 12:29:46 -0800401static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700402msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
403{
404 writel_relaxed(arg, host->base + MMCIARGUMENT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700405 writel_relaxed(c, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530406 /*
407 * As after sending the command, we don't write any of the
408 * controller registers and just wait for the
409 * CMD_RESPOND_END/CMD_SENT/Command failure notication
410 * from Controller.
411 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700412 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800413}
414
415static void
416msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
417{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700418 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800419
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700420 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
421 writel_relaxed((unsigned int)host->curr.xfer_size,
422 host->base + MMCIDATALENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700423 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
424 msmsdcc_delay(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800425
San Mehat6ac9ea62009-12-02 17:24:58 -0800426 if (host->cmd_cmd) {
427 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700428 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800429 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800430}
431
San Mehat9d2bd732009-09-22 16:44:22 -0700432static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530433msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700434{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530435 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700436 unsigned long flags;
437 struct mmc_request *mrq;
438
439 spin_lock_irqsave(&host->lock, flags);
440 mrq = host->curr.mrq;
441 BUG_ON(!mrq);
442
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530443 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700444 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700445 goto out;
446 }
447
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530448 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700449 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700450 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700451 } else {
452 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530453 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700454 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530455 mmc_hostname(host->mmc), host->dma.result);
456 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700457 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530458 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530459 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700460 host->dma.err.flush[0], host->dma.err.flush[1],
461 host->dma.err.flush[2], host->dma.err.flush[3],
462 host->dma.err.flush[4],
463 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530464 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700465 if (!mrq->data->error)
466 mrq->data->error = -EIO;
467 }
San Mehat9d2bd732009-09-22 16:44:22 -0700468 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents,
469 host->dma.dir);
470
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700471 if (host->curr.user_pages) {
472 struct scatterlist *sg = host->dma.sg;
473 int i;
474
475 for (i = 0; i < host->dma.num_ents; i++, sg++)
476 flush_dcache_page(sg_page(sg));
477 }
478
San Mehat9d2bd732009-09-22 16:44:22 -0700479 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800480 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700481
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530482 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
483 (host->curr.wait_for_auto_prog_done &&
484 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700485 /*
486 * If we've already gotten our DATAEND / DATABLKEND
487 * for this request, then complete it through here.
488 */
San Mehat9d2bd732009-09-22 16:44:22 -0700489
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700490 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700491 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700492 host->curr.xfer_remain -= host->curr.xfer_size;
493 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700494 if (host->dummy_52_needed) {
495 mrq->data->bytes_xfered = host->curr.data_xfered;
496 host->dummy_52_sent = 1;
497 msmsdcc_start_command(host, &dummy52cmd,
498 MCI_CPSM_PROGENA);
499 goto out;
500 }
501 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530502 if (!mrq->data->stop || mrq->cmd->error ||
503 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700504 host->curr.mrq = NULL;
505 host->curr.cmd = NULL;
506 mrq->data->bytes_xfered = host->curr.data_xfered;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700507 del_timer(&host->req_tout_timer);
San Mehat9d2bd732009-09-22 16:44:22 -0700508 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700509
San Mehat9d2bd732009-09-22 16:44:22 -0700510 mmc_request_done(host->mmc, mrq);
511 return;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530512 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
513 || !mrq->sbc)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700514 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530515 }
San Mehat9d2bd732009-09-22 16:44:22 -0700516 }
517
518out:
519 spin_unlock_irqrestore(&host->lock, flags);
520 return;
521}
522
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700523#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
524/**
525 * Callback notification from SPS driver
526 *
527 * This callback function gets triggered called from
528 * SPS driver when requested SPS data transfer is
529 * completed.
530 *
531 * SPS driver invokes this callback in BAM irq context so
532 * SDCC driver schedule a tasklet for further processing
533 * this callback notification at later point of time in
534 * tasklet context and immediately returns control back
535 * to SPS driver.
536 *
537 * @nofity - Pointer to sps event notify sturcture
538 *
539 */
540static void
541msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
542{
543 struct msmsdcc_host *host =
544 (struct msmsdcc_host *)
545 ((struct sps_event_notify *)notify)->user;
546
547 host->sps.notify = *notify;
548 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
549 mmc_hostname(host->mmc), __func__, notify->event_id,
550 notify->data.transfer.iovec.addr,
551 notify->data.transfer.iovec.size,
552 notify->data.transfer.iovec.flags);
553 /* Schedule a tasklet for completing data transfer */
554 tasklet_schedule(&host->sps.tlet);
555}
556
557/**
558 * Tasklet handler for processing SPS callback event
559 *
560 * This function processing SPS event notification and
561 * checks if the SPS transfer is completed or not and
562 * then accordingly notifies status to MMC core layer.
563 *
564 * This function is called in tasklet context.
565 *
566 * @data - Pointer to sdcc driver data
567 *
568 */
569static void msmsdcc_sps_complete_tlet(unsigned long data)
570{
571 unsigned long flags;
572 int i, rc;
573 u32 data_xfered = 0;
574 struct mmc_request *mrq;
575 struct sps_iovec iovec;
576 struct sps_pipe *sps_pipe_handle;
577 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
578 struct sps_event_notify *notify = &host->sps.notify;
579
580 spin_lock_irqsave(&host->lock, flags);
581 if (host->sps.dir == DMA_FROM_DEVICE)
582 sps_pipe_handle = host->sps.prod.pipe_handle;
583 else
584 sps_pipe_handle = host->sps.cons.pipe_handle;
585 mrq = host->curr.mrq;
586
587 if (!mrq) {
588 spin_unlock_irqrestore(&host->lock, flags);
589 return;
590 }
591
592 pr_debug("%s: %s: sps event_id=%d\n",
593 mmc_hostname(host->mmc), __func__,
594 notify->event_id);
595
596 if (msmsdcc_is_dml_busy(host)) {
597 /* oops !!! this should never happen. */
598 pr_err("%s: %s: Received SPS EOT event"
599 " but DML HW is still busy !!!\n",
600 mmc_hostname(host->mmc), __func__);
601 }
602 /*
603 * Got End of transfer event!!! Check if all of the data
604 * has been transferred?
605 */
606 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
607 rc = sps_get_iovec(sps_pipe_handle, &iovec);
608 if (rc) {
609 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
610 mmc_hostname(host->mmc), __func__, rc, i);
611 break;
612 }
613 data_xfered += iovec.size;
614 }
615
616 if (data_xfered == host->curr.xfer_size) {
617 host->curr.data_xfered = host->curr.xfer_size;
618 host->curr.xfer_remain -= host->curr.xfer_size;
619 pr_debug("%s: Data xfer success. data_xfered=0x%x",
620 mmc_hostname(host->mmc),
621 host->curr.xfer_size);
622 } else {
623 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
624 " xfer_size=%d", mmc_hostname(host->mmc),
625 data_xfered, host->curr.xfer_size);
626 msmsdcc_reset_and_restore(host);
627 if (!mrq->data->error)
628 mrq->data->error = -EIO;
629 }
630
631 /* Unmap sg buffers */
632 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
633 host->sps.dir);
634
635 host->sps.sg = NULL;
636 host->sps.busy = 0;
637
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530638 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
639 (host->curr.wait_for_auto_prog_done &&
640 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700641 /*
642 * If we've already gotten our DATAEND / DATABLKEND
643 * for this request, then complete it through here.
644 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700645
646 if (!mrq->data->error) {
647 host->curr.data_xfered = host->curr.xfer_size;
648 host->curr.xfer_remain -= host->curr.xfer_size;
649 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700650 if (host->dummy_52_needed) {
651 mrq->data->bytes_xfered = host->curr.data_xfered;
652 host->dummy_52_sent = 1;
653 msmsdcc_start_command(host, &dummy52cmd,
654 MCI_CPSM_PROGENA);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700655 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700656 return;
657 }
658 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530659 if (!mrq->data->stop || mrq->cmd->error ||
660 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700661 host->curr.mrq = NULL;
662 host->curr.cmd = NULL;
663 mrq->data->bytes_xfered = host->curr.data_xfered;
664 del_timer(&host->req_tout_timer);
665 spin_unlock_irqrestore(&host->lock, flags);
666
667 mmc_request_done(host->mmc, mrq);
668 return;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530669 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
670 || !mrq->sbc)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700671 msmsdcc_start_command(host, mrq->data->stop, 0);
672 }
673 }
674 spin_unlock_irqrestore(&host->lock, flags);
675}
676
677/**
678 * Exit from current SPS data transfer
679 *
680 * This function exits from current SPS data transfer.
681 *
682 * This function should be called when error condition
683 * is encountered during data transfer.
684 *
685 * @host - Pointer to sdcc host structure
686 *
687 */
688static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
689{
690 struct mmc_request *mrq;
691
692 mrq = host->curr.mrq;
693 BUG_ON(!mrq);
694
695 msmsdcc_reset_and_restore(host);
696 if (!mrq->data->error)
697 mrq->data->error = -EIO;
698
699 /* Unmap sg buffers */
700 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
701 host->sps.dir);
702
703 host->sps.sg = NULL;
704 host->sps.busy = 0;
705 if (host->curr.data)
706 msmsdcc_stop_data(host);
707
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530708 if (!mrq->data->stop || mrq->cmd->error ||
709 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700710 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530711 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
712 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700713 msmsdcc_start_command(host, mrq->data->stop, 0);
714
715}
716#else
717static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
718static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
719static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
720#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
721
722static void msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
723
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530724static void
725msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
726 unsigned int result,
727 struct msm_dmov_errdata *err)
728{
729 struct msmsdcc_dma_data *dma_data =
730 container_of(cmd, struct msmsdcc_dma_data, hdr);
731 struct msmsdcc_host *host = dma_data->host;
732
733 dma_data->result = result;
734 if (err)
735 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
736
737 tasklet_schedule(&host->dma_tlet);
738}
739
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700740static int msmsdcc_check_dma_op_req(struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700741{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700742 if (((data->blksz * data->blocks) < MCI_FIFOSIZE) ||
743 ((data->blksz * data->blocks) % MCI_FIFOSIZE))
San Mehat9d2bd732009-09-22 16:44:22 -0700744 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700745 else
746 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700747}
748
749static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
750{
751 struct msmsdcc_nc_dmadata *nc;
752 dmov_box *box;
753 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700754 unsigned int n;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530755 int i, err = 0, box_cmd_cnt = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700756 struct scatterlist *sg = data->sg;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530757 unsigned int len, offset;
San Mehat9d2bd732009-09-22 16:44:22 -0700758
Krishna Konda25786ec2011-07-25 16:21:36 -0700759 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700760 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700761
Krishna Konda25786ec2011-07-25 16:21:36 -0700762 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
763
San Mehat9d2bd732009-09-22 16:44:22 -0700764 host->dma.sg = data->sg;
765 host->dma.num_ents = data->sg_len;
766
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530767 /* Prevent memory corruption */
768 BUG_ON(host->dma.num_ents > msmsdcc_get_nr_sg(host));
San Mehat56a8b5b2009-11-21 12:29:46 -0800769
San Mehat9d2bd732009-09-22 16:44:22 -0700770 nc = host->dma.nc;
771
San Mehat9d2bd732009-09-22 16:44:22 -0700772 if (data->flags & MMC_DATA_READ)
773 host->dma.dir = DMA_FROM_DEVICE;
774 else
775 host->dma.dir = DMA_TO_DEVICE;
776
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700777 n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
778 host->dma.num_ents, host->dma.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700779
780 if (n != host->dma.num_ents) {
781 pr_err("%s: Unable to map in all sg elements\n",
782 mmc_hostname(host->mmc));
783 host->dma.sg = NULL;
784 host->dma.num_ents = 0;
785 return -ENOMEM;
San Mehat56a8b5b2009-11-21 12:29:46 -0800786 }
San Mehat9d2bd732009-09-22 16:44:22 -0700787
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530788 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
789 host->curr.user_pages = 0;
790 box = &nc->cmd[0];
791 for (i = 0; i < host->dma.num_ents; i++) {
792 len = sg_dma_len(sg);
793 offset = 0;
794
795 do {
796 /* Check if we can do DMA */
797 if (!len || (box_cmd_cnt >= MMC_MAX_DMA_CMDS)) {
798 err = -ENOTSUPP;
799 goto unmap;
800 }
801
802 box->cmd = CMD_MODE_BOX;
803
804 if (len >= MMC_MAX_DMA_BOX_LENGTH) {
805 len = MMC_MAX_DMA_BOX_LENGTH;
806 len -= len % data->blksz;
807 }
808 rows = (len % MCI_FIFOSIZE) ?
809 (len / MCI_FIFOSIZE) + 1 :
810 (len / MCI_FIFOSIZE);
811
812 if (data->flags & MMC_DATA_READ) {
813 box->src_row_addr = msmsdcc_fifo_addr(host);
814 box->dst_row_addr = sg_dma_address(sg) + offset;
815 box->src_dst_len = (MCI_FIFOSIZE << 16) |
816 (MCI_FIFOSIZE);
817 box->row_offset = MCI_FIFOSIZE;
818 box->num_rows = rows * ((1 << 16) + 1);
819 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
820 } else {
821 box->src_row_addr = sg_dma_address(sg) + offset;
822 box->dst_row_addr = msmsdcc_fifo_addr(host);
823 box->src_dst_len = (MCI_FIFOSIZE << 16) |
824 (MCI_FIFOSIZE);
825 box->row_offset = (MCI_FIFOSIZE << 16);
826 box->num_rows = rows * ((1 << 16) + 1);
827 box->cmd |= CMD_DST_CRCI(host->dma.crci);
828 }
829
830 offset += len;
831 len = sg_dma_len(sg) - offset;
832 box++;
833 box_cmd_cnt++;
834 } while (len);
835 sg++;
836 }
837 /* Mark last command */
838 box--;
839 box->cmd |= CMD_LC;
840
841 /* location of command block must be 64 bit aligned */
842 BUG_ON(host->dma.cmd_busaddr & 0x07);
843
844 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
845 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
846 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
847 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
848
849 /* Flush all data to memory before starting dma */
850 mb();
851
852unmap:
853 if (err) {
854 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
855 host->dma.num_ents, host->dma.dir);
856 pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
857 mmc_hostname(host->mmc), err);
858 }
859
860 return err;
San Mehat9d2bd732009-09-22 16:44:22 -0700861}
862
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700863#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
864/**
865 * Submits data transfer request to SPS driver
866 *
867 * This function make sg (scatter gather) data buffers
868 * DMA ready and then submits them to SPS driver for
869 * transfer.
870 *
871 * @host - Pointer to sdcc host structure
872 * @data - Pointer to mmc_data structure
873 *
874 * @return 0 if success else negative value
875 */
876static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
877 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -0800878{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700879 int rc = 0;
880 u32 flags;
881 int i;
882 u32 addr, len, data_cnt;
883 struct scatterlist *sg = data->sg;
884 struct sps_pipe *sps_pipe_handle;
885
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530886 /* Prevent memory corruption */
887 BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700888
889 host->sps.sg = data->sg;
890 host->sps.num_ents = data->sg_len;
891 host->sps.xfer_req_cnt = 0;
892 if (data->flags & MMC_DATA_READ) {
893 host->sps.dir = DMA_FROM_DEVICE;
894 sps_pipe_handle = host->sps.prod.pipe_handle;
895 } else {
896 host->sps.dir = DMA_TO_DEVICE;
897 sps_pipe_handle = host->sps.cons.pipe_handle;
898 }
899
900 /* Make sg buffers DMA ready */
901 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
902 host->sps.dir);
903
904 if (rc != data->sg_len) {
905 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
906 mmc_hostname(host->mmc), rc);
907 host->sps.sg = NULL;
908 host->sps.num_ents = 0;
909 rc = -ENOMEM;
910 goto dma_map_err;
911 }
912
913 pr_debug("%s: %s: %s: pipe=0x%x, total_xfer=0x%x, sg_len=%d\n",
914 mmc_hostname(host->mmc), __func__,
915 host->sps.dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
916 (u32)sps_pipe_handle, host->curr.xfer_size, data->sg_len);
917
918 for (i = 0; i < data->sg_len; i++) {
919 /*
920 * Check if this is the last buffer to transfer?
921 * If yes then set the INT and EOT flags.
922 */
923 len = sg_dma_len(sg);
924 addr = sg_dma_address(sg);
925 flags = 0;
926 while (len > 0) {
927 if (len > SPS_MAX_DESC_SIZE) {
928 data_cnt = SPS_MAX_DESC_SIZE;
929 } else {
930 data_cnt = len;
931 if (i == data->sg_len - 1)
932 flags = SPS_IOVEC_FLAG_INT |
933 SPS_IOVEC_FLAG_EOT;
934 }
935 rc = sps_transfer_one(sps_pipe_handle, addr,
936 data_cnt, host, flags);
937 if (rc) {
938 pr_err("%s: sps_transfer_one() error! rc=%d,"
939 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
940 mmc_hostname(host->mmc), rc,
941 (u32)sps_pipe_handle, (u32)sg, i);
942 goto dma_map_err;
943 }
944 addr += data_cnt;
945 len -= data_cnt;
946 host->sps.xfer_req_cnt++;
947 }
948 sg++;
949 }
950 goto out;
951
952dma_map_err:
953 /* unmap sg buffers */
954 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
955 host->sps.dir);
956out:
957 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -0700958}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700959#else
960static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
961 struct mmc_data *data) { return 0; }
962#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -0700963
964static void
San Mehat56a8b5b2009-11-21 12:29:46 -0800965msmsdcc_start_command_deferred(struct msmsdcc_host *host,
966 struct mmc_command *cmd, u32 *c)
967{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700968 DBG(host, "op %02x arg %08x flags %08x\n",
969 cmd->opcode, cmd->arg, cmd->flags);
970
San Mehat56a8b5b2009-11-21 12:29:46 -0800971 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
972
973 if (cmd->flags & MMC_RSP_PRESENT) {
974 if (cmd->flags & MMC_RSP_136)
975 *c |= MCI_CPSM_LONGRSP;
976 *c |= MCI_CPSM_RESPONSE;
977 }
978
979 if (/*interrupt*/0)
980 *c |= MCI_CPSM_INTERRUPT;
981
Subhash Jadavanide0fc772011-11-13 12:27:52 +0530982 if (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
983 cmd->opcode == MMC_READ_MULTIPLE_BLOCK ||
984 cmd->opcode == MMC_WRITE_BLOCK ||
985 cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK ||
986 cmd->opcode == SD_IO_RW_EXTENDED)
San Mehat56a8b5b2009-11-21 12:29:46 -0800987 *c |= MCI_CSPM_DATCMD;
988
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700989 /* Check if AUTO CMD19 is required or not? */
Subhash Jadavani1d6ba602011-09-21 18:10:54 +0530990 if (host->tuning_needed) {
991 /*
992 * For open ended block read operation (without CMD23),
993 * AUTO_CMD19 bit should be set while sending the READ command.
994 * For close ended block read operation (with CMD23),
995 * AUTO_CMD19 bit should be set while sending CMD23.
996 */
Subhash Jadavanide0fc772011-11-13 12:27:52 +0530997 if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
998 host->curr.mrq->cmd->opcode ==
999 MMC_READ_MULTIPLE_BLOCK) ||
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301000 (!host->curr.mrq->sbc &&
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301001 (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
1002 cmd->opcode == MMC_READ_MULTIPLE_BLOCK))) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301003 msmsdcc_enable_cdr_cm_sdc4_dll(host);
1004 *c |= MCI_CSPM_AUTO_CMD19;
1005 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001006 }
1007
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301008 if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301009 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001010 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301011 }
1012
San Mehat56a8b5b2009-11-21 12:29:46 -08001013 if (cmd == cmd->mrq->stop)
1014 *c |= MCI_CSPM_MCIABORT;
1015
San Mehat56a8b5b2009-11-21 12:29:46 -08001016 if (host->curr.cmd != NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001017 pr_err("%s: Overlapping command requests\n",
1018 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -08001019 }
1020 host->curr.cmd = cmd;
1021}
1022
1023static void
1024msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1025 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001026{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301027 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001028 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001029 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001030 unsigned int pio_irqmask = 0;
1031
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301032 BUG_ON(!data->sg);
1033 BUG_ON(!data->sg_len);
1034
San Mehat9d2bd732009-09-22 16:44:22 -07001035 host->curr.data = data;
1036 host->curr.xfer_size = data->blksz * data->blocks;
1037 host->curr.xfer_remain = host->curr.xfer_size;
1038 host->curr.data_xfered = 0;
1039 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301040 host->curr.got_auto_prog_done = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001041
1042 memset(&host->pio, 0, sizeof(host->pio));
1043
San Mehat9d2bd732009-09-22 16:44:22 -07001044 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1045
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301046 if (host->curr.wait_for_auto_prog_done)
1047 datactrl |= MCI_AUTO_PROG_DONE;
1048
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001049 if (!msmsdcc_check_dma_op_req(data)) {
1050 if (host->is_dma_mode && !msmsdcc_config_dma(host, data)) {
1051 datactrl |= MCI_DPSM_DMAENABLE;
1052 } else if (host->is_sps_mode) {
1053 if (!msmsdcc_is_dml_busy(host)) {
1054 if (!msmsdcc_sps_start_xfer(host, data)) {
1055 /* Now kick start DML transfer */
1056 mb();
1057 msmsdcc_dml_start_xfer(host, data);
1058 datactrl |= MCI_DPSM_DMAENABLE;
1059 host->sps.busy = 1;
1060 }
1061 } else {
1062 /*
1063 * Can't proceed with new transfer as
1064 * previous trasnfer is already in progress.
1065 * There is no point of going into PIO mode
1066 * as well. Is this a time to do kernel panic?
1067 */
1068 pr_err("%s: %s: DML HW is busy!!!"
1069 " Can't perform new SPS transfers"
1070 " now\n", mmc_hostname(host->mmc),
1071 __func__);
1072 }
1073 }
1074 }
1075
1076 /* Is data transfer in PIO mode required? */
1077 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001078 host->pio.sg = data->sg;
1079 host->pio.sg_len = data->sg_len;
1080 host->pio.sg_off = 0;
1081
1082 if (data->flags & MMC_DATA_READ) {
1083 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1084 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1085 pio_irqmask |= MCI_RXDATAAVLBLMASK;
1086 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001087 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1088 MCI_TXFIFOEMPTYMASK;
San Mehat9d2bd732009-09-22 16:44:22 -07001089 }
1090
1091 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301092 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
San Mehat9d2bd732009-09-22 16:44:22 -07001093
San Mehat56a8b5b2009-11-21 12:29:46 -08001094 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001095 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001096 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -07001097
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001098 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
1099 /* Use ADM (Application Data Mover) HW for Data transfer */
1100 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001101 host->cmd_timeout = timeout;
1102 host->cmd_pio_irqmask = pio_irqmask;
1103 host->cmd_datactrl = datactrl;
1104 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001105
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001106 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1107 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001108 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001109
1110 if (cmd) {
1111 msmsdcc_start_command_deferred(host, cmd, &c);
1112 host->cmd_c = c;
1113 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001114 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1115 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1116 host->base + MMCIMASK0);
1117 mb();
1118 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001119 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001120 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001121 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001122
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001123 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001124
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001125 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1126 (~(MCI_IRQ_PIO))) | pio_irqmask,
1127 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001128 writel_relaxed(datactrl, base + MMCIDATACTRL);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301129 /*
1130 * We don't need delay after writing to DATA_CTRL register
1131 * if we are not writing to CMD register immediately after
1132 * this. As we already have delay before sending the
1133 * command, we just need mb() here.
1134 */
1135 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001136
1137 if (cmd) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001138 msmsdcc_delay(host); /* Delay between data/command */
San Mehat56a8b5b2009-11-21 12:29:46 -08001139 /* Daisy-chain the command if requested */
1140 msmsdcc_start_command(host, cmd, c);
1141 }
San Mehat9d2bd732009-09-22 16:44:22 -07001142 }
1143}
1144
1145static void
1146msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1147{
San Mehat56a8b5b2009-11-21 12:29:46 -08001148 msmsdcc_start_command_deferred(host, cmd, &c);
1149 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001150}
1151
1152static void
1153msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1154 unsigned int status)
1155{
1156 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001157 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1158 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1159 pr_err("%s: Data CRC error\n",
1160 mmc_hostname(host->mmc));
1161 pr_err("%s: opcode 0x%.8x\n", __func__,
1162 data->mrq->cmd->opcode);
1163 pr_err("%s: blksz %d, blocks %d\n", __func__,
1164 data->blksz, data->blocks);
1165 data->error = -EILSEQ;
1166 }
San Mehat9d2bd732009-09-22 16:44:22 -07001167 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001168 /* CRC is optional for the bus test commands, not all
1169 * cards respond back with CRC. However controller
1170 * waits for the CRC and times out. Hence ignore the
1171 * data timeouts during the Bustest.
1172 */
1173 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1174 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1175 pr_err("%s: Data timeout\n",
1176 mmc_hostname(host->mmc));
1177 data->error = -ETIMEDOUT;
1178 }
San Mehat9d2bd732009-09-22 16:44:22 -07001179 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001180 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001181 data->error = -EIO;
1182 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001183 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001184 data->error = -EIO;
1185 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001186 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001187 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001188 data->error = -EIO;
1189 }
San Mehat9d2bd732009-09-22 16:44:22 -07001190
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001191 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001192 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001193 host->dummy_52_needed = 0;
1194}
San Mehat9d2bd732009-09-22 16:44:22 -07001195
1196static int
1197msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1198{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001199 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001200 uint32_t *ptr = (uint32_t *) buffer;
1201 int count = 0;
1202
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301203 if (remain % 4)
1204 remain = ((remain >> 2) + 1) << 2;
1205
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001206 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1207
1208 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001209 ptr++;
1210 count += sizeof(uint32_t);
1211
1212 remain -= sizeof(uint32_t);
1213 if (remain == 0)
1214 break;
1215 }
1216 return count;
1217}
1218
1219static int
1220msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001221 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001222{
1223 void __iomem *base = host->base;
1224 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001225 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001226
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001227 while (readl_relaxed(base + MMCISTATUS) &
1228 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1229 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001230
San Mehat9d2bd732009-09-22 16:44:22 -07001231 count = min(remain, maxcnt);
1232
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301233 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1234 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001235 ptr += count;
1236 remain -= count;
1237
1238 if (remain == 0)
1239 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001240 }
1241 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001242
1243 return ptr - buffer;
1244}
1245
San Mehat1cd22962010-02-03 12:59:29 -08001246static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001247msmsdcc_pio_irq(int irq, void *dev_id)
1248{
1249 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001250 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001251 uint32_t status;
1252
Murali Palnati36448a42011-09-02 15:06:18 +05301253 spin_lock(&host->lock);
1254
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001255 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001256
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001257 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301258 (MCI_IRQ_PIO)) == 0) {
1259 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001260 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301261 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001262
1263#if IRQ_DEBUG
1264 msmsdcc_print_status(host, "irq1-r", status);
1265#endif
1266
San Mehat9d2bd732009-09-22 16:44:22 -07001267 do {
1268 unsigned long flags;
1269 unsigned int remain, len;
1270 char *buffer;
1271
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001272 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1273 | MCI_RXDATAAVLBL)))
1274 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001275
1276 /* Map the current scatter buffer */
1277 local_irq_save(flags);
1278 buffer = kmap_atomic(sg_page(host->pio.sg),
1279 KM_BIO_SRC_IRQ) + host->pio.sg->offset;
1280 buffer += host->pio.sg_off;
1281 remain = host->pio.sg->length - host->pio.sg_off;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001282
San Mehat9d2bd732009-09-22 16:44:22 -07001283 len = 0;
1284 if (status & MCI_RXACTIVE)
1285 len = msmsdcc_pio_read(host, buffer, remain);
1286 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001287 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001288
1289 /* Unmap the buffer */
1290 kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
1291 local_irq_restore(flags);
1292
1293 host->pio.sg_off += len;
1294 host->curr.xfer_remain -= len;
1295 host->curr.data_xfered += len;
1296 remain -= len;
1297
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001298 if (remain) /* Done with this page? */
1299 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001300
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001301 if (status & MCI_RXACTIVE && host->curr.user_pages)
1302 flush_dcache_page(sg_page(host->pio.sg));
San Mehat9d2bd732009-09-22 16:44:22 -07001303
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001304 if (!--host->pio.sg_len) {
1305 memset(&host->pio, 0, sizeof(host->pio));
1306 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001307 }
1308
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001309 /* Advance to next sg */
1310 host->pio.sg++;
1311 host->pio.sg_off = 0;
1312
1313 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001314 } while (1);
1315
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001316 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1317 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1318 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1319 host->base + MMCIMASK0);
1320 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301321 /*
1322 * back to back write to MASK0 register don't need
1323 * synchronization delay.
1324 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001325 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1326 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1327 }
1328 mb();
1329 } else if (!host->curr.xfer_remain) {
1330 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1331 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1332 mb();
1333 }
San Mehat9d2bd732009-09-22 16:44:22 -07001334
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001335 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001336
1337 return IRQ_HANDLED;
1338}
1339
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001340static void
1341msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1342
1343static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1344 struct mmc_data *data)
1345{
1346 u32 loop_cnt = 0;
1347
1348 /*
1349 * For read commands with data less than fifo size, it is possible to
1350 * get DATAEND first and RXDATA_AVAIL might be set later because of
1351 * synchronization delay through the asynchronous RX FIFO. Thus, for
1352 * such cases, even after DATAEND interrupt is received software
1353 * should poll for RXDATA_AVAIL until the requested data is read out
1354 * of FIFO. This change is needed to get around this abnormal but
1355 * sometimes expected behavior of SDCC3 controller.
1356 *
1357 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1358 * after the data is loaded into RX FIFO. This would amount to less
1359 * than a microsecond and thus looping for 1000 times is good enough
1360 * for that delay.
1361 */
1362 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1363 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1364 spin_unlock(&host->lock);
1365 msmsdcc_pio_irq(1, host);
1366 spin_lock(&host->lock);
1367 }
1368 }
1369 if (loop_cnt == 1000) {
1370 pr_info("%s: Timed out while polling for Rx Data\n",
1371 mmc_hostname(host->mmc));
1372 data->error = -ETIMEDOUT;
1373 msmsdcc_reset_and_restore(host);
1374 }
1375}
1376
San Mehat9d2bd732009-09-22 16:44:22 -07001377static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1378{
1379 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001380
1381 host->curr.cmd = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001382 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1383 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1384 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1385 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -07001386
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001387 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Sahitya Tummala5a0ae912011-07-18 13:34:01 +05301388 pr_debug("%s: Command timeout\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001389 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001390 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
1391 !host->cmd19_tuning_in_progress) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001392 pr_err("%s: Command CRC error\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001393 cmd->error = -EILSEQ;
1394 }
1395
1396 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001397 if (host->curr.data && host->dma.sg &&
1398 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001399 msm_dmov_stop_cmd(host->dma.channel,
1400 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001401 else if (host->curr.data && host->sps.sg &&
1402 host->is_sps_mode){
1403 /* Stop current SPS transfer */
1404 msmsdcc_sps_exit_curr_xfer(host);
1405 }
San Mehat9d2bd732009-09-22 16:44:22 -07001406 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301407 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001408 msmsdcc_stop_data(host);
1409 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301410 } else { /* host->data == NULL */
1411 if (!cmd->error && host->prog_enable) {
1412 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001413 host->prog_enable = 0;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301414 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001415 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301416 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301417 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301418 host->prog_enable = 0;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001419 if (host->dummy_52_needed)
1420 host->dummy_52_needed = 0;
1421 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001422 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301423 msmsdcc_request_end(host, cmd->mrq);
1424 }
1425 }
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301426 } else if ((cmd == host->curr.mrq->sbc) && cmd->data) {
1427 if (cmd->data->flags & MMC_DATA_READ)
1428 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1429 else
1430 msmsdcc_request_start(host, host->curr.mrq);
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301431 } else if (cmd->data) {
1432 if (!(cmd->data->flags & MMC_DATA_READ))
1433 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001434 }
1435}
1436
San Mehat9d2bd732009-09-22 16:44:22 -07001437static irqreturn_t
1438msmsdcc_irq(int irq, void *dev_id)
1439{
1440 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001441 u32 status;
1442 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001443 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001444
1445 spin_lock(&host->lock);
1446
1447 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001448 struct mmc_command *cmd;
1449 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001450
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001451 if (timer) {
1452 timer = 0;
1453 msmsdcc_delay(host);
1454 }
San Mehat865c8062009-11-13 13:42:06 -08001455
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001456 if (!host->clks_on) {
1457 pr_debug("%s: %s: SDIO async irq received\n",
1458 mmc_hostname(host->mmc), __func__);
1459 host->mmc->ios.clock = host->clk_rate;
1460 spin_unlock(&host->lock);
1461 host->mmc->ops->set_ios(host->mmc, &host->mmc->ios);
1462 spin_lock(&host->lock);
1463 if (host->plat->cfg_mpm_sdiowakeup &&
1464 (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
1465 wake_lock(&host->sdio_wlock);
1466 /* only ansyc interrupt can come when clocks are off */
1467 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301468 if (host->clk_rate <=
1469 msmsdcc_get_min_sup_clk_rate(host))
1470 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001471 }
1472
1473 status = readl_relaxed(host->base + MMCISTATUS);
1474
1475 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1476 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001477 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001478
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001479#if IRQ_DEBUG
1480 msmsdcc_print_status(host, "irq0-r", status);
1481#endif
1482 status &= readl_relaxed(host->base + MMCIMASK0);
1483 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301484 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301485 if (host->clk_rate <=
1486 msmsdcc_get_min_sup_clk_rate(host))
1487 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001488#if IRQ_DEBUG
1489 msmsdcc_print_status(host, "irq0-p", status);
1490#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001491
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001492#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
1493 if (status & MCI_SDIOINTROPE) {
1494 if (host->sdcc_suspending)
1495 wake_lock(&host->sdio_suspend_wlock);
1496 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001497 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001498#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001499 data = host->curr.data;
1500
1501 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001502 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1503 MCI_CMDTIMEOUT)) {
1504 if (status & MCI_CMDTIMEOUT)
1505 pr_debug("%s: dummy CMD52 timeout\n",
1506 mmc_hostname(host->mmc));
1507 if (status & MCI_CMDCRCFAIL)
1508 pr_debug("%s: dummy CMD52 CRC failed\n",
1509 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001510 host->dummy_52_sent = 0;
1511 host->dummy_52_needed = 0;
1512 if (data) {
1513 msmsdcc_stop_data(host);
1514 msmsdcc_request_end(host, data->mrq);
1515 }
1516 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001517 spin_unlock(&host->lock);
1518 return IRQ_HANDLED;
1519 }
1520 break;
1521 }
1522
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001523 /*
1524 * Check for proper command response
1525 */
1526 cmd = host->curr.cmd;
1527 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1528 MCI_CMDTIMEOUT | MCI_PROGDONE |
1529 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1530 msmsdcc_do_cmdirq(host, status);
1531 }
1532
Sathish Ambley081d7842011-11-29 11:19:41 -08001533 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001534 /* Check for data errors */
1535 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1536 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1537 msmsdcc_data_err(host, data, status);
1538 host->curr.data_xfered = 0;
1539 if (host->dma.sg && host->is_dma_mode)
1540 msm_dmov_stop_cmd(host->dma.channel,
1541 &host->dma.hdr, 0);
1542 else if (host->sps.sg && host->is_sps_mode) {
1543 /* Stop current SPS transfer */
1544 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301545 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001546 msmsdcc_reset_and_restore(host);
1547 if (host->curr.data)
1548 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301549 if (!data->stop || (host->curr.mrq->sbc
1550 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001551 timer |=
1552 msmsdcc_request_end(host,
1553 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301554 else if ((host->curr.mrq->sbc
1555 && data->error) ||
1556 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001557 msmsdcc_start_command(host,
1558 data->stop,
1559 0);
1560 timer = 1;
1561 }
1562 }
1563 }
1564
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301565 /* Check for prog done */
1566 if (host->curr.wait_for_auto_prog_done &&
1567 (status & MCI_PROGDONE))
1568 host->curr.got_auto_prog_done = 1;
1569
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001570 /* Check for data done */
1571 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1572 host->curr.got_dataend = 1;
1573
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301574 if (host->curr.got_dataend &&
1575 (!host->curr.wait_for_auto_prog_done ||
1576 (host->curr.wait_for_auto_prog_done &&
1577 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001578 /*
1579 * If DMA is still in progress, we complete
1580 * via the completion handler
1581 */
1582 if (!host->dma.busy && !host->sps.busy) {
1583 /*
1584 * There appears to be an issue in the
1585 * controller where if you request a
1586 * small block transfer (< fifo size),
1587 * you may get your DATAEND/DATABLKEND
1588 * irq without the PIO data irq.
1589 *
1590 * Check to see if theres still data
1591 * to be read, and simulate a PIO irq.
1592 */
1593 if (data->flags & MMC_DATA_READ)
1594 msmsdcc_wait_for_rxdata(host,
1595 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001596 if (!data->error) {
1597 host->curr.data_xfered =
1598 host->curr.xfer_size;
1599 host->curr.xfer_remain -=
1600 host->curr.xfer_size;
1601 }
1602
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001603 if (!host->dummy_52_needed) {
1604 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301605 if (!data->stop ||
1606 (host->curr.mrq->sbc
1607 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001608 msmsdcc_request_end(
1609 host,
1610 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301611 else if ((host->curr.mrq->sbc
1612 && data->error) ||
1613 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001614 msmsdcc_start_command(
1615 host,
1616 data->stop, 0);
1617 timer = 1;
1618 }
1619 } else {
1620 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001621 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001622 &dummy52cmd,
1623 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001624 }
1625 }
1626 }
1627 }
1628
San Mehat9d2bd732009-09-22 16:44:22 -07001629 ret = 1;
1630 } while (status);
1631
1632 spin_unlock(&host->lock);
1633
San Mehat9d2bd732009-09-22 16:44:22 -07001634 return IRQ_RETVAL(ret);
1635}
1636
1637static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001638msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1639{
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301640 if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001641 /* Queue/read data, daisy-chain command when data starts */
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301642 if (mrq->sbc)
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301643 msmsdcc_start_data(host, mrq->data, mrq->sbc, 0);
1644 else
1645 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001646 } else {
1647 msmsdcc_start_command(host, mrq->cmd, 0);
1648 }
1649}
1650
1651static void
San Mehat9d2bd732009-09-22 16:44:22 -07001652msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1653{
1654 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001655 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001656
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001657 /*
1658 * Get the SDIO AL client out of LPM.
1659 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001660 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001661 if (host->plat->is_sdio_al_client)
1662 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001663
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301664 /* check if sps pipe reset is pending? */
1665 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1666 msmsdcc_sps_pipes_reset_and_restore(host);
1667 host->sps.pipe_reset_pending = false;
1668 }
1669
San Mehat9d2bd732009-09-22 16:44:22 -07001670 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001671 WARN(host->curr.mrq, "Request in progress\n");
1672 WARN(!host->pwr, "SDCC power is turned off\n");
1673 WARN(!host->clks_on, "SDCC clocks are turned off\n");
1674 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
San Mehat9d2bd732009-09-22 16:44:22 -07001675
1676 if (host->eject) {
1677 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1678 mrq->cmd->error = 0;
1679 mrq->data->bytes_xfered = mrq->data->blksz *
1680 mrq->data->blocks;
1681 } else
1682 mrq->cmd->error = -ENOMEDIUM;
1683
1684 spin_unlock_irqrestore(&host->lock, flags);
1685 mmc_request_done(mmc, mrq);
1686 return;
1687 }
1688
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301689 /*
1690 * Kick the software command timeout timer here.
1691 * Timer expires in 10 secs.
1692 */
1693 mod_timer(&host->req_tout_timer,
1694 (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
San Mehat9d2bd732009-09-22 16:44:22 -07001695
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301696 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301697 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301698 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
1699 mrq->cmd->opcode == 54) {
Pratibhasagar V1c11da62011-11-14 12:36:35 +05301700 if (!host->sdcc_version)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001701 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301702 else
1703 /*
1704 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
1705 * write operations using CMD53 and CMD54.
1706 * Setting this bit with CMD53 would
1707 * automatically triggers PROG_DONE interrupt
1708 * without the need of sending dummy CMD52.
1709 */
1710 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani758cf8c2011-11-13 11:59:55 +05301711 } else if (mrq->cmd->opcode == MMC_WRITE_BLOCK &&
1712 host->sdcc_version) {
1713 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001714 }
San Mehat9d2bd732009-09-22 16:44:22 -07001715 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301716
Pratibhasagar V00b94332011-10-18 14:57:27 +05301717 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301718 mrq->sbc->mrq = mrq;
1719 mrq->sbc->data = mrq->data;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301720 if (mrq->data->flags & MMC_DATA_WRITE) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301721 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301722 msmsdcc_start_command(host, mrq->sbc, 0);
1723 } else {
1724 msmsdcc_request_start(host, mrq);
1725 }
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301726 } else {
1727 msmsdcc_request_start(host, mrq);
1728 }
1729
San Mehat9d2bd732009-09-22 16:44:22 -07001730 spin_unlock_irqrestore(&host->lock, flags);
1731}
1732
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001733static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1734 int min_uV, int max_uV)
1735{
1736 int rc = 0;
1737
1738 if (vreg->set_voltage_sup) {
1739 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1740 if (rc) {
1741 pr_err("%s: regulator_set_voltage(%s) failed."
1742 " min_uV=%d, max_uV=%d, rc=%d\n",
1743 __func__, vreg->name, min_uV, max_uV, rc);
1744 }
1745 }
1746
1747 return rc;
1748}
1749
1750static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1751 int uA_load)
1752{
1753 int rc = 0;
1754
Krishna Kondafea60182011-11-01 16:01:34 -07001755 /* regulators that do not support regulator_set_voltage also
1756 do not support regulator_set_optimum_mode */
1757 if (vreg->set_voltage_sup) {
1758 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1759 if (rc < 0)
1760 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
1761 "uA_load=%d) failed. rc=%d\n", __func__,
1762 vreg->name, uA_load, rc);
1763 else
1764 /* regulator_set_optimum_mode() can return non zero
1765 * value even for success case.
1766 */
1767 rc = 0;
1768 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001769
1770 return rc;
1771}
1772
1773static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1774 struct device *dev)
1775{
1776 int rc = 0;
1777
1778 /* check if regulator is already initialized? */
1779 if (vreg->reg)
1780 goto out;
1781
1782 /* Get the regulator handle */
1783 vreg->reg = regulator_get(dev, vreg->name);
1784 if (IS_ERR(vreg->reg)) {
1785 rc = PTR_ERR(vreg->reg);
1786 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
1787 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001788 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001789 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001790
1791 if (regulator_count_voltages(vreg->reg) > 0)
1792 vreg->set_voltage_sup = 1;
1793
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001794out:
1795 return rc;
1796}
1797
1798static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
1799{
1800 if (vreg->reg)
1801 regulator_put(vreg->reg);
1802}
1803
1804/* This init function should be called only once for each SDCC slot */
1805static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
1806{
1807 int rc = 0;
1808 struct msm_mmc_slot_reg_data *curr_slot;
1809 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1810 struct device *dev = mmc_dev(host->mmc);
1811
1812 curr_slot = host->plat->vreg_data;
1813 if (!curr_slot)
1814 goto out;
1815
1816 curr_vdd_reg = curr_slot->vdd_data;
1817 curr_vccq_reg = curr_slot->vccq_data;
1818 curr_vddp_reg = curr_slot->vddp_data;
1819
1820 if (is_init) {
1821 /*
1822 * Get the regulator handle from voltage regulator framework
1823 * and then try to set the voltage level for the regulator
1824 */
1825 if (curr_vdd_reg) {
1826 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
1827 if (rc)
1828 goto out;
1829 }
1830 if (curr_vccq_reg) {
1831 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
1832 if (rc)
1833 goto vdd_reg_deinit;
1834 }
1835 if (curr_vddp_reg) {
1836 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
1837 if (rc)
1838 goto vccq_reg_deinit;
1839 }
1840 goto out;
1841 } else {
1842 /* Deregister all regulators from regulator framework */
1843 goto vddp_reg_deinit;
1844 }
1845vddp_reg_deinit:
1846 if (curr_vddp_reg)
1847 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
1848vccq_reg_deinit:
1849 if (curr_vccq_reg)
1850 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
1851vdd_reg_deinit:
1852 if (curr_vdd_reg)
1853 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
1854out:
1855 return rc;
1856}
1857
1858static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
1859{
1860 int rc = 0;
1861
Subhash Jadavanicc922692011-08-01 23:05:01 +05301862 /* Put regulator in HPM (high power mode) */
1863 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
1864 if (rc < 0)
1865 goto out;
1866
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001867 if (!vreg->is_enabled) {
1868 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301869 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
1870 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001871 if (rc)
1872 goto out;
1873
1874 rc = regulator_enable(vreg->reg);
1875 if (rc) {
1876 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
1877 __func__, vreg->name, rc);
1878 goto out;
1879 }
1880 vreg->is_enabled = true;
1881 }
1882
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001883out:
1884 return rc;
1885}
1886
1887static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
1888{
1889 int rc = 0;
1890
1891 /* Never disable regulator marked as always_on */
1892 if (vreg->is_enabled && !vreg->always_on) {
1893 rc = regulator_disable(vreg->reg);
1894 if (rc) {
1895 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
1896 __func__, vreg->name, rc);
1897 goto out;
1898 }
1899 vreg->is_enabled = false;
1900
1901 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
1902 if (rc < 0)
1903 goto out;
1904
1905 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301906 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001907 if (rc)
1908 goto out;
1909 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
1910 /* Put always_on regulator in LPM (low power mode) */
1911 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
1912 if (rc < 0)
1913 goto out;
1914 }
1915out:
1916 return rc;
1917}
1918
1919static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
1920{
1921 int rc = 0, i;
1922 struct msm_mmc_slot_reg_data *curr_slot;
1923 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1924 struct msm_mmc_reg_data *vreg_table[3];
1925
1926 curr_slot = host->plat->vreg_data;
1927 if (!curr_slot)
1928 goto out;
1929
1930 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
1931 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
1932 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
1933
1934 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
1935 if (vreg_table[i]) {
1936 if (enable)
1937 rc = msmsdcc_vreg_enable(vreg_table[i]);
1938 else
1939 rc = msmsdcc_vreg_disable(vreg_table[i]);
1940 if (rc)
1941 goto out;
1942 }
1943 }
1944out:
1945 return rc;
1946}
1947
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301948static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001949{
1950 int rc = 0;
1951
1952 if (host->plat->vreg_data) {
1953 struct msm_mmc_reg_data *vddp_reg =
1954 host->plat->vreg_data->vddp_data;
1955
1956 if (vddp_reg && vddp_reg->is_enabled)
1957 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
1958 }
1959
1960 return rc;
1961}
1962
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301963static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
1964{
1965 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1966 int rc = 0;
1967
1968 if (curr_slot && curr_slot->vddp_data) {
1969 rc = msmsdcc_set_vddp_level(host,
1970 curr_slot->vddp_data->low_vol_level);
1971
1972 if (rc)
1973 pr_err("%s: %s: failed to change vddp level to %d",
1974 mmc_hostname(host->mmc), __func__,
1975 curr_slot->vddp_data->low_vol_level);
1976 }
1977
1978 return rc;
1979}
1980
1981static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
1982{
1983 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1984 int rc = 0;
1985
1986 if (curr_slot && curr_slot->vddp_data) {
1987 rc = msmsdcc_set_vddp_level(host,
1988 curr_slot->vddp_data->high_vol_level);
1989
1990 if (rc)
1991 pr_err("%s: %s: failed to change vddp level to %d",
1992 mmc_hostname(host->mmc), __func__,
1993 curr_slot->vddp_data->high_vol_level);
1994 }
1995
1996 return rc;
1997}
1998
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001999static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2000{
2001 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2002 return 1;
2003 return 0;
2004}
2005
2006static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
2007{
2008 if (enable) {
2009 if (!IS_ERR_OR_NULL(host->dfab_pclk))
2010 clk_enable(host->dfab_pclk);
2011 if (!IS_ERR(host->pclk))
2012 clk_enable(host->pclk);
2013 clk_enable(host->clk);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302014 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002015 } else {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302016 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002017 clk_disable(host->clk);
2018 if (!IS_ERR(host->pclk))
2019 clk_disable(host->pclk);
2020 if (!IS_ERR_OR_NULL(host->dfab_pclk))
2021 clk_disable(host->dfab_pclk);
2022 }
2023}
2024
2025static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2026 unsigned int req_clk)
2027{
2028 unsigned int sel_clk = -1;
2029
2030 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2031 unsigned char cnt;
2032
2033 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2034 if (host->plat->sup_clk_table[cnt] > req_clk)
2035 break;
2036 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2037 sel_clk = host->plat->sup_clk_table[cnt];
2038 break;
2039 } else
2040 sel_clk = host->plat->sup_clk_table[cnt];
2041 }
2042 } else {
2043 if ((req_clk < host->plat->msmsdcc_fmax) &&
2044 (req_clk > host->plat->msmsdcc_fmid))
2045 sel_clk = host->plat->msmsdcc_fmid;
2046 else
2047 sel_clk = req_clk;
2048 }
2049
2050 return sel_clk;
2051}
2052
2053static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2054 struct msmsdcc_host *host)
2055{
2056 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2057 return host->plat->sup_clk_table[0];
2058 else
2059 return host->plat->msmsdcc_fmin;
2060}
2061
2062static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2063 struct msmsdcc_host *host)
2064{
2065 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2066 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2067 else
2068 return host->plat->msmsdcc_fmax;
2069}
2070
2071static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302072{
2073 struct msm_mmc_gpio_data *curr;
2074 int i, rc = 0;
2075
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002076 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302077 for (i = 0; i < curr->size; i++) {
2078 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002079 if (curr->gpio[i].is_always_on &&
2080 curr->gpio[i].is_enabled)
2081 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302082 rc = gpio_request(curr->gpio[i].no,
2083 curr->gpio[i].name);
2084 if (rc) {
2085 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2086 mmc_hostname(host->mmc),
2087 curr->gpio[i].no,
2088 curr->gpio[i].name, rc);
2089 goto free_gpios;
2090 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002091 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302092 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002093 if (curr->gpio[i].is_always_on)
2094 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302095 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002096 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302097 }
2098 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002099 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302100
2101free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002102 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302103 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002104 curr->gpio[i].is_enabled = false;
2105 }
2106out:
2107 return rc;
2108}
2109
2110static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2111{
2112 struct msm_mmc_pad_data *curr;
2113 int i;
2114
2115 curr = host->plat->pin_data->pad_data;
2116 for (i = 0; i < curr->drv->size; i++) {
2117 if (enable)
2118 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2119 curr->drv->on[i].val);
2120 else
2121 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2122 curr->drv->off[i].val);
2123 }
2124
2125 for (i = 0; i < curr->pull->size; i++) {
2126 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002127 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002128 curr->pull->on[i].val);
2129 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002130 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002131 curr->pull->off[i].val);
2132 }
2133
2134 return 0;
2135}
2136
2137static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2138{
2139 int rc = 0;
2140
2141 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2142 return 0;
2143
2144 if (host->plat->pin_data->is_gpio)
2145 rc = msmsdcc_setup_gpio(host, enable);
2146 else
2147 rc = msmsdcc_setup_pad(host, enable);
2148
2149 if (!rc)
2150 host->plat->pin_data->cfg_sts = enable;
2151
2152 return rc;
2153}
2154
2155static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2156{
2157 unsigned int wakeup_irq;
2158
2159 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2160 host->plat->sdiowakeup_irq :
2161 host->core_irqres->start;
2162
2163 if (!host->irq_wake_enabled) {
2164 enable_irq_wake(wakeup_irq);
2165 host->irq_wake_enabled = true;
2166 }
2167}
2168
2169static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2170{
2171 unsigned int wakeup_irq;
2172
2173 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2174 host->plat->sdiowakeup_irq :
2175 host->core_irqres->start;
2176
2177 if (host->irq_wake_enabled) {
2178 disable_irq_wake(wakeup_irq);
2179 host->irq_wake_enabled = false;
2180 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302181}
2182
San Mehat9d2bd732009-09-22 16:44:22 -07002183static void
2184msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2185{
2186 struct msmsdcc_host *host = mmc_priv(mmc);
2187 u32 clk = 0, pwr = 0;
2188 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002189 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002190 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002191
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002192 DBG(host, "ios->clock = %u\n", ios->clock);
Sahitya Tummala7a892482011-01-18 11:22:49 +05302193
San Mehat9d2bd732009-09-22 16:44:22 -07002194 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002195 spin_lock_irqsave(&host->lock, flags);
2196 if (!host->clks_on) {
2197 msmsdcc_setup_clocks(host, true);
2198 host->clks_on = 1;
2199 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2200 if (!host->plat->sdiowakeup_irq) {
2201 writel_relaxed(host->mci_irqenable,
2202 host->base + MMCIMASK0);
2203 mb();
2204 if (host->plat->cfg_mpm_sdiowakeup &&
2205 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2206 host->plat->cfg_mpm_sdiowakeup(
2207 mmc_dev(mmc), SDC_DAT1_DISWAKE);
2208 msmsdcc_disable_irq_wake(host);
2209 } else if (!(mmc->pm_flags &
2210 MMC_PM_WAKE_SDIO_IRQ)) {
2211 writel_relaxed(host->mci_irqenable,
2212 host->base + MMCIMASK0);
2213 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05302214 } else {
2215 writel_relaxed(host->mci_irqenable,
2216 host->base + MMCIMASK0);
2217 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002218 }
San Mehat9d2bd732009-09-22 16:44:22 -07002219 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002220 spin_unlock_irqrestore(&host->lock, flags);
2221
2222 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2223 /*
2224 * For DDR50 mode, controller needs clock rate to be
2225 * double than what is required on the SD card CLK pin.
2226 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302227 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002228 /*
2229 * Make sure that we don't double the clock if
2230 * doubled clock rate is already set
2231 */
2232 if (!host->ddr_doubled_clk_rate ||
2233 (host->ddr_doubled_clk_rate &&
2234 (host->ddr_doubled_clk_rate != ios->clock))) {
2235 host->ddr_doubled_clk_rate =
2236 msmsdcc_get_sup_clk_rate(
2237 host, (ios->clock * 2));
2238 clock = host->ddr_doubled_clk_rate;
2239 }
2240 } else {
2241 host->ddr_doubled_clk_rate = 0;
2242 }
2243
2244 if (clock != host->clk_rate) {
2245 rc = clk_set_rate(host->clk, clock);
2246 if (rc < 0)
2247 pr_debug("%s: failed to set clk rate %u\n",
2248 mmc_hostname(mmc), clock);
2249 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302250 host->reg_write_delay =
2251 (1 + ((3 * USEC_PER_SEC) /
2252 (host->clk_rate ? host->clk_rate :
2253 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002254 }
2255 /*
2256 * give atleast 2 MCLK cycles delay for clocks
2257 * and SDCC core to stabilize
2258 */
2259 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002260 clk |= MCI_CLK_ENABLE;
2261 }
2262
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002263 if (ios->bus_width == MMC_BUS_WIDTH_8)
2264 clk |= MCI_CLK_WIDEBUS_8;
2265 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2266 clk |= MCI_CLK_WIDEBUS_4;
2267 else
2268 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002269
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002270 if (msmsdcc_is_pwrsave(host))
2271 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002272
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002273 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002274
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002275 host->tuning_needed = 0;
2276 /*
2277 * Select the controller timing mode according
2278 * to current bus speed mode
2279 */
2280 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2281 (ios->timing == MMC_TIMING_UHS_SDR50)) {
2282 clk |= (4 << 14);
2283 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302284 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002285 clk |= (3 << 14);
2286 } else {
2287 clk |= (2 << 14); /* feedback clock */
2288 }
2289
2290 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2291 clk |= (2 << 23);
2292
2293 if (host->io_pad_pwr_switch)
2294 clk |= IO_PAD_PWR_SWITCH;
2295
2296 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
San Mehat9d2bd732009-09-22 16:44:22 -07002297 pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002298 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2299 pwr |= msmsdcc_setup_vreg(host, !!ios->vdd);
San Mehat9d2bd732009-09-22 16:44:22 -07002300
2301 switch (ios->power_mode) {
2302 case MMC_POWER_OFF:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002303 htc_pwrsink_set(PWRSINK_SDCARD, 0);
2304 if (!host->sdcc_irq_disabled) {
2305 if (host->plat->cfg_mpm_sdiowakeup)
2306 host->plat->cfg_mpm_sdiowakeup(
2307 mmc_dev(mmc), SDC_DAT1_DISABLE);
2308 disable_irq(host->core_irqres->start);
2309 host->sdcc_irq_disabled = 1;
2310 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302311 /*
2312 * As VDD pad rail is always on, set low voltage for VDD
2313 * pad rail when slot is unused (when card is not present
2314 * or during system suspend).
2315 */
2316 msmsdcc_set_vddp_low_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002317 msmsdcc_setup_pins(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002318 break;
2319 case MMC_POWER_UP:
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302320 /* writing PWR_UP bit is redundant */
San Mehat9d2bd732009-09-22 16:44:22 -07002321 pwr |= MCI_PWR_UP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002322 if (host->sdcc_irq_disabled) {
2323 if (host->plat->cfg_mpm_sdiowakeup)
2324 host->plat->cfg_mpm_sdiowakeup(
2325 mmc_dev(mmc), SDC_DAT1_ENABLE);
2326 enable_irq(host->core_irqres->start);
2327 host->sdcc_irq_disabled = 0;
2328 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302329 msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002330 msmsdcc_setup_pins(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07002331 break;
2332 case MMC_POWER_ON:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002333 htc_pwrsink_set(PWRSINK_SDCARD, 100);
San Mehat9d2bd732009-09-22 16:44:22 -07002334 pwr |= MCI_PWR_ON;
2335 break;
2336 }
2337
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002338 spin_lock_irqsave(&host->lock, flags);
2339 if (!host->clks_on) {
2340 /* force the clocks to be on */
2341 msmsdcc_setup_clocks(host, true);
2342 /*
2343 * give atleast 2 MCLK cycles delay for clocks
2344 * and SDCC core to stabilize
2345 */
2346 msmsdcc_delay(host);
2347 }
2348 writel_relaxed(clk, host->base + MMCICLOCK);
2349 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002350
2351 if (host->pwr != pwr) {
2352 host->pwr = pwr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002353 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302354 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002355 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002356 if (!host->clks_on) {
2357 /* force the clocks to be off */
2358 msmsdcc_setup_clocks(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002359 }
2360
2361 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
2362 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2363 if (!host->plat->sdiowakeup_irq) {
2364 writel_relaxed(MCI_SDIOINTMASK,
2365 host->base + MMCIMASK0);
2366 mb();
2367 if (host->plat->cfg_mpm_sdiowakeup &&
2368 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2369 host->plat->cfg_mpm_sdiowakeup(
2370 mmc_dev(mmc), SDC_DAT1_ENWAKE);
2371 msmsdcc_enable_irq_wake(host);
2372 } else if (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2373 writel_relaxed(0, host->base + MMCIMASK0);
2374 } else {
2375 writel_relaxed(MCI_SDIOINTMASK,
2376 host->base + MMCIMASK0);
2377 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302378 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002379 }
2380 msmsdcc_setup_clocks(host, false);
2381 host->clks_on = 0;
2382 }
San Mehat4adbbcc2009-11-08 13:00:37 -08002383 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002384}
2385
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002386int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2387{
2388 struct msmsdcc_host *host = mmc_priv(mmc);
2389 u32 clk;
2390
2391 clk = readl_relaxed(host->base + MMCICLOCK);
2392 pr_debug("Changing to pwr_save=%d", pwrsave);
2393 if (pwrsave && msmsdcc_is_pwrsave(host))
2394 clk |= MCI_CLK_PWRSAVE;
2395 else
2396 clk &= ~MCI_CLK_PWRSAVE;
2397 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302398 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002399
2400 return 0;
2401}
2402
2403static int msmsdcc_get_ro(struct mmc_host *mmc)
2404{
2405 int status = -ENOSYS;
2406 struct msmsdcc_host *host = mmc_priv(mmc);
2407
2408 if (host->plat->wpswitch) {
2409 status = host->plat->wpswitch(mmc_dev(mmc));
2410 } else if (host->plat->wpswitch_gpio) {
2411 status = gpio_request(host->plat->wpswitch_gpio,
2412 "SD_WP_Switch");
2413 if (status) {
2414 pr_err("%s: %s: Failed to request GPIO %d\n",
2415 mmc_hostname(mmc), __func__,
2416 host->plat->wpswitch_gpio);
2417 } else {
2418 status = gpio_direction_input(
2419 host->plat->wpswitch_gpio);
2420 if (!status) {
2421 /*
2422 * Wait for atleast 300ms as debounce
2423 * time for GPIO input to stabilize.
2424 */
2425 msleep(300);
2426 status = gpio_get_value_cansleep(
2427 host->plat->wpswitch_gpio);
2428 status ^= !host->plat->wpswitch_polarity;
2429 }
2430 gpio_free(host->plat->wpswitch_gpio);
2431 }
2432 }
2433
2434 if (status < 0)
2435 status = -ENOSYS;
2436 pr_debug("%s: Card read-only status %d\n", __func__, status);
2437
2438 return status;
2439}
2440
2441#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002442static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2443{
2444 struct msmsdcc_host *host = mmc_priv(mmc);
2445 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002446
2447 if (enable) {
2448 spin_lock_irqsave(&host->lock, flags);
2449 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
2450 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
2451 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2452 spin_unlock_irqrestore(&host->lock, flags);
2453 } else {
2454 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
2455 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
2456 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2457 }
2458 mb();
2459}
2460#endif /* CONFIG_MMC_MSM_SDIO_SUPPORT */
2461
2462#ifdef CONFIG_PM_RUNTIME
2463static int msmsdcc_enable(struct mmc_host *mmc)
2464{
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302465 int rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002466 struct device *dev = mmc->parent;
2467
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302468 if (dev->power.runtime_status == RPM_SUSPENDING) {
2469 if (mmc->suspend_task == current) {
2470 pm_runtime_get_noresume(dev);
2471 goto out;
2472 }
2473 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002474
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302475 rc = pm_runtime_get_sync(dev);
2476
2477 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002478 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2479 __func__, rc);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302480 return rc;
2481 }
2482out:
2483 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002484}
2485
2486static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2487{
2488 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302489 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002490
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302491 if (host->plat->disable_runtime_pm)
2492 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002493 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO)
2494 return -ENOTSUPP;
2495
2496 rc = pm_runtime_put_sync(mmc->parent);
2497
2498 if (rc < 0)
2499 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2500 __func__, rc);
2501 return rc;
2502}
2503#else
2504#define msmsdcc_enable NULL
2505#define msmsdcc_disable NULL
2506#endif
2507
2508static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2509 struct mmc_ios *ios)
2510{
2511 struct msmsdcc_host *host = mmc_priv(mmc);
2512 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302513 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002514
2515 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2516 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302517 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002518 goto out;
2519 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2520 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302521 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002522 goto out;
2523 }
San Mehat9d2bd732009-09-22 16:44:22 -07002524
2525 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002526 /*
2527 * If we are here means voltage switch from high voltage to
2528 * low voltage is required
2529 */
2530
2531 /*
2532 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2533 * register until they become all zeros.
2534 */
2535 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302536 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002537 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2538 mmc_hostname(mmc), __func__);
2539 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002540 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002541
2542 /* Stop SD CLK output. */
2543 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2544 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302545 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002546 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002547
2548 /*
2549 * Switch VDDPX from high voltage to low voltage
2550 * to change the VDD of the SD IO pads.
2551 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302552 rc = msmsdcc_set_vddp_low_vol(host);
2553 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002554 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002555
2556 spin_lock_irqsave(&host->lock, flags);
2557 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2558 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302559 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002560 host->io_pad_pwr_switch = 1;
2561 spin_unlock_irqrestore(&host->lock, flags);
2562
2563 /* Wait 5 ms for the voltage regulater in the card to become stable. */
2564 usleep_range(5000, 5500);
2565
2566 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302567 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002568 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2569 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302570 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002571 spin_unlock_irqrestore(&host->lock, flags);
2572
2573 /*
2574 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
2575 * don't become all ones within 1 ms then a Voltage Switch
2576 * sequence has failed and a power cycle to the card is required.
2577 * Otherwise Voltage Switch sequence is completed successfully.
2578 */
2579 usleep_range(1000, 1500);
2580
2581 spin_lock_irqsave(&host->lock, flags);
2582 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
2583 != (0xF << 1)) {
2584 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
2585 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302586 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002587 goto out_unlock;
2588 }
2589
2590out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302591 /* Enable PWRSAVE */
2592 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2593 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002594 spin_unlock_irqrestore(&host->lock, flags);
2595out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302596 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002597}
2598
2599static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2600 u8 phase);
2601/* Initialize the DLL (Programmable Delay Line ) */
2602static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
2603{
2604 int rc = 0;
2605 u32 wait_timeout;
2606
2607 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
2608 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2609 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2610
2611 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
2612 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2613 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2614
2615 msmsdcc_delay(host);
2616
2617 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
2618 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2619 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2620
2621 /* Initialize the phase to 0 */
2622 rc = msmsdcc_config_cm_sdc4_dll_phase(host, 0);
2623 if (rc)
2624 goto out;
2625
2626 wait_timeout = 1000;
2627 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
2628 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
2629 /* max. wait for 1 sec for LOCK bit to be set */
2630 if (--wait_timeout == 0) {
2631 pr_err("%s: %s: DLL failed to lock at phase: %d",
2632 mmc_hostname(host->mmc), __func__, 0);
2633 rc = -1;
2634 goto out;
2635 }
2636 /* wait for 1ms */
2637 usleep_range(1000, 1500);
2638 }
2639out:
2640 return rc;
2641}
2642
2643/*
2644 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
2645 * calibration sequence. This function should be called before
2646 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
2647 * commands (CMD17/CMD18).
2648 */
2649static void msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
2650{
2651 /* Set CDR_EN bit to 1. */
2652 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) |
2653 MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2654
2655 /* Set CDR_EXT_EN bit to 0. */
2656 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2657 & ~MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2658
2659 /* Set CK_OUT_EN bit to 0. */
2660 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2661 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2662
2663 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2664 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)
2665 ;
2666
2667 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2668 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2669 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2670
2671 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register is 1. */
2672 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN))
2673 ;
2674}
2675
2676static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2677 u8 phase)
2678{
2679 int rc = 0;
2680 u32 mclk_freq = 0;
2681 u32 wait_timeout;
2682
2683 /* Set CDR_EN bit to 0. */
2684 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2685 & ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2686
2687 /* Set CDR_EXT_EN bit to 1. */
2688 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2689 | MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2690
2691 /* Program the MCLK value to MCLK_FREQ bit field */
2692 if (host->clk_rate <= 112000000)
2693 mclk_freq = 0;
2694 else if (host->clk_rate <= 125000000)
2695 mclk_freq = 1;
2696 else if (host->clk_rate <= 137000000)
2697 mclk_freq = 2;
2698 else if (host->clk_rate <= 150000000)
2699 mclk_freq = 3;
2700 else if (host->clk_rate <= 162000000)
2701 mclk_freq = 4;
2702 else if (host->clk_rate <= 175000000)
2703 mclk_freq = 5;
2704 else if (host->clk_rate <= 187000000)
2705 mclk_freq = 6;
2706 else if (host->clk_rate <= 200000000)
2707 mclk_freq = 7;
2708
2709 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2710 & ~(7 << 24)) | (mclk_freq << 24)),
2711 host->base + MCI_DLL_CONFIG);
2712
2713 /* Set CK_OUT_EN bit to 0. */
2714 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2715 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2716
2717 /* Set DLL_EN bit to 1. */
2718 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2719 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
2720
2721 wait_timeout = 1000;
2722 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2723 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN) {
2724 /* max. wait for 1 sec for LOCK bit for be set */
2725 if (--wait_timeout == 0) {
2726 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 0",
2727 mmc_hostname(host->mmc), __func__, phase);
2728 rc = -1;
2729 goto out;
2730 }
2731 /* wait for 1ms */
2732 usleep_range(1000, 1500);
2733 }
2734
2735 /*
2736 * Write the selected DLL clock output phase (0 ... 15)
2737 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
2738 */
2739 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2740 & ~(0xF << 20)) | (phase << 20)),
2741 host->base + MCI_DLL_CONFIG);
2742
2743 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2744 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2745 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2746
2747 wait_timeout = 1000;
2748 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
2749 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)) {
2750 /* max. wait for 1 sec for LOCK bit for be set */
2751 if (--wait_timeout == 0) {
2752 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 1",
2753 mmc_hostname(host->mmc), __func__, phase);
2754 rc = -1;
2755 goto out;
2756 }
2757 /* wait for 1ms */
2758 usleep_range(1000, 1500);
2759 }
2760out:
2761 return rc;
2762}
2763
2764static int msmsdcc_execute_tuning(struct mmc_host *mmc)
2765{
2766 struct msmsdcc_host *host = mmc_priv(mmc);
2767 u8 phase;
2768 u8 *data_buf;
2769 u8 tuned_phases[16], tuned_phase_cnt = 0;
2770 int rc = 0;
2771
2772 /* Tuning is only required for SDR50 & SDR104 modes */
2773 if (!host->tuning_needed) {
2774 rc = 0;
2775 goto out;
2776 }
2777
2778 host->cmd19_tuning_in_progress = 1;
2779 /*
2780 * Make sure that clock is always enabled when DLL
2781 * tuning is in progress. Keeping PWRSAVE ON may
2782 * turn off the clock. So let's disable the PWRSAVE
2783 * here and re-enable it once tuning is completed.
2784 */
2785 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2786 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302787 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002788 /* first of all reset the tuning block */
2789 rc = msmsdcc_init_cm_sdc4_dll(host);
2790 if (rc)
2791 goto out;
2792
2793 data_buf = kmalloc(64, GFP_KERNEL);
2794 if (!data_buf) {
2795 rc = -ENOMEM;
2796 goto out;
2797 }
2798
2799 phase = 0;
2800 do {
2801 struct mmc_command cmd = {0};
2802 struct mmc_data data = {0};
2803 struct mmc_request mrq = {
2804 .cmd = &cmd,
2805 .data = &data
2806 };
2807 struct scatterlist sg;
2808
2809 /* set the phase in delay line hw block */
2810 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2811 if (rc)
2812 goto kfree;
2813
2814 cmd.opcode = MMC_SEND_TUNING_BLOCK;
2815 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
2816
2817 data.blksz = 64;
2818 data.blocks = 1;
2819 data.flags = MMC_DATA_READ;
2820 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
2821
2822 data.sg = &sg;
2823 data.sg_len = 1;
2824 sg_init_one(&sg, data_buf, 64);
2825 memset(data_buf, 0, 64);
2826 mmc_wait_for_req(mmc, &mrq);
2827
2828 if (!cmd.error && !data.error &&
2829 !memcmp(data_buf, cmd19_tuning_block, 64)) {
2830 /* tuning is successful with this tuning point */
2831 tuned_phases[tuned_phase_cnt++] = phase;
2832 }
2833 } while (++phase < 16);
2834
2835 kfree(data_buf);
2836
2837 if (tuned_phase_cnt) {
2838 tuned_phase_cnt--;
2839 tuned_phase_cnt = (tuned_phase_cnt * 3) / 4;
2840 phase = tuned_phases[tuned_phase_cnt];
2841 /*
2842 * Finally set the selected phase in delay
2843 * line hw block.
2844 */
2845 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2846 if (rc)
2847 goto out;
2848 } else {
2849 /* tuning failed */
2850 rc = -EAGAIN;
2851 pr_err("%s: %s: no tuning point found",
2852 mmc_hostname(mmc), __func__);
2853 }
2854 goto out;
2855
2856kfree:
2857 kfree(data_buf);
2858out:
2859 /* re-enable PWESAVE */
2860 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2861 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302862 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002863 host->cmd19_tuning_in_progress = 0;
2864 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07002865}
2866
2867static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002868 .enable = msmsdcc_enable,
2869 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07002870 .request = msmsdcc_request,
2871 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002872 .get_ro = msmsdcc_get_ro,
2873#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002874 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002875#endif
2876 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
2877 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07002878};
2879
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002880static unsigned int
2881msmsdcc_slot_status(struct msmsdcc_host *host)
2882{
2883 int status;
2884 unsigned int gpio_no = host->plat->status_gpio;
2885
2886 status = gpio_request(gpio_no, "SD_HW_Detect");
2887 if (status) {
2888 pr_err("%s: %s: Failed to request GPIO %d\n",
2889 mmc_hostname(host->mmc), __func__, gpio_no);
2890 } else {
2891 status = gpio_direction_input(gpio_no);
2892 if (!status)
2893 status = !gpio_get_value_cansleep(gpio_no);
2894 gpio_free(gpio_no);
2895 }
2896 return status;
2897}
2898
San Mehat9d2bd732009-09-22 16:44:22 -07002899static void
2900msmsdcc_check_status(unsigned long data)
2901{
2902 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
2903 unsigned int status;
2904
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002905 if (host->plat->status || host->plat->status_gpio) {
2906 if (host->plat->status)
2907 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07002908 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002909 status = msmsdcc_slot_status(host);
2910
2911 host->eject = !status;
2912 if (status ^ host->oldstat) {
2913 pr_info("%s: Slot status change detected (%d -> %d)\n",
2914 mmc_hostname(host->mmc), host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07002915 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002916 }
2917 host->oldstat = status;
2918 } else {
2919 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07002920 }
San Mehat9d2bd732009-09-22 16:44:22 -07002921}
2922
2923static irqreturn_t
2924msmsdcc_platform_status_irq(int irq, void *dev_id)
2925{
2926 struct msmsdcc_host *host = dev_id;
2927
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002928 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07002929 msmsdcc_check_status((unsigned long) host);
2930 return IRQ_HANDLED;
2931}
2932
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002933static irqreturn_t
2934msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
2935{
2936 struct msmsdcc_host *host = dev_id;
2937
2938 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
2939 spin_lock(&host->lock);
2940 if (!host->sdio_irq_disabled) {
2941 disable_irq_nosync(irq);
2942 if (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2943 wake_lock(&host->sdio_wlock);
2944 msmsdcc_disable_irq_wake(host);
2945 }
2946 host->sdio_irq_disabled = 1;
2947 }
2948 if (host->plat->is_sdio_al_client) {
2949 if (!host->clks_on) {
2950 msmsdcc_setup_clocks(host, true);
2951 host->clks_on = 1;
2952 }
2953 if (host->sdcc_irq_disabled) {
2954 writel_relaxed(host->mci_irqenable,
2955 host->base + MMCIMASK0);
2956 mb();
2957 enable_irq(host->core_irqres->start);
2958 host->sdcc_irq_disabled = 0;
2959 }
2960 wake_lock(&host->sdio_wlock);
2961 }
2962 spin_unlock(&host->lock);
2963
2964 return IRQ_HANDLED;
2965}
2966
San Mehat9d2bd732009-09-22 16:44:22 -07002967static void
2968msmsdcc_status_notify_cb(int card_present, void *dev_id)
2969{
2970 struct msmsdcc_host *host = dev_id;
2971
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002972 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07002973 card_present);
2974 msmsdcc_check_status((unsigned long) host);
2975}
2976
San Mehat9d2bd732009-09-22 16:44:22 -07002977static int
2978msmsdcc_init_dma(struct msmsdcc_host *host)
2979{
2980 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
2981 host->dma.host = host;
2982 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07002983 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07002984
2985 if (!host->dmares)
2986 return -ENODEV;
2987
2988 host->dma.nc = dma_alloc_coherent(NULL,
2989 sizeof(struct msmsdcc_nc_dmadata),
2990 &host->dma.nc_busaddr,
2991 GFP_KERNEL);
2992 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07002993 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07002994 return -ENOMEM;
2995 }
2996 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
2997 host->dma.cmd_busaddr = host->dma.nc_busaddr;
2998 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
2999 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
3000 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07003001 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07003002
3003 return 0;
3004}
3005
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003006#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
3007/**
3008 * Allocate and Connect a SDCC peripheral's SPS endpoint
3009 *
3010 * This function allocates endpoint context and
3011 * connect it with memory endpoint by calling
3012 * appropriate SPS driver APIs.
3013 *
3014 * Also registers a SPS callback function with
3015 * SPS driver
3016 *
3017 * This function should only be called once typically
3018 * during driver probe.
3019 *
3020 * @host - Pointer to sdcc host structure
3021 * @ep - Pointer to sps endpoint data structure
3022 * @is_produce - 1 means Producer endpoint
3023 * 0 means Consumer endpoint
3024 *
3025 * @return - 0 if successful else negative value.
3026 *
3027 */
3028static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
3029 struct msmsdcc_sps_ep_conn_data *ep,
3030 bool is_producer)
3031{
3032 int rc = 0;
3033 struct sps_pipe *sps_pipe_handle;
3034 struct sps_connect *sps_config = &ep->config;
3035 struct sps_register_event *sps_event = &ep->event;
3036
3037 /* Allocate endpoint context */
3038 sps_pipe_handle = sps_alloc_endpoint();
3039 if (!sps_pipe_handle) {
3040 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
3041 mmc_hostname(host->mmc), is_producer);
3042 rc = -ENOMEM;
3043 goto out;
3044 }
3045
3046 /* Get default connection configuration for an endpoint */
3047 rc = sps_get_config(sps_pipe_handle, sps_config);
3048 if (rc) {
3049 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
3050 " rc=%d", mmc_hostname(host->mmc),
3051 (u32)sps_pipe_handle, rc);
3052 goto get_config_err;
3053 }
3054
3055 /* Modify the default connection configuration */
3056 if (is_producer) {
3057 /*
3058 * For SDCC producer transfer, source should be
3059 * SDCC peripheral where as destination should
3060 * be system memory.
3061 */
3062 sps_config->source = host->sps.bam_handle;
3063 sps_config->destination = SPS_DEV_HANDLE_MEM;
3064 /* Producer pipe will handle this connection */
3065 sps_config->mode = SPS_MODE_SRC;
3066 sps_config->options =
3067 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3068 } else {
3069 /*
3070 * For SDCC consumer transfer, source should be
3071 * system memory where as destination should
3072 * SDCC peripheral
3073 */
3074 sps_config->source = SPS_DEV_HANDLE_MEM;
3075 sps_config->destination = host->sps.bam_handle;
3076 sps_config->mode = SPS_MODE_DEST;
3077 sps_config->options =
3078 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3079 }
3080
3081 /* Producer pipe index */
3082 sps_config->src_pipe_index = host->sps.src_pipe_index;
3083 /* Consumer pipe index */
3084 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
3085 /*
3086 * This event thresold value is only significant for BAM-to-BAM
3087 * transfer. It's ignored for BAM-to-System mode transfer.
3088 */
3089 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05303090
3091 /* Allocate maximum descriptor fifo size */
3092 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
3093 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003094 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
3095 sps_config->desc.size,
3096 &sps_config->desc.phys_base,
3097 GFP_KERNEL);
3098
Pratibhasagar V00b94332011-10-18 14:57:27 +05303099 if (!sps_config->desc.base) {
3100 rc = -ENOMEM;
3101 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3102 , mmc_hostname(host->mmc));
3103 goto get_config_err;
3104 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003105 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3106
3107 /* Establish connection between peripheral and memory endpoint */
3108 rc = sps_connect(sps_pipe_handle, sps_config);
3109 if (rc) {
3110 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3111 " rc=%d", mmc_hostname(host->mmc),
3112 (u32)sps_pipe_handle, rc);
3113 goto sps_connect_err;
3114 }
3115
3116 sps_event->mode = SPS_TRIGGER_CALLBACK;
3117 sps_event->options = SPS_O_EOT;
3118 sps_event->callback = msmsdcc_sps_complete_cb;
3119 sps_event->xfer_done = NULL;
3120 sps_event->user = (void *)host;
3121
3122 /* Register callback event for EOT (End of transfer) event. */
3123 rc = sps_register_event(sps_pipe_handle, sps_event);
3124 if (rc) {
3125 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3126 " rc=%d", mmc_hostname(host->mmc),
3127 (u32)sps_pipe_handle, rc);
3128 goto reg_event_err;
3129 }
3130 /* Now save the sps pipe handle */
3131 ep->pipe_handle = sps_pipe_handle;
3132 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3133 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3134 __func__, is_producer ? "READ" : "WRITE",
3135 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3136 goto out;
3137
3138reg_event_err:
3139 sps_disconnect(sps_pipe_handle);
3140sps_connect_err:
3141 dma_free_coherent(mmc_dev(host->mmc),
3142 sps_config->desc.size,
3143 sps_config->desc.base,
3144 sps_config->desc.phys_base);
3145get_config_err:
3146 sps_free_endpoint(sps_pipe_handle);
3147out:
3148 return rc;
3149}
3150
3151/**
3152 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3153 *
3154 * This function disconnect endpoint and deallocates
3155 * endpoint context.
3156 *
3157 * This function should only be called once typically
3158 * during driver remove.
3159 *
3160 * @host - Pointer to sdcc host structure
3161 * @ep - Pointer to sps endpoint data structure
3162 *
3163 */
3164static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3165 struct msmsdcc_sps_ep_conn_data *ep)
3166{
3167 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3168 struct sps_connect *sps_config = &ep->config;
3169 struct sps_register_event *sps_event = &ep->event;
3170
3171 sps_event->xfer_done = NULL;
3172 sps_event->callback = NULL;
3173 sps_register_event(sps_pipe_handle, sps_event);
3174 sps_disconnect(sps_pipe_handle);
3175 dma_free_coherent(mmc_dev(host->mmc),
3176 sps_config->desc.size,
3177 sps_config->desc.base,
3178 sps_config->desc.phys_base);
3179 sps_free_endpoint(sps_pipe_handle);
3180}
3181
3182/**
3183 * Reset SDCC peripheral's SPS endpoint
3184 *
3185 * This function disconnects an endpoint.
3186 *
3187 * This function should be called for reseting
3188 * SPS endpoint when data transfer error is
3189 * encountered during data transfer. This
3190 * can be considered as soft reset to endpoint.
3191 *
3192 * This function should only be called if
3193 * msmsdcc_sps_init() is already called.
3194 *
3195 * @host - Pointer to sdcc host structure
3196 * @ep - Pointer to sps endpoint data structure
3197 *
3198 * @return - 0 if successful else negative value.
3199 */
3200static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3201 struct msmsdcc_sps_ep_conn_data *ep)
3202{
3203 int rc = 0;
3204 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3205
3206 rc = sps_disconnect(sps_pipe_handle);
3207 if (rc) {
3208 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3209 " rc=%d", mmc_hostname(host->mmc), __func__,
3210 (u32)sps_pipe_handle, rc);
3211 goto out;
3212 }
3213 out:
3214 return rc;
3215}
3216
3217/**
3218 * Restore SDCC peripheral's SPS endpoint
3219 *
3220 * This function connects an endpoint.
3221 *
3222 * This function should be called for restoring
3223 * SPS endpoint after data transfer error is
3224 * encountered during data transfer. This
3225 * can be considered as soft reset to endpoint.
3226 *
3227 * This function should only be called if
3228 * msmsdcc_sps_reset_ep() is called before.
3229 *
3230 * @host - Pointer to sdcc host structure
3231 * @ep - Pointer to sps endpoint data structure
3232 *
3233 * @return - 0 if successful else negative value.
3234 */
3235static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3236 struct msmsdcc_sps_ep_conn_data *ep)
3237{
3238 int rc = 0;
3239 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3240 struct sps_connect *sps_config = &ep->config;
3241 struct sps_register_event *sps_event = &ep->event;
3242
3243 /* Establish connection between peripheral and memory endpoint */
3244 rc = sps_connect(sps_pipe_handle, sps_config);
3245 if (rc) {
3246 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3247 " rc=%d", mmc_hostname(host->mmc), __func__,
3248 (u32)sps_pipe_handle, rc);
3249 goto out;
3250 }
3251
3252 /* Register callback event for EOT (End of transfer) event. */
3253 rc = sps_register_event(sps_pipe_handle, sps_event);
3254 if (rc) {
3255 pr_err("%s: %s: sps_register_event() failed!!!"
3256 " pipe_handle=0x%x, rc=%d",
3257 mmc_hostname(host->mmc), __func__,
3258 (u32)sps_pipe_handle, rc);
3259 goto reg_event_err;
3260 }
3261 goto out;
3262
3263reg_event_err:
3264 sps_disconnect(sps_pipe_handle);
3265out:
3266 return rc;
3267}
3268
3269/**
3270 * Initialize SPS HW connected with SDCC core
3271 *
3272 * This function register BAM HW resources with
3273 * SPS driver and then initialize 2 SPS endpoints
3274 *
3275 * This function should only be called once typically
3276 * during driver probe.
3277 *
3278 * @host - Pointer to sdcc host structure
3279 *
3280 * @return - 0 if successful else negative value.
3281 *
3282 */
3283static int msmsdcc_sps_init(struct msmsdcc_host *host)
3284{
3285 int rc = 0;
3286 struct sps_bam_props bam = {0};
3287
3288 host->bam_base = ioremap(host->bam_memres->start,
3289 resource_size(host->bam_memres));
3290 if (!host->bam_base) {
3291 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3292 " size=0x%x", mmc_hostname(host->mmc),
3293 host->bam_memres->start,
3294 (host->bam_memres->end -
3295 host->bam_memres->start));
3296 rc = -ENOMEM;
3297 goto out;
3298 }
3299
3300 bam.phys_addr = host->bam_memres->start;
3301 bam.virt_addr = host->bam_base;
3302 /*
3303 * This event thresold value is only significant for BAM-to-BAM
3304 * transfer. It's ignored for BAM-to-System mode transfer.
3305 */
3306 bam.event_threshold = 0x10; /* Pipe event threshold */
3307 /*
3308 * This threshold controls when the BAM publish
3309 * the descriptor size on the sideband interface.
3310 * SPS HW will only be used when
3311 * data transfer size > MCI_FIFOSIZE (64 bytes).
3312 * PIO mode will be used when
3313 * data transfer size < MCI_FIFOSIZE (64 bytes).
3314 * So set this thresold value to 64 bytes.
3315 */
3316 bam.summing_threshold = 64;
3317 /* SPS driver wll handle the SDCC BAM IRQ */
3318 bam.irq = (u32)host->bam_irqres->start;
3319 bam.manage = SPS_BAM_MGR_LOCAL;
3320
3321 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3322 (u32)bam.phys_addr);
3323 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3324 (u32)bam.virt_addr);
3325
3326 /* Register SDCC Peripheral BAM device to SPS driver */
3327 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3328 if (rc) {
3329 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3330 mmc_hostname(host->mmc), rc);
3331 goto reg_bam_err;
3332 }
3333 pr_info("%s: BAM device registered. bam_handle=0x%x",
3334 mmc_hostname(host->mmc), host->sps.bam_handle);
3335
3336 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3337 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3338
3339 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3340 SPS_PROD_PERIPHERAL);
3341 if (rc)
3342 goto sps_reset_err;
3343 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3344 SPS_CONS_PERIPHERAL);
3345 if (rc)
3346 goto cons_conn_err;
3347
3348 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3349 mmc_hostname(host->mmc),
3350 (unsigned long long)host->bam_memres->start,
3351 (unsigned int)host->bam_irqres->start);
3352 goto out;
3353
3354cons_conn_err:
3355 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3356sps_reset_err:
3357 sps_deregister_bam_device(host->sps.bam_handle);
3358reg_bam_err:
3359 iounmap(host->bam_base);
3360out:
3361 return rc;
3362}
3363
3364/**
3365 * De-initialize SPS HW connected with SDCC core
3366 *
3367 * This function deinitialize SPS endpoints and then
3368 * deregisters BAM resources from SPS driver.
3369 *
3370 * This function should only be called once typically
3371 * during driver remove.
3372 *
3373 * @host - Pointer to sdcc host structure
3374 *
3375 */
3376static void msmsdcc_sps_exit(struct msmsdcc_host *host)
3377{
3378 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
3379 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3380 sps_deregister_bam_device(host->sps.bam_handle);
3381 iounmap(host->bam_base);
3382}
3383#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
3384
3385static ssize_t
3386show_polling(struct device *dev, struct device_attribute *attr, char *buf)
3387{
3388 struct mmc_host *mmc = dev_get_drvdata(dev);
3389 struct msmsdcc_host *host = mmc_priv(mmc);
3390 int poll;
3391 unsigned long flags;
3392
3393 spin_lock_irqsave(&host->lock, flags);
3394 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
3395 spin_unlock_irqrestore(&host->lock, flags);
3396
3397 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
3398}
3399
3400static ssize_t
3401set_polling(struct device *dev, struct device_attribute *attr,
3402 const char *buf, size_t count)
3403{
3404 struct mmc_host *mmc = dev_get_drvdata(dev);
3405 struct msmsdcc_host *host = mmc_priv(mmc);
3406 int value;
3407 unsigned long flags;
3408
3409 sscanf(buf, "%d", &value);
3410
3411 spin_lock_irqsave(&host->lock, flags);
3412 if (value) {
3413 mmc->caps |= MMC_CAP_NEEDS_POLL;
3414 mmc_detect_change(host->mmc, 0);
3415 } else {
3416 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3417 }
3418#ifdef CONFIG_HAS_EARLYSUSPEND
3419 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
3420#endif
3421 spin_unlock_irqrestore(&host->lock, flags);
3422 return count;
3423}
3424
3425static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
3426 show_polling, set_polling);
3427static struct attribute *dev_attrs[] = {
3428 &dev_attr_polling.attr,
3429 NULL,
3430};
3431static struct attribute_group dev_attr_grp = {
3432 .attrs = dev_attrs,
3433};
3434
3435#ifdef CONFIG_HAS_EARLYSUSPEND
3436static void msmsdcc_early_suspend(struct early_suspend *h)
3437{
3438 struct msmsdcc_host *host =
3439 container_of(h, struct msmsdcc_host, early_suspend);
3440 unsigned long flags;
3441
3442 spin_lock_irqsave(&host->lock, flags);
3443 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
3444 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3445 spin_unlock_irqrestore(&host->lock, flags);
3446};
3447static void msmsdcc_late_resume(struct early_suspend *h)
3448{
3449 struct msmsdcc_host *host =
3450 container_of(h, struct msmsdcc_host, early_suspend);
3451 unsigned long flags;
3452
3453 if (host->polling_enabled) {
3454 spin_lock_irqsave(&host->lock, flags);
3455 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
3456 mmc_detect_change(host->mmc, 0);
3457 spin_unlock_irqrestore(&host->lock, flags);
3458 }
3459};
3460#endif
3461
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303462void msmsdcc_print_regs(const char *name, void __iomem *base,
3463 unsigned int no_of_regs)
3464{
3465 unsigned int i;
3466
3467 if (!base)
3468 return;
3469 pr_info("===== %s: Register Dumps @base=0x%x =====\n",
3470 name, (u32)base);
3471 for (i = 0; i < no_of_regs; i = i + 4) {
3472 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x.\n", i*4,
3473 (u32)readl_relaxed(base + i*4),
3474 (u32)readl_relaxed(base + ((i+1)*4)),
3475 (u32)readl_relaxed(base + ((i+2)*4)),
3476 (u32)readl_relaxed(base + ((i+3)*4)));
3477 }
3478}
3479
3480static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
3481{
3482 /* Dump current state of SDCC clocks, power and irq */
3483 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
3484 (host->pwr ? "ON" : "OFF"));
3485 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
3486 mmc_hostname(host->mmc),
3487 (host->clks_on ? "ON" : "OFF"),
3488 (u32)clk_get_rate(host->clk));
3489 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
3490 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
3491
3492 /* Now dump SDCC registers. Don't print FIFO registers */
3493 if (host->clks_on)
3494 msmsdcc_print_regs("SDCC-CORE", host->base, 28);
3495
3496 if (host->curr.data) {
3497 if (msmsdcc_check_dma_op_req(host->curr.data))
3498 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
3499 else if (host->is_dma_mode)
3500 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
3501 mmc_hostname(host->mmc), host->dma.busy,
3502 host->dma.channel, host->dma.crci);
3503 else if (host->is_sps_mode)
3504 pr_info("%s: SPS mode: busy=%d\n",
3505 mmc_hostname(host->mmc), host->sps.busy);
3506
3507 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
3508 mmc_hostname(host->mmc), host->curr.xfer_size,
3509 host->curr.data_xfered, host->curr.xfer_remain);
3510 pr_info("%s: got_dataend=%d, prog_enable=%d,"
3511 " wait_for_auto_prog_done=%d,"
3512 " got_auto_prog_done=%d\n",
3513 mmc_hostname(host->mmc), host->curr.got_dataend,
3514 host->prog_enable, host->curr.wait_for_auto_prog_done,
3515 host->curr.got_auto_prog_done);
3516 }
3517
3518}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003519static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
3520{
3521 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3522 struct mmc_request *mrq;
3523 unsigned long flags;
3524
3525 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003526 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003527 pr_info("%s: %s: dummy CMD52 timeout\n",
3528 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003529 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003530 }
3531
3532 mrq = host->curr.mrq;
3533
3534 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303535 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
3536 mrq->cmd->opcode);
3537 msmsdcc_dump_sdcc_state(host);
3538
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003539 if (!mrq->cmd->error)
3540 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303541 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003542 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003543 if (mrq->data && !mrq->data->error)
3544 mrq->data->error = -ETIMEDOUT;
3545 host->curr.data_xfered = 0;
3546 if (host->dma.sg && host->is_dma_mode) {
3547 msm_dmov_stop_cmd(host->dma.channel,
3548 &host->dma.hdr, 0);
3549 } else if (host->sps.sg && host->is_sps_mode) {
3550 /* Stop current SPS transfer */
3551 msmsdcc_sps_exit_curr_xfer(host);
3552 } else {
3553 msmsdcc_reset_and_restore(host);
3554 msmsdcc_stop_data(host);
3555 if (mrq->data && mrq->data->stop)
3556 msmsdcc_start_command(host,
3557 mrq->data->stop, 0);
3558 else
3559 msmsdcc_request_end(host, mrq);
3560 }
3561 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05303562 host->prog_enable = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003563 msmsdcc_reset_and_restore(host);
3564 msmsdcc_request_end(host, mrq);
3565 }
3566 }
3567 spin_unlock_irqrestore(&host->lock, flags);
3568}
3569
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303570static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
3571{
3572 int i, ret;
3573 struct mmc_platform_data *pdata;
3574 struct device_node *np = dev->of_node;
3575 u32 bus_width = 0;
3576 u32 *clk_table;
3577 int clk_table_len;
3578 u32 *sup_voltages;
3579 int sup_volt_len;
3580
3581 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
3582 if (!pdata) {
3583 dev_err(dev, "could not allocate memory for platform data\n");
3584 goto err;
3585 }
3586
3587 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
3588 if (bus_width == 8) {
3589 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
3590 } else if (bus_width == 4) {
3591 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
3592 } else {
3593 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
3594 pdata->mmc_bus_width = 0;
3595 }
3596
3597 if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
3598 size_t sz;
3599 sz = sup_volt_len / sizeof(*sup_voltages);
3600 if (sz > 0) {
3601 sup_voltages = devm_kzalloc(dev,
3602 sz * sizeof(*sup_voltages), GFP_KERNEL);
3603 if (!sup_voltages) {
3604 dev_err(dev, "No memory for supported voltage\n");
3605 goto err;
3606 }
3607
3608 ret = of_property_read_u32_array(np,
3609 "qcom,sdcc-sup-voltages", sup_voltages, sz);
3610 if (ret < 0) {
3611 dev_err(dev, "error while reading voltage"
3612 "ranges %d\n", ret);
3613 goto err;
3614 }
3615 } else {
3616 dev_err(dev, "No supported voltages\n");
3617 goto err;
3618 }
3619 for (i = 0; i < sz; i += 2) {
3620 u32 mask;
3621
3622 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
3623 sup_voltages[i + 1]);
3624 if (!mask)
3625 dev_err(dev, "Invalide voltage range %d\n", i);
3626 pdata->ocr_mask |= mask;
3627 }
3628 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
3629 } else {
3630 dev_err(dev, "Supported voltage range not specified\n");
3631 }
3632
3633 if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
3634 size_t sz;
3635 sz = clk_table_len / sizeof(*clk_table);
3636
3637 if (sz > 0) {
3638 clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
3639 GFP_KERNEL);
3640 if (!clk_table) {
3641 dev_err(dev, "No memory for clock table\n");
3642 goto err;
3643 }
3644
3645 ret = of_property_read_u32_array(np,
3646 "qcom,sdcc-clk-rates", clk_table, sz);
3647 if (ret < 0) {
3648 dev_err(dev, "error while reading clk"
3649 "table %d\n", ret);
3650 goto err;
3651 }
3652 } else {
3653 dev_err(dev, "clk_table not specified\n");
3654 goto err;
3655 }
3656 pdata->sup_clk_table = clk_table;
3657 pdata->sup_clk_cnt = sz;
3658 } else {
3659 dev_err(dev, "Supported clock rates not specified\n");
3660 }
3661
3662 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
3663 pdata->nonremovable = true;
3664 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
3665 pdata->disable_cmd23 = true;
3666
3667 return pdata;
3668err:
3669 return NULL;
3670}
3671
San Mehat9d2bd732009-09-22 16:44:22 -07003672static int
3673msmsdcc_probe(struct platform_device *pdev)
3674{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303675 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07003676 struct msmsdcc_host *host;
3677 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003678 unsigned long flags;
3679 struct resource *core_irqres = NULL;
3680 struct resource *bam_irqres = NULL;
3681 struct resource *core_memres = NULL;
3682 struct resource *dml_memres = NULL;
3683 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07003684 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07003685 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05303686 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003687 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07003688
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303689 if (pdev->dev.of_node) {
3690 plat = msmsdcc_populate_pdata(&pdev->dev);
3691 of_property_read_u32((&pdev->dev)->of_node,
3692 "cell-index", &pdev->id);
3693 } else {
3694 plat = pdev->dev.platform_data;
3695 }
3696
San Mehat9d2bd732009-09-22 16:44:22 -07003697 /* must have platform data */
3698 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003699 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003700 ret = -EINVAL;
3701 goto out;
3702 }
3703
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003704 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07003705 return -EINVAL;
3706
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05303707 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
3708 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
3709 return -EINVAL;
3710 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003711
San Mehat9d2bd732009-09-22 16:44:22 -07003712 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003713 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003714 return -ENXIO;
3715 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303716 if (pdev->dev.of_node) {
3717 /*
3718 * Device tree iomem resources are only accessible by index.
3719 * index = 0 -> SDCC register interface
3720 * index = 1 -> DML register interface
3721 * index = 2 -> BAM register interface
3722 * IRQ resources:
3723 * index = 0 -> SDCC IRQ
3724 * index = 1 -> BAM IRQ
3725 */
3726 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
3727 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
3728 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
3729 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
3730 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
3731 } else {
3732 for (i = 0; i < pdev->num_resources; i++) {
3733 if (pdev->resource[i].flags & IORESOURCE_MEM) {
3734 if (!strncmp(pdev->resource[i].name,
3735 "sdcc_dml_addr",
3736 sizeof("sdcc_dml_addr")))
3737 dml_memres = &pdev->resource[i];
3738 else if (!strncmp(pdev->resource[i].name,
3739 "sdcc_bam_addr",
3740 sizeof("sdcc_bam_addr")))
3741 bam_memres = &pdev->resource[i];
3742 else
3743 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07003744
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303745 }
3746 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
3747 if (!strncmp(pdev->resource[i].name,
3748 "sdcc_bam_irq",
3749 sizeof("sdcc_bam_irq")))
3750 bam_irqres = &pdev->resource[i];
3751 else
3752 core_irqres = &pdev->resource[i];
3753 }
3754 if (pdev->resource[i].flags & IORESOURCE_DMA) {
3755 if (!strncmp(pdev->resource[i].name,
3756 "sdcc_dma_chnl",
3757 sizeof("sdcc_dma_chnl")))
3758 dmares = &pdev->resource[i];
3759 else if (!strncmp(pdev->resource[i].name,
3760 "sdcc_dma_crci",
3761 sizeof("sdcc_dma_crci")))
3762 dma_crci_res = &pdev->resource[i];
3763 }
Krishna Konda25786ec2011-07-25 16:21:36 -07003764 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003765 }
3766
3767 if (!core_irqres || !core_memres) {
3768 pr_err("%s: Invalid sdcc core resource\n", __func__);
3769 return -ENXIO;
3770 }
3771
3772 /*
3773 * Both BAM and DML memory resource should be preset.
3774 * BAM IRQ resource should also be present.
3775 */
3776 if ((bam_memres && !dml_memres) ||
3777 (!bam_memres && dml_memres) ||
3778 ((bam_memres && dml_memres) && !bam_irqres)) {
3779 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003780 return -ENXIO;
3781 }
3782
3783 /*
3784 * Setup our host structure
3785 */
San Mehat9d2bd732009-09-22 16:44:22 -07003786 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
3787 if (!mmc) {
3788 ret = -ENOMEM;
3789 goto out;
3790 }
3791
3792 host = mmc_priv(mmc);
3793 host->pdev_id = pdev->id;
3794 host->plat = plat;
3795 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08003796 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05303797
3798 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003799 host->is_sps_mode = 1;
3800 else if (dmares)
3801 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07003802
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003803 host->base = ioremap(core_memres->start,
3804 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07003805 if (!host->base) {
3806 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003807 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003808 }
3809
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003810 host->core_irqres = core_irqres;
3811 host->bam_irqres = bam_irqres;
3812 host->core_memres = core_memres;
3813 host->dml_memres = dml_memres;
3814 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07003815 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07003816 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07003817 spin_lock_init(&host->lock);
3818
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003819#ifdef CONFIG_MMC_EMBEDDED_SDIO
3820 if (plat->embedded_sdio)
3821 mmc_set_embedded_sdio_data(mmc,
3822 &plat->embedded_sdio->cis,
3823 &plat->embedded_sdio->cccr,
3824 plat->embedded_sdio->funcs,
3825 plat->embedded_sdio->num_funcs);
3826#endif
3827
Sahitya Tummala62612cf2010-12-08 15:03:03 +05303828 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
3829 (unsigned long)host);
3830
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003831 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
3832 (unsigned long)host);
3833 if (host->is_dma_mode) {
3834 /* Setup DMA */
3835 ret = msmsdcc_init_dma(host);
3836 if (ret)
3837 goto ioremap_free;
3838 } else {
3839 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003840 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003841 }
3842
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003843 /*
3844 * Setup SDCC clock if derived from Dayatona
3845 * fabric core clock.
3846 */
3847 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07003848 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003849 if (!IS_ERR(host->dfab_pclk)) {
3850 /* Set the clock rate to 64MHz for max. performance */
3851 ret = clk_set_rate(host->dfab_pclk, 64000000);
3852 if (ret)
3853 goto dfab_pclk_put;
3854 ret = clk_enable(host->dfab_pclk);
3855 if (ret)
3856 goto dfab_pclk_put;
3857 } else
3858 goto dma_free;
3859 }
3860
3861 /*
3862 * Setup main peripheral bus clock
3863 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003864 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003865 if (!IS_ERR(host->pclk)) {
3866 ret = clk_enable(host->pclk);
3867 if (ret)
3868 goto pclk_put;
3869
3870 host->pclk_rate = clk_get_rate(host->pclk);
3871 }
3872
3873 /*
3874 * Setup SDC MMC clock
3875 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003876 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07003877 if (IS_ERR(host->clk)) {
3878 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003879 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07003880 }
3881
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003882 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
3883 if (ret) {
3884 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
3885 goto clk_put;
3886 }
3887
3888 ret = clk_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003889 if (ret)
3890 goto clk_put;
3891
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003892 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303893 if (!host->clk_rate)
3894 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05303895
3896 /*
3897 * Lookup the Controller Version, to identify the supported features
3898 * Version number read as 0 would indicate SDCC3 or earlier versions
3899 */
3900 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
3901 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
3902 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303903 /*
3904 * Set the register write delay according to min. clock frequency
3905 * supported and update later when the host->clk_rate changes.
3906 */
3907 host->reg_write_delay =
3908 (1 + ((3 * USEC_PER_SEC) /
3909 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003910
3911 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05303912 /* Apply Hard reset to SDCC to put it in power on default state */
3913 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003914
3915 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07003916 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003917 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07003918 goto clk_disable;
3919 }
3920
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003921
3922 /* Clocks has to be running before accessing SPS/DML HW blocks */
3923 if (host->is_sps_mode) {
3924 /* Initialize SPS */
3925 ret = msmsdcc_sps_init(host);
3926 if (ret)
3927 goto vreg_deinit;
3928 /* Initialize DML */
3929 ret = msmsdcc_dml_init(host);
3930 if (ret)
3931 goto sps_exit;
3932 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05303933 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07003934
San Mehat9d2bd732009-09-22 16:44:22 -07003935 /*
3936 * Setup MMC host structure
3937 */
3938 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003939 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
3940 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003941 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003942 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
3943 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07003944
San Mehat9d2bd732009-09-22 16:44:22 -07003945 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05303946 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05303947
3948 /*
3949 * If we send the CMD23 before multi block write/read command
3950 * then we need not to send CMD12 at the end of the transfer.
3951 * If we don't send the CMD12 then only way to detect the PROG_DONE
3952 * status is to use the AUTO_PROG_DONE status provided by SDCC4
3953 * controller. So let's enable the CMD23 for SDCC4 only.
3954 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05303955 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05303956 mmc->caps |= MMC_CAP_CMD23;
3957
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003958 mmc->caps |= plat->uhs_caps;
3959 /*
3960 * XPC controls the maximum current in the default speed mode of SDXC
3961 * card. XPC=0 means 100mA (max.) but speed class is not supported.
3962 * XPC=1 means 150mA (max.) and speed class is supported.
3963 */
3964 if (plat->xpc_cap)
3965 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
3966 MMC_CAP_SET_XPC_180);
3967
3968 if (plat->nonremovable)
3969 mmc->caps |= MMC_CAP_NONREMOVABLE;
3970#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
3971 mmc->caps |= MMC_CAP_SDIO_IRQ;
3972#endif
3973
3974 if (plat->is_sdio_al_client)
3975 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07003976
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05303977 mmc->max_segs = msmsdcc_get_nr_sg(host);
3978 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
3979 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07003980
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05303981 mmc->max_req_size = MMC_MAX_REQ_SIZE;
3982 mmc->max_seg_size = msmsdcc_get_max_seg_size(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003983
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003984 writel_relaxed(0, host->base + MMCIMASK0);
3985 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -07003986
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003987 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
3988 mb();
3989 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07003990
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003991 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
3992 DRIVER_NAME " (cmd)", host);
3993 if (ret)
3994 goto dml_exit;
3995
3996 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
3997 DRIVER_NAME " (pio)", host);
3998 if (ret)
3999 goto irq_free;
4000
4001 /*
4002 * Enable SDCC IRQ only when host is powered on. Otherwise, this
4003 * IRQ is un-necessarily being monitored by MPM (Modem power
4004 * management block) during idle-power collapse. The MPM will be
4005 * configured to monitor the DATA1 GPIO line with level-low trigger
4006 * and thus depending on the GPIO status, it prevents TCXO shutdown
4007 * during idle-power collapse.
4008 */
4009 disable_irq(core_irqres->start);
4010 host->sdcc_irq_disabled = 1;
4011
4012 if (plat->sdiowakeup_irq) {
4013 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4014 mmc_hostname(mmc));
4015 ret = request_irq(plat->sdiowakeup_irq,
4016 msmsdcc_platform_sdiowakeup_irq,
4017 IRQF_SHARED | IRQF_TRIGGER_LOW,
4018 DRIVER_NAME "sdiowakeup", host);
4019 if (ret) {
4020 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
4021 plat->sdiowakeup_irq, ret);
4022 goto pio_irq_free;
4023 } else {
4024 spin_lock_irqsave(&host->lock, flags);
4025 if (!host->sdio_irq_disabled) {
4026 disable_irq_nosync(plat->sdiowakeup_irq);
4027 host->sdio_irq_disabled = 1;
4028 }
4029 spin_unlock_irqrestore(&host->lock, flags);
4030 }
4031 }
4032
4033 if (plat->cfg_mpm_sdiowakeup) {
4034 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4035 mmc_hostname(mmc));
4036 }
4037
4038 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
4039 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004040 /*
4041 * Setup card detect change
4042 */
4043
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004044 if (plat->status || plat->status_gpio) {
4045 if (plat->status)
4046 host->oldstat = plat->status(mmc_dev(host->mmc));
4047 else
4048 host->oldstat = msmsdcc_slot_status(host);
4049 host->eject = !host->oldstat;
4050 }
San Mehat9d2bd732009-09-22 16:44:22 -07004051
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004052 if (plat->status_irq) {
4053 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07004054 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004055 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07004056 DRIVER_NAME " (slot)",
4057 host);
4058 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004059 pr_err("Unable to get slot IRQ %d (%d)\n",
4060 plat->status_irq, ret);
4061 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004062 }
4063 } else if (plat->register_status_notify) {
4064 plat->register_status_notify(msmsdcc_status_notify_cb, host);
4065 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004066 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07004067 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004068
4069 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004070
4071 ret = pm_runtime_set_active(&(pdev)->dev);
4072 if (ret < 0)
4073 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
4074 __func__, ret);
4075 /*
4076 * There is no notion of suspend/resume for SD/MMC/SDIO
4077 * cards. So host can be suspended/resumed with out
4078 * worrying about its children.
4079 */
4080 pm_suspend_ignore_children(&(pdev)->dev, true);
4081
4082 /*
4083 * MMC/SD/SDIO bus suspend/resume operations are defined
4084 * only for the slots that will be used for non-removable
4085 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
4086 * defined. Otherwise, they simply become card removal and
4087 * insertion events during suspend and resume respectively.
4088 * Hence, enable run-time PM only for slots for which bus
4089 * suspend/resume operations are defined.
4090 */
4091#ifdef CONFIG_MMC_UNSAFE_RESUME
4092 /*
4093 * If this capability is set, MMC core will enable/disable host
4094 * for every claim/release operation on a host. We use this
4095 * notification to increment/decrement runtime pm usage count.
4096 */
4097 mmc->caps |= MMC_CAP_DISABLE;
4098 pm_runtime_enable(&(pdev)->dev);
4099#else
4100 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
4101 mmc->caps |= MMC_CAP_DISABLE;
4102 pm_runtime_enable(&(pdev)->dev);
4103 }
4104#endif
4105 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
4106 (unsigned long)host);
4107
San Mehat9d2bd732009-09-22 16:44:22 -07004108 mmc_add_host(mmc);
4109
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004110#ifdef CONFIG_HAS_EARLYSUSPEND
4111 host->early_suspend.suspend = msmsdcc_early_suspend;
4112 host->early_suspend.resume = msmsdcc_late_resume;
4113 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
4114 register_early_suspend(&host->early_suspend);
4115#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004116
Krishna Konda25786ec2011-07-25 16:21:36 -07004117 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
4118 " dmacrcri %d\n", mmc_hostname(mmc),
4119 (unsigned long long)core_memres->start,
4120 (unsigned int) core_irqres->start,
4121 (unsigned int) plat->status_irq, host->dma.channel,
4122 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004123
4124 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
4125 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
4126 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
4127 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
4128 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
4129 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
4130 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
4131 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
4132 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
4133 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
4134 host->eject);
4135 pr_info("%s: Power save feature enable = %d\n",
4136 mmc_hostname(mmc), msmsdcc_pwrsave);
4137
Krishna Konda25786ec2011-07-25 16:21:36 -07004138 if (host->is_dma_mode && host->dma.channel != -1
4139 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004140 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004141 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004142 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004143 mmc_hostname(mmc), host->dma.cmd_busaddr,
4144 host->dma.cmdptr_busaddr);
4145 } else if (host->is_sps_mode) {
4146 pr_info("%s: SPS-BAM data transfer mode available\n",
4147 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004148 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004149 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004150
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004151#if defined(CONFIG_DEBUG_FS)
4152 msmsdcc_dbg_createhost(host);
4153#endif
4154 if (!plat->status_irq) {
4155 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
4156 if (ret)
4157 goto platform_irq_free;
4158 }
San Mehat9d2bd732009-09-22 16:44:22 -07004159 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004160
4161 platform_irq_free:
4162 del_timer_sync(&host->req_tout_timer);
4163 pm_runtime_disable(&(pdev)->dev);
4164 pm_runtime_set_suspended(&(pdev)->dev);
4165
4166 if (plat->status_irq)
4167 free_irq(plat->status_irq, host);
4168 sdiowakeup_irq_free:
4169 wake_lock_destroy(&host->sdio_suspend_wlock);
4170 if (plat->sdiowakeup_irq)
4171 free_irq(plat->sdiowakeup_irq, host);
4172 pio_irq_free:
4173 if (plat->sdiowakeup_irq)
4174 wake_lock_destroy(&host->sdio_wlock);
4175 free_irq(core_irqres->start, host);
4176 irq_free:
4177 free_irq(core_irqres->start, host);
4178 dml_exit:
4179 if (host->is_sps_mode)
4180 msmsdcc_dml_exit(host);
4181 sps_exit:
4182 if (host->is_sps_mode)
4183 msmsdcc_sps_exit(host);
4184 vreg_deinit:
4185 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07004186 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004187 clk_disable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004188 clk_put:
4189 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004190 pclk_disable:
4191 if (!IS_ERR(host->pclk))
4192 clk_disable(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07004193 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004194 if (!IS_ERR(host->pclk))
4195 clk_put(host->pclk);
4196 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4197 clk_disable(host->dfab_pclk);
4198 dfab_pclk_put:
4199 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4200 clk_put(host->dfab_pclk);
4201 dma_free:
4202 if (host->is_dma_mode) {
4203 if (host->dmares)
4204 dma_free_coherent(NULL,
4205 sizeof(struct msmsdcc_nc_dmadata),
4206 host->dma.nc, host->dma.nc_busaddr);
4207 }
4208 ioremap_free:
4209 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07004210 host_free:
4211 mmc_free_host(mmc);
4212 out:
4213 return ret;
4214}
4215
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004216static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07004217{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004218 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4219 struct mmc_platform_data *plat;
4220 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004221
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004222 if (!mmc)
4223 return -ENXIO;
4224
4225 if (pm_runtime_suspended(&(pdev)->dev))
4226 pm_runtime_resume(&(pdev)->dev);
4227
4228 host = mmc_priv(mmc);
4229
4230 DBG(host, "Removing SDCC device = %d\n", pdev->id);
4231 plat = host->plat;
4232
4233 if (!plat->status_irq)
4234 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
4235
4236 del_timer_sync(&host->req_tout_timer);
4237 tasklet_kill(&host->dma_tlet);
4238 tasklet_kill(&host->sps.tlet);
4239 mmc_remove_host(mmc);
4240
4241 if (plat->status_irq)
4242 free_irq(plat->status_irq, host);
4243
4244 wake_lock_destroy(&host->sdio_suspend_wlock);
4245 if (plat->sdiowakeup_irq) {
4246 wake_lock_destroy(&host->sdio_wlock);
4247 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
4248 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07004249 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004250
4251 free_irq(host->core_irqres->start, host);
4252 free_irq(host->core_irqres->start, host);
4253
4254 clk_put(host->clk);
4255 if (!IS_ERR(host->pclk))
4256 clk_put(host->pclk);
4257 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4258 clk_put(host->dfab_pclk);
4259
4260 msmsdcc_vreg_init(host, false);
4261
4262 if (host->is_dma_mode) {
4263 if (host->dmares)
4264 dma_free_coherent(NULL,
4265 sizeof(struct msmsdcc_nc_dmadata),
4266 host->dma.nc, host->dma.nc_busaddr);
4267 }
4268
4269 if (host->is_sps_mode) {
4270 msmsdcc_dml_exit(host);
4271 msmsdcc_sps_exit(host);
4272 }
4273
4274 iounmap(host->base);
4275 mmc_free_host(mmc);
4276
4277#ifdef CONFIG_HAS_EARLYSUSPEND
4278 unregister_early_suspend(&host->early_suspend);
4279#endif
4280 pm_runtime_disable(&(pdev)->dev);
4281 pm_runtime_set_suspended(&(pdev)->dev);
4282
4283 return 0;
4284}
4285
4286#ifdef CONFIG_MSM_SDIO_AL
4287int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4288{
4289 struct msmsdcc_host *host = mmc_priv(mmc);
4290 unsigned long flags;
4291
4292 spin_lock_irqsave(&host->lock, flags);
4293 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
4294 enable ? "En" : "Dis");
4295
4296 if (enable) {
4297 if (!host->sdcc_irq_disabled) {
4298 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05304299 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004300 host->sdcc_irq_disabled = 1;
4301 }
4302
4303 if (host->clks_on) {
4304 msmsdcc_setup_clocks(host, false);
4305 host->clks_on = 0;
4306 }
4307
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304308 if (host->plat->sdio_lpm_gpio_setup &&
4309 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004310 spin_unlock_irqrestore(&host->lock, flags);
4311 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
4312 spin_lock_irqsave(&host->lock, flags);
4313 host->sdio_gpio_lpm = 1;
4314 }
4315
4316 if (host->sdio_irq_disabled) {
4317 msmsdcc_enable_irq_wake(host);
4318 enable_irq(host->plat->sdiowakeup_irq);
4319 host->sdio_irq_disabled = 0;
4320 }
4321 } else {
4322 if (!host->sdio_irq_disabled) {
4323 disable_irq_nosync(host->plat->sdiowakeup_irq);
4324 host->sdio_irq_disabled = 1;
4325 msmsdcc_disable_irq_wake(host);
4326 }
4327
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304328 if (host->plat->sdio_lpm_gpio_setup &&
4329 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004330 spin_unlock_irqrestore(&host->lock, flags);
4331 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
4332 spin_lock_irqsave(&host->lock, flags);
4333 host->sdio_gpio_lpm = 0;
4334 }
4335
4336 if (!host->clks_on) {
4337 msmsdcc_setup_clocks(host, true);
4338 host->clks_on = 1;
4339 }
4340
4341 if (host->sdcc_irq_disabled) {
4342 writel_relaxed(host->mci_irqenable,
4343 host->base + MMCIMASK0);
4344 mb();
4345 enable_irq(host->core_irqres->start);
4346 host->sdcc_irq_disabled = 0;
4347 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004348 }
4349 spin_unlock_irqrestore(&host->lock, flags);
4350 return 0;
4351}
4352#else
4353int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4354{
4355 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004356}
4357#endif
4358
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004359#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07004360static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004361msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004362{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004363 struct mmc_host *mmc = dev_get_drvdata(dev);
4364 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07004365 int rc = 0;
4366
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004367 if (host->plat->is_sdio_al_client)
4368 return 0;
4369
Sahitya Tummala7661a452011-07-18 13:28:35 +05304370 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004371 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004372 host->sdcc_suspending = 1;
4373 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07004374
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004375 /*
4376 * If the clocks are already turned off by SDIO clients (as
4377 * part of LPM), then clocks should be turned on before
4378 * calling mmc_suspend_host() because mmc_suspend_host might
4379 * send some commands to the card. The clocks will be turned
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304380 * off again after mmc_suspend_host. Thus for SDIO
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004381 * cards, clocks will be turned on before mmc_suspend_host
4382 * and turned off after mmc_suspend_host.
4383 */
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304384 if (mmc->card && mmc_card_sdio(mmc->card)) {
4385 mmc->ios.clock = host->clk_rate;
4386 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4387 }
San Mehat9d2bd732009-09-22 16:44:22 -07004388
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004389 /*
4390 * MMC core thinks that host is disabled by now since
4391 * runtime suspend is scheduled after msmsdcc_disable()
4392 * is called. Thus, MMC core will try to enable the host
4393 * while suspending it. This results in a synchronous
4394 * runtime resume request while in runtime suspending
4395 * context and hence inorder to complete this resume
4396 * requet, it will wait for suspend to be complete,
4397 * but runtime suspend also can not proceed further
4398 * until the host is resumed. Thus, it leads to a hang.
4399 * Hence, increase the pm usage count before suspending
4400 * the host so that any resume requests after this will
4401 * simple become pm usage counter increment operations.
4402 */
4403 pm_runtime_get_noresume(dev);
4404 rc = mmc_suspend_host(mmc);
4405 pm_runtime_put_noidle(dev);
4406
4407 if (!rc) {
4408 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
4409 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ)) {
4410 disable_irq(host->core_irqres->start);
4411 host->sdcc_irq_disabled = 1;
4412
4413 /*
4414 * If MMC core level suspend is not supported,
4415 * turn off clocks to allow deep sleep (TCXO
4416 * shutdown).
4417 */
4418 mmc->ios.clock = 0;
4419 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4420 enable_irq(host->core_irqres->start);
4421 host->sdcc_irq_disabled = 0;
4422
4423 if (host->plat->sdiowakeup_irq) {
4424 host->sdio_irq_disabled = 0;
4425 msmsdcc_enable_irq_wake(host);
4426 enable_irq(host->plat->sdiowakeup_irq);
4427 }
4428 }
4429 }
4430 host->sdcc_suspending = 0;
4431 mmc->suspend_task = NULL;
4432 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
4433 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004434 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304435 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004436 return rc;
4437}
4438
4439static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004440msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004441{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004442 struct mmc_host *mmc = dev_get_drvdata(dev);
4443 struct msmsdcc_host *host = mmc_priv(mmc);
4444 unsigned long flags;
4445
4446 if (host->plat->is_sdio_al_client)
4447 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07004448
Sahitya Tummala7661a452011-07-18 13:28:35 +05304449 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004450 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004451 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
4452 if (host->sdcc_irq_disabled) {
4453 enable_irq(host->core_irqres->start);
4454 host->sdcc_irq_disabled = 0;
4455 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304456 mmc->ios.clock = host->clk_rate;
4457 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07004458
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304459 spin_lock_irqsave(&host->lock, flags);
4460 writel_relaxed(host->mci_irqenable,
4461 host->base + MMCIMASK0);
4462 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07004463
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304464 if ((mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) &&
4465 !host->sdio_irq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004466 if (host->plat->sdiowakeup_irq) {
4467 disable_irq_nosync(
4468 host->plat->sdiowakeup_irq);
4469 msmsdcc_disable_irq_wake(host);
4470 host->sdio_irq_disabled = 1;
4471 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304472 }
San Mehat9d2bd732009-09-22 16:44:22 -07004473
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304474 spin_unlock_irqrestore(&host->lock, flags);
4475 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004476
4477 mmc_resume_host(mmc);
4478
4479 /*
4480 * FIXME: Clearing of flags must be handled in clients
4481 * resume handler.
4482 */
4483 spin_lock_irqsave(&host->lock, flags);
4484 mmc->pm_flags = 0;
4485 spin_unlock_irqrestore(&host->lock, flags);
4486
4487 /*
4488 * After resuming the host wait for sometime so that
4489 * the SDIO work will be processed.
4490 */
4491 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO)) {
4492 if ((host->plat->cfg_mpm_sdiowakeup ||
4493 host->plat->sdiowakeup_irq) &&
4494 wake_lock_active(&host->sdio_wlock))
4495 wake_lock_timeout(&host->sdio_wlock, 1);
4496 }
4497
4498 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004499 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304500 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004501 return 0;
4502}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004503
4504static int msmsdcc_runtime_idle(struct device *dev)
4505{
4506 struct mmc_host *mmc = dev_get_drvdata(dev);
4507 struct msmsdcc_host *host = mmc_priv(mmc);
4508
4509 if (host->plat->is_sdio_al_client)
4510 return 0;
4511
4512 /* Idle timeout is not configurable for now */
4513 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
4514
4515 return -EAGAIN;
4516}
4517
4518static int msmsdcc_pm_suspend(struct device *dev)
4519{
4520 struct mmc_host *mmc = dev_get_drvdata(dev);
4521 struct msmsdcc_host *host = mmc_priv(mmc);
4522 int rc = 0;
4523
4524 if (host->plat->is_sdio_al_client)
4525 return 0;
4526
4527
4528 if (host->plat->status_irq)
4529 disable_irq(host->plat->status_irq);
4530
4531 if (!pm_runtime_suspended(dev))
4532 rc = msmsdcc_runtime_suspend(dev);
4533
4534 return rc;
4535}
4536
4537static int msmsdcc_pm_resume(struct device *dev)
4538{
4539 struct mmc_host *mmc = dev_get_drvdata(dev);
4540 struct msmsdcc_host *host = mmc_priv(mmc);
4541 int rc = 0;
4542
4543 if (host->plat->is_sdio_al_client)
4544 return 0;
4545
Sahitya Tummalafb486372011-09-02 19:01:49 +05304546 if (!pm_runtime_suspended(dev))
4547 rc = msmsdcc_runtime_resume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004548 if (host->plat->status_irq) {
4549 msmsdcc_check_status((unsigned long)host);
4550 enable_irq(host->plat->status_irq);
4551 }
4552
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004553 return rc;
4554}
4555
Daniel Walker08ecfde2010-06-23 12:32:20 -07004556#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004557#define msmsdcc_runtime_suspend NULL
4558#define msmsdcc_runtime_resume NULL
4559#define msmsdcc_runtime_idle NULL
4560#define msmsdcc_pm_suspend NULL
4561#define msmsdcc_pm_resume NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07004562#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004563
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004564static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
4565 .runtime_suspend = msmsdcc_runtime_suspend,
4566 .runtime_resume = msmsdcc_runtime_resume,
4567 .runtime_idle = msmsdcc_runtime_idle,
4568 .suspend = msmsdcc_pm_suspend,
4569 .resume = msmsdcc_pm_resume,
4570};
4571
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304572static const struct of_device_id msmsdcc_dt_match[] = {
4573 {.compatible = "qcom,msm-sdcc"},
4574
4575};
4576MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
4577
San Mehat9d2bd732009-09-22 16:44:22 -07004578static struct platform_driver msmsdcc_driver = {
4579 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004580 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07004581 .driver = {
4582 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004583 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304584 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07004585 },
4586};
4587
4588static int __init msmsdcc_init(void)
4589{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004590#if defined(CONFIG_DEBUG_FS)
4591 int ret = 0;
4592 ret = msmsdcc_dbg_init();
4593 if (ret) {
4594 pr_err("Failed to create debug fs dir \n");
4595 return ret;
4596 }
4597#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004598 return platform_driver_register(&msmsdcc_driver);
4599}
4600
4601static void __exit msmsdcc_exit(void)
4602{
4603 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004604
4605#if defined(CONFIG_DEBUG_FS)
4606 debugfs_remove(debugfs_file);
4607 debugfs_remove(debugfs_dir);
4608#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004609}
4610
4611module_init(msmsdcc_init);
4612module_exit(msmsdcc_exit);
4613
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004614MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07004615MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004616
4617#if defined(CONFIG_DEBUG_FS)
4618
4619static int
4620msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
4621{
4622 file->private_data = inode->i_private;
4623 return 0;
4624}
4625
4626static ssize_t
4627msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
4628 size_t count, loff_t *ppos)
4629{
4630 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
4631 char buf[1024];
4632 int max, i;
4633
4634 i = 0;
4635 max = sizeof(buf) - 1;
4636
4637 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
4638 host->curr.cmd, host->curr.data);
4639 if (host->curr.cmd) {
4640 struct mmc_command *cmd = host->curr.cmd;
4641
4642 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
4643 cmd->opcode, cmd->arg, cmd->flags);
4644 }
4645 if (host->curr.data) {
4646 struct mmc_data *data = host->curr.data;
4647 i += scnprintf(buf + i, max - i,
4648 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
4649 data->timeout_ns, data->timeout_clks,
4650 data->blksz, data->blocks, data->error,
4651 data->flags);
4652 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
4653 host->curr.xfer_size, host->curr.xfer_remain,
4654 host->curr.data_xfered, host->dma.sg);
4655 }
4656
4657 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
4658}
4659
4660static const struct file_operations msmsdcc_dbg_state_ops = {
4661 .read = msmsdcc_dbg_state_read,
4662 .open = msmsdcc_dbg_state_open,
4663};
4664
4665static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
4666{
4667 if (debugfs_dir) {
4668 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
4669 0644, debugfs_dir, host,
4670 &msmsdcc_dbg_state_ops);
4671 }
4672}
4673
4674static int __init msmsdcc_dbg_init(void)
4675{
4676 int err;
4677
4678 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
4679 if (IS_ERR(debugfs_dir)) {
4680 err = PTR_ERR(debugfs_dir);
4681 debugfs_dir = NULL;
4682 return err;
4683 }
4684
4685 return 0;
4686}
4687#endif