blob: eeca25a6a9f394de7ffd468785c0743df0db91e8 [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
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302504static int msmsdcc_enable(struct mmc_host *mmc)
2505{
2506 struct msmsdcc_host *host = mmc_priv(mmc);
2507 unsigned long flags;
2508
2509 spin_lock_irqsave(&host->lock, flags);
2510 if (!host->clks_on) {
2511 msmsdcc_setup_clocks(host, true);
2512 host->clks_on = 1;
2513 }
2514 spin_unlock_irqrestore(&host->lock, flags);
2515
2516 return 0;
2517}
2518
2519static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2520{
2521 struct msmsdcc_host *host = mmc_priv(mmc);
2522 unsigned long flags;
2523
2524 if (mmc->card && mmc_card_sdio(mmc->card))
2525 return -ENOTSUPP;
2526
2527 spin_lock_irqsave(&host->lock, flags);
2528 if (host->clks_on) {
2529 msmsdcc_setup_clocks(host, false);
2530 host->clks_on = 0;
2531 }
2532 spin_unlock_irqrestore(&host->lock, flags);
2533
2534 return 0;
2535}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002536#endif
2537
2538static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2539 struct mmc_ios *ios)
2540{
2541 struct msmsdcc_host *host = mmc_priv(mmc);
2542 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302543 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002544
2545 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2546 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302547 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002548 goto out;
2549 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2550 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302551 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002552 goto out;
2553 }
San Mehat9d2bd732009-09-22 16:44:22 -07002554
2555 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002556 /*
2557 * If we are here means voltage switch from high voltage to
2558 * low voltage is required
2559 */
2560
2561 /*
2562 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2563 * register until they become all zeros.
2564 */
2565 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302566 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002567 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2568 mmc_hostname(mmc), __func__);
2569 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002570 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002571
2572 /* Stop SD CLK output. */
2573 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2574 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302575 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002576 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002577
2578 /*
2579 * Switch VDDPX from high voltage to low voltage
2580 * to change the VDD of the SD IO pads.
2581 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302582 rc = msmsdcc_set_vddp_low_vol(host);
2583 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002584 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002585
2586 spin_lock_irqsave(&host->lock, flags);
2587 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2588 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302589 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002590 host->io_pad_pwr_switch = 1;
2591 spin_unlock_irqrestore(&host->lock, flags);
2592
2593 /* Wait 5 ms for the voltage regulater in the card to become stable. */
2594 usleep_range(5000, 5500);
2595
2596 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302597 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002598 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2599 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302600 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002601 spin_unlock_irqrestore(&host->lock, flags);
2602
2603 /*
2604 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
2605 * don't become all ones within 1 ms then a Voltage Switch
2606 * sequence has failed and a power cycle to the card is required.
2607 * Otherwise Voltage Switch sequence is completed successfully.
2608 */
2609 usleep_range(1000, 1500);
2610
2611 spin_lock_irqsave(&host->lock, flags);
2612 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
2613 != (0xF << 1)) {
2614 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
2615 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302616 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002617 goto out_unlock;
2618 }
2619
2620out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302621 /* Enable PWRSAVE */
2622 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2623 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002624 spin_unlock_irqrestore(&host->lock, flags);
2625out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302626 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002627}
2628
2629static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2630 u8 phase);
2631/* Initialize the DLL (Programmable Delay Line ) */
2632static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
2633{
2634 int rc = 0;
2635 u32 wait_timeout;
2636
2637 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
2638 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2639 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2640
2641 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
2642 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2643 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2644
2645 msmsdcc_delay(host);
2646
2647 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
2648 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2649 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2650
2651 /* Initialize the phase to 0 */
2652 rc = msmsdcc_config_cm_sdc4_dll_phase(host, 0);
2653 if (rc)
2654 goto out;
2655
2656 wait_timeout = 1000;
2657 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
2658 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
2659 /* max. wait for 1 sec for LOCK bit to be set */
2660 if (--wait_timeout == 0) {
2661 pr_err("%s: %s: DLL failed to lock at phase: %d",
2662 mmc_hostname(host->mmc), __func__, 0);
2663 rc = -1;
2664 goto out;
2665 }
2666 /* wait for 1ms */
2667 usleep_range(1000, 1500);
2668 }
2669out:
2670 return rc;
2671}
2672
2673/*
2674 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
2675 * calibration sequence. This function should be called before
2676 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
2677 * commands (CMD17/CMD18).
2678 */
2679static void msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
2680{
2681 /* Set CDR_EN bit to 1. */
2682 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) |
2683 MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2684
2685 /* Set CDR_EXT_EN bit to 0. */
2686 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2687 & ~MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2688
2689 /* Set CK_OUT_EN bit to 0. */
2690 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2691 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2692
2693 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2694 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)
2695 ;
2696
2697 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2698 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2699 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2700
2701 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register is 1. */
2702 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN))
2703 ;
2704}
2705
2706static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2707 u8 phase)
2708{
2709 int rc = 0;
2710 u32 mclk_freq = 0;
2711 u32 wait_timeout;
2712
2713 /* Set CDR_EN bit to 0. */
2714 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2715 & ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2716
2717 /* Set CDR_EXT_EN bit to 1. */
2718 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2719 | MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2720
2721 /* Program the MCLK value to MCLK_FREQ bit field */
2722 if (host->clk_rate <= 112000000)
2723 mclk_freq = 0;
2724 else if (host->clk_rate <= 125000000)
2725 mclk_freq = 1;
2726 else if (host->clk_rate <= 137000000)
2727 mclk_freq = 2;
2728 else if (host->clk_rate <= 150000000)
2729 mclk_freq = 3;
2730 else if (host->clk_rate <= 162000000)
2731 mclk_freq = 4;
2732 else if (host->clk_rate <= 175000000)
2733 mclk_freq = 5;
2734 else if (host->clk_rate <= 187000000)
2735 mclk_freq = 6;
2736 else if (host->clk_rate <= 200000000)
2737 mclk_freq = 7;
2738
2739 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2740 & ~(7 << 24)) | (mclk_freq << 24)),
2741 host->base + MCI_DLL_CONFIG);
2742
2743 /* Set CK_OUT_EN bit to 0. */
2744 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2745 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2746
2747 /* Set DLL_EN bit to 1. */
2748 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2749 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
2750
2751 wait_timeout = 1000;
2752 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2753 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN) {
2754 /* max. wait for 1 sec for LOCK bit for be set */
2755 if (--wait_timeout == 0) {
2756 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 0",
2757 mmc_hostname(host->mmc), __func__, phase);
2758 rc = -1;
2759 goto out;
2760 }
2761 /* wait for 1ms */
2762 usleep_range(1000, 1500);
2763 }
2764
2765 /*
2766 * Write the selected DLL clock output phase (0 ... 15)
2767 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
2768 */
2769 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2770 & ~(0xF << 20)) | (phase << 20)),
2771 host->base + MCI_DLL_CONFIG);
2772
2773 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2774 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2775 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2776
2777 wait_timeout = 1000;
2778 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
2779 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)) {
2780 /* max. wait for 1 sec for LOCK bit for be set */
2781 if (--wait_timeout == 0) {
2782 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 1",
2783 mmc_hostname(host->mmc), __func__, phase);
2784 rc = -1;
2785 goto out;
2786 }
2787 /* wait for 1ms */
2788 usleep_range(1000, 1500);
2789 }
2790out:
2791 return rc;
2792}
2793
2794static int msmsdcc_execute_tuning(struct mmc_host *mmc)
2795{
2796 struct msmsdcc_host *host = mmc_priv(mmc);
2797 u8 phase;
2798 u8 *data_buf;
2799 u8 tuned_phases[16], tuned_phase_cnt = 0;
2800 int rc = 0;
2801
2802 /* Tuning is only required for SDR50 & SDR104 modes */
2803 if (!host->tuning_needed) {
2804 rc = 0;
2805 goto out;
2806 }
2807
2808 host->cmd19_tuning_in_progress = 1;
2809 /*
2810 * Make sure that clock is always enabled when DLL
2811 * tuning is in progress. Keeping PWRSAVE ON may
2812 * turn off the clock. So let's disable the PWRSAVE
2813 * here and re-enable it once tuning is completed.
2814 */
2815 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2816 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302817 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002818 /* first of all reset the tuning block */
2819 rc = msmsdcc_init_cm_sdc4_dll(host);
2820 if (rc)
2821 goto out;
2822
2823 data_buf = kmalloc(64, GFP_KERNEL);
2824 if (!data_buf) {
2825 rc = -ENOMEM;
2826 goto out;
2827 }
2828
2829 phase = 0;
2830 do {
2831 struct mmc_command cmd = {0};
2832 struct mmc_data data = {0};
2833 struct mmc_request mrq = {
2834 .cmd = &cmd,
2835 .data = &data
2836 };
2837 struct scatterlist sg;
2838
2839 /* set the phase in delay line hw block */
2840 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2841 if (rc)
2842 goto kfree;
2843
2844 cmd.opcode = MMC_SEND_TUNING_BLOCK;
2845 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
2846
2847 data.blksz = 64;
2848 data.blocks = 1;
2849 data.flags = MMC_DATA_READ;
2850 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
2851
2852 data.sg = &sg;
2853 data.sg_len = 1;
2854 sg_init_one(&sg, data_buf, 64);
2855 memset(data_buf, 0, 64);
2856 mmc_wait_for_req(mmc, &mrq);
2857
2858 if (!cmd.error && !data.error &&
2859 !memcmp(data_buf, cmd19_tuning_block, 64)) {
2860 /* tuning is successful with this tuning point */
2861 tuned_phases[tuned_phase_cnt++] = phase;
2862 }
2863 } while (++phase < 16);
2864
2865 kfree(data_buf);
2866
2867 if (tuned_phase_cnt) {
2868 tuned_phase_cnt--;
2869 tuned_phase_cnt = (tuned_phase_cnt * 3) / 4;
2870 phase = tuned_phases[tuned_phase_cnt];
2871 /*
2872 * Finally set the selected phase in delay
2873 * line hw block.
2874 */
2875 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2876 if (rc)
2877 goto out;
2878 } else {
2879 /* tuning failed */
2880 rc = -EAGAIN;
2881 pr_err("%s: %s: no tuning point found",
2882 mmc_hostname(mmc), __func__);
2883 }
2884 goto out;
2885
2886kfree:
2887 kfree(data_buf);
2888out:
2889 /* re-enable PWESAVE */
2890 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2891 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302892 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002893 host->cmd19_tuning_in_progress = 0;
2894 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07002895}
2896
2897static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002898 .enable = msmsdcc_enable,
2899 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07002900 .request = msmsdcc_request,
2901 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002902 .get_ro = msmsdcc_get_ro,
2903#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002904 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002905#endif
2906 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
2907 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07002908};
2909
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002910static unsigned int
2911msmsdcc_slot_status(struct msmsdcc_host *host)
2912{
2913 int status;
2914 unsigned int gpio_no = host->plat->status_gpio;
2915
2916 status = gpio_request(gpio_no, "SD_HW_Detect");
2917 if (status) {
2918 pr_err("%s: %s: Failed to request GPIO %d\n",
2919 mmc_hostname(host->mmc), __func__, gpio_no);
2920 } else {
2921 status = gpio_direction_input(gpio_no);
2922 if (!status)
2923 status = !gpio_get_value_cansleep(gpio_no);
2924 gpio_free(gpio_no);
2925 }
2926 return status;
2927}
2928
San Mehat9d2bd732009-09-22 16:44:22 -07002929static void
2930msmsdcc_check_status(unsigned long data)
2931{
2932 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
2933 unsigned int status;
2934
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002935 if (host->plat->status || host->plat->status_gpio) {
2936 if (host->plat->status)
2937 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07002938 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002939 status = msmsdcc_slot_status(host);
2940
2941 host->eject = !status;
2942 if (status ^ host->oldstat) {
2943 pr_info("%s: Slot status change detected (%d -> %d)\n",
2944 mmc_hostname(host->mmc), host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07002945 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002946 }
2947 host->oldstat = status;
2948 } else {
2949 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07002950 }
San Mehat9d2bd732009-09-22 16:44:22 -07002951}
2952
2953static irqreturn_t
2954msmsdcc_platform_status_irq(int irq, void *dev_id)
2955{
2956 struct msmsdcc_host *host = dev_id;
2957
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002958 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07002959 msmsdcc_check_status((unsigned long) host);
2960 return IRQ_HANDLED;
2961}
2962
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002963static irqreturn_t
2964msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
2965{
2966 struct msmsdcc_host *host = dev_id;
2967
2968 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
2969 spin_lock(&host->lock);
2970 if (!host->sdio_irq_disabled) {
2971 disable_irq_nosync(irq);
2972 if (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2973 wake_lock(&host->sdio_wlock);
2974 msmsdcc_disable_irq_wake(host);
2975 }
2976 host->sdio_irq_disabled = 1;
2977 }
2978 if (host->plat->is_sdio_al_client) {
2979 if (!host->clks_on) {
2980 msmsdcc_setup_clocks(host, true);
2981 host->clks_on = 1;
2982 }
2983 if (host->sdcc_irq_disabled) {
2984 writel_relaxed(host->mci_irqenable,
2985 host->base + MMCIMASK0);
2986 mb();
2987 enable_irq(host->core_irqres->start);
2988 host->sdcc_irq_disabled = 0;
2989 }
2990 wake_lock(&host->sdio_wlock);
2991 }
2992 spin_unlock(&host->lock);
2993
2994 return IRQ_HANDLED;
2995}
2996
San Mehat9d2bd732009-09-22 16:44:22 -07002997static void
2998msmsdcc_status_notify_cb(int card_present, void *dev_id)
2999{
3000 struct msmsdcc_host *host = dev_id;
3001
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003002 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07003003 card_present);
3004 msmsdcc_check_status((unsigned long) host);
3005}
3006
San Mehat9d2bd732009-09-22 16:44:22 -07003007static int
3008msmsdcc_init_dma(struct msmsdcc_host *host)
3009{
3010 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
3011 host->dma.host = host;
3012 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003013 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003014
3015 if (!host->dmares)
3016 return -ENODEV;
3017
3018 host->dma.nc = dma_alloc_coherent(NULL,
3019 sizeof(struct msmsdcc_nc_dmadata),
3020 &host->dma.nc_busaddr,
3021 GFP_KERNEL);
3022 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003023 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07003024 return -ENOMEM;
3025 }
3026 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
3027 host->dma.cmd_busaddr = host->dma.nc_busaddr;
3028 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
3029 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
3030 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07003031 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07003032
3033 return 0;
3034}
3035
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003036#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
3037/**
3038 * Allocate and Connect a SDCC peripheral's SPS endpoint
3039 *
3040 * This function allocates endpoint context and
3041 * connect it with memory endpoint by calling
3042 * appropriate SPS driver APIs.
3043 *
3044 * Also registers a SPS callback function with
3045 * SPS driver
3046 *
3047 * This function should only be called once typically
3048 * during driver probe.
3049 *
3050 * @host - Pointer to sdcc host structure
3051 * @ep - Pointer to sps endpoint data structure
3052 * @is_produce - 1 means Producer endpoint
3053 * 0 means Consumer endpoint
3054 *
3055 * @return - 0 if successful else negative value.
3056 *
3057 */
3058static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
3059 struct msmsdcc_sps_ep_conn_data *ep,
3060 bool is_producer)
3061{
3062 int rc = 0;
3063 struct sps_pipe *sps_pipe_handle;
3064 struct sps_connect *sps_config = &ep->config;
3065 struct sps_register_event *sps_event = &ep->event;
3066
3067 /* Allocate endpoint context */
3068 sps_pipe_handle = sps_alloc_endpoint();
3069 if (!sps_pipe_handle) {
3070 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
3071 mmc_hostname(host->mmc), is_producer);
3072 rc = -ENOMEM;
3073 goto out;
3074 }
3075
3076 /* Get default connection configuration for an endpoint */
3077 rc = sps_get_config(sps_pipe_handle, sps_config);
3078 if (rc) {
3079 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
3080 " rc=%d", mmc_hostname(host->mmc),
3081 (u32)sps_pipe_handle, rc);
3082 goto get_config_err;
3083 }
3084
3085 /* Modify the default connection configuration */
3086 if (is_producer) {
3087 /*
3088 * For SDCC producer transfer, source should be
3089 * SDCC peripheral where as destination should
3090 * be system memory.
3091 */
3092 sps_config->source = host->sps.bam_handle;
3093 sps_config->destination = SPS_DEV_HANDLE_MEM;
3094 /* Producer pipe will handle this connection */
3095 sps_config->mode = SPS_MODE_SRC;
3096 sps_config->options =
3097 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3098 } else {
3099 /*
3100 * For SDCC consumer transfer, source should be
3101 * system memory where as destination should
3102 * SDCC peripheral
3103 */
3104 sps_config->source = SPS_DEV_HANDLE_MEM;
3105 sps_config->destination = host->sps.bam_handle;
3106 sps_config->mode = SPS_MODE_DEST;
3107 sps_config->options =
3108 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3109 }
3110
3111 /* Producer pipe index */
3112 sps_config->src_pipe_index = host->sps.src_pipe_index;
3113 /* Consumer pipe index */
3114 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
3115 /*
3116 * This event thresold value is only significant for BAM-to-BAM
3117 * transfer. It's ignored for BAM-to-System mode transfer.
3118 */
3119 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05303120
3121 /* Allocate maximum descriptor fifo size */
3122 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
3123 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003124 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
3125 sps_config->desc.size,
3126 &sps_config->desc.phys_base,
3127 GFP_KERNEL);
3128
Pratibhasagar V00b94332011-10-18 14:57:27 +05303129 if (!sps_config->desc.base) {
3130 rc = -ENOMEM;
3131 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3132 , mmc_hostname(host->mmc));
3133 goto get_config_err;
3134 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003135 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3136
3137 /* Establish connection between peripheral and memory endpoint */
3138 rc = sps_connect(sps_pipe_handle, sps_config);
3139 if (rc) {
3140 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3141 " rc=%d", mmc_hostname(host->mmc),
3142 (u32)sps_pipe_handle, rc);
3143 goto sps_connect_err;
3144 }
3145
3146 sps_event->mode = SPS_TRIGGER_CALLBACK;
3147 sps_event->options = SPS_O_EOT;
3148 sps_event->callback = msmsdcc_sps_complete_cb;
3149 sps_event->xfer_done = NULL;
3150 sps_event->user = (void *)host;
3151
3152 /* Register callback event for EOT (End of transfer) event. */
3153 rc = sps_register_event(sps_pipe_handle, sps_event);
3154 if (rc) {
3155 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3156 " rc=%d", mmc_hostname(host->mmc),
3157 (u32)sps_pipe_handle, rc);
3158 goto reg_event_err;
3159 }
3160 /* Now save the sps pipe handle */
3161 ep->pipe_handle = sps_pipe_handle;
3162 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3163 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3164 __func__, is_producer ? "READ" : "WRITE",
3165 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3166 goto out;
3167
3168reg_event_err:
3169 sps_disconnect(sps_pipe_handle);
3170sps_connect_err:
3171 dma_free_coherent(mmc_dev(host->mmc),
3172 sps_config->desc.size,
3173 sps_config->desc.base,
3174 sps_config->desc.phys_base);
3175get_config_err:
3176 sps_free_endpoint(sps_pipe_handle);
3177out:
3178 return rc;
3179}
3180
3181/**
3182 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3183 *
3184 * This function disconnect endpoint and deallocates
3185 * endpoint context.
3186 *
3187 * This function should only be called once typically
3188 * during driver remove.
3189 *
3190 * @host - Pointer to sdcc host structure
3191 * @ep - Pointer to sps endpoint data structure
3192 *
3193 */
3194static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3195 struct msmsdcc_sps_ep_conn_data *ep)
3196{
3197 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3198 struct sps_connect *sps_config = &ep->config;
3199 struct sps_register_event *sps_event = &ep->event;
3200
3201 sps_event->xfer_done = NULL;
3202 sps_event->callback = NULL;
3203 sps_register_event(sps_pipe_handle, sps_event);
3204 sps_disconnect(sps_pipe_handle);
3205 dma_free_coherent(mmc_dev(host->mmc),
3206 sps_config->desc.size,
3207 sps_config->desc.base,
3208 sps_config->desc.phys_base);
3209 sps_free_endpoint(sps_pipe_handle);
3210}
3211
3212/**
3213 * Reset SDCC peripheral's SPS endpoint
3214 *
3215 * This function disconnects an endpoint.
3216 *
3217 * This function should be called for reseting
3218 * SPS endpoint when data transfer error is
3219 * encountered during data transfer. This
3220 * can be considered as soft reset to endpoint.
3221 *
3222 * This function should only be called if
3223 * msmsdcc_sps_init() is already called.
3224 *
3225 * @host - Pointer to sdcc host structure
3226 * @ep - Pointer to sps endpoint data structure
3227 *
3228 * @return - 0 if successful else negative value.
3229 */
3230static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3231 struct msmsdcc_sps_ep_conn_data *ep)
3232{
3233 int rc = 0;
3234 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3235
3236 rc = sps_disconnect(sps_pipe_handle);
3237 if (rc) {
3238 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3239 " rc=%d", mmc_hostname(host->mmc), __func__,
3240 (u32)sps_pipe_handle, rc);
3241 goto out;
3242 }
3243 out:
3244 return rc;
3245}
3246
3247/**
3248 * Restore SDCC peripheral's SPS endpoint
3249 *
3250 * This function connects an endpoint.
3251 *
3252 * This function should be called for restoring
3253 * SPS endpoint after data transfer error is
3254 * encountered during data transfer. This
3255 * can be considered as soft reset to endpoint.
3256 *
3257 * This function should only be called if
3258 * msmsdcc_sps_reset_ep() is called before.
3259 *
3260 * @host - Pointer to sdcc host structure
3261 * @ep - Pointer to sps endpoint data structure
3262 *
3263 * @return - 0 if successful else negative value.
3264 */
3265static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3266 struct msmsdcc_sps_ep_conn_data *ep)
3267{
3268 int rc = 0;
3269 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3270 struct sps_connect *sps_config = &ep->config;
3271 struct sps_register_event *sps_event = &ep->event;
3272
3273 /* Establish connection between peripheral and memory endpoint */
3274 rc = sps_connect(sps_pipe_handle, sps_config);
3275 if (rc) {
3276 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3277 " rc=%d", mmc_hostname(host->mmc), __func__,
3278 (u32)sps_pipe_handle, rc);
3279 goto out;
3280 }
3281
3282 /* Register callback event for EOT (End of transfer) event. */
3283 rc = sps_register_event(sps_pipe_handle, sps_event);
3284 if (rc) {
3285 pr_err("%s: %s: sps_register_event() failed!!!"
3286 " pipe_handle=0x%x, rc=%d",
3287 mmc_hostname(host->mmc), __func__,
3288 (u32)sps_pipe_handle, rc);
3289 goto reg_event_err;
3290 }
3291 goto out;
3292
3293reg_event_err:
3294 sps_disconnect(sps_pipe_handle);
3295out:
3296 return rc;
3297}
3298
3299/**
3300 * Initialize SPS HW connected with SDCC core
3301 *
3302 * This function register BAM HW resources with
3303 * SPS driver and then initialize 2 SPS endpoints
3304 *
3305 * This function should only be called once typically
3306 * during driver probe.
3307 *
3308 * @host - Pointer to sdcc host structure
3309 *
3310 * @return - 0 if successful else negative value.
3311 *
3312 */
3313static int msmsdcc_sps_init(struct msmsdcc_host *host)
3314{
3315 int rc = 0;
3316 struct sps_bam_props bam = {0};
3317
3318 host->bam_base = ioremap(host->bam_memres->start,
3319 resource_size(host->bam_memres));
3320 if (!host->bam_base) {
3321 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3322 " size=0x%x", mmc_hostname(host->mmc),
3323 host->bam_memres->start,
3324 (host->bam_memres->end -
3325 host->bam_memres->start));
3326 rc = -ENOMEM;
3327 goto out;
3328 }
3329
3330 bam.phys_addr = host->bam_memres->start;
3331 bam.virt_addr = host->bam_base;
3332 /*
3333 * This event thresold value is only significant for BAM-to-BAM
3334 * transfer. It's ignored for BAM-to-System mode transfer.
3335 */
3336 bam.event_threshold = 0x10; /* Pipe event threshold */
3337 /*
3338 * This threshold controls when the BAM publish
3339 * the descriptor size on the sideband interface.
3340 * SPS HW will only be used when
3341 * data transfer size > MCI_FIFOSIZE (64 bytes).
3342 * PIO mode will be used when
3343 * data transfer size < MCI_FIFOSIZE (64 bytes).
3344 * So set this thresold value to 64 bytes.
3345 */
3346 bam.summing_threshold = 64;
3347 /* SPS driver wll handle the SDCC BAM IRQ */
3348 bam.irq = (u32)host->bam_irqres->start;
3349 bam.manage = SPS_BAM_MGR_LOCAL;
3350
3351 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3352 (u32)bam.phys_addr);
3353 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3354 (u32)bam.virt_addr);
3355
3356 /* Register SDCC Peripheral BAM device to SPS driver */
3357 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3358 if (rc) {
3359 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3360 mmc_hostname(host->mmc), rc);
3361 goto reg_bam_err;
3362 }
3363 pr_info("%s: BAM device registered. bam_handle=0x%x",
3364 mmc_hostname(host->mmc), host->sps.bam_handle);
3365
3366 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3367 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3368
3369 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3370 SPS_PROD_PERIPHERAL);
3371 if (rc)
3372 goto sps_reset_err;
3373 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3374 SPS_CONS_PERIPHERAL);
3375 if (rc)
3376 goto cons_conn_err;
3377
3378 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3379 mmc_hostname(host->mmc),
3380 (unsigned long long)host->bam_memres->start,
3381 (unsigned int)host->bam_irqres->start);
3382 goto out;
3383
3384cons_conn_err:
3385 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3386sps_reset_err:
3387 sps_deregister_bam_device(host->sps.bam_handle);
3388reg_bam_err:
3389 iounmap(host->bam_base);
3390out:
3391 return rc;
3392}
3393
3394/**
3395 * De-initialize SPS HW connected with SDCC core
3396 *
3397 * This function deinitialize SPS endpoints and then
3398 * deregisters BAM resources from SPS driver.
3399 *
3400 * This function should only be called once typically
3401 * during driver remove.
3402 *
3403 * @host - Pointer to sdcc host structure
3404 *
3405 */
3406static void msmsdcc_sps_exit(struct msmsdcc_host *host)
3407{
3408 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
3409 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3410 sps_deregister_bam_device(host->sps.bam_handle);
3411 iounmap(host->bam_base);
3412}
3413#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
3414
3415static ssize_t
3416show_polling(struct device *dev, struct device_attribute *attr, char *buf)
3417{
3418 struct mmc_host *mmc = dev_get_drvdata(dev);
3419 struct msmsdcc_host *host = mmc_priv(mmc);
3420 int poll;
3421 unsigned long flags;
3422
3423 spin_lock_irqsave(&host->lock, flags);
3424 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
3425 spin_unlock_irqrestore(&host->lock, flags);
3426
3427 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
3428}
3429
3430static ssize_t
3431set_polling(struct device *dev, struct device_attribute *attr,
3432 const char *buf, size_t count)
3433{
3434 struct mmc_host *mmc = dev_get_drvdata(dev);
3435 struct msmsdcc_host *host = mmc_priv(mmc);
3436 int value;
3437 unsigned long flags;
3438
3439 sscanf(buf, "%d", &value);
3440
3441 spin_lock_irqsave(&host->lock, flags);
3442 if (value) {
3443 mmc->caps |= MMC_CAP_NEEDS_POLL;
3444 mmc_detect_change(host->mmc, 0);
3445 } else {
3446 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3447 }
3448#ifdef CONFIG_HAS_EARLYSUSPEND
3449 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
3450#endif
3451 spin_unlock_irqrestore(&host->lock, flags);
3452 return count;
3453}
3454
3455static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
3456 show_polling, set_polling);
3457static struct attribute *dev_attrs[] = {
3458 &dev_attr_polling.attr,
3459 NULL,
3460};
3461static struct attribute_group dev_attr_grp = {
3462 .attrs = dev_attrs,
3463};
3464
3465#ifdef CONFIG_HAS_EARLYSUSPEND
3466static void msmsdcc_early_suspend(struct early_suspend *h)
3467{
3468 struct msmsdcc_host *host =
3469 container_of(h, struct msmsdcc_host, early_suspend);
3470 unsigned long flags;
3471
3472 spin_lock_irqsave(&host->lock, flags);
3473 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
3474 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3475 spin_unlock_irqrestore(&host->lock, flags);
3476};
3477static void msmsdcc_late_resume(struct early_suspend *h)
3478{
3479 struct msmsdcc_host *host =
3480 container_of(h, struct msmsdcc_host, early_suspend);
3481 unsigned long flags;
3482
3483 if (host->polling_enabled) {
3484 spin_lock_irqsave(&host->lock, flags);
3485 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
3486 mmc_detect_change(host->mmc, 0);
3487 spin_unlock_irqrestore(&host->lock, flags);
3488 }
3489};
3490#endif
3491
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303492void msmsdcc_print_regs(const char *name, void __iomem *base,
3493 unsigned int no_of_regs)
3494{
3495 unsigned int i;
3496
3497 if (!base)
3498 return;
3499 pr_info("===== %s: Register Dumps @base=0x%x =====\n",
3500 name, (u32)base);
3501 for (i = 0; i < no_of_regs; i = i + 4) {
3502 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x.\n", i*4,
3503 (u32)readl_relaxed(base + i*4),
3504 (u32)readl_relaxed(base + ((i+1)*4)),
3505 (u32)readl_relaxed(base + ((i+2)*4)),
3506 (u32)readl_relaxed(base + ((i+3)*4)));
3507 }
3508}
3509
3510static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
3511{
3512 /* Dump current state of SDCC clocks, power and irq */
3513 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
3514 (host->pwr ? "ON" : "OFF"));
3515 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
3516 mmc_hostname(host->mmc),
3517 (host->clks_on ? "ON" : "OFF"),
3518 (u32)clk_get_rate(host->clk));
3519 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
3520 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
3521
3522 /* Now dump SDCC registers. Don't print FIFO registers */
3523 if (host->clks_on)
3524 msmsdcc_print_regs("SDCC-CORE", host->base, 28);
3525
3526 if (host->curr.data) {
3527 if (msmsdcc_check_dma_op_req(host->curr.data))
3528 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
3529 else if (host->is_dma_mode)
3530 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
3531 mmc_hostname(host->mmc), host->dma.busy,
3532 host->dma.channel, host->dma.crci);
3533 else if (host->is_sps_mode)
3534 pr_info("%s: SPS mode: busy=%d\n",
3535 mmc_hostname(host->mmc), host->sps.busy);
3536
3537 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
3538 mmc_hostname(host->mmc), host->curr.xfer_size,
3539 host->curr.data_xfered, host->curr.xfer_remain);
3540 pr_info("%s: got_dataend=%d, prog_enable=%d,"
3541 " wait_for_auto_prog_done=%d,"
3542 " got_auto_prog_done=%d\n",
3543 mmc_hostname(host->mmc), host->curr.got_dataend,
3544 host->prog_enable, host->curr.wait_for_auto_prog_done,
3545 host->curr.got_auto_prog_done);
3546 }
3547
3548}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003549static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
3550{
3551 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3552 struct mmc_request *mrq;
3553 unsigned long flags;
3554
3555 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003556 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003557 pr_info("%s: %s: dummy CMD52 timeout\n",
3558 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003559 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003560 }
3561
3562 mrq = host->curr.mrq;
3563
3564 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303565 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
3566 mrq->cmd->opcode);
3567 msmsdcc_dump_sdcc_state(host);
3568
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003569 if (!mrq->cmd->error)
3570 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303571 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003572 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003573 if (mrq->data && !mrq->data->error)
3574 mrq->data->error = -ETIMEDOUT;
3575 host->curr.data_xfered = 0;
3576 if (host->dma.sg && host->is_dma_mode) {
3577 msm_dmov_stop_cmd(host->dma.channel,
3578 &host->dma.hdr, 0);
3579 } else if (host->sps.sg && host->is_sps_mode) {
3580 /* Stop current SPS transfer */
3581 msmsdcc_sps_exit_curr_xfer(host);
3582 } else {
3583 msmsdcc_reset_and_restore(host);
3584 msmsdcc_stop_data(host);
3585 if (mrq->data && mrq->data->stop)
3586 msmsdcc_start_command(host,
3587 mrq->data->stop, 0);
3588 else
3589 msmsdcc_request_end(host, mrq);
3590 }
3591 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05303592 host->prog_enable = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003593 msmsdcc_reset_and_restore(host);
3594 msmsdcc_request_end(host, mrq);
3595 }
3596 }
3597 spin_unlock_irqrestore(&host->lock, flags);
3598}
3599
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303600static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
3601{
3602 int i, ret;
3603 struct mmc_platform_data *pdata;
3604 struct device_node *np = dev->of_node;
3605 u32 bus_width = 0;
3606 u32 *clk_table;
3607 int clk_table_len;
3608 u32 *sup_voltages;
3609 int sup_volt_len;
3610
3611 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
3612 if (!pdata) {
3613 dev_err(dev, "could not allocate memory for platform data\n");
3614 goto err;
3615 }
3616
3617 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
3618 if (bus_width == 8) {
3619 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
3620 } else if (bus_width == 4) {
3621 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
3622 } else {
3623 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
3624 pdata->mmc_bus_width = 0;
3625 }
3626
3627 if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
3628 size_t sz;
3629 sz = sup_volt_len / sizeof(*sup_voltages);
3630 if (sz > 0) {
3631 sup_voltages = devm_kzalloc(dev,
3632 sz * sizeof(*sup_voltages), GFP_KERNEL);
3633 if (!sup_voltages) {
3634 dev_err(dev, "No memory for supported voltage\n");
3635 goto err;
3636 }
3637
3638 ret = of_property_read_u32_array(np,
3639 "qcom,sdcc-sup-voltages", sup_voltages, sz);
3640 if (ret < 0) {
3641 dev_err(dev, "error while reading voltage"
3642 "ranges %d\n", ret);
3643 goto err;
3644 }
3645 } else {
3646 dev_err(dev, "No supported voltages\n");
3647 goto err;
3648 }
3649 for (i = 0; i < sz; i += 2) {
3650 u32 mask;
3651
3652 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
3653 sup_voltages[i + 1]);
3654 if (!mask)
3655 dev_err(dev, "Invalide voltage range %d\n", i);
3656 pdata->ocr_mask |= mask;
3657 }
3658 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
3659 } else {
3660 dev_err(dev, "Supported voltage range not specified\n");
3661 }
3662
3663 if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
3664 size_t sz;
3665 sz = clk_table_len / sizeof(*clk_table);
3666
3667 if (sz > 0) {
3668 clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
3669 GFP_KERNEL);
3670 if (!clk_table) {
3671 dev_err(dev, "No memory for clock table\n");
3672 goto err;
3673 }
3674
3675 ret = of_property_read_u32_array(np,
3676 "qcom,sdcc-clk-rates", clk_table, sz);
3677 if (ret < 0) {
3678 dev_err(dev, "error while reading clk"
3679 "table %d\n", ret);
3680 goto err;
3681 }
3682 } else {
3683 dev_err(dev, "clk_table not specified\n");
3684 goto err;
3685 }
3686 pdata->sup_clk_table = clk_table;
3687 pdata->sup_clk_cnt = sz;
3688 } else {
3689 dev_err(dev, "Supported clock rates not specified\n");
3690 }
3691
3692 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
3693 pdata->nonremovable = true;
3694 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
3695 pdata->disable_cmd23 = true;
3696
3697 return pdata;
3698err:
3699 return NULL;
3700}
3701
San Mehat9d2bd732009-09-22 16:44:22 -07003702static int
3703msmsdcc_probe(struct platform_device *pdev)
3704{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303705 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07003706 struct msmsdcc_host *host;
3707 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003708 unsigned long flags;
3709 struct resource *core_irqres = NULL;
3710 struct resource *bam_irqres = NULL;
3711 struct resource *core_memres = NULL;
3712 struct resource *dml_memres = NULL;
3713 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07003714 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07003715 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05303716 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003717 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07003718
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303719 if (pdev->dev.of_node) {
3720 plat = msmsdcc_populate_pdata(&pdev->dev);
3721 of_property_read_u32((&pdev->dev)->of_node,
3722 "cell-index", &pdev->id);
3723 } else {
3724 plat = pdev->dev.platform_data;
3725 }
3726
San Mehat9d2bd732009-09-22 16:44:22 -07003727 /* must have platform data */
3728 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003729 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003730 ret = -EINVAL;
3731 goto out;
3732 }
3733
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003734 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07003735 return -EINVAL;
3736
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05303737 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
3738 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
3739 return -EINVAL;
3740 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003741
San Mehat9d2bd732009-09-22 16:44:22 -07003742 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003743 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003744 return -ENXIO;
3745 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303746 if (pdev->dev.of_node) {
3747 /*
3748 * Device tree iomem resources are only accessible by index.
3749 * index = 0 -> SDCC register interface
3750 * index = 1 -> DML register interface
3751 * index = 2 -> BAM register interface
3752 * IRQ resources:
3753 * index = 0 -> SDCC IRQ
3754 * index = 1 -> BAM IRQ
3755 */
3756 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
3757 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
3758 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
3759 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
3760 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
3761 } else {
3762 for (i = 0; i < pdev->num_resources; i++) {
3763 if (pdev->resource[i].flags & IORESOURCE_MEM) {
3764 if (!strncmp(pdev->resource[i].name,
3765 "sdcc_dml_addr",
3766 sizeof("sdcc_dml_addr")))
3767 dml_memres = &pdev->resource[i];
3768 else if (!strncmp(pdev->resource[i].name,
3769 "sdcc_bam_addr",
3770 sizeof("sdcc_bam_addr")))
3771 bam_memres = &pdev->resource[i];
3772 else
3773 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07003774
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303775 }
3776 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
3777 if (!strncmp(pdev->resource[i].name,
3778 "sdcc_bam_irq",
3779 sizeof("sdcc_bam_irq")))
3780 bam_irqres = &pdev->resource[i];
3781 else
3782 core_irqres = &pdev->resource[i];
3783 }
3784 if (pdev->resource[i].flags & IORESOURCE_DMA) {
3785 if (!strncmp(pdev->resource[i].name,
3786 "sdcc_dma_chnl",
3787 sizeof("sdcc_dma_chnl")))
3788 dmares = &pdev->resource[i];
3789 else if (!strncmp(pdev->resource[i].name,
3790 "sdcc_dma_crci",
3791 sizeof("sdcc_dma_crci")))
3792 dma_crci_res = &pdev->resource[i];
3793 }
Krishna Konda25786ec2011-07-25 16:21:36 -07003794 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003795 }
3796
3797 if (!core_irqres || !core_memres) {
3798 pr_err("%s: Invalid sdcc core resource\n", __func__);
3799 return -ENXIO;
3800 }
3801
3802 /*
3803 * Both BAM and DML memory resource should be preset.
3804 * BAM IRQ resource should also be present.
3805 */
3806 if ((bam_memres && !dml_memres) ||
3807 (!bam_memres && dml_memres) ||
3808 ((bam_memres && dml_memres) && !bam_irqres)) {
3809 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003810 return -ENXIO;
3811 }
3812
3813 /*
3814 * Setup our host structure
3815 */
San Mehat9d2bd732009-09-22 16:44:22 -07003816 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
3817 if (!mmc) {
3818 ret = -ENOMEM;
3819 goto out;
3820 }
3821
3822 host = mmc_priv(mmc);
3823 host->pdev_id = pdev->id;
3824 host->plat = plat;
3825 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08003826 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05303827
3828 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003829 host->is_sps_mode = 1;
3830 else if (dmares)
3831 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07003832
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003833 host->base = ioremap(core_memres->start,
3834 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07003835 if (!host->base) {
3836 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003837 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003838 }
3839
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003840 host->core_irqres = core_irqres;
3841 host->bam_irqres = bam_irqres;
3842 host->core_memres = core_memres;
3843 host->dml_memres = dml_memres;
3844 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07003845 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07003846 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07003847 spin_lock_init(&host->lock);
3848
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003849#ifdef CONFIG_MMC_EMBEDDED_SDIO
3850 if (plat->embedded_sdio)
3851 mmc_set_embedded_sdio_data(mmc,
3852 &plat->embedded_sdio->cis,
3853 &plat->embedded_sdio->cccr,
3854 plat->embedded_sdio->funcs,
3855 plat->embedded_sdio->num_funcs);
3856#endif
3857
Sahitya Tummala62612cf2010-12-08 15:03:03 +05303858 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
3859 (unsigned long)host);
3860
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003861 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
3862 (unsigned long)host);
3863 if (host->is_dma_mode) {
3864 /* Setup DMA */
3865 ret = msmsdcc_init_dma(host);
3866 if (ret)
3867 goto ioremap_free;
3868 } else {
3869 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003870 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003871 }
3872
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003873 /*
3874 * Setup SDCC clock if derived from Dayatona
3875 * fabric core clock.
3876 */
3877 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07003878 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003879 if (!IS_ERR(host->dfab_pclk)) {
3880 /* Set the clock rate to 64MHz for max. performance */
3881 ret = clk_set_rate(host->dfab_pclk, 64000000);
3882 if (ret)
3883 goto dfab_pclk_put;
3884 ret = clk_enable(host->dfab_pclk);
3885 if (ret)
3886 goto dfab_pclk_put;
3887 } else
3888 goto dma_free;
3889 }
3890
3891 /*
3892 * Setup main peripheral bus clock
3893 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003894 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003895 if (!IS_ERR(host->pclk)) {
3896 ret = clk_enable(host->pclk);
3897 if (ret)
3898 goto pclk_put;
3899
3900 host->pclk_rate = clk_get_rate(host->pclk);
3901 }
3902
3903 /*
3904 * Setup SDC MMC clock
3905 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003906 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07003907 if (IS_ERR(host->clk)) {
3908 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003909 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07003910 }
3911
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003912 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
3913 if (ret) {
3914 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
3915 goto clk_put;
3916 }
3917
3918 ret = clk_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003919 if (ret)
3920 goto clk_put;
3921
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003922 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303923 if (!host->clk_rate)
3924 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05303925
3926 /*
3927 * Lookup the Controller Version, to identify the supported features
3928 * Version number read as 0 would indicate SDCC3 or earlier versions
3929 */
3930 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
3931 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
3932 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303933 /*
3934 * Set the register write delay according to min. clock frequency
3935 * supported and update later when the host->clk_rate changes.
3936 */
3937 host->reg_write_delay =
3938 (1 + ((3 * USEC_PER_SEC) /
3939 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003940
3941 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05303942 /* Apply Hard reset to SDCC to put it in power on default state */
3943 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003944
3945 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07003946 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003947 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07003948 goto clk_disable;
3949 }
3950
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003951
3952 /* Clocks has to be running before accessing SPS/DML HW blocks */
3953 if (host->is_sps_mode) {
3954 /* Initialize SPS */
3955 ret = msmsdcc_sps_init(host);
3956 if (ret)
3957 goto vreg_deinit;
3958 /* Initialize DML */
3959 ret = msmsdcc_dml_init(host);
3960 if (ret)
3961 goto sps_exit;
3962 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05303963 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07003964
San Mehat9d2bd732009-09-22 16:44:22 -07003965 /*
3966 * Setup MMC host structure
3967 */
3968 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003969 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
3970 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003971 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003972 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
3973 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07003974
San Mehat9d2bd732009-09-22 16:44:22 -07003975 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05303976 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05303977
3978 /*
3979 * If we send the CMD23 before multi block write/read command
3980 * then we need not to send CMD12 at the end of the transfer.
3981 * If we don't send the CMD12 then only way to detect the PROG_DONE
3982 * status is to use the AUTO_PROG_DONE status provided by SDCC4
3983 * controller. So let's enable the CMD23 for SDCC4 only.
3984 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05303985 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05303986 mmc->caps |= MMC_CAP_CMD23;
3987
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003988 mmc->caps |= plat->uhs_caps;
3989 /*
3990 * XPC controls the maximum current in the default speed mode of SDXC
3991 * card. XPC=0 means 100mA (max.) but speed class is not supported.
3992 * XPC=1 means 150mA (max.) and speed class is supported.
3993 */
3994 if (plat->xpc_cap)
3995 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
3996 MMC_CAP_SET_XPC_180);
3997
3998 if (plat->nonremovable)
3999 mmc->caps |= MMC_CAP_NONREMOVABLE;
4000#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
4001 mmc->caps |= MMC_CAP_SDIO_IRQ;
4002#endif
4003
4004 if (plat->is_sdio_al_client)
4005 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07004006
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304007 mmc->max_segs = msmsdcc_get_nr_sg(host);
4008 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
4009 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07004010
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304011 mmc->max_req_size = MMC_MAX_REQ_SIZE;
4012 mmc->max_seg_size = msmsdcc_get_max_seg_size(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004013
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004014 writel_relaxed(0, host->base + MMCIMASK0);
4015 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -07004016
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004017 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
4018 mb();
4019 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07004020
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004021 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
4022 DRIVER_NAME " (cmd)", host);
4023 if (ret)
4024 goto dml_exit;
4025
4026 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
4027 DRIVER_NAME " (pio)", host);
4028 if (ret)
4029 goto irq_free;
4030
4031 /*
4032 * Enable SDCC IRQ only when host is powered on. Otherwise, this
4033 * IRQ is un-necessarily being monitored by MPM (Modem power
4034 * management block) during idle-power collapse. The MPM will be
4035 * configured to monitor the DATA1 GPIO line with level-low trigger
4036 * and thus depending on the GPIO status, it prevents TCXO shutdown
4037 * during idle-power collapse.
4038 */
4039 disable_irq(core_irqres->start);
4040 host->sdcc_irq_disabled = 1;
4041
4042 if (plat->sdiowakeup_irq) {
4043 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4044 mmc_hostname(mmc));
4045 ret = request_irq(plat->sdiowakeup_irq,
4046 msmsdcc_platform_sdiowakeup_irq,
4047 IRQF_SHARED | IRQF_TRIGGER_LOW,
4048 DRIVER_NAME "sdiowakeup", host);
4049 if (ret) {
4050 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
4051 plat->sdiowakeup_irq, ret);
4052 goto pio_irq_free;
4053 } else {
4054 spin_lock_irqsave(&host->lock, flags);
4055 if (!host->sdio_irq_disabled) {
4056 disable_irq_nosync(plat->sdiowakeup_irq);
4057 host->sdio_irq_disabled = 1;
4058 }
4059 spin_unlock_irqrestore(&host->lock, flags);
4060 }
4061 }
4062
4063 if (plat->cfg_mpm_sdiowakeup) {
4064 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4065 mmc_hostname(mmc));
4066 }
4067
4068 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
4069 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004070 /*
4071 * Setup card detect change
4072 */
4073
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004074 if (plat->status || plat->status_gpio) {
4075 if (plat->status)
4076 host->oldstat = plat->status(mmc_dev(host->mmc));
4077 else
4078 host->oldstat = msmsdcc_slot_status(host);
4079 host->eject = !host->oldstat;
4080 }
San Mehat9d2bd732009-09-22 16:44:22 -07004081
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004082 if (plat->status_irq) {
4083 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07004084 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004085 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07004086 DRIVER_NAME " (slot)",
4087 host);
4088 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004089 pr_err("Unable to get slot IRQ %d (%d)\n",
4090 plat->status_irq, ret);
4091 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004092 }
4093 } else if (plat->register_status_notify) {
4094 plat->register_status_notify(msmsdcc_status_notify_cb, host);
4095 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004096 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07004097 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004098
4099 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004100
4101 ret = pm_runtime_set_active(&(pdev)->dev);
4102 if (ret < 0)
4103 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
4104 __func__, ret);
4105 /*
4106 * There is no notion of suspend/resume for SD/MMC/SDIO
4107 * cards. So host can be suspended/resumed with out
4108 * worrying about its children.
4109 */
4110 pm_suspend_ignore_children(&(pdev)->dev, true);
4111
4112 /*
4113 * MMC/SD/SDIO bus suspend/resume operations are defined
4114 * only for the slots that will be used for non-removable
4115 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
4116 * defined. Otherwise, they simply become card removal and
4117 * insertion events during suspend and resume respectively.
4118 * Hence, enable run-time PM only for slots for which bus
4119 * suspend/resume operations are defined.
4120 */
4121#ifdef CONFIG_MMC_UNSAFE_RESUME
4122 /*
4123 * If this capability is set, MMC core will enable/disable host
4124 * for every claim/release operation on a host. We use this
4125 * notification to increment/decrement runtime pm usage count.
4126 */
4127 mmc->caps |= MMC_CAP_DISABLE;
4128 pm_runtime_enable(&(pdev)->dev);
4129#else
4130 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
4131 mmc->caps |= MMC_CAP_DISABLE;
4132 pm_runtime_enable(&(pdev)->dev);
4133 }
4134#endif
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05304135#ifndef CONFIG_PM_RUNTIME
4136 mmc_set_disable_delay(mmc, MSM_MMC_DISABLE_TIMEOUT);
4137#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004138 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
4139 (unsigned long)host);
4140
San Mehat9d2bd732009-09-22 16:44:22 -07004141 mmc_add_host(mmc);
4142
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004143#ifdef CONFIG_HAS_EARLYSUSPEND
4144 host->early_suspend.suspend = msmsdcc_early_suspend;
4145 host->early_suspend.resume = msmsdcc_late_resume;
4146 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
4147 register_early_suspend(&host->early_suspend);
4148#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004149
Krishna Konda25786ec2011-07-25 16:21:36 -07004150 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
4151 " dmacrcri %d\n", mmc_hostname(mmc),
4152 (unsigned long long)core_memres->start,
4153 (unsigned int) core_irqres->start,
4154 (unsigned int) plat->status_irq, host->dma.channel,
4155 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004156
4157 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
4158 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
4159 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
4160 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
4161 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
4162 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
4163 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
4164 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
4165 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
4166 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
4167 host->eject);
4168 pr_info("%s: Power save feature enable = %d\n",
4169 mmc_hostname(mmc), msmsdcc_pwrsave);
4170
Krishna Konda25786ec2011-07-25 16:21:36 -07004171 if (host->is_dma_mode && host->dma.channel != -1
4172 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004173 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004174 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004175 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004176 mmc_hostname(mmc), host->dma.cmd_busaddr,
4177 host->dma.cmdptr_busaddr);
4178 } else if (host->is_sps_mode) {
4179 pr_info("%s: SPS-BAM data transfer mode available\n",
4180 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004181 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004182 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004183
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004184#if defined(CONFIG_DEBUG_FS)
4185 msmsdcc_dbg_createhost(host);
4186#endif
4187 if (!plat->status_irq) {
4188 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
4189 if (ret)
4190 goto platform_irq_free;
4191 }
San Mehat9d2bd732009-09-22 16:44:22 -07004192 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004193
4194 platform_irq_free:
4195 del_timer_sync(&host->req_tout_timer);
4196 pm_runtime_disable(&(pdev)->dev);
4197 pm_runtime_set_suspended(&(pdev)->dev);
4198
4199 if (plat->status_irq)
4200 free_irq(plat->status_irq, host);
4201 sdiowakeup_irq_free:
4202 wake_lock_destroy(&host->sdio_suspend_wlock);
4203 if (plat->sdiowakeup_irq)
4204 free_irq(plat->sdiowakeup_irq, host);
4205 pio_irq_free:
4206 if (plat->sdiowakeup_irq)
4207 wake_lock_destroy(&host->sdio_wlock);
4208 free_irq(core_irqres->start, host);
4209 irq_free:
4210 free_irq(core_irqres->start, host);
4211 dml_exit:
4212 if (host->is_sps_mode)
4213 msmsdcc_dml_exit(host);
4214 sps_exit:
4215 if (host->is_sps_mode)
4216 msmsdcc_sps_exit(host);
4217 vreg_deinit:
4218 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07004219 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004220 clk_disable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004221 clk_put:
4222 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004223 pclk_disable:
4224 if (!IS_ERR(host->pclk))
4225 clk_disable(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07004226 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004227 if (!IS_ERR(host->pclk))
4228 clk_put(host->pclk);
4229 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4230 clk_disable(host->dfab_pclk);
4231 dfab_pclk_put:
4232 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4233 clk_put(host->dfab_pclk);
4234 dma_free:
4235 if (host->is_dma_mode) {
4236 if (host->dmares)
4237 dma_free_coherent(NULL,
4238 sizeof(struct msmsdcc_nc_dmadata),
4239 host->dma.nc, host->dma.nc_busaddr);
4240 }
4241 ioremap_free:
4242 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07004243 host_free:
4244 mmc_free_host(mmc);
4245 out:
4246 return ret;
4247}
4248
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004249static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07004250{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004251 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4252 struct mmc_platform_data *plat;
4253 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004254
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004255 if (!mmc)
4256 return -ENXIO;
4257
4258 if (pm_runtime_suspended(&(pdev)->dev))
4259 pm_runtime_resume(&(pdev)->dev);
4260
4261 host = mmc_priv(mmc);
4262
4263 DBG(host, "Removing SDCC device = %d\n", pdev->id);
4264 plat = host->plat;
4265
4266 if (!plat->status_irq)
4267 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
4268
4269 del_timer_sync(&host->req_tout_timer);
4270 tasklet_kill(&host->dma_tlet);
4271 tasklet_kill(&host->sps.tlet);
4272 mmc_remove_host(mmc);
4273
4274 if (plat->status_irq)
4275 free_irq(plat->status_irq, host);
4276
4277 wake_lock_destroy(&host->sdio_suspend_wlock);
4278 if (plat->sdiowakeup_irq) {
4279 wake_lock_destroy(&host->sdio_wlock);
4280 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
4281 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07004282 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004283
4284 free_irq(host->core_irqres->start, host);
4285 free_irq(host->core_irqres->start, host);
4286
4287 clk_put(host->clk);
4288 if (!IS_ERR(host->pclk))
4289 clk_put(host->pclk);
4290 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4291 clk_put(host->dfab_pclk);
4292
4293 msmsdcc_vreg_init(host, false);
4294
4295 if (host->is_dma_mode) {
4296 if (host->dmares)
4297 dma_free_coherent(NULL,
4298 sizeof(struct msmsdcc_nc_dmadata),
4299 host->dma.nc, host->dma.nc_busaddr);
4300 }
4301
4302 if (host->is_sps_mode) {
4303 msmsdcc_dml_exit(host);
4304 msmsdcc_sps_exit(host);
4305 }
4306
4307 iounmap(host->base);
4308 mmc_free_host(mmc);
4309
4310#ifdef CONFIG_HAS_EARLYSUSPEND
4311 unregister_early_suspend(&host->early_suspend);
4312#endif
4313 pm_runtime_disable(&(pdev)->dev);
4314 pm_runtime_set_suspended(&(pdev)->dev);
4315
4316 return 0;
4317}
4318
4319#ifdef CONFIG_MSM_SDIO_AL
4320int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4321{
4322 struct msmsdcc_host *host = mmc_priv(mmc);
4323 unsigned long flags;
4324
4325 spin_lock_irqsave(&host->lock, flags);
4326 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
4327 enable ? "En" : "Dis");
4328
4329 if (enable) {
4330 if (!host->sdcc_irq_disabled) {
4331 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05304332 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004333 host->sdcc_irq_disabled = 1;
4334 }
4335
4336 if (host->clks_on) {
4337 msmsdcc_setup_clocks(host, false);
4338 host->clks_on = 0;
4339 }
4340
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304341 if (host->plat->sdio_lpm_gpio_setup &&
4342 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004343 spin_unlock_irqrestore(&host->lock, flags);
4344 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
4345 spin_lock_irqsave(&host->lock, flags);
4346 host->sdio_gpio_lpm = 1;
4347 }
4348
4349 if (host->sdio_irq_disabled) {
4350 msmsdcc_enable_irq_wake(host);
4351 enable_irq(host->plat->sdiowakeup_irq);
4352 host->sdio_irq_disabled = 0;
4353 }
4354 } else {
4355 if (!host->sdio_irq_disabled) {
4356 disable_irq_nosync(host->plat->sdiowakeup_irq);
4357 host->sdio_irq_disabled = 1;
4358 msmsdcc_disable_irq_wake(host);
4359 }
4360
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304361 if (host->plat->sdio_lpm_gpio_setup &&
4362 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004363 spin_unlock_irqrestore(&host->lock, flags);
4364 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
4365 spin_lock_irqsave(&host->lock, flags);
4366 host->sdio_gpio_lpm = 0;
4367 }
4368
4369 if (!host->clks_on) {
4370 msmsdcc_setup_clocks(host, true);
4371 host->clks_on = 1;
4372 }
4373
4374 if (host->sdcc_irq_disabled) {
4375 writel_relaxed(host->mci_irqenable,
4376 host->base + MMCIMASK0);
4377 mb();
4378 enable_irq(host->core_irqres->start);
4379 host->sdcc_irq_disabled = 0;
4380 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004381 }
4382 spin_unlock_irqrestore(&host->lock, flags);
4383 return 0;
4384}
4385#else
4386int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4387{
4388 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004389}
4390#endif
4391
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004392#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07004393static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004394msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004395{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004396 struct mmc_host *mmc = dev_get_drvdata(dev);
4397 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07004398 int rc = 0;
4399
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004400 if (host->plat->is_sdio_al_client)
4401 return 0;
4402
Sahitya Tummala7661a452011-07-18 13:28:35 +05304403 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004404 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004405 host->sdcc_suspending = 1;
4406 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07004407
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004408 /*
4409 * If the clocks are already turned off by SDIO clients (as
4410 * part of LPM), then clocks should be turned on before
4411 * calling mmc_suspend_host() because mmc_suspend_host might
4412 * send some commands to the card. The clocks will be turned
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304413 * off again after mmc_suspend_host. Thus for SDIO
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004414 * cards, clocks will be turned on before mmc_suspend_host
4415 * and turned off after mmc_suspend_host.
4416 */
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304417 if (mmc->card && mmc_card_sdio(mmc->card)) {
4418 mmc->ios.clock = host->clk_rate;
4419 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4420 }
San Mehat9d2bd732009-09-22 16:44:22 -07004421
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004422 /*
4423 * MMC core thinks that host is disabled by now since
4424 * runtime suspend is scheduled after msmsdcc_disable()
4425 * is called. Thus, MMC core will try to enable the host
4426 * while suspending it. This results in a synchronous
4427 * runtime resume request while in runtime suspending
4428 * context and hence inorder to complete this resume
4429 * requet, it will wait for suspend to be complete,
4430 * but runtime suspend also can not proceed further
4431 * until the host is resumed. Thus, it leads to a hang.
4432 * Hence, increase the pm usage count before suspending
4433 * the host so that any resume requests after this will
4434 * simple become pm usage counter increment operations.
4435 */
4436 pm_runtime_get_noresume(dev);
4437 rc = mmc_suspend_host(mmc);
4438 pm_runtime_put_noidle(dev);
4439
4440 if (!rc) {
4441 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
4442 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ)) {
4443 disable_irq(host->core_irqres->start);
4444 host->sdcc_irq_disabled = 1;
4445
4446 /*
4447 * If MMC core level suspend is not supported,
4448 * turn off clocks to allow deep sleep (TCXO
4449 * shutdown).
4450 */
4451 mmc->ios.clock = 0;
4452 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4453 enable_irq(host->core_irqres->start);
4454 host->sdcc_irq_disabled = 0;
4455
4456 if (host->plat->sdiowakeup_irq) {
4457 host->sdio_irq_disabled = 0;
4458 msmsdcc_enable_irq_wake(host);
4459 enable_irq(host->plat->sdiowakeup_irq);
4460 }
4461 }
4462 }
4463 host->sdcc_suspending = 0;
4464 mmc->suspend_task = NULL;
4465 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
4466 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004467 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304468 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004469 return rc;
4470}
4471
4472static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004473msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004474{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004475 struct mmc_host *mmc = dev_get_drvdata(dev);
4476 struct msmsdcc_host *host = mmc_priv(mmc);
4477 unsigned long flags;
4478
4479 if (host->plat->is_sdio_al_client)
4480 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07004481
Sahitya Tummala7661a452011-07-18 13:28:35 +05304482 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004483 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004484 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
4485 if (host->sdcc_irq_disabled) {
4486 enable_irq(host->core_irqres->start);
4487 host->sdcc_irq_disabled = 0;
4488 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304489 mmc->ios.clock = host->clk_rate;
4490 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07004491
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304492 spin_lock_irqsave(&host->lock, flags);
4493 writel_relaxed(host->mci_irqenable,
4494 host->base + MMCIMASK0);
4495 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07004496
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304497 if ((mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) &&
4498 !host->sdio_irq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004499 if (host->plat->sdiowakeup_irq) {
4500 disable_irq_nosync(
4501 host->plat->sdiowakeup_irq);
4502 msmsdcc_disable_irq_wake(host);
4503 host->sdio_irq_disabled = 1;
4504 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304505 }
San Mehat9d2bd732009-09-22 16:44:22 -07004506
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304507 spin_unlock_irqrestore(&host->lock, flags);
4508 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004509
4510 mmc_resume_host(mmc);
4511
4512 /*
4513 * FIXME: Clearing of flags must be handled in clients
4514 * resume handler.
4515 */
4516 spin_lock_irqsave(&host->lock, flags);
4517 mmc->pm_flags = 0;
4518 spin_unlock_irqrestore(&host->lock, flags);
4519
4520 /*
4521 * After resuming the host wait for sometime so that
4522 * the SDIO work will be processed.
4523 */
4524 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO)) {
4525 if ((host->plat->cfg_mpm_sdiowakeup ||
4526 host->plat->sdiowakeup_irq) &&
4527 wake_lock_active(&host->sdio_wlock))
4528 wake_lock_timeout(&host->sdio_wlock, 1);
4529 }
4530
4531 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004532 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304533 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004534 return 0;
4535}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004536
4537static int msmsdcc_runtime_idle(struct device *dev)
4538{
4539 struct mmc_host *mmc = dev_get_drvdata(dev);
4540 struct msmsdcc_host *host = mmc_priv(mmc);
4541
4542 if (host->plat->is_sdio_al_client)
4543 return 0;
4544
4545 /* Idle timeout is not configurable for now */
4546 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
4547
4548 return -EAGAIN;
4549}
4550
4551static int msmsdcc_pm_suspend(struct device *dev)
4552{
4553 struct mmc_host *mmc = dev_get_drvdata(dev);
4554 struct msmsdcc_host *host = mmc_priv(mmc);
4555 int rc = 0;
4556
4557 if (host->plat->is_sdio_al_client)
4558 return 0;
4559
4560
4561 if (host->plat->status_irq)
4562 disable_irq(host->plat->status_irq);
4563
4564 if (!pm_runtime_suspended(dev))
4565 rc = msmsdcc_runtime_suspend(dev);
4566
4567 return rc;
4568}
4569
4570static int msmsdcc_pm_resume(struct device *dev)
4571{
4572 struct mmc_host *mmc = dev_get_drvdata(dev);
4573 struct msmsdcc_host *host = mmc_priv(mmc);
4574 int rc = 0;
4575
4576 if (host->plat->is_sdio_al_client)
4577 return 0;
4578
Sahitya Tummalafb486372011-09-02 19:01:49 +05304579 if (!pm_runtime_suspended(dev))
4580 rc = msmsdcc_runtime_resume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004581 if (host->plat->status_irq) {
4582 msmsdcc_check_status((unsigned long)host);
4583 enable_irq(host->plat->status_irq);
4584 }
4585
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004586 return rc;
4587}
4588
Daniel Walker08ecfde2010-06-23 12:32:20 -07004589#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004590#define msmsdcc_runtime_suspend NULL
4591#define msmsdcc_runtime_resume NULL
4592#define msmsdcc_runtime_idle NULL
4593#define msmsdcc_pm_suspend NULL
4594#define msmsdcc_pm_resume NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07004595#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004596
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004597static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
4598 .runtime_suspend = msmsdcc_runtime_suspend,
4599 .runtime_resume = msmsdcc_runtime_resume,
4600 .runtime_idle = msmsdcc_runtime_idle,
4601 .suspend = msmsdcc_pm_suspend,
4602 .resume = msmsdcc_pm_resume,
4603};
4604
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304605static const struct of_device_id msmsdcc_dt_match[] = {
4606 {.compatible = "qcom,msm-sdcc"},
4607
4608};
4609MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
4610
San Mehat9d2bd732009-09-22 16:44:22 -07004611static struct platform_driver msmsdcc_driver = {
4612 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004613 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07004614 .driver = {
4615 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004616 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304617 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07004618 },
4619};
4620
4621static int __init msmsdcc_init(void)
4622{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004623#if defined(CONFIG_DEBUG_FS)
4624 int ret = 0;
4625 ret = msmsdcc_dbg_init();
4626 if (ret) {
4627 pr_err("Failed to create debug fs dir \n");
4628 return ret;
4629 }
4630#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004631 return platform_driver_register(&msmsdcc_driver);
4632}
4633
4634static void __exit msmsdcc_exit(void)
4635{
4636 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004637
4638#if defined(CONFIG_DEBUG_FS)
4639 debugfs_remove(debugfs_file);
4640 debugfs_remove(debugfs_dir);
4641#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004642}
4643
4644module_init(msmsdcc_init);
4645module_exit(msmsdcc_exit);
4646
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004647MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07004648MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004649
4650#if defined(CONFIG_DEBUG_FS)
4651
4652static int
4653msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
4654{
4655 file->private_data = inode->i_private;
4656 return 0;
4657}
4658
4659static ssize_t
4660msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
4661 size_t count, loff_t *ppos)
4662{
4663 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
4664 char buf[1024];
4665 int max, i;
4666
4667 i = 0;
4668 max = sizeof(buf) - 1;
4669
4670 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
4671 host->curr.cmd, host->curr.data);
4672 if (host->curr.cmd) {
4673 struct mmc_command *cmd = host->curr.cmd;
4674
4675 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
4676 cmd->opcode, cmd->arg, cmd->flags);
4677 }
4678 if (host->curr.data) {
4679 struct mmc_data *data = host->curr.data;
4680 i += scnprintf(buf + i, max - i,
4681 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
4682 data->timeout_ns, data->timeout_clks,
4683 data->blksz, data->blocks, data->error,
4684 data->flags);
4685 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
4686 host->curr.xfer_size, host->curr.xfer_remain,
4687 host->curr.data_xfered, host->dma.sg);
4688 }
4689
4690 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
4691}
4692
4693static const struct file_operations msmsdcc_dbg_state_ops = {
4694 .read = msmsdcc_dbg_state_read,
4695 .open = msmsdcc_dbg_state_open,
4696};
4697
4698static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
4699{
4700 if (debugfs_dir) {
4701 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
4702 0644, debugfs_dir, host,
4703 &msmsdcc_dbg_state_ops);
4704 }
4705}
4706
4707static int __init msmsdcc_dbg_init(void)
4708{
4709 int err;
4710
4711 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
4712 if (IS_ERR(debugfs_dir)) {
4713 err = PTR_ERR(debugfs_dir);
4714 debugfs_dir = NULL;
4715 return err;
4716 }
4717
4718 return 0;
4719}
4720#endif