blob: de3ca98b004620c59dd7782d46ce8d10d8622cbf [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>
22#include <linux/device.h>
23#include <linux/interrupt.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070024#include <linux/irq.h>
San Mehat9d2bd732009-09-22 16:44:22 -070025#include <linux/delay.h>
26#include <linux/err.h>
27#include <linux/highmem.h>
28#include <linux/log2.h>
29#include <linux/mmc/host.h>
30#include <linux/mmc/card.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070031#include <linux/mmc/mmc.h>
San Mehatb3fa5792009-11-02 18:46:09 -080032#include <linux/mmc/sdio.h>
San Mehat9d2bd732009-09-22 16:44:22 -070033#include <linux/clk.h>
34#include <linux/scatterlist.h>
35#include <linux/platform_device.h>
36#include <linux/dma-mapping.h>
37#include <linux/debugfs.h>
38#include <linux/io.h>
39#include <linux/memory.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070040#include <linux/pm_runtime.h>
41#include <linux/wakelock.h>
Sahitya Tummala7a892482011-01-18 11:22:49 +053042#include <linux/gpio.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070043#include <linux/regulator/consumer.h>
44#include <linux/slab.h>
45#include <linux/mmc/mmc.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
71/* 16 KB */
72#define SPS_MAX_DESC_SIZE (16 * 1024)
73
74#if defined(CONFIG_DEBUG_FS)
75static void msmsdcc_dbg_createhost(struct msmsdcc_host *);
76static struct dentry *debugfs_dir;
77static struct dentry *debugfs_file;
78static int msmsdcc_dbg_init(void);
79#endif
80
San Mehat9d2bd732009-09-22 16:44:22 -070081static unsigned int msmsdcc_pwrsave = 1;
San Mehat9d2bd732009-09-22 16:44:22 -070082
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070083static struct mmc_command dummy52cmd;
84static struct mmc_request dummy52mrq = {
85 .cmd = &dummy52cmd,
86 .data = NULL,
87 .stop = NULL,
88};
89static struct mmc_command dummy52cmd = {
90 .opcode = SD_IO_RW_DIRECT,
91 .flags = MMC_RSP_PRESENT,
92 .data = NULL,
93 .mrq = &dummy52mrq,
94};
95/*
96 * An array holding the Tuning pattern to compare with when
97 * executing a tuning cycle.
98 */
99static const u32 cmd19_tuning_block[16] = {
100 0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
101 0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
102 0xF0FFF0FF, 0x3CCCFC0F, 0xCFCC33CC, 0xEEFFEFFF,
103 0xFDFFFDFF, 0xFFBFFFDF, 0xFFF7FFBB, 0xDE7B7FF7
104};
San Mehat865c8062009-11-13 13:42:06 -0800105
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700106#if IRQ_DEBUG == 1
107static char *irq_status_bits[] = { "cmdcrcfail", "datcrcfail", "cmdtimeout",
108 "dattimeout", "txunderrun", "rxoverrun",
109 "cmdrespend", "cmdsent", "dataend", NULL,
110 "datablkend", "cmdactive", "txactive",
111 "rxactive", "txhalfempty", "rxhalffull",
112 "txfifofull", "rxfifofull", "txfifoempty",
113 "rxfifoempty", "txdataavlbl", "rxdataavlbl",
114 "sdiointr", "progdone", "atacmdcompl",
115 "sdiointrope", "ccstimeout", NULL, NULL,
116 NULL, NULL, NULL };
117
118static void
119msmsdcc_print_status(struct msmsdcc_host *host, char *hdr, uint32_t status)
San Mehat865c8062009-11-13 13:42:06 -0800120{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700121 int i;
San Mehat8b1c2ba2009-11-16 10:17:30 -0800122
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700123 pr_debug("%s-%s ", mmc_hostname(host->mmc), hdr);
124 for (i = 0; i < 32; i++) {
125 if (status & (1 << i))
126 pr_debug("%s ", irq_status_bits[i]);
San Mehat865c8062009-11-13 13:42:06 -0800127 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700128 pr_debug("\n");
San Mehatc7fc9372009-11-22 17:19:07 -0800129}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700130#endif
San Mehat865c8062009-11-13 13:42:06 -0800131
San Mehat9d2bd732009-09-22 16:44:22 -0700132static void
133msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
134 u32 c);
135
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700136#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
137static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
138 struct msmsdcc_sps_ep_conn_data *ep);
139static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
140 struct msmsdcc_sps_ep_conn_data *ep);
141#else
142static inline int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
143 struct msmsdcc_sps_ep_conn_data *ep,
144 bool is_producer) { return 0; }
145static inline void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
146 struct msmsdcc_sps_ep_conn_data *ep) { }
147static inline int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
148 struct msmsdcc_sps_ep_conn_data *ep)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530149{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700150 return 0;
151}
152static inline int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
153 struct msmsdcc_sps_ep_conn_data *ep)
154{
155 return 0;
156}
157static inline int msmsdcc_sps_init(struct msmsdcc_host *host) { return 0; }
158static inline void msmsdcc_sps_exit(struct msmsdcc_host *host) {}
159#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530160
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700161/**
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530162 * Apply soft reset to all SDCC BAM pipes
163 *
164 * This function applies soft reset to SDCC BAM pipe.
165 *
166 * This function should be called to recover from error
167 * conditions encountered during CMD/DATA tranfsers with card.
168 *
169 * @host - Pointer to driver's host structure
170 *
171 */
172static void msmsdcc_sps_pipes_reset_and_restore(struct msmsdcc_host *host)
173{
174 int rc;
175
176 /* Reset all SDCC BAM pipes */
177 rc = msmsdcc_sps_reset_ep(host, &host->sps.prod);
178 if (rc)
179 pr_err("%s:msmsdcc_sps_reset_ep(prod) error=%d\n",
180 mmc_hostname(host->mmc), rc);
181 rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
182 if (rc)
183 pr_err("%s:msmsdcc_sps_reset_ep(cons) error=%d\n",
184 mmc_hostname(host->mmc), rc);
185
186 /* Restore all BAM pipes connections */
187 rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
188 if (rc)
189 pr_err("%s:msmsdcc_sps_restore_ep(prod) error=%d\n",
190 mmc_hostname(host->mmc), rc);
191 rc = msmsdcc_sps_restore_ep(host, &host->sps.cons);
192 if (rc)
193 pr_err("%s:msmsdcc_sps_restore_ep(cons) error=%d\n",
194 mmc_hostname(host->mmc), rc);
195}
196
197/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700198 * Apply soft reset
199 *
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530200 * This function applies soft reset to SDCC core and DML core.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700201 *
202 * This function should be called to recover from error
203 * conditions encountered with CMD/DATA tranfsers with card.
204 *
205 * Soft reset should only be used with SDCC controller v4.
206 *
207 * @host - Pointer to driver's host structure
208 *
209 */
210static void msmsdcc_soft_reset_and_restore(struct msmsdcc_host *host)
211{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700212 if (host->is_sps_mode) {
213 /* Reset DML first */
214 msmsdcc_dml_reset(host);
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530215 /*
216 * delay the SPS pipe reset in thread context as
217 * sps_connect/sps_disconnect APIs can be called
218 * only from non-atomic context.
219 */
220 host->sps.pipe_reset_pending = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700221 }
222 /*
223 * Reset SDCC controller's DPSM (data path state machine
224 * and CPSM (command path state machine).
225 */
226 mb();
227 writel_relaxed(0, host->base + MMCICOMMAND);
228 writel_relaxed(0, host->base + MMCIDATACTRL);
229 mb();
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530230
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700231 pr_debug("%s: Applied soft reset to Controller\n",
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530232 mmc_hostname(host->mmc));
233
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530234 if (host->is_sps_mode)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700235 msmsdcc_dml_init(host);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530236}
237
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700238static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
239{
240 if (host->plat->sdcc_v4_sup) {
241 msmsdcc_soft_reset_and_restore(host);
242 } else {
243 /* Give Clock reset (hard reset) to controller */
244 u32 mci_clk = 0;
245 u32 mci_mask0 = 0;
246 int ret;
247
248 /* Save the controller state */
249 mci_clk = readl_relaxed(host->base + MMCICLOCK);
250 mci_mask0 = readl_relaxed(host->base + MMCIMASK0);
251
252 mb();
253 /* Reset the controller */
254 ret = clk_reset(host->clk, CLK_RESET_ASSERT);
255 if (ret)
256 pr_err("%s: Clock assert failed at %u Hz"
257 " with err %d\n", mmc_hostname(host->mmc),
258 host->clk_rate, ret);
259
260 ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
261 if (ret)
262 pr_err("%s: Clock deassert failed at %u Hz"
263 " with err %d\n", mmc_hostname(host->mmc),
264 host->clk_rate, ret);
265
266 pr_debug("%s: Controller has been reinitialized\n",
267 mmc_hostname(host->mmc));
268
269 mb();
270 /* Restore the contoller state */
271 writel_relaxed(host->pwr, host->base + MMCIPOWER);
272 writel_relaxed(mci_clk, host->base + MMCICLOCK);
273 writel_relaxed(mci_mask0, host->base + MMCIMASK0);
274 ret = clk_set_rate(host->clk, host->clk_rate);
275 if (ret)
276 pr_err("%s: Failed to set clk rate %u Hz. err %d\n",
277 mmc_hostname(host->mmc),
278 host->clk_rate, ret);
279 mb();
280 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700281 if (host->dummy_52_needed)
282 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700283}
284
285static int
San Mehat9d2bd732009-09-22 16:44:22 -0700286msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
287{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700288 int retval = 0;
289
San Mehat9d2bd732009-09-22 16:44:22 -0700290 BUG_ON(host->curr.data);
291
292 host->curr.mrq = NULL;
293 host->curr.cmd = NULL;
294
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700295 del_timer(&host->req_tout_timer);
296
San Mehat9d2bd732009-09-22 16:44:22 -0700297 if (mrq->data)
298 mrq->data->bytes_xfered = host->curr.data_xfered;
299 if (mrq->cmd->error == -ETIMEDOUT)
300 mdelay(5);
301
302 /*
303 * Need to drop the host lock here; mmc_request_done may call
304 * back into the driver...
305 */
306 spin_unlock(&host->lock);
307 mmc_request_done(host->mmc, mrq);
308 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700309
310 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700311}
312
Krishna Konda3e5c4d02011-07-11 16:31:45 -0700313static inline void msmsdcc_delay(struct msmsdcc_host *host);
314
San Mehat9d2bd732009-09-22 16:44:22 -0700315static void
316msmsdcc_stop_data(struct msmsdcc_host *host)
317{
San Mehat9d2bd732009-09-22 16:44:22 -0700318 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530319 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530320 host->curr.wait_for_auto_prog_done = 0;
321 host->curr.got_auto_prog_done = 0;
Krishna Konda3f5d48f2011-07-27 10:47:31 -0700322 writel_relaxed(readl_relaxed(host->base + MMCIDATACTRL) &
323 (~(MCI_DPSM_ENABLE)), host->base + MMCIDATACTRL);
Krishna Konda3e5c4d02011-07-11 16:31:45 -0700324 msmsdcc_delay(host); /* Allow the DPSM to be reset */
San Mehat9d2bd732009-09-22 16:44:22 -0700325}
326
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700327static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700328{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700329 return host->core_memres->start + MMCIFIFO;
330}
331
332static inline unsigned int msmsdcc_get_min_sup_clk_rate(
333 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530334
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700335static inline void msmsdcc_delay(struct msmsdcc_host *host)
336{
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530337 ktime_t start, diff;
338
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700339 mb();
340 udelay(1 + ((3 * USEC_PER_SEC) /
341 (host->clk_rate ? host->clk_rate :
342 msmsdcc_get_min_sup_clk_rate(host))));
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530343
344 if (host->plat->sdcc_v4_sup &&
345 (readl_relaxed(host->base + MCI_STATUS2) &
346 MCI_MCLK_REG_WR_ACTIVE)) {
347 start = ktime_get();
348 while (readl_relaxed(host->base + MCI_STATUS2) &
349 MCI_MCLK_REG_WR_ACTIVE) {
350 diff = ktime_sub(ktime_get(), start);
351 /* poll for max. 1 ms */
352 if (ktime_to_us(diff) > 1000) {
353 pr_warning("%s: previous reg. write is"
354 " still active\n",
355 mmc_hostname(host->mmc));
356 break;
357 }
358 }
359 }
San Mehat9d2bd732009-09-22 16:44:22 -0700360}
361
San Mehat56a8b5b2009-11-21 12:29:46 -0800362static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700363msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
364{
365 writel_relaxed(arg, host->base + MMCIARGUMENT);
366 msmsdcc_delay(host);
367 writel_relaxed(c, host->base + MMCICOMMAND);
368 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800369}
370
371static void
372msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
373{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700374 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800375
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700376 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
377 writel_relaxed((unsigned int)host->curr.xfer_size,
378 host->base + MMCIDATALENGTH);
379 msmsdcc_delay(host); /* Allow data parms to be applied */
380 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
381 msmsdcc_delay(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800382
San Mehat6ac9ea62009-12-02 17:24:58 -0800383 if (host->cmd_cmd) {
384 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700385 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800386 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800387}
388
San Mehat9d2bd732009-09-22 16:44:22 -0700389static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530390msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700391{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530392 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700393 unsigned long flags;
394 struct mmc_request *mrq;
395
396 spin_lock_irqsave(&host->lock, flags);
397 mrq = host->curr.mrq;
398 BUG_ON(!mrq);
399
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530400 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700401 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700402 goto out;
403 }
404
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530405 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700406 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700407 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700408 } else {
409 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530410 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700411 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530412 mmc_hostname(host->mmc), host->dma.result);
413 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700414 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530415 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530416 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700417 host->dma.err.flush[0], host->dma.err.flush[1],
418 host->dma.err.flush[2], host->dma.err.flush[3],
419 host->dma.err.flush[4],
420 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530421 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700422 if (!mrq->data->error)
423 mrq->data->error = -EIO;
424 }
San Mehat9d2bd732009-09-22 16:44:22 -0700425 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents,
426 host->dma.dir);
427
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700428 if (host->curr.user_pages) {
429 struct scatterlist *sg = host->dma.sg;
430 int i;
431
432 for (i = 0; i < host->dma.num_ents; i++, sg++)
433 flush_dcache_page(sg_page(sg));
434 }
435
San Mehat9d2bd732009-09-22 16:44:22 -0700436 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800437 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700438
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530439 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
440 (host->curr.wait_for_auto_prog_done &&
441 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700442 /*
443 * If we've already gotten our DATAEND / DATABLKEND
444 * for this request, then complete it through here.
445 */
San Mehat9d2bd732009-09-22 16:44:22 -0700446
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700447 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700448 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700449 host->curr.xfer_remain -= host->curr.xfer_size;
450 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700451 if (host->dummy_52_needed) {
452 mrq->data->bytes_xfered = host->curr.data_xfered;
453 host->dummy_52_sent = 1;
454 msmsdcc_start_command(host, &dummy52cmd,
455 MCI_CPSM_PROGENA);
456 goto out;
457 }
458 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530459 if (!mrq->data->stop || mrq->cmd->error ||
460 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700461 host->curr.mrq = NULL;
462 host->curr.cmd = NULL;
463 mrq->data->bytes_xfered = host->curr.data_xfered;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700464 del_timer(&host->req_tout_timer);
San Mehat9d2bd732009-09-22 16:44:22 -0700465 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700466
San Mehat9d2bd732009-09-22 16:44:22 -0700467 mmc_request_done(host->mmc, mrq);
468 return;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530469 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
470 || !mrq->sbc)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700471 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530472 }
San Mehat9d2bd732009-09-22 16:44:22 -0700473 }
474
475out:
476 spin_unlock_irqrestore(&host->lock, flags);
477 return;
478}
479
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700480#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
481/**
482 * Callback notification from SPS driver
483 *
484 * This callback function gets triggered called from
485 * SPS driver when requested SPS data transfer is
486 * completed.
487 *
488 * SPS driver invokes this callback in BAM irq context so
489 * SDCC driver schedule a tasklet for further processing
490 * this callback notification at later point of time in
491 * tasklet context and immediately returns control back
492 * to SPS driver.
493 *
494 * @nofity - Pointer to sps event notify sturcture
495 *
496 */
497static void
498msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
499{
500 struct msmsdcc_host *host =
501 (struct msmsdcc_host *)
502 ((struct sps_event_notify *)notify)->user;
503
504 host->sps.notify = *notify;
505 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
506 mmc_hostname(host->mmc), __func__, notify->event_id,
507 notify->data.transfer.iovec.addr,
508 notify->data.transfer.iovec.size,
509 notify->data.transfer.iovec.flags);
510 /* Schedule a tasklet for completing data transfer */
511 tasklet_schedule(&host->sps.tlet);
512}
513
514/**
515 * Tasklet handler for processing SPS callback event
516 *
517 * This function processing SPS event notification and
518 * checks if the SPS transfer is completed or not and
519 * then accordingly notifies status to MMC core layer.
520 *
521 * This function is called in tasklet context.
522 *
523 * @data - Pointer to sdcc driver data
524 *
525 */
526static void msmsdcc_sps_complete_tlet(unsigned long data)
527{
528 unsigned long flags;
529 int i, rc;
530 u32 data_xfered = 0;
531 struct mmc_request *mrq;
532 struct sps_iovec iovec;
533 struct sps_pipe *sps_pipe_handle;
534 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
535 struct sps_event_notify *notify = &host->sps.notify;
536
537 spin_lock_irqsave(&host->lock, flags);
538 if (host->sps.dir == DMA_FROM_DEVICE)
539 sps_pipe_handle = host->sps.prod.pipe_handle;
540 else
541 sps_pipe_handle = host->sps.cons.pipe_handle;
542 mrq = host->curr.mrq;
543
544 if (!mrq) {
545 spin_unlock_irqrestore(&host->lock, flags);
546 return;
547 }
548
549 pr_debug("%s: %s: sps event_id=%d\n",
550 mmc_hostname(host->mmc), __func__,
551 notify->event_id);
552
553 if (msmsdcc_is_dml_busy(host)) {
554 /* oops !!! this should never happen. */
555 pr_err("%s: %s: Received SPS EOT event"
556 " but DML HW is still busy !!!\n",
557 mmc_hostname(host->mmc), __func__);
558 }
559 /*
560 * Got End of transfer event!!! Check if all of the data
561 * has been transferred?
562 */
563 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
564 rc = sps_get_iovec(sps_pipe_handle, &iovec);
565 if (rc) {
566 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
567 mmc_hostname(host->mmc), __func__, rc, i);
568 break;
569 }
570 data_xfered += iovec.size;
571 }
572
573 if (data_xfered == host->curr.xfer_size) {
574 host->curr.data_xfered = host->curr.xfer_size;
575 host->curr.xfer_remain -= host->curr.xfer_size;
576 pr_debug("%s: Data xfer success. data_xfered=0x%x",
577 mmc_hostname(host->mmc),
578 host->curr.xfer_size);
579 } else {
580 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
581 " xfer_size=%d", mmc_hostname(host->mmc),
582 data_xfered, host->curr.xfer_size);
583 msmsdcc_reset_and_restore(host);
584 if (!mrq->data->error)
585 mrq->data->error = -EIO;
586 }
587
588 /* Unmap sg buffers */
589 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
590 host->sps.dir);
591
592 host->sps.sg = NULL;
593 host->sps.busy = 0;
594
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530595 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
596 (host->curr.wait_for_auto_prog_done &&
597 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700598 /*
599 * If we've already gotten our DATAEND / DATABLKEND
600 * for this request, then complete it through here.
601 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700602
603 if (!mrq->data->error) {
604 host->curr.data_xfered = host->curr.xfer_size;
605 host->curr.xfer_remain -= host->curr.xfer_size;
606 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700607 if (host->dummy_52_needed) {
608 mrq->data->bytes_xfered = host->curr.data_xfered;
609 host->dummy_52_sent = 1;
610 msmsdcc_start_command(host, &dummy52cmd,
611 MCI_CPSM_PROGENA);
612 return;
613 }
614 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530615 if (!mrq->data->stop || mrq->cmd->error ||
616 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700617 host->curr.mrq = NULL;
618 host->curr.cmd = NULL;
619 mrq->data->bytes_xfered = host->curr.data_xfered;
620 del_timer(&host->req_tout_timer);
621 spin_unlock_irqrestore(&host->lock, flags);
622
623 mmc_request_done(host->mmc, mrq);
624 return;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530625 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
626 || !mrq->sbc)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700627 msmsdcc_start_command(host, mrq->data->stop, 0);
628 }
629 }
630 spin_unlock_irqrestore(&host->lock, flags);
631}
632
633/**
634 * Exit from current SPS data transfer
635 *
636 * This function exits from current SPS data transfer.
637 *
638 * This function should be called when error condition
639 * is encountered during data transfer.
640 *
641 * @host - Pointer to sdcc host structure
642 *
643 */
644static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
645{
646 struct mmc_request *mrq;
647
648 mrq = host->curr.mrq;
649 BUG_ON(!mrq);
650
651 msmsdcc_reset_and_restore(host);
652 if (!mrq->data->error)
653 mrq->data->error = -EIO;
654
655 /* Unmap sg buffers */
656 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
657 host->sps.dir);
658
659 host->sps.sg = NULL;
660 host->sps.busy = 0;
661 if (host->curr.data)
662 msmsdcc_stop_data(host);
663
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530664 if (!mrq->data->stop || mrq->cmd->error ||
665 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700666 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530667 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
668 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700669 msmsdcc_start_command(host, mrq->data->stop, 0);
670
671}
672#else
673static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
674static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
675static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
676#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
677
678static void msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
679
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530680static void
681msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
682 unsigned int result,
683 struct msm_dmov_errdata *err)
684{
685 struct msmsdcc_dma_data *dma_data =
686 container_of(cmd, struct msmsdcc_dma_data, hdr);
687 struct msmsdcc_host *host = dma_data->host;
688
689 dma_data->result = result;
690 if (err)
691 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
692
693 tasklet_schedule(&host->dma_tlet);
694}
695
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700696static int msmsdcc_check_dma_op_req(struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700697{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700698 if (((data->blksz * data->blocks) < MCI_FIFOSIZE) ||
699 ((data->blksz * data->blocks) % MCI_FIFOSIZE))
San Mehat9d2bd732009-09-22 16:44:22 -0700700 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700701 else
702 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700703}
704
705static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
706{
707 struct msmsdcc_nc_dmadata *nc;
708 dmov_box *box;
709 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700710 unsigned int n;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700711 int i;
San Mehat9d2bd732009-09-22 16:44:22 -0700712 struct scatterlist *sg = data->sg;
713
Krishna Konda25786ec2011-07-25 16:21:36 -0700714 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700715 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700716
Krishna Konda25786ec2011-07-25 16:21:36 -0700717 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
718
San Mehat9d2bd732009-09-22 16:44:22 -0700719 host->dma.sg = data->sg;
720 host->dma.num_ents = data->sg_len;
721
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700722 BUG_ON(host->dma.num_ents > NR_SG); /* Prevent memory corruption */
San Mehat56a8b5b2009-11-21 12:29:46 -0800723
San Mehat9d2bd732009-09-22 16:44:22 -0700724 nc = host->dma.nc;
725
San Mehat9d2bd732009-09-22 16:44:22 -0700726 if (data->flags & MMC_DATA_READ)
727 host->dma.dir = DMA_FROM_DEVICE;
728 else
729 host->dma.dir = DMA_TO_DEVICE;
730
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700731 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
San Mehat9d2bd732009-09-22 16:44:22 -0700732 host->curr.user_pages = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700733 box = &nc->cmd[0];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700734 for (i = 0; i < host->dma.num_ents; i++) {
San Mehat9d2bd732009-09-22 16:44:22 -0700735 box->cmd = CMD_MODE_BOX;
736
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700737 /* Initialize sg dma address */
738 sg->dma_address = pfn_to_dma(mmc_dev(host->mmc),
739 page_to_pfn(sg_page(sg)))
740 + sg->offset;
741
742 if (i == (host->dma.num_ents - 1))
San Mehat9d2bd732009-09-22 16:44:22 -0700743 box->cmd |= CMD_LC;
744 rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ?
745 (sg_dma_len(sg) / MCI_FIFOSIZE) + 1 :
746 (sg_dma_len(sg) / MCI_FIFOSIZE) ;
747
748 if (data->flags & MMC_DATA_READ) {
749 box->src_row_addr = msmsdcc_fifo_addr(host);
750 box->dst_row_addr = sg_dma_address(sg);
751
752 box->src_dst_len = (MCI_FIFOSIZE << 16) |
753 (MCI_FIFOSIZE);
754 box->row_offset = MCI_FIFOSIZE;
755
756 box->num_rows = rows * ((1 << 16) + 1);
Krishna Konda25786ec2011-07-25 16:21:36 -0700757 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
San Mehat9d2bd732009-09-22 16:44:22 -0700758 } else {
759 box->src_row_addr = sg_dma_address(sg);
760 box->dst_row_addr = msmsdcc_fifo_addr(host);
761
762 box->src_dst_len = (MCI_FIFOSIZE << 16) |
763 (MCI_FIFOSIZE);
764 box->row_offset = (MCI_FIFOSIZE << 16);
765
766 box->num_rows = rows * ((1 << 16) + 1);
Krishna Konda25786ec2011-07-25 16:21:36 -0700767 box->cmd |= CMD_DST_CRCI(host->dma.crci);
San Mehat9d2bd732009-09-22 16:44:22 -0700768 }
769 box++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700770 sg++;
771 }
772
773 /* location of command block must be 64 bit aligned */
774 BUG_ON(host->dma.cmd_busaddr & 0x07);
775
776 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
777 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
778 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
779 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700780
781 n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
782 host->dma.num_ents, host->dma.dir);
783 /* dsb inside dma_map_sg will write nc out to mem as well */
784
785 if (n != host->dma.num_ents) {
786 pr_err("%s: Unable to map in all sg elements\n",
787 mmc_hostname(host->mmc));
788 host->dma.sg = NULL;
789 host->dma.num_ents = 0;
790 return -ENOMEM;
San Mehat56a8b5b2009-11-21 12:29:46 -0800791 }
San Mehat9d2bd732009-09-22 16:44:22 -0700792
793 return 0;
794}
795
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700796#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
797/**
798 * Submits data transfer request to SPS driver
799 *
800 * This function make sg (scatter gather) data buffers
801 * DMA ready and then submits them to SPS driver for
802 * transfer.
803 *
804 * @host - Pointer to sdcc host structure
805 * @data - Pointer to mmc_data structure
806 *
807 * @return 0 if success else negative value
808 */
809static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
810 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -0800811{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700812 int rc = 0;
813 u32 flags;
814 int i;
815 u32 addr, len, data_cnt;
816 struct scatterlist *sg = data->sg;
817 struct sps_pipe *sps_pipe_handle;
818
819 BUG_ON(data->sg_len > NR_SG); /* Prevent memory corruption */
820
821 host->sps.sg = data->sg;
822 host->sps.num_ents = data->sg_len;
823 host->sps.xfer_req_cnt = 0;
824 if (data->flags & MMC_DATA_READ) {
825 host->sps.dir = DMA_FROM_DEVICE;
826 sps_pipe_handle = host->sps.prod.pipe_handle;
827 } else {
828 host->sps.dir = DMA_TO_DEVICE;
829 sps_pipe_handle = host->sps.cons.pipe_handle;
830 }
831
832 /* Make sg buffers DMA ready */
833 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
834 host->sps.dir);
835
836 if (rc != data->sg_len) {
837 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
838 mmc_hostname(host->mmc), rc);
839 host->sps.sg = NULL;
840 host->sps.num_ents = 0;
841 rc = -ENOMEM;
842 goto dma_map_err;
843 }
844
845 pr_debug("%s: %s: %s: pipe=0x%x, total_xfer=0x%x, sg_len=%d\n",
846 mmc_hostname(host->mmc), __func__,
847 host->sps.dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
848 (u32)sps_pipe_handle, host->curr.xfer_size, data->sg_len);
849
850 for (i = 0; i < data->sg_len; i++) {
851 /*
852 * Check if this is the last buffer to transfer?
853 * If yes then set the INT and EOT flags.
854 */
855 len = sg_dma_len(sg);
856 addr = sg_dma_address(sg);
857 flags = 0;
858 while (len > 0) {
859 if (len > SPS_MAX_DESC_SIZE) {
860 data_cnt = SPS_MAX_DESC_SIZE;
861 } else {
862 data_cnt = len;
863 if (i == data->sg_len - 1)
864 flags = SPS_IOVEC_FLAG_INT |
865 SPS_IOVEC_FLAG_EOT;
866 }
867 rc = sps_transfer_one(sps_pipe_handle, addr,
868 data_cnt, host, flags);
869 if (rc) {
870 pr_err("%s: sps_transfer_one() error! rc=%d,"
871 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
872 mmc_hostname(host->mmc), rc,
873 (u32)sps_pipe_handle, (u32)sg, i);
874 goto dma_map_err;
875 }
876 addr += data_cnt;
877 len -= data_cnt;
878 host->sps.xfer_req_cnt++;
879 }
880 sg++;
881 }
882 goto out;
883
884dma_map_err:
885 /* unmap sg buffers */
886 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
887 host->sps.dir);
888out:
889 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -0700890}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700891#else
892static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
893 struct mmc_data *data) { return 0; }
894#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -0700895
896static void
San Mehat56a8b5b2009-11-21 12:29:46 -0800897msmsdcc_start_command_deferred(struct msmsdcc_host *host,
898 struct mmc_command *cmd, u32 *c)
899{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700900 DBG(host, "op %02x arg %08x flags %08x\n",
901 cmd->opcode, cmd->arg, cmd->flags);
902
San Mehat56a8b5b2009-11-21 12:29:46 -0800903 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
904
905 if (cmd->flags & MMC_RSP_PRESENT) {
906 if (cmd->flags & MMC_RSP_136)
907 *c |= MCI_CPSM_LONGRSP;
908 *c |= MCI_CPSM_RESPONSE;
909 }
910
911 if (/*interrupt*/0)
912 *c |= MCI_CPSM_INTERRUPT;
913
914 if ((((cmd->opcode == 17) || (cmd->opcode == 18)) ||
915 ((cmd->opcode == 24) || (cmd->opcode == 25))) ||
916 (cmd->opcode == 53))
917 *c |= MCI_CSPM_DATCMD;
918
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700919 /* Check if AUTO CMD19 is required or not? */
920 if (((cmd->opcode == 17) || (cmd->opcode == 18)) &&
921 host->tuning_needed) {
922 msmsdcc_enable_cdr_cm_sdc4_dll(host);
923 *c |= MCI_CSPM_AUTO_CMD19;
924 }
925
Sahitya Tummalad5137bd2010-12-08 15:03:04 +0530926 if (host->prog_scan && (cmd->opcode == 12)) {
927 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700928 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +0530929 }
930
San Mehat56a8b5b2009-11-21 12:29:46 -0800931 if (cmd == cmd->mrq->stop)
932 *c |= MCI_CSPM_MCIABORT;
933
San Mehat56a8b5b2009-11-21 12:29:46 -0800934 if (host->curr.cmd != NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700935 pr_err("%s: Overlapping command requests\n",
936 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -0800937 }
938 host->curr.cmd = cmd;
939}
940
941static void
942msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
943 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -0700944{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +0530945 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -0700946 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700947 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -0700948 unsigned int pio_irqmask = 0;
949
950 host->curr.data = data;
951 host->curr.xfer_size = data->blksz * data->blocks;
952 host->curr.xfer_remain = host->curr.xfer_size;
953 host->curr.data_xfered = 0;
954 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530955 host->curr.got_auto_prog_done = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700956
957 memset(&host->pio, 0, sizeof(host->pio));
958
San Mehat9d2bd732009-09-22 16:44:22 -0700959 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
960
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530961 if (host->curr.wait_for_auto_prog_done)
962 datactrl |= MCI_AUTO_PROG_DONE;
963
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700964 if (!msmsdcc_check_dma_op_req(data)) {
965 if (host->is_dma_mode && !msmsdcc_config_dma(host, data)) {
966 datactrl |= MCI_DPSM_DMAENABLE;
967 } else if (host->is_sps_mode) {
968 if (!msmsdcc_is_dml_busy(host)) {
969 if (!msmsdcc_sps_start_xfer(host, data)) {
970 /* Now kick start DML transfer */
971 mb();
972 msmsdcc_dml_start_xfer(host, data);
973 datactrl |= MCI_DPSM_DMAENABLE;
974 host->sps.busy = 1;
975 }
976 } else {
977 /*
978 * Can't proceed with new transfer as
979 * previous trasnfer is already in progress.
980 * There is no point of going into PIO mode
981 * as well. Is this a time to do kernel panic?
982 */
983 pr_err("%s: %s: DML HW is busy!!!"
984 " Can't perform new SPS transfers"
985 " now\n", mmc_hostname(host->mmc),
986 __func__);
987 }
988 }
989 }
990
991 /* Is data transfer in PIO mode required? */
992 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700993 host->pio.sg = data->sg;
994 host->pio.sg_len = data->sg_len;
995 host->pio.sg_off = 0;
996
997 if (data->flags & MMC_DATA_READ) {
998 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
999 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1000 pio_irqmask |= MCI_RXDATAAVLBLMASK;
1001 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001002 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1003 MCI_TXFIFOEMPTYMASK;
San Mehat9d2bd732009-09-22 16:44:22 -07001004 }
1005
1006 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301007 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
San Mehat9d2bd732009-09-22 16:44:22 -07001008
San Mehat56a8b5b2009-11-21 12:29:46 -08001009 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001010 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001011 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -07001012
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001013 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
1014 /* Use ADM (Application Data Mover) HW for Data transfer */
1015 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001016 host->cmd_timeout = timeout;
1017 host->cmd_pio_irqmask = pio_irqmask;
1018 host->cmd_datactrl = datactrl;
1019 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001020
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001021 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1022 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001023 host->dma.busy = 1;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301024 if ((data->flags & MMC_DATA_WRITE) && !host->curr.mrq->sbc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001025 host->prog_scan = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001026
1027 if (cmd) {
1028 msmsdcc_start_command_deferred(host, cmd, &c);
1029 host->cmd_c = c;
1030 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001031 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1032 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1033 host->base + MMCIMASK0);
1034 mb();
1035 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001036 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001037 /* SPS-BAM mode or PIO mode */
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301038 if ((data->flags & MMC_DATA_WRITE) && !host->curr.mrq->sbc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001039 host->prog_scan = 1;
1040 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001041
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001042 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001043
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001044 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1045 (~(MCI_IRQ_PIO))) | pio_irqmask,
1046 host->base + MMCIMASK0);
1047 msmsdcc_delay(host); /* Allow parms to be applied */
1048 writel_relaxed(datactrl, base + MMCIDATACTRL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001049
1050 if (cmd) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001051 msmsdcc_delay(host); /* Delay between data/command */
San Mehat56a8b5b2009-11-21 12:29:46 -08001052 /* Daisy-chain the command if requested */
1053 msmsdcc_start_command(host, cmd, c);
1054 }
San Mehat9d2bd732009-09-22 16:44:22 -07001055 }
1056}
1057
1058static void
1059msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1060{
San Mehat56a8b5b2009-11-21 12:29:46 -08001061 msmsdcc_start_command_deferred(host, cmd, &c);
1062 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001063}
1064
1065static void
1066msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1067 unsigned int status)
1068{
1069 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001070 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1071 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1072 pr_err("%s: Data CRC error\n",
1073 mmc_hostname(host->mmc));
1074 pr_err("%s: opcode 0x%.8x\n", __func__,
1075 data->mrq->cmd->opcode);
1076 pr_err("%s: blksz %d, blocks %d\n", __func__,
1077 data->blksz, data->blocks);
1078 data->error = -EILSEQ;
1079 }
San Mehat9d2bd732009-09-22 16:44:22 -07001080 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001081 /* CRC is optional for the bus test commands, not all
1082 * cards respond back with CRC. However controller
1083 * waits for the CRC and times out. Hence ignore the
1084 * data timeouts during the Bustest.
1085 */
1086 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1087 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1088 pr_err("%s: Data timeout\n",
1089 mmc_hostname(host->mmc));
1090 data->error = -ETIMEDOUT;
1091 }
San Mehat9d2bd732009-09-22 16:44:22 -07001092 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001093 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001094 data->error = -EIO;
1095 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001096 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001097 data->error = -EIO;
1098 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001099 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001100 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001101 data->error = -EIO;
1102 }
San Mehat9d2bd732009-09-22 16:44:22 -07001103
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001104 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001105 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001106 host->dummy_52_needed = 0;
1107}
San Mehat9d2bd732009-09-22 16:44:22 -07001108
1109static int
1110msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1111{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001112 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001113 uint32_t *ptr = (uint32_t *) buffer;
1114 int count = 0;
1115
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301116 if (remain % 4)
1117 remain = ((remain >> 2) + 1) << 2;
1118
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001119 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1120
1121 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001122 ptr++;
1123 count += sizeof(uint32_t);
1124
1125 remain -= sizeof(uint32_t);
1126 if (remain == 0)
1127 break;
1128 }
1129 return count;
1130}
1131
1132static int
1133msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001134 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001135{
1136 void __iomem *base = host->base;
1137 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001138 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001139
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001140 while (readl_relaxed(base + MMCISTATUS) &
1141 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1142 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001143
San Mehat9d2bd732009-09-22 16:44:22 -07001144 count = min(remain, maxcnt);
1145
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301146 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1147 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001148 ptr += count;
1149 remain -= count;
1150
1151 if (remain == 0)
1152 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001153 }
1154 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001155
1156 return ptr - buffer;
1157}
1158
San Mehat1cd22962010-02-03 12:59:29 -08001159static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001160msmsdcc_pio_irq(int irq, void *dev_id)
1161{
1162 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001163 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001164 uint32_t status;
1165
Murali Palnati36448a42011-09-02 15:06:18 +05301166 spin_lock(&host->lock);
1167
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001168 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001169
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001170 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301171 (MCI_IRQ_PIO)) == 0) {
1172 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001173 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301174 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001175
1176#if IRQ_DEBUG
1177 msmsdcc_print_status(host, "irq1-r", status);
1178#endif
1179
San Mehat9d2bd732009-09-22 16:44:22 -07001180 do {
1181 unsigned long flags;
1182 unsigned int remain, len;
1183 char *buffer;
1184
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001185 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1186 | MCI_RXDATAAVLBL)))
1187 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001188
1189 /* Map the current scatter buffer */
1190 local_irq_save(flags);
1191 buffer = kmap_atomic(sg_page(host->pio.sg),
1192 KM_BIO_SRC_IRQ) + host->pio.sg->offset;
1193 buffer += host->pio.sg_off;
1194 remain = host->pio.sg->length - host->pio.sg_off;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001195
San Mehat9d2bd732009-09-22 16:44:22 -07001196 len = 0;
1197 if (status & MCI_RXACTIVE)
1198 len = msmsdcc_pio_read(host, buffer, remain);
1199 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001200 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001201
1202 /* Unmap the buffer */
1203 kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
1204 local_irq_restore(flags);
1205
1206 host->pio.sg_off += len;
1207 host->curr.xfer_remain -= len;
1208 host->curr.data_xfered += len;
1209 remain -= len;
1210
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001211 if (remain) /* Done with this page? */
1212 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001213
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001214 if (status & MCI_RXACTIVE && host->curr.user_pages)
1215 flush_dcache_page(sg_page(host->pio.sg));
San Mehat9d2bd732009-09-22 16:44:22 -07001216
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001217 if (!--host->pio.sg_len) {
1218 memset(&host->pio, 0, sizeof(host->pio));
1219 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001220 }
1221
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001222 /* Advance to next sg */
1223 host->pio.sg++;
1224 host->pio.sg_off = 0;
1225
1226 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001227 } while (1);
1228
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001229 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1230 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1231 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1232 host->base + MMCIMASK0);
1233 if (!host->curr.xfer_remain) {
1234 /* Delay needed (same port was just written) */
1235 msmsdcc_delay(host);
1236 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1237 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1238 }
1239 mb();
1240 } else if (!host->curr.xfer_remain) {
1241 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1242 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1243 mb();
1244 }
San Mehat9d2bd732009-09-22 16:44:22 -07001245
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001246 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001247
1248 return IRQ_HANDLED;
1249}
1250
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001251static void
1252msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1253
1254static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1255 struct mmc_data *data)
1256{
1257 u32 loop_cnt = 0;
1258
1259 /*
1260 * For read commands with data less than fifo size, it is possible to
1261 * get DATAEND first and RXDATA_AVAIL might be set later because of
1262 * synchronization delay through the asynchronous RX FIFO. Thus, for
1263 * such cases, even after DATAEND interrupt is received software
1264 * should poll for RXDATA_AVAIL until the requested data is read out
1265 * of FIFO. This change is needed to get around this abnormal but
1266 * sometimes expected behavior of SDCC3 controller.
1267 *
1268 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1269 * after the data is loaded into RX FIFO. This would amount to less
1270 * than a microsecond and thus looping for 1000 times is good enough
1271 * for that delay.
1272 */
1273 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1274 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1275 spin_unlock(&host->lock);
1276 msmsdcc_pio_irq(1, host);
1277 spin_lock(&host->lock);
1278 }
1279 }
1280 if (loop_cnt == 1000) {
1281 pr_info("%s: Timed out while polling for Rx Data\n",
1282 mmc_hostname(host->mmc));
1283 data->error = -ETIMEDOUT;
1284 msmsdcc_reset_and_restore(host);
1285 }
1286}
1287
San Mehat9d2bd732009-09-22 16:44:22 -07001288static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1289{
1290 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001291
1292 host->curr.cmd = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001293 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1294 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1295 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1296 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -07001297
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001298 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Sahitya Tummala5a0ae912011-07-18 13:34:01 +05301299 pr_debug("%s: Command timeout\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001300 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001301 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
1302 !host->cmd19_tuning_in_progress) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001303 pr_err("%s: Command CRC error\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001304 cmd->error = -EILSEQ;
1305 }
1306
1307 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001308 if (host->curr.data && host->dma.sg &&
1309 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001310 msm_dmov_stop_cmd(host->dma.channel,
1311 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001312 else if (host->curr.data && host->sps.sg &&
1313 host->is_sps_mode){
1314 /* Stop current SPS transfer */
1315 msmsdcc_sps_exit_curr_xfer(host);
1316 }
San Mehat9d2bd732009-09-22 16:44:22 -07001317 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301318 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001319 msmsdcc_stop_data(host);
1320 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301321 } else { /* host->data == NULL */
1322 if (!cmd->error && host->prog_enable) {
1323 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001324 host->prog_scan = 0;
1325 host->prog_enable = 0;
1326 msmsdcc_request_end(host, cmd->mrq);
1327 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301328 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301329 } else {
1330 if (host->prog_enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001331 host->prog_scan = 0;
1332 host->prog_enable = 0;
1333 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001334 if (host->dummy_52_needed)
1335 host->dummy_52_needed = 0;
1336 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001337 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301338 msmsdcc_request_end(host, cmd->mrq);
1339 }
1340 }
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301341 } else if (cmd == host->curr.mrq->sbc) {
1342 msmsdcc_request_start(host, host->curr.mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001343 } else if (cmd->data) {
San Mehat56a8b5b2009-11-21 12:29:46 -08001344 if (!(cmd->data->flags & MMC_DATA_READ))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001345 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001346 }
1347}
1348
San Mehat9d2bd732009-09-22 16:44:22 -07001349static irqreturn_t
1350msmsdcc_irq(int irq, void *dev_id)
1351{
1352 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001353 u32 status;
1354 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001355 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001356
1357 spin_lock(&host->lock);
1358
1359 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001360 struct mmc_command *cmd;
1361 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001362
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001363 if (timer) {
1364 timer = 0;
1365 msmsdcc_delay(host);
1366 }
San Mehat865c8062009-11-13 13:42:06 -08001367
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001368 if (!host->clks_on) {
1369 pr_debug("%s: %s: SDIO async irq received\n",
1370 mmc_hostname(host->mmc), __func__);
1371 host->mmc->ios.clock = host->clk_rate;
1372 spin_unlock(&host->lock);
1373 host->mmc->ops->set_ios(host->mmc, &host->mmc->ios);
1374 spin_lock(&host->lock);
1375 if (host->plat->cfg_mpm_sdiowakeup &&
1376 (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
1377 wake_lock(&host->sdio_wlock);
1378 /* only ansyc interrupt can come when clocks are off */
1379 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
1380 }
1381
1382 status = readl_relaxed(host->base + MMCISTATUS);
1383
1384 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1385 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001386 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001387
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001388#if IRQ_DEBUG
1389 msmsdcc_print_status(host, "irq0-r", status);
1390#endif
1391 status &= readl_relaxed(host->base + MMCIMASK0);
1392 writel_relaxed(status, host->base + MMCICLEAR);
1393 mb();
1394#if IRQ_DEBUG
1395 msmsdcc_print_status(host, "irq0-p", status);
1396#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001397
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001398#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
1399 if (status & MCI_SDIOINTROPE) {
1400 if (host->sdcc_suspending)
1401 wake_lock(&host->sdio_suspend_wlock);
1402 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001403 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001404#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001405 data = host->curr.data;
1406
1407 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001408 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1409 MCI_CMDTIMEOUT)) {
1410 if (status & MCI_CMDTIMEOUT)
1411 pr_debug("%s: dummy CMD52 timeout\n",
1412 mmc_hostname(host->mmc));
1413 if (status & MCI_CMDCRCFAIL)
1414 pr_debug("%s: dummy CMD52 CRC failed\n",
1415 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001416 host->dummy_52_sent = 0;
1417 host->dummy_52_needed = 0;
1418 if (data) {
1419 msmsdcc_stop_data(host);
1420 msmsdcc_request_end(host, data->mrq);
1421 }
1422 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001423 spin_unlock(&host->lock);
1424 return IRQ_HANDLED;
1425 }
1426 break;
1427 }
1428
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001429 /*
1430 * Check for proper command response
1431 */
1432 cmd = host->curr.cmd;
1433 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1434 MCI_CMDTIMEOUT | MCI_PROGDONE |
1435 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1436 msmsdcc_do_cmdirq(host, status);
1437 }
1438
1439 if (data) {
1440 /* Check for data errors */
1441 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1442 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1443 msmsdcc_data_err(host, data, status);
1444 host->curr.data_xfered = 0;
1445 if (host->dma.sg && host->is_dma_mode)
1446 msm_dmov_stop_cmd(host->dma.channel,
1447 &host->dma.hdr, 0);
1448 else if (host->sps.sg && host->is_sps_mode) {
1449 /* Stop current SPS transfer */
1450 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301451 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001452 msmsdcc_reset_and_restore(host);
1453 if (host->curr.data)
1454 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301455 if (!data->stop || (host->curr.mrq->sbc
1456 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001457 timer |=
1458 msmsdcc_request_end(host,
1459 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301460 else if ((host->curr.mrq->sbc
1461 && data->error) ||
1462 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001463 msmsdcc_start_command(host,
1464 data->stop,
1465 0);
1466 timer = 1;
1467 }
1468 }
1469 }
1470
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301471 /* Check for prog done */
1472 if (host->curr.wait_for_auto_prog_done &&
1473 (status & MCI_PROGDONE))
1474 host->curr.got_auto_prog_done = 1;
1475
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001476 /* Check for data done */
1477 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1478 host->curr.got_dataend = 1;
1479
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301480 if (host->curr.got_dataend &&
1481 (!host->curr.wait_for_auto_prog_done ||
1482 (host->curr.wait_for_auto_prog_done &&
1483 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001484 /*
1485 * If DMA is still in progress, we complete
1486 * via the completion handler
1487 */
1488 if (!host->dma.busy && !host->sps.busy) {
1489 /*
1490 * There appears to be an issue in the
1491 * controller where if you request a
1492 * small block transfer (< fifo size),
1493 * you may get your DATAEND/DATABLKEND
1494 * irq without the PIO data irq.
1495 *
1496 * Check to see if theres still data
1497 * to be read, and simulate a PIO irq.
1498 */
1499 if (data->flags & MMC_DATA_READ)
1500 msmsdcc_wait_for_rxdata(host,
1501 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001502 if (!data->error) {
1503 host->curr.data_xfered =
1504 host->curr.xfer_size;
1505 host->curr.xfer_remain -=
1506 host->curr.xfer_size;
1507 }
1508
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001509 if (!host->dummy_52_needed) {
1510 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301511 if (!data->stop ||
1512 (host->curr.mrq->sbc
1513 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001514 msmsdcc_request_end(
1515 host,
1516 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301517 else if ((host->curr.mrq->sbc
1518 && data->error) ||
1519 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001520 msmsdcc_start_command(
1521 host,
1522 data->stop, 0);
1523 timer = 1;
1524 }
1525 } else {
1526 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001527 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001528 &dummy52cmd,
1529 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001530 }
1531 }
1532 }
1533 }
1534
San Mehat9d2bd732009-09-22 16:44:22 -07001535 ret = 1;
1536 } while (status);
1537
1538 spin_unlock(&host->lock);
1539
San Mehat9d2bd732009-09-22 16:44:22 -07001540 return IRQ_RETVAL(ret);
1541}
1542
1543static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001544msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1545{
1546 if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
1547 /* Queue/read data, daisy-chain command when data starts */
1548 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
1549 } else {
1550 msmsdcc_start_command(host, mrq->cmd, 0);
1551 }
1552}
1553
1554static void
San Mehat9d2bd732009-09-22 16:44:22 -07001555msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1556{
1557 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001558 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001559
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001560 /*
1561 * Get the SDIO AL client out of LPM.
1562 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001563 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001564 if (host->plat->is_sdio_al_client)
1565 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001566
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301567 /* check if sps pipe reset is pending? */
1568 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1569 msmsdcc_sps_pipes_reset_and_restore(host);
1570 host->sps.pipe_reset_pending = false;
1571 }
1572
San Mehat9d2bd732009-09-22 16:44:22 -07001573 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001574 WARN(host->curr.mrq, "Request in progress\n");
1575 WARN(!host->pwr, "SDCC power is turned off\n");
1576 WARN(!host->clks_on, "SDCC clocks are turned off\n");
1577 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
San Mehat9d2bd732009-09-22 16:44:22 -07001578
1579 if (host->eject) {
1580 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1581 mrq->cmd->error = 0;
1582 mrq->data->bytes_xfered = mrq->data->blksz *
1583 mrq->data->blocks;
1584 } else
1585 mrq->cmd->error = -ENOMEDIUM;
1586
1587 spin_unlock_irqrestore(&host->lock, flags);
1588 mmc_request_done(mmc, mrq);
1589 return;
1590 }
1591
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301592 /*
1593 * Kick the software command timeout timer here.
1594 * Timer expires in 10 secs.
1595 */
1596 mod_timer(&host->req_tout_timer,
1597 (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
San Mehat9d2bd732009-09-22 16:44:22 -07001598
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301599 host->curr.mrq = mrq;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301600 if (mrq->data && mrq->data->flags == MMC_DATA_WRITE) {
1601 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
1602 mrq->cmd->opcode == 54) {
1603 if (!host->plat->sdcc_v4_sup)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001604 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301605 else
1606 /*
1607 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
1608 * write operations using CMD53 and CMD54.
1609 * Setting this bit with CMD53 would
1610 * automatically triggers PROG_DONE interrupt
1611 * without the need of sending dummy CMD52.
1612 */
1613 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001614 }
San Mehat9d2bd732009-09-22 16:44:22 -07001615 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301616
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301617 if (mrq->sbc) {
1618 mrq->sbc->mrq = mrq;
1619 mrq->sbc->data = mrq->data;
1620 if (mrq->data->flags == MMC_DATA_WRITE)
1621 host->curr.wait_for_auto_prog_done = 1;
1622 msmsdcc_start_command(host, mrq->sbc, 0);
1623 } else {
1624 msmsdcc_request_start(host, mrq);
1625 }
1626
San Mehat9d2bd732009-09-22 16:44:22 -07001627 spin_unlock_irqrestore(&host->lock, flags);
1628}
1629
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001630static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1631 int min_uV, int max_uV)
1632{
1633 int rc = 0;
1634
1635 if (vreg->set_voltage_sup) {
1636 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1637 if (rc) {
1638 pr_err("%s: regulator_set_voltage(%s) failed."
1639 " min_uV=%d, max_uV=%d, rc=%d\n",
1640 __func__, vreg->name, min_uV, max_uV, rc);
1641 }
1642 }
1643
1644 return rc;
1645}
1646
1647static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1648 int uA_load)
1649{
1650 int rc = 0;
1651
1652 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1653 if (rc < 0)
1654 pr_err("%s: regulator_set_optimum_mode(reg=%s, uA_load=%d)"
1655 " failed. rc=%d\n", __func__, vreg->name,
1656 uA_load, rc);
1657 else
1658 /* regulator_set_optimum_mode() can return non zero value
1659 * even for success case.
1660 */
1661 rc = 0;
1662
1663 return rc;
1664}
1665
1666static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1667 struct device *dev)
1668{
1669 int rc = 0;
1670
1671 /* check if regulator is already initialized? */
1672 if (vreg->reg)
1673 goto out;
1674
1675 /* Get the regulator handle */
1676 vreg->reg = regulator_get(dev, vreg->name);
1677 if (IS_ERR(vreg->reg)) {
1678 rc = PTR_ERR(vreg->reg);
1679 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
1680 __func__, vreg->name, rc);
1681 }
1682out:
1683 return rc;
1684}
1685
1686static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
1687{
1688 if (vreg->reg)
1689 regulator_put(vreg->reg);
1690}
1691
1692/* This init function should be called only once for each SDCC slot */
1693static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
1694{
1695 int rc = 0;
1696 struct msm_mmc_slot_reg_data *curr_slot;
1697 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1698 struct device *dev = mmc_dev(host->mmc);
1699
1700 curr_slot = host->plat->vreg_data;
1701 if (!curr_slot)
1702 goto out;
1703
1704 curr_vdd_reg = curr_slot->vdd_data;
1705 curr_vccq_reg = curr_slot->vccq_data;
1706 curr_vddp_reg = curr_slot->vddp_data;
1707
1708 if (is_init) {
1709 /*
1710 * Get the regulator handle from voltage regulator framework
1711 * and then try to set the voltage level for the regulator
1712 */
1713 if (curr_vdd_reg) {
1714 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
1715 if (rc)
1716 goto out;
1717 }
1718 if (curr_vccq_reg) {
1719 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
1720 if (rc)
1721 goto vdd_reg_deinit;
1722 }
1723 if (curr_vddp_reg) {
1724 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
1725 if (rc)
1726 goto vccq_reg_deinit;
1727 }
1728 goto out;
1729 } else {
1730 /* Deregister all regulators from regulator framework */
1731 goto vddp_reg_deinit;
1732 }
1733vddp_reg_deinit:
1734 if (curr_vddp_reg)
1735 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
1736vccq_reg_deinit:
1737 if (curr_vccq_reg)
1738 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
1739vdd_reg_deinit:
1740 if (curr_vdd_reg)
1741 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
1742out:
1743 return rc;
1744}
1745
1746static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
1747{
1748 int rc = 0;
1749
Subhash Jadavanicc922692011-08-01 23:05:01 +05301750 /* Put regulator in HPM (high power mode) */
1751 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
1752 if (rc < 0)
1753 goto out;
1754
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001755 if (!vreg->is_enabled) {
1756 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301757 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
1758 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001759 if (rc)
1760 goto out;
1761
1762 rc = regulator_enable(vreg->reg);
1763 if (rc) {
1764 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
1765 __func__, vreg->name, rc);
1766 goto out;
1767 }
1768 vreg->is_enabled = true;
1769 }
1770
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001771out:
1772 return rc;
1773}
1774
1775static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
1776{
1777 int rc = 0;
1778
1779 /* Never disable regulator marked as always_on */
1780 if (vreg->is_enabled && !vreg->always_on) {
1781 rc = regulator_disable(vreg->reg);
1782 if (rc) {
1783 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
1784 __func__, vreg->name, rc);
1785 goto out;
1786 }
1787 vreg->is_enabled = false;
1788
1789 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
1790 if (rc < 0)
1791 goto out;
1792
1793 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301794 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001795 if (rc)
1796 goto out;
1797 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
1798 /* Put always_on regulator in LPM (low power mode) */
1799 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
1800 if (rc < 0)
1801 goto out;
1802 }
1803out:
1804 return rc;
1805}
1806
1807static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
1808{
1809 int rc = 0, i;
1810 struct msm_mmc_slot_reg_data *curr_slot;
1811 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1812 struct msm_mmc_reg_data *vreg_table[3];
1813
1814 curr_slot = host->plat->vreg_data;
1815 if (!curr_slot)
1816 goto out;
1817
1818 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
1819 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
1820 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
1821
1822 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
1823 if (vreg_table[i]) {
1824 if (enable)
1825 rc = msmsdcc_vreg_enable(vreg_table[i]);
1826 else
1827 rc = msmsdcc_vreg_disable(vreg_table[i]);
1828 if (rc)
1829 goto out;
1830 }
1831 }
1832out:
1833 return rc;
1834}
1835
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301836static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001837{
1838 int rc = 0;
1839
1840 if (host->plat->vreg_data) {
1841 struct msm_mmc_reg_data *vddp_reg =
1842 host->plat->vreg_data->vddp_data;
1843
1844 if (vddp_reg && vddp_reg->is_enabled)
1845 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
1846 }
1847
1848 return rc;
1849}
1850
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301851static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
1852{
1853 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1854 int rc = 0;
1855
1856 if (curr_slot && curr_slot->vddp_data) {
1857 rc = msmsdcc_set_vddp_level(host,
1858 curr_slot->vddp_data->low_vol_level);
1859
1860 if (rc)
1861 pr_err("%s: %s: failed to change vddp level to %d",
1862 mmc_hostname(host->mmc), __func__,
1863 curr_slot->vddp_data->low_vol_level);
1864 }
1865
1866 return rc;
1867}
1868
1869static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
1870{
1871 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1872 int rc = 0;
1873
1874 if (curr_slot && curr_slot->vddp_data) {
1875 rc = msmsdcc_set_vddp_level(host,
1876 curr_slot->vddp_data->high_vol_level);
1877
1878 if (rc)
1879 pr_err("%s: %s: failed to change vddp level to %d",
1880 mmc_hostname(host->mmc), __func__,
1881 curr_slot->vddp_data->high_vol_level);
1882 }
1883
1884 return rc;
1885}
1886
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001887static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
1888{
1889 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
1890 return 1;
1891 return 0;
1892}
1893
1894static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
1895{
1896 if (enable) {
1897 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1898 clk_enable(host->dfab_pclk);
1899 if (!IS_ERR(host->pclk))
1900 clk_enable(host->pclk);
1901 clk_enable(host->clk);
1902 } else {
1903 clk_disable(host->clk);
1904 if (!IS_ERR(host->pclk))
1905 clk_disable(host->pclk);
1906 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1907 clk_disable(host->dfab_pclk);
1908 }
1909}
1910
1911static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
1912 unsigned int req_clk)
1913{
1914 unsigned int sel_clk = -1;
1915
1916 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
1917 unsigned char cnt;
1918
1919 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
1920 if (host->plat->sup_clk_table[cnt] > req_clk)
1921 break;
1922 else if (host->plat->sup_clk_table[cnt] == req_clk) {
1923 sel_clk = host->plat->sup_clk_table[cnt];
1924 break;
1925 } else
1926 sel_clk = host->plat->sup_clk_table[cnt];
1927 }
1928 } else {
1929 if ((req_clk < host->plat->msmsdcc_fmax) &&
1930 (req_clk > host->plat->msmsdcc_fmid))
1931 sel_clk = host->plat->msmsdcc_fmid;
1932 else
1933 sel_clk = req_clk;
1934 }
1935
1936 return sel_clk;
1937}
1938
1939static inline unsigned int msmsdcc_get_min_sup_clk_rate(
1940 struct msmsdcc_host *host)
1941{
1942 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
1943 return host->plat->sup_clk_table[0];
1944 else
1945 return host->plat->msmsdcc_fmin;
1946}
1947
1948static inline unsigned int msmsdcc_get_max_sup_clk_rate(
1949 struct msmsdcc_host *host)
1950{
1951 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
1952 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
1953 else
1954 return host->plat->msmsdcc_fmax;
1955}
1956
1957static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05301958{
1959 struct msm_mmc_gpio_data *curr;
1960 int i, rc = 0;
1961
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001962 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301963 for (i = 0; i < curr->size; i++) {
1964 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001965 if (curr->gpio[i].is_always_on &&
1966 curr->gpio[i].is_enabled)
1967 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301968 rc = gpio_request(curr->gpio[i].no,
1969 curr->gpio[i].name);
1970 if (rc) {
1971 pr_err("%s: gpio_request(%d, %s) failed %d\n",
1972 mmc_hostname(host->mmc),
1973 curr->gpio[i].no,
1974 curr->gpio[i].name, rc);
1975 goto free_gpios;
1976 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001977 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301978 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001979 if (curr->gpio[i].is_always_on)
1980 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301981 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001982 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301983 }
1984 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001985 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301986
1987free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001988 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05301989 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001990 curr->gpio[i].is_enabled = false;
1991 }
1992out:
1993 return rc;
1994}
1995
1996static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
1997{
1998 struct msm_mmc_pad_data *curr;
1999 int i;
2000
2001 curr = host->plat->pin_data->pad_data;
2002 for (i = 0; i < curr->drv->size; i++) {
2003 if (enable)
2004 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2005 curr->drv->on[i].val);
2006 else
2007 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2008 curr->drv->off[i].val);
2009 }
2010
2011 for (i = 0; i < curr->pull->size; i++) {
2012 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002013 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002014 curr->pull->on[i].val);
2015 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002016 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002017 curr->pull->off[i].val);
2018 }
2019
2020 return 0;
2021}
2022
2023static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2024{
2025 int rc = 0;
2026
2027 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2028 return 0;
2029
2030 if (host->plat->pin_data->is_gpio)
2031 rc = msmsdcc_setup_gpio(host, enable);
2032 else
2033 rc = msmsdcc_setup_pad(host, enable);
2034
2035 if (!rc)
2036 host->plat->pin_data->cfg_sts = enable;
2037
2038 return rc;
2039}
2040
2041static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2042{
2043 unsigned int wakeup_irq;
2044
2045 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2046 host->plat->sdiowakeup_irq :
2047 host->core_irqres->start;
2048
2049 if (!host->irq_wake_enabled) {
2050 enable_irq_wake(wakeup_irq);
2051 host->irq_wake_enabled = true;
2052 }
2053}
2054
2055static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2056{
2057 unsigned int wakeup_irq;
2058
2059 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2060 host->plat->sdiowakeup_irq :
2061 host->core_irqres->start;
2062
2063 if (host->irq_wake_enabled) {
2064 disable_irq_wake(wakeup_irq);
2065 host->irq_wake_enabled = false;
2066 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302067}
2068
San Mehat9d2bd732009-09-22 16:44:22 -07002069static void
2070msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2071{
2072 struct msmsdcc_host *host = mmc_priv(mmc);
2073 u32 clk = 0, pwr = 0;
2074 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002075 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002076 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002077
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002078 DBG(host, "ios->clock = %u\n", ios->clock);
Sahitya Tummala7a892482011-01-18 11:22:49 +05302079
San Mehat9d2bd732009-09-22 16:44:22 -07002080 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002081 spin_lock_irqsave(&host->lock, flags);
2082 if (!host->clks_on) {
2083 msmsdcc_setup_clocks(host, true);
2084 host->clks_on = 1;
2085 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2086 if (!host->plat->sdiowakeup_irq) {
2087 writel_relaxed(host->mci_irqenable,
2088 host->base + MMCIMASK0);
2089 mb();
2090 if (host->plat->cfg_mpm_sdiowakeup &&
2091 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2092 host->plat->cfg_mpm_sdiowakeup(
2093 mmc_dev(mmc), SDC_DAT1_DISWAKE);
2094 msmsdcc_disable_irq_wake(host);
2095 } else if (!(mmc->pm_flags &
2096 MMC_PM_WAKE_SDIO_IRQ)) {
2097 writel_relaxed(host->mci_irqenable,
2098 host->base + MMCIMASK0);
2099 }
2100 }
San Mehat9d2bd732009-09-22 16:44:22 -07002101 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002102 spin_unlock_irqrestore(&host->lock, flags);
2103
2104 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2105 /*
2106 * For DDR50 mode, controller needs clock rate to be
2107 * double than what is required on the SD card CLK pin.
2108 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302109 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002110 /*
2111 * Make sure that we don't double the clock if
2112 * doubled clock rate is already set
2113 */
2114 if (!host->ddr_doubled_clk_rate ||
2115 (host->ddr_doubled_clk_rate &&
2116 (host->ddr_doubled_clk_rate != ios->clock))) {
2117 host->ddr_doubled_clk_rate =
2118 msmsdcc_get_sup_clk_rate(
2119 host, (ios->clock * 2));
2120 clock = host->ddr_doubled_clk_rate;
2121 }
2122 } else {
2123 host->ddr_doubled_clk_rate = 0;
2124 }
2125
2126 if (clock != host->clk_rate) {
2127 rc = clk_set_rate(host->clk, clock);
2128 if (rc < 0)
2129 pr_debug("%s: failed to set clk rate %u\n",
2130 mmc_hostname(mmc), clock);
2131 host->clk_rate = clock;
2132 }
2133 /*
2134 * give atleast 2 MCLK cycles delay for clocks
2135 * and SDCC core to stabilize
2136 */
2137 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002138 clk |= MCI_CLK_ENABLE;
2139 }
2140
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002141 if (ios->bus_width == MMC_BUS_WIDTH_8)
2142 clk |= MCI_CLK_WIDEBUS_8;
2143 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2144 clk |= MCI_CLK_WIDEBUS_4;
2145 else
2146 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002147
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002148 if (msmsdcc_is_pwrsave(host))
2149 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002150
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002151 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002152
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002153 host->tuning_needed = 0;
2154 /*
2155 * Select the controller timing mode according
2156 * to current bus speed mode
2157 */
2158 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2159 (ios->timing == MMC_TIMING_UHS_SDR50)) {
2160 clk |= (4 << 14);
2161 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302162 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002163 clk |= (3 << 14);
2164 } else {
2165 clk |= (2 << 14); /* feedback clock */
2166 }
2167
2168 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2169 clk |= (2 << 23);
2170
2171 if (host->io_pad_pwr_switch)
2172 clk |= IO_PAD_PWR_SWITCH;
2173
2174 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
San Mehat9d2bd732009-09-22 16:44:22 -07002175 pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002176 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2177 pwr |= msmsdcc_setup_vreg(host, !!ios->vdd);
San Mehat9d2bd732009-09-22 16:44:22 -07002178
2179 switch (ios->power_mode) {
2180 case MMC_POWER_OFF:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002181 htc_pwrsink_set(PWRSINK_SDCARD, 0);
2182 if (!host->sdcc_irq_disabled) {
2183 if (host->plat->cfg_mpm_sdiowakeup)
2184 host->plat->cfg_mpm_sdiowakeup(
2185 mmc_dev(mmc), SDC_DAT1_DISABLE);
2186 disable_irq(host->core_irqres->start);
2187 host->sdcc_irq_disabled = 1;
2188 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302189 /*
2190 * As VDD pad rail is always on, set low voltage for VDD
2191 * pad rail when slot is unused (when card is not present
2192 * or during system suspend).
2193 */
2194 msmsdcc_set_vddp_low_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002195 msmsdcc_setup_pins(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002196 break;
2197 case MMC_POWER_UP:
2198 pwr |= MCI_PWR_UP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002199 if (host->sdcc_irq_disabled) {
2200 if (host->plat->cfg_mpm_sdiowakeup)
2201 host->plat->cfg_mpm_sdiowakeup(
2202 mmc_dev(mmc), SDC_DAT1_ENABLE);
2203 enable_irq(host->core_irqres->start);
2204 host->sdcc_irq_disabled = 0;
2205 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302206 msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002207 msmsdcc_setup_pins(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07002208 break;
2209 case MMC_POWER_ON:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002210 htc_pwrsink_set(PWRSINK_SDCARD, 100);
San Mehat9d2bd732009-09-22 16:44:22 -07002211 pwr |= MCI_PWR_ON;
2212 break;
2213 }
2214
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002215 spin_lock_irqsave(&host->lock, flags);
2216 if (!host->clks_on) {
2217 /* force the clocks to be on */
2218 msmsdcc_setup_clocks(host, true);
2219 /*
2220 * give atleast 2 MCLK cycles delay for clocks
2221 * and SDCC core to stabilize
2222 */
2223 msmsdcc_delay(host);
2224 }
2225 writel_relaxed(clk, host->base + MMCICLOCK);
2226 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002227
2228 if (host->pwr != pwr) {
2229 host->pwr = pwr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002230 writel_relaxed(pwr, host->base + MMCIPOWER);
2231 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07002232 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002233 if (!host->clks_on) {
2234 /* force the clocks to be off */
2235 msmsdcc_setup_clocks(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002236 }
2237
2238 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
2239 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2240 if (!host->plat->sdiowakeup_irq) {
2241 writel_relaxed(MCI_SDIOINTMASK,
2242 host->base + MMCIMASK0);
2243 mb();
2244 if (host->plat->cfg_mpm_sdiowakeup &&
2245 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2246 host->plat->cfg_mpm_sdiowakeup(
2247 mmc_dev(mmc), SDC_DAT1_ENWAKE);
2248 msmsdcc_enable_irq_wake(host);
2249 } else if (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2250 writel_relaxed(0, host->base + MMCIMASK0);
2251 } else {
2252 writel_relaxed(MCI_SDIOINTMASK,
2253 host->base + MMCIMASK0);
2254 }
2255 msmsdcc_delay(host);
2256 }
2257 msmsdcc_setup_clocks(host, false);
2258 host->clks_on = 0;
2259 }
San Mehat4adbbcc2009-11-08 13:00:37 -08002260 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002261}
2262
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002263int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2264{
2265 struct msmsdcc_host *host = mmc_priv(mmc);
2266 u32 clk;
2267
2268 clk = readl_relaxed(host->base + MMCICLOCK);
2269 pr_debug("Changing to pwr_save=%d", pwrsave);
2270 if (pwrsave && msmsdcc_is_pwrsave(host))
2271 clk |= MCI_CLK_PWRSAVE;
2272 else
2273 clk &= ~MCI_CLK_PWRSAVE;
2274 writel_relaxed(clk, host->base + MMCICLOCK);
2275 mb();
2276
2277 return 0;
2278}
2279
2280static int msmsdcc_get_ro(struct mmc_host *mmc)
2281{
2282 int status = -ENOSYS;
2283 struct msmsdcc_host *host = mmc_priv(mmc);
2284
2285 if (host->plat->wpswitch) {
2286 status = host->plat->wpswitch(mmc_dev(mmc));
2287 } else if (host->plat->wpswitch_gpio) {
2288 status = gpio_request(host->plat->wpswitch_gpio,
2289 "SD_WP_Switch");
2290 if (status) {
2291 pr_err("%s: %s: Failed to request GPIO %d\n",
2292 mmc_hostname(mmc), __func__,
2293 host->plat->wpswitch_gpio);
2294 } else {
2295 status = gpio_direction_input(
2296 host->plat->wpswitch_gpio);
2297 if (!status) {
2298 /*
2299 * Wait for atleast 300ms as debounce
2300 * time for GPIO input to stabilize.
2301 */
2302 msleep(300);
2303 status = gpio_get_value_cansleep(
2304 host->plat->wpswitch_gpio);
2305 status ^= !host->plat->wpswitch_polarity;
2306 }
2307 gpio_free(host->plat->wpswitch_gpio);
2308 }
2309 }
2310
2311 if (status < 0)
2312 status = -ENOSYS;
2313 pr_debug("%s: Card read-only status %d\n", __func__, status);
2314
2315 return status;
2316}
2317
2318#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002319static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2320{
2321 struct msmsdcc_host *host = mmc_priv(mmc);
2322 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002323
2324 if (enable) {
2325 spin_lock_irqsave(&host->lock, flags);
2326 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
2327 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
2328 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2329 spin_unlock_irqrestore(&host->lock, flags);
2330 } else {
2331 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
2332 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
2333 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2334 }
2335 mb();
2336}
2337#endif /* CONFIG_MMC_MSM_SDIO_SUPPORT */
2338
2339#ifdef CONFIG_PM_RUNTIME
2340static int msmsdcc_enable(struct mmc_host *mmc)
2341{
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302342 int rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002343 struct device *dev = mmc->parent;
2344
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302345 if (dev->power.runtime_status == RPM_SUSPENDING) {
2346 if (mmc->suspend_task == current) {
2347 pm_runtime_get_noresume(dev);
2348 goto out;
2349 }
2350 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002351
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302352 rc = pm_runtime_get_sync(dev);
2353
2354 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002355 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2356 __func__, rc);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302357 return rc;
2358 }
2359out:
2360 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002361}
2362
2363static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2364{
2365 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302366 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002367
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302368 if (host->plat->disable_runtime_pm)
2369 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002370 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO)
2371 return -ENOTSUPP;
2372
2373 rc = pm_runtime_put_sync(mmc->parent);
2374
2375 if (rc < 0)
2376 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2377 __func__, rc);
2378 return rc;
2379}
2380#else
2381#define msmsdcc_enable NULL
2382#define msmsdcc_disable NULL
2383#endif
2384
2385static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2386 struct mmc_ios *ios)
2387{
2388 struct msmsdcc_host *host = mmc_priv(mmc);
2389 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302390 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002391
2392 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2393 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302394 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002395 goto out;
2396 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2397 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302398 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002399 goto out;
2400 }
San Mehat9d2bd732009-09-22 16:44:22 -07002401
2402 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002403 /*
2404 * If we are here means voltage switch from high voltage to
2405 * low voltage is required
2406 */
2407
2408 /*
2409 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2410 * register until they become all zeros.
2411 */
2412 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302413 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002414 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2415 mmc_hostname(mmc), __func__);
2416 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002417 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002418
2419 /* Stop SD CLK output. */
2420 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2421 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2422
San Mehat9d2bd732009-09-22 16:44:22 -07002423 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002424
2425 /*
2426 * Switch VDDPX from high voltage to low voltage
2427 * to change the VDD of the SD IO pads.
2428 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302429 rc = msmsdcc_set_vddp_low_vol(host);
2430 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002431 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002432
2433 spin_lock_irqsave(&host->lock, flags);
2434 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2435 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
2436 host->io_pad_pwr_switch = 1;
2437 spin_unlock_irqrestore(&host->lock, flags);
2438
2439 /* Wait 5 ms for the voltage regulater in the card to become stable. */
2440 usleep_range(5000, 5500);
2441
2442 spin_lock_irqsave(&host->lock, flags);
2443 /* Start SD CLK output. */
2444 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2445 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2446 spin_unlock_irqrestore(&host->lock, flags);
2447
2448 /*
2449 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
2450 * don't become all ones within 1 ms then a Voltage Switch
2451 * sequence has failed and a power cycle to the card is required.
2452 * Otherwise Voltage Switch sequence is completed successfully.
2453 */
2454 usleep_range(1000, 1500);
2455
2456 spin_lock_irqsave(&host->lock, flags);
2457 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
2458 != (0xF << 1)) {
2459 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
2460 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302461 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002462 goto out_unlock;
2463 }
2464
2465out_unlock:
2466 spin_unlock_irqrestore(&host->lock, flags);
2467out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302468 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002469}
2470
2471static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2472 u8 phase);
2473/* Initialize the DLL (Programmable Delay Line ) */
2474static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
2475{
2476 int rc = 0;
2477 u32 wait_timeout;
2478
2479 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
2480 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2481 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2482
2483 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
2484 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2485 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2486
2487 msmsdcc_delay(host);
2488
2489 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
2490 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2491 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2492
2493 /* Initialize the phase to 0 */
2494 rc = msmsdcc_config_cm_sdc4_dll_phase(host, 0);
2495 if (rc)
2496 goto out;
2497
2498 wait_timeout = 1000;
2499 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
2500 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
2501 /* max. wait for 1 sec for LOCK bit to be set */
2502 if (--wait_timeout == 0) {
2503 pr_err("%s: %s: DLL failed to lock at phase: %d",
2504 mmc_hostname(host->mmc), __func__, 0);
2505 rc = -1;
2506 goto out;
2507 }
2508 /* wait for 1ms */
2509 usleep_range(1000, 1500);
2510 }
2511out:
2512 return rc;
2513}
2514
2515/*
2516 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
2517 * calibration sequence. This function should be called before
2518 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
2519 * commands (CMD17/CMD18).
2520 */
2521static void msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
2522{
2523 /* Set CDR_EN bit to 1. */
2524 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) |
2525 MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2526
2527 /* Set CDR_EXT_EN bit to 0. */
2528 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2529 & ~MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2530
2531 /* Set CK_OUT_EN bit to 0. */
2532 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2533 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2534
2535 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2536 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)
2537 ;
2538
2539 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2540 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2541 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2542
2543 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register is 1. */
2544 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN))
2545 ;
2546}
2547
2548static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2549 u8 phase)
2550{
2551 int rc = 0;
2552 u32 mclk_freq = 0;
2553 u32 wait_timeout;
2554
2555 /* Set CDR_EN bit to 0. */
2556 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2557 & ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2558
2559 /* Set CDR_EXT_EN bit to 1. */
2560 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2561 | MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2562
2563 /* Program the MCLK value to MCLK_FREQ bit field */
2564 if (host->clk_rate <= 112000000)
2565 mclk_freq = 0;
2566 else if (host->clk_rate <= 125000000)
2567 mclk_freq = 1;
2568 else if (host->clk_rate <= 137000000)
2569 mclk_freq = 2;
2570 else if (host->clk_rate <= 150000000)
2571 mclk_freq = 3;
2572 else if (host->clk_rate <= 162000000)
2573 mclk_freq = 4;
2574 else if (host->clk_rate <= 175000000)
2575 mclk_freq = 5;
2576 else if (host->clk_rate <= 187000000)
2577 mclk_freq = 6;
2578 else if (host->clk_rate <= 200000000)
2579 mclk_freq = 7;
2580
2581 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2582 & ~(7 << 24)) | (mclk_freq << 24)),
2583 host->base + MCI_DLL_CONFIG);
2584
2585 /* Set CK_OUT_EN bit to 0. */
2586 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2587 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2588
2589 /* Set DLL_EN bit to 1. */
2590 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2591 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
2592
2593 wait_timeout = 1000;
2594 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2595 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN) {
2596 /* max. wait for 1 sec for LOCK bit for be set */
2597 if (--wait_timeout == 0) {
2598 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 0",
2599 mmc_hostname(host->mmc), __func__, phase);
2600 rc = -1;
2601 goto out;
2602 }
2603 /* wait for 1ms */
2604 usleep_range(1000, 1500);
2605 }
2606
2607 /*
2608 * Write the selected DLL clock output phase (0 ... 15)
2609 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
2610 */
2611 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2612 & ~(0xF << 20)) | (phase << 20)),
2613 host->base + MCI_DLL_CONFIG);
2614
2615 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2616 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2617 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2618
2619 wait_timeout = 1000;
2620 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
2621 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)) {
2622 /* max. wait for 1 sec for LOCK bit for be set */
2623 if (--wait_timeout == 0) {
2624 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 1",
2625 mmc_hostname(host->mmc), __func__, phase);
2626 rc = -1;
2627 goto out;
2628 }
2629 /* wait for 1ms */
2630 usleep_range(1000, 1500);
2631 }
2632out:
2633 return rc;
2634}
2635
2636static int msmsdcc_execute_tuning(struct mmc_host *mmc)
2637{
2638 struct msmsdcc_host *host = mmc_priv(mmc);
2639 u8 phase;
2640 u8 *data_buf;
2641 u8 tuned_phases[16], tuned_phase_cnt = 0;
2642 int rc = 0;
2643
2644 /* Tuning is only required for SDR50 & SDR104 modes */
2645 if (!host->tuning_needed) {
2646 rc = 0;
2647 goto out;
2648 }
2649
2650 host->cmd19_tuning_in_progress = 1;
2651 /*
2652 * Make sure that clock is always enabled when DLL
2653 * tuning is in progress. Keeping PWRSAVE ON may
2654 * turn off the clock. So let's disable the PWRSAVE
2655 * here and re-enable it once tuning is completed.
2656 */
2657 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2658 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2659 /* first of all reset the tuning block */
2660 rc = msmsdcc_init_cm_sdc4_dll(host);
2661 if (rc)
2662 goto out;
2663
2664 data_buf = kmalloc(64, GFP_KERNEL);
2665 if (!data_buf) {
2666 rc = -ENOMEM;
2667 goto out;
2668 }
2669
2670 phase = 0;
2671 do {
2672 struct mmc_command cmd = {0};
2673 struct mmc_data data = {0};
2674 struct mmc_request mrq = {
2675 .cmd = &cmd,
2676 .data = &data
2677 };
2678 struct scatterlist sg;
2679
2680 /* set the phase in delay line hw block */
2681 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2682 if (rc)
2683 goto kfree;
2684
2685 cmd.opcode = MMC_SEND_TUNING_BLOCK;
2686 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
2687
2688 data.blksz = 64;
2689 data.blocks = 1;
2690 data.flags = MMC_DATA_READ;
2691 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
2692
2693 data.sg = &sg;
2694 data.sg_len = 1;
2695 sg_init_one(&sg, data_buf, 64);
2696 memset(data_buf, 0, 64);
2697 mmc_wait_for_req(mmc, &mrq);
2698
2699 if (!cmd.error && !data.error &&
2700 !memcmp(data_buf, cmd19_tuning_block, 64)) {
2701 /* tuning is successful with this tuning point */
2702 tuned_phases[tuned_phase_cnt++] = phase;
2703 }
2704 } while (++phase < 16);
2705
2706 kfree(data_buf);
2707
2708 if (tuned_phase_cnt) {
2709 tuned_phase_cnt--;
2710 tuned_phase_cnt = (tuned_phase_cnt * 3) / 4;
2711 phase = tuned_phases[tuned_phase_cnt];
2712 /*
2713 * Finally set the selected phase in delay
2714 * line hw block.
2715 */
2716 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2717 if (rc)
2718 goto out;
2719 } else {
2720 /* tuning failed */
2721 rc = -EAGAIN;
2722 pr_err("%s: %s: no tuning point found",
2723 mmc_hostname(mmc), __func__);
2724 }
2725 goto out;
2726
2727kfree:
2728 kfree(data_buf);
2729out:
2730 /* re-enable PWESAVE */
2731 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2732 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2733 host->cmd19_tuning_in_progress = 0;
2734 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07002735}
2736
2737static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002738 .enable = msmsdcc_enable,
2739 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07002740 .request = msmsdcc_request,
2741 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002742 .get_ro = msmsdcc_get_ro,
2743#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002744 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002745#endif
2746 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
2747 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07002748};
2749
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002750static unsigned int
2751msmsdcc_slot_status(struct msmsdcc_host *host)
2752{
2753 int status;
2754 unsigned int gpio_no = host->plat->status_gpio;
2755
2756 status = gpio_request(gpio_no, "SD_HW_Detect");
2757 if (status) {
2758 pr_err("%s: %s: Failed to request GPIO %d\n",
2759 mmc_hostname(host->mmc), __func__, gpio_no);
2760 } else {
2761 status = gpio_direction_input(gpio_no);
2762 if (!status)
2763 status = !gpio_get_value_cansleep(gpio_no);
2764 gpio_free(gpio_no);
2765 }
2766 return status;
2767}
2768
San Mehat9d2bd732009-09-22 16:44:22 -07002769static void
2770msmsdcc_check_status(unsigned long data)
2771{
2772 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
2773 unsigned int status;
2774
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002775 if (host->plat->status || host->plat->status_gpio) {
2776 if (host->plat->status)
2777 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07002778 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002779 status = msmsdcc_slot_status(host);
2780
2781 host->eject = !status;
2782 if (status ^ host->oldstat) {
2783 pr_info("%s: Slot status change detected (%d -> %d)\n",
2784 mmc_hostname(host->mmc), host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07002785 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002786 }
2787 host->oldstat = status;
2788 } else {
2789 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07002790 }
San Mehat9d2bd732009-09-22 16:44:22 -07002791}
2792
2793static irqreturn_t
2794msmsdcc_platform_status_irq(int irq, void *dev_id)
2795{
2796 struct msmsdcc_host *host = dev_id;
2797
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002798 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07002799 msmsdcc_check_status((unsigned long) host);
2800 return IRQ_HANDLED;
2801}
2802
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002803static irqreturn_t
2804msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
2805{
2806 struct msmsdcc_host *host = dev_id;
2807
2808 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
2809 spin_lock(&host->lock);
2810 if (!host->sdio_irq_disabled) {
2811 disable_irq_nosync(irq);
2812 if (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2813 wake_lock(&host->sdio_wlock);
2814 msmsdcc_disable_irq_wake(host);
2815 }
2816 host->sdio_irq_disabled = 1;
2817 }
2818 if (host->plat->is_sdio_al_client) {
2819 if (!host->clks_on) {
2820 msmsdcc_setup_clocks(host, true);
2821 host->clks_on = 1;
2822 }
2823 if (host->sdcc_irq_disabled) {
2824 writel_relaxed(host->mci_irqenable,
2825 host->base + MMCIMASK0);
2826 mb();
2827 enable_irq(host->core_irqres->start);
2828 host->sdcc_irq_disabled = 0;
2829 }
2830 wake_lock(&host->sdio_wlock);
2831 }
2832 spin_unlock(&host->lock);
2833
2834 return IRQ_HANDLED;
2835}
2836
San Mehat9d2bd732009-09-22 16:44:22 -07002837static void
2838msmsdcc_status_notify_cb(int card_present, void *dev_id)
2839{
2840 struct msmsdcc_host *host = dev_id;
2841
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002842 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07002843 card_present);
2844 msmsdcc_check_status((unsigned long) host);
2845}
2846
San Mehat9d2bd732009-09-22 16:44:22 -07002847static int
2848msmsdcc_init_dma(struct msmsdcc_host *host)
2849{
2850 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
2851 host->dma.host = host;
2852 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07002853 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07002854
2855 if (!host->dmares)
2856 return -ENODEV;
2857
2858 host->dma.nc = dma_alloc_coherent(NULL,
2859 sizeof(struct msmsdcc_nc_dmadata),
2860 &host->dma.nc_busaddr,
2861 GFP_KERNEL);
2862 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07002863 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07002864 return -ENOMEM;
2865 }
2866 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
2867 host->dma.cmd_busaddr = host->dma.nc_busaddr;
2868 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
2869 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
2870 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07002871 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07002872
2873 return 0;
2874}
2875
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002876#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
2877/**
2878 * Allocate and Connect a SDCC peripheral's SPS endpoint
2879 *
2880 * This function allocates endpoint context and
2881 * connect it with memory endpoint by calling
2882 * appropriate SPS driver APIs.
2883 *
2884 * Also registers a SPS callback function with
2885 * SPS driver
2886 *
2887 * This function should only be called once typically
2888 * during driver probe.
2889 *
2890 * @host - Pointer to sdcc host structure
2891 * @ep - Pointer to sps endpoint data structure
2892 * @is_produce - 1 means Producer endpoint
2893 * 0 means Consumer endpoint
2894 *
2895 * @return - 0 if successful else negative value.
2896 *
2897 */
2898static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
2899 struct msmsdcc_sps_ep_conn_data *ep,
2900 bool is_producer)
2901{
2902 int rc = 0;
2903 struct sps_pipe *sps_pipe_handle;
2904 struct sps_connect *sps_config = &ep->config;
2905 struct sps_register_event *sps_event = &ep->event;
2906
2907 /* Allocate endpoint context */
2908 sps_pipe_handle = sps_alloc_endpoint();
2909 if (!sps_pipe_handle) {
2910 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
2911 mmc_hostname(host->mmc), is_producer);
2912 rc = -ENOMEM;
2913 goto out;
2914 }
2915
2916 /* Get default connection configuration for an endpoint */
2917 rc = sps_get_config(sps_pipe_handle, sps_config);
2918 if (rc) {
2919 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
2920 " rc=%d", mmc_hostname(host->mmc),
2921 (u32)sps_pipe_handle, rc);
2922 goto get_config_err;
2923 }
2924
2925 /* Modify the default connection configuration */
2926 if (is_producer) {
2927 /*
2928 * For SDCC producer transfer, source should be
2929 * SDCC peripheral where as destination should
2930 * be system memory.
2931 */
2932 sps_config->source = host->sps.bam_handle;
2933 sps_config->destination = SPS_DEV_HANDLE_MEM;
2934 /* Producer pipe will handle this connection */
2935 sps_config->mode = SPS_MODE_SRC;
2936 sps_config->options =
2937 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
2938 } else {
2939 /*
2940 * For SDCC consumer transfer, source should be
2941 * system memory where as destination should
2942 * SDCC peripheral
2943 */
2944 sps_config->source = SPS_DEV_HANDLE_MEM;
2945 sps_config->destination = host->sps.bam_handle;
2946 sps_config->mode = SPS_MODE_DEST;
2947 sps_config->options =
2948 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
2949 }
2950
2951 /* Producer pipe index */
2952 sps_config->src_pipe_index = host->sps.src_pipe_index;
2953 /* Consumer pipe index */
2954 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
2955 /*
2956 * This event thresold value is only significant for BAM-to-BAM
2957 * transfer. It's ignored for BAM-to-System mode transfer.
2958 */
2959 sps_config->event_thresh = 0x10;
2960 /*
2961 * Max. no of scatter/gather buffers that can
2962 * be passed by block layer = 32 (NR_SG).
2963 * Each BAM descritor needs 64 bits (8 bytes).
2964 * One BAM descriptor is required per buffer transfer.
2965 * So we would require total 256 (32 * 8) bytes of descriptor FIFO.
2966 * But due to HW limitation we need to allocate atleast one extra
2967 * descriptor memory (256 bytes + 8 bytes). But in order to be
2968 * in power of 2, we are allocating 512 bytes of memory.
2969 */
2970 sps_config->desc.size = 512;
2971 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
2972 sps_config->desc.size,
2973 &sps_config->desc.phys_base,
2974 GFP_KERNEL);
2975
2976 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
2977
2978 /* Establish connection between peripheral and memory endpoint */
2979 rc = sps_connect(sps_pipe_handle, sps_config);
2980 if (rc) {
2981 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
2982 " rc=%d", mmc_hostname(host->mmc),
2983 (u32)sps_pipe_handle, rc);
2984 goto sps_connect_err;
2985 }
2986
2987 sps_event->mode = SPS_TRIGGER_CALLBACK;
2988 sps_event->options = SPS_O_EOT;
2989 sps_event->callback = msmsdcc_sps_complete_cb;
2990 sps_event->xfer_done = NULL;
2991 sps_event->user = (void *)host;
2992
2993 /* Register callback event for EOT (End of transfer) event. */
2994 rc = sps_register_event(sps_pipe_handle, sps_event);
2995 if (rc) {
2996 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
2997 " rc=%d", mmc_hostname(host->mmc),
2998 (u32)sps_pipe_handle, rc);
2999 goto reg_event_err;
3000 }
3001 /* Now save the sps pipe handle */
3002 ep->pipe_handle = sps_pipe_handle;
3003 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3004 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3005 __func__, is_producer ? "READ" : "WRITE",
3006 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3007 goto out;
3008
3009reg_event_err:
3010 sps_disconnect(sps_pipe_handle);
3011sps_connect_err:
3012 dma_free_coherent(mmc_dev(host->mmc),
3013 sps_config->desc.size,
3014 sps_config->desc.base,
3015 sps_config->desc.phys_base);
3016get_config_err:
3017 sps_free_endpoint(sps_pipe_handle);
3018out:
3019 return rc;
3020}
3021
3022/**
3023 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3024 *
3025 * This function disconnect endpoint and deallocates
3026 * endpoint context.
3027 *
3028 * This function should only be called once typically
3029 * during driver remove.
3030 *
3031 * @host - Pointer to sdcc host structure
3032 * @ep - Pointer to sps endpoint data structure
3033 *
3034 */
3035static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3036 struct msmsdcc_sps_ep_conn_data *ep)
3037{
3038 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3039 struct sps_connect *sps_config = &ep->config;
3040 struct sps_register_event *sps_event = &ep->event;
3041
3042 sps_event->xfer_done = NULL;
3043 sps_event->callback = NULL;
3044 sps_register_event(sps_pipe_handle, sps_event);
3045 sps_disconnect(sps_pipe_handle);
3046 dma_free_coherent(mmc_dev(host->mmc),
3047 sps_config->desc.size,
3048 sps_config->desc.base,
3049 sps_config->desc.phys_base);
3050 sps_free_endpoint(sps_pipe_handle);
3051}
3052
3053/**
3054 * Reset SDCC peripheral's SPS endpoint
3055 *
3056 * This function disconnects an endpoint.
3057 *
3058 * This function should be called for reseting
3059 * SPS endpoint when data transfer error is
3060 * encountered during data transfer. This
3061 * can be considered as soft reset to endpoint.
3062 *
3063 * This function should only be called if
3064 * msmsdcc_sps_init() is already called.
3065 *
3066 * @host - Pointer to sdcc host structure
3067 * @ep - Pointer to sps endpoint data structure
3068 *
3069 * @return - 0 if successful else negative value.
3070 */
3071static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3072 struct msmsdcc_sps_ep_conn_data *ep)
3073{
3074 int rc = 0;
3075 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3076
3077 rc = sps_disconnect(sps_pipe_handle);
3078 if (rc) {
3079 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3080 " rc=%d", mmc_hostname(host->mmc), __func__,
3081 (u32)sps_pipe_handle, rc);
3082 goto out;
3083 }
3084 out:
3085 return rc;
3086}
3087
3088/**
3089 * Restore SDCC peripheral's SPS endpoint
3090 *
3091 * This function connects an endpoint.
3092 *
3093 * This function should be called for restoring
3094 * SPS endpoint after data transfer error is
3095 * encountered during data transfer. This
3096 * can be considered as soft reset to endpoint.
3097 *
3098 * This function should only be called if
3099 * msmsdcc_sps_reset_ep() is called before.
3100 *
3101 * @host - Pointer to sdcc host structure
3102 * @ep - Pointer to sps endpoint data structure
3103 *
3104 * @return - 0 if successful else negative value.
3105 */
3106static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3107 struct msmsdcc_sps_ep_conn_data *ep)
3108{
3109 int rc = 0;
3110 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3111 struct sps_connect *sps_config = &ep->config;
3112 struct sps_register_event *sps_event = &ep->event;
3113
3114 /* Establish connection between peripheral and memory endpoint */
3115 rc = sps_connect(sps_pipe_handle, sps_config);
3116 if (rc) {
3117 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3118 " rc=%d", mmc_hostname(host->mmc), __func__,
3119 (u32)sps_pipe_handle, rc);
3120 goto out;
3121 }
3122
3123 /* Register callback event for EOT (End of transfer) event. */
3124 rc = sps_register_event(sps_pipe_handle, sps_event);
3125 if (rc) {
3126 pr_err("%s: %s: sps_register_event() failed!!!"
3127 " pipe_handle=0x%x, rc=%d",
3128 mmc_hostname(host->mmc), __func__,
3129 (u32)sps_pipe_handle, rc);
3130 goto reg_event_err;
3131 }
3132 goto out;
3133
3134reg_event_err:
3135 sps_disconnect(sps_pipe_handle);
3136out:
3137 return rc;
3138}
3139
3140/**
3141 * Initialize SPS HW connected with SDCC core
3142 *
3143 * This function register BAM HW resources with
3144 * SPS driver and then initialize 2 SPS endpoints
3145 *
3146 * This function should only be called once typically
3147 * during driver probe.
3148 *
3149 * @host - Pointer to sdcc host structure
3150 *
3151 * @return - 0 if successful else negative value.
3152 *
3153 */
3154static int msmsdcc_sps_init(struct msmsdcc_host *host)
3155{
3156 int rc = 0;
3157 struct sps_bam_props bam = {0};
3158
3159 host->bam_base = ioremap(host->bam_memres->start,
3160 resource_size(host->bam_memres));
3161 if (!host->bam_base) {
3162 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3163 " size=0x%x", mmc_hostname(host->mmc),
3164 host->bam_memres->start,
3165 (host->bam_memres->end -
3166 host->bam_memres->start));
3167 rc = -ENOMEM;
3168 goto out;
3169 }
3170
3171 bam.phys_addr = host->bam_memres->start;
3172 bam.virt_addr = host->bam_base;
3173 /*
3174 * This event thresold value is only significant for BAM-to-BAM
3175 * transfer. It's ignored for BAM-to-System mode transfer.
3176 */
3177 bam.event_threshold = 0x10; /* Pipe event threshold */
3178 /*
3179 * This threshold controls when the BAM publish
3180 * the descriptor size on the sideband interface.
3181 * SPS HW will only be used when
3182 * data transfer size > MCI_FIFOSIZE (64 bytes).
3183 * PIO mode will be used when
3184 * data transfer size < MCI_FIFOSIZE (64 bytes).
3185 * So set this thresold value to 64 bytes.
3186 */
3187 bam.summing_threshold = 64;
3188 /* SPS driver wll handle the SDCC BAM IRQ */
3189 bam.irq = (u32)host->bam_irqres->start;
3190 bam.manage = SPS_BAM_MGR_LOCAL;
3191
3192 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3193 (u32)bam.phys_addr);
3194 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3195 (u32)bam.virt_addr);
3196
3197 /* Register SDCC Peripheral BAM device to SPS driver */
3198 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3199 if (rc) {
3200 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3201 mmc_hostname(host->mmc), rc);
3202 goto reg_bam_err;
3203 }
3204 pr_info("%s: BAM device registered. bam_handle=0x%x",
3205 mmc_hostname(host->mmc), host->sps.bam_handle);
3206
3207 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3208 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3209
3210 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3211 SPS_PROD_PERIPHERAL);
3212 if (rc)
3213 goto sps_reset_err;
3214 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3215 SPS_CONS_PERIPHERAL);
3216 if (rc)
3217 goto cons_conn_err;
3218
3219 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3220 mmc_hostname(host->mmc),
3221 (unsigned long long)host->bam_memres->start,
3222 (unsigned int)host->bam_irqres->start);
3223 goto out;
3224
3225cons_conn_err:
3226 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3227sps_reset_err:
3228 sps_deregister_bam_device(host->sps.bam_handle);
3229reg_bam_err:
3230 iounmap(host->bam_base);
3231out:
3232 return rc;
3233}
3234
3235/**
3236 * De-initialize SPS HW connected with SDCC core
3237 *
3238 * This function deinitialize SPS endpoints and then
3239 * deregisters BAM resources from SPS driver.
3240 *
3241 * This function should only be called once typically
3242 * during driver remove.
3243 *
3244 * @host - Pointer to sdcc host structure
3245 *
3246 */
3247static void msmsdcc_sps_exit(struct msmsdcc_host *host)
3248{
3249 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
3250 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3251 sps_deregister_bam_device(host->sps.bam_handle);
3252 iounmap(host->bam_base);
3253}
3254#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
3255
3256static ssize_t
3257show_polling(struct device *dev, struct device_attribute *attr, char *buf)
3258{
3259 struct mmc_host *mmc = dev_get_drvdata(dev);
3260 struct msmsdcc_host *host = mmc_priv(mmc);
3261 int poll;
3262 unsigned long flags;
3263
3264 spin_lock_irqsave(&host->lock, flags);
3265 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
3266 spin_unlock_irqrestore(&host->lock, flags);
3267
3268 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
3269}
3270
3271static ssize_t
3272set_polling(struct device *dev, struct device_attribute *attr,
3273 const char *buf, size_t count)
3274{
3275 struct mmc_host *mmc = dev_get_drvdata(dev);
3276 struct msmsdcc_host *host = mmc_priv(mmc);
3277 int value;
3278 unsigned long flags;
3279
3280 sscanf(buf, "%d", &value);
3281
3282 spin_lock_irqsave(&host->lock, flags);
3283 if (value) {
3284 mmc->caps |= MMC_CAP_NEEDS_POLL;
3285 mmc_detect_change(host->mmc, 0);
3286 } else {
3287 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3288 }
3289#ifdef CONFIG_HAS_EARLYSUSPEND
3290 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
3291#endif
3292 spin_unlock_irqrestore(&host->lock, flags);
3293 return count;
3294}
3295
3296static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
3297 show_polling, set_polling);
3298static struct attribute *dev_attrs[] = {
3299 &dev_attr_polling.attr,
3300 NULL,
3301};
3302static struct attribute_group dev_attr_grp = {
3303 .attrs = dev_attrs,
3304};
3305
3306#ifdef CONFIG_HAS_EARLYSUSPEND
3307static void msmsdcc_early_suspend(struct early_suspend *h)
3308{
3309 struct msmsdcc_host *host =
3310 container_of(h, struct msmsdcc_host, early_suspend);
3311 unsigned long flags;
3312
3313 spin_lock_irqsave(&host->lock, flags);
3314 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
3315 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3316 spin_unlock_irqrestore(&host->lock, flags);
3317};
3318static void msmsdcc_late_resume(struct early_suspend *h)
3319{
3320 struct msmsdcc_host *host =
3321 container_of(h, struct msmsdcc_host, early_suspend);
3322 unsigned long flags;
3323
3324 if (host->polling_enabled) {
3325 spin_lock_irqsave(&host->lock, flags);
3326 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
3327 mmc_detect_change(host->mmc, 0);
3328 spin_unlock_irqrestore(&host->lock, flags);
3329 }
3330};
3331#endif
3332
3333static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
3334{
3335 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3336 struct mmc_request *mrq;
3337 unsigned long flags;
3338
3339 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003340 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003341 pr_info("%s: %s: dummy CMD52 timeout\n",
3342 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003343 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003344 }
3345
3346 mrq = host->curr.mrq;
3347
3348 if (mrq && mrq->cmd) {
3349 pr_info("%s: %s CMD%d\n", mmc_hostname(host->mmc),
3350 __func__, mrq->cmd->opcode);
3351 if (!mrq->cmd->error)
3352 mrq->cmd->error = -ETIMEDOUT;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003353 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003354 host->dummy_52_needed = 0;
3355 if (host->curr.data) {
3356 pr_info("%s: %s Request timeout\n",
3357 mmc_hostname(host->mmc), __func__);
3358 if (mrq->data && !mrq->data->error)
3359 mrq->data->error = -ETIMEDOUT;
3360 host->curr.data_xfered = 0;
3361 if (host->dma.sg && host->is_dma_mode) {
3362 msm_dmov_stop_cmd(host->dma.channel,
3363 &host->dma.hdr, 0);
3364 } else if (host->sps.sg && host->is_sps_mode) {
3365 /* Stop current SPS transfer */
3366 msmsdcc_sps_exit_curr_xfer(host);
3367 } else {
3368 msmsdcc_reset_and_restore(host);
3369 msmsdcc_stop_data(host);
3370 if (mrq->data && mrq->data->stop)
3371 msmsdcc_start_command(host,
3372 mrq->data->stop, 0);
3373 else
3374 msmsdcc_request_end(host, mrq);
3375 }
3376 } else {
3377 if (host->prog_enable) {
3378 host->prog_scan = 0;
3379 host->prog_enable = 0;
3380 }
3381 msmsdcc_reset_and_restore(host);
3382 msmsdcc_request_end(host, mrq);
3383 }
3384 }
3385 spin_unlock_irqrestore(&host->lock, flags);
3386}
3387
San Mehat9d2bd732009-09-22 16:44:22 -07003388static int
3389msmsdcc_probe(struct platform_device *pdev)
3390{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003391 struct mmc_platform_data *plat = pdev->dev.platform_data;
San Mehat9d2bd732009-09-22 16:44:22 -07003392 struct msmsdcc_host *host;
3393 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003394 unsigned long flags;
3395 struct resource *core_irqres = NULL;
3396 struct resource *bam_irqres = NULL;
3397 struct resource *core_memres = NULL;
3398 struct resource *dml_memres = NULL;
3399 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07003400 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07003401 struct resource *dma_crci_res = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07003402 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003403 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07003404
3405 /* must have platform data */
3406 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003407 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003408 ret = -EINVAL;
3409 goto out;
3410 }
3411
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003412 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07003413 return -EINVAL;
3414
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003415 if (plat->is_sdio_al_client)
3416 if (!plat->sdio_lpm_gpio_setup || !plat->sdiowakeup_irq)
3417 return -EINVAL;
3418
San Mehat9d2bd732009-09-22 16:44:22 -07003419 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003420 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003421 return -ENXIO;
3422 }
3423
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003424 for (i = 0; i < pdev->num_resources; i++) {
3425 if (pdev->resource[i].flags & IORESOURCE_MEM) {
3426 if (!strcmp(pdev->resource[i].name,
3427 "sdcc_dml_addr"))
3428 dml_memres = &pdev->resource[i];
3429 else if (!strcmp(pdev->resource[i].name,
3430 "sdcc_bam_addr"))
3431 bam_memres = &pdev->resource[i];
3432 else
3433 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07003434
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003435 }
3436 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
3437 if (!strcmp(pdev->resource[i].name,
3438 "sdcc_bam_irq"))
3439 bam_irqres = &pdev->resource[i];
3440 else
3441 core_irqres = &pdev->resource[i];
3442 }
Krishna Konda25786ec2011-07-25 16:21:36 -07003443 if (pdev->resource[i].flags & IORESOURCE_DMA) {
3444 if (!strncmp(pdev->resource[i].name,
3445 "sdcc_dma_chnl",
3446 sizeof("sdcc_dma_chnl")))
3447 dmares = &pdev->resource[i];
3448 else if (!strncmp(pdev->resource[i].name,
3449 "sdcc_dma_crci",
3450 sizeof("sdcc_dma_crci")))
3451 dma_crci_res = &pdev->resource[i];
3452 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003453 }
3454
3455 if (!core_irqres || !core_memres) {
3456 pr_err("%s: Invalid sdcc core resource\n", __func__);
3457 return -ENXIO;
3458 }
3459
3460 /*
3461 * Both BAM and DML memory resource should be preset.
3462 * BAM IRQ resource should also be present.
3463 */
3464 if ((bam_memres && !dml_memres) ||
3465 (!bam_memres && dml_memres) ||
3466 ((bam_memres && dml_memres) && !bam_irqres)) {
3467 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003468 return -ENXIO;
3469 }
3470
3471 /*
3472 * Setup our host structure
3473 */
San Mehat9d2bd732009-09-22 16:44:22 -07003474 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
3475 if (!mmc) {
3476 ret = -ENOMEM;
3477 goto out;
3478 }
3479
3480 host = mmc_priv(mmc);
3481 host->pdev_id = pdev->id;
3482 host->plat = plat;
3483 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08003484 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05303485
3486 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003487 host->is_sps_mode = 1;
3488 else if (dmares)
3489 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07003490
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003491 host->base = ioremap(core_memres->start,
3492 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07003493 if (!host->base) {
3494 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003495 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003496 }
3497
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003498 host->core_irqres = core_irqres;
3499 host->bam_irqres = bam_irqres;
3500 host->core_memres = core_memres;
3501 host->dml_memres = dml_memres;
3502 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07003503 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07003504 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07003505 spin_lock_init(&host->lock);
3506
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003507#ifdef CONFIG_MMC_EMBEDDED_SDIO
3508 if (plat->embedded_sdio)
3509 mmc_set_embedded_sdio_data(mmc,
3510 &plat->embedded_sdio->cis,
3511 &plat->embedded_sdio->cccr,
3512 plat->embedded_sdio->funcs,
3513 plat->embedded_sdio->num_funcs);
3514#endif
3515
Sahitya Tummala62612cf2010-12-08 15:03:03 +05303516 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
3517 (unsigned long)host);
3518
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003519 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
3520 (unsigned long)host);
3521 if (host->is_dma_mode) {
3522 /* Setup DMA */
3523 ret = msmsdcc_init_dma(host);
3524 if (ret)
3525 goto ioremap_free;
3526 } else {
3527 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003528 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003529 }
3530
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003531 /*
3532 * Setup SDCC clock if derived from Dayatona
3533 * fabric core clock.
3534 */
3535 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07003536 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003537 if (!IS_ERR(host->dfab_pclk)) {
3538 /* Set the clock rate to 64MHz for max. performance */
3539 ret = clk_set_rate(host->dfab_pclk, 64000000);
3540 if (ret)
3541 goto dfab_pclk_put;
3542 ret = clk_enable(host->dfab_pclk);
3543 if (ret)
3544 goto dfab_pclk_put;
3545 } else
3546 goto dma_free;
3547 }
3548
3549 /*
3550 * Setup main peripheral bus clock
3551 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003552 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003553 if (!IS_ERR(host->pclk)) {
3554 ret = clk_enable(host->pclk);
3555 if (ret)
3556 goto pclk_put;
3557
3558 host->pclk_rate = clk_get_rate(host->pclk);
3559 }
3560
3561 /*
3562 * Setup SDC MMC clock
3563 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003564 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07003565 if (IS_ERR(host->clk)) {
3566 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003567 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07003568 }
3569
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003570 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
3571 if (ret) {
3572 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
3573 goto clk_put;
3574 }
3575
3576 ret = clk_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003577 if (ret)
3578 goto clk_put;
3579
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003580 host->clk_rate = clk_get_rate(host->clk);
3581
3582 host->clks_on = 1;
3583
3584 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07003585 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003586 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07003587 goto clk_disable;
3588 }
3589
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003590
3591 /* Clocks has to be running before accessing SPS/DML HW blocks */
3592 if (host->is_sps_mode) {
3593 /* Initialize SPS */
3594 ret = msmsdcc_sps_init(host);
3595 if (ret)
3596 goto vreg_deinit;
3597 /* Initialize DML */
3598 ret = msmsdcc_dml_init(host);
3599 if (ret)
3600 goto sps_exit;
3601 }
San Mehat9d2bd732009-09-22 16:44:22 -07003602
San Mehat9d2bd732009-09-22 16:44:22 -07003603 /*
3604 * Setup MMC host structure
3605 */
3606 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003607 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
3608 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003609 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003610 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
3611 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07003612
San Mehat9d2bd732009-09-22 16:44:22 -07003613 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05303614
3615 /*
3616 * If we send the CMD23 before multi block write/read command
3617 * then we need not to send CMD12 at the end of the transfer.
3618 * If we don't send the CMD12 then only way to detect the PROG_DONE
3619 * status is to use the AUTO_PROG_DONE status provided by SDCC4
3620 * controller. So let's enable the CMD23 for SDCC4 only.
3621 */
Sahitya Tummala85fa0702011-09-15 09:39:37 +05303622 if (!plat->disable_cmd23 && host->plat->sdcc_v4_sup)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05303623 mmc->caps |= MMC_CAP_CMD23;
3624
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003625 mmc->caps |= plat->uhs_caps;
3626 /*
3627 * XPC controls the maximum current in the default speed mode of SDXC
3628 * card. XPC=0 means 100mA (max.) but speed class is not supported.
3629 * XPC=1 means 150mA (max.) and speed class is supported.
3630 */
3631 if (plat->xpc_cap)
3632 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
3633 MMC_CAP_SET_XPC_180);
3634
3635 if (plat->nonremovable)
3636 mmc->caps |= MMC_CAP_NONREMOVABLE;
3637#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
3638 mmc->caps |= MMC_CAP_SDIO_IRQ;
3639#endif
3640
3641 if (plat->is_sdio_al_client)
3642 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07003643
Martin K. Petersena36274e2010-09-10 01:33:59 -04003644 mmc->max_segs = NR_SG;
San Mehat9d2bd732009-09-22 16:44:22 -07003645 mmc->max_blk_size = 4096; /* MCI_DATA_CTL BLOCKSIZE up to 4096 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003646 mmc->max_blk_count = 65535;
San Mehat9d2bd732009-09-22 16:44:22 -07003647
3648 mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */
3649 mmc->max_seg_size = mmc->max_req_size;
3650
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003651 writel_relaxed(0, host->base + MMCIMASK0);
3652 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -07003653
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003654 /* Delay needed (MMCIMASK0 was just written above) */
3655 msmsdcc_delay(host);
3656 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
3657 mb();
3658 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07003659
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003660 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
3661 DRIVER_NAME " (cmd)", host);
3662 if (ret)
3663 goto dml_exit;
3664
3665 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
3666 DRIVER_NAME " (pio)", host);
3667 if (ret)
3668 goto irq_free;
3669
3670 /*
3671 * Enable SDCC IRQ only when host is powered on. Otherwise, this
3672 * IRQ is un-necessarily being monitored by MPM (Modem power
3673 * management block) during idle-power collapse. The MPM will be
3674 * configured to monitor the DATA1 GPIO line with level-low trigger
3675 * and thus depending on the GPIO status, it prevents TCXO shutdown
3676 * during idle-power collapse.
3677 */
3678 disable_irq(core_irqres->start);
3679 host->sdcc_irq_disabled = 1;
3680
3681 if (plat->sdiowakeup_irq) {
3682 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3683 mmc_hostname(mmc));
3684 ret = request_irq(plat->sdiowakeup_irq,
3685 msmsdcc_platform_sdiowakeup_irq,
3686 IRQF_SHARED | IRQF_TRIGGER_LOW,
3687 DRIVER_NAME "sdiowakeup", host);
3688 if (ret) {
3689 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
3690 plat->sdiowakeup_irq, ret);
3691 goto pio_irq_free;
3692 } else {
3693 spin_lock_irqsave(&host->lock, flags);
3694 if (!host->sdio_irq_disabled) {
3695 disable_irq_nosync(plat->sdiowakeup_irq);
3696 host->sdio_irq_disabled = 1;
3697 }
3698 spin_unlock_irqrestore(&host->lock, flags);
3699 }
3700 }
3701
3702 if (plat->cfg_mpm_sdiowakeup) {
3703 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3704 mmc_hostname(mmc));
3705 }
3706
3707 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
3708 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003709 /*
3710 * Setup card detect change
3711 */
3712
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003713 if (plat->status || plat->status_gpio) {
3714 if (plat->status)
3715 host->oldstat = plat->status(mmc_dev(host->mmc));
3716 else
3717 host->oldstat = msmsdcc_slot_status(host);
3718 host->eject = !host->oldstat;
3719 }
San Mehat9d2bd732009-09-22 16:44:22 -07003720
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003721 if (plat->status_irq) {
3722 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07003723 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003724 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07003725 DRIVER_NAME " (slot)",
3726 host);
3727 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003728 pr_err("Unable to get slot IRQ %d (%d)\n",
3729 plat->status_irq, ret);
3730 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003731 }
3732 } else if (plat->register_status_notify) {
3733 plat->register_status_notify(msmsdcc_status_notify_cb, host);
3734 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003735 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07003736 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003737
3738 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003739
3740 ret = pm_runtime_set_active(&(pdev)->dev);
3741 if (ret < 0)
3742 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3743 __func__, ret);
3744 /*
3745 * There is no notion of suspend/resume for SD/MMC/SDIO
3746 * cards. So host can be suspended/resumed with out
3747 * worrying about its children.
3748 */
3749 pm_suspend_ignore_children(&(pdev)->dev, true);
3750
3751 /*
3752 * MMC/SD/SDIO bus suspend/resume operations are defined
3753 * only for the slots that will be used for non-removable
3754 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
3755 * defined. Otherwise, they simply become card removal and
3756 * insertion events during suspend and resume respectively.
3757 * Hence, enable run-time PM only for slots for which bus
3758 * suspend/resume operations are defined.
3759 */
3760#ifdef CONFIG_MMC_UNSAFE_RESUME
3761 /*
3762 * If this capability is set, MMC core will enable/disable host
3763 * for every claim/release operation on a host. We use this
3764 * notification to increment/decrement runtime pm usage count.
3765 */
3766 mmc->caps |= MMC_CAP_DISABLE;
3767 pm_runtime_enable(&(pdev)->dev);
3768#else
3769 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
3770 mmc->caps |= MMC_CAP_DISABLE;
3771 pm_runtime_enable(&(pdev)->dev);
3772 }
3773#endif
3774 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
3775 (unsigned long)host);
3776
San Mehat9d2bd732009-09-22 16:44:22 -07003777 mmc_add_host(mmc);
3778
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003779#ifdef CONFIG_HAS_EARLYSUSPEND
3780 host->early_suspend.suspend = msmsdcc_early_suspend;
3781 host->early_suspend.resume = msmsdcc_late_resume;
3782 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
3783 register_early_suspend(&host->early_suspend);
3784#endif
San Mehat9d2bd732009-09-22 16:44:22 -07003785
Krishna Konda25786ec2011-07-25 16:21:36 -07003786 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
3787 " dmacrcri %d\n", mmc_hostname(mmc),
3788 (unsigned long long)core_memres->start,
3789 (unsigned int) core_irqres->start,
3790 (unsigned int) plat->status_irq, host->dma.channel,
3791 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003792
3793 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
3794 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
3795 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
3796 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
3797 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
3798 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
3799 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
3800 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
3801 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
3802 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
3803 host->eject);
3804 pr_info("%s: Power save feature enable = %d\n",
3805 mmc_hostname(mmc), msmsdcc_pwrsave);
3806
Krishna Konda25786ec2011-07-25 16:21:36 -07003807 if (host->is_dma_mode && host->dma.channel != -1
3808 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003809 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003810 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003811 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003812 mmc_hostname(mmc), host->dma.cmd_busaddr,
3813 host->dma.cmdptr_busaddr);
3814 } else if (host->is_sps_mode) {
3815 pr_info("%s: SPS-BAM data transfer mode available\n",
3816 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003817 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003818 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003819
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003820#if defined(CONFIG_DEBUG_FS)
3821 msmsdcc_dbg_createhost(host);
3822#endif
3823 if (!plat->status_irq) {
3824 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
3825 if (ret)
3826 goto platform_irq_free;
3827 }
San Mehat9d2bd732009-09-22 16:44:22 -07003828 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003829
3830 platform_irq_free:
3831 del_timer_sync(&host->req_tout_timer);
3832 pm_runtime_disable(&(pdev)->dev);
3833 pm_runtime_set_suspended(&(pdev)->dev);
3834
3835 if (plat->status_irq)
3836 free_irq(plat->status_irq, host);
3837 sdiowakeup_irq_free:
3838 wake_lock_destroy(&host->sdio_suspend_wlock);
3839 if (plat->sdiowakeup_irq)
3840 free_irq(plat->sdiowakeup_irq, host);
3841 pio_irq_free:
3842 if (plat->sdiowakeup_irq)
3843 wake_lock_destroy(&host->sdio_wlock);
3844 free_irq(core_irqres->start, host);
3845 irq_free:
3846 free_irq(core_irqres->start, host);
3847 dml_exit:
3848 if (host->is_sps_mode)
3849 msmsdcc_dml_exit(host);
3850 sps_exit:
3851 if (host->is_sps_mode)
3852 msmsdcc_sps_exit(host);
3853 vreg_deinit:
3854 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07003855 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003856 clk_disable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003857 clk_put:
3858 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003859 pclk_disable:
3860 if (!IS_ERR(host->pclk))
3861 clk_disable(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07003862 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003863 if (!IS_ERR(host->pclk))
3864 clk_put(host->pclk);
3865 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3866 clk_disable(host->dfab_pclk);
3867 dfab_pclk_put:
3868 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3869 clk_put(host->dfab_pclk);
3870 dma_free:
3871 if (host->is_dma_mode) {
3872 if (host->dmares)
3873 dma_free_coherent(NULL,
3874 sizeof(struct msmsdcc_nc_dmadata),
3875 host->dma.nc, host->dma.nc_busaddr);
3876 }
3877 ioremap_free:
3878 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07003879 host_free:
3880 mmc_free_host(mmc);
3881 out:
3882 return ret;
3883}
3884
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003885static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07003886{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003887 struct mmc_host *mmc = mmc_get_drvdata(pdev);
3888 struct mmc_platform_data *plat;
3889 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07003890
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003891 if (!mmc)
3892 return -ENXIO;
3893
3894 if (pm_runtime_suspended(&(pdev)->dev))
3895 pm_runtime_resume(&(pdev)->dev);
3896
3897 host = mmc_priv(mmc);
3898
3899 DBG(host, "Removing SDCC device = %d\n", pdev->id);
3900 plat = host->plat;
3901
3902 if (!plat->status_irq)
3903 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
3904
3905 del_timer_sync(&host->req_tout_timer);
3906 tasklet_kill(&host->dma_tlet);
3907 tasklet_kill(&host->sps.tlet);
3908 mmc_remove_host(mmc);
3909
3910 if (plat->status_irq)
3911 free_irq(plat->status_irq, host);
3912
3913 wake_lock_destroy(&host->sdio_suspend_wlock);
3914 if (plat->sdiowakeup_irq) {
3915 wake_lock_destroy(&host->sdio_wlock);
3916 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
3917 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07003918 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003919
3920 free_irq(host->core_irqres->start, host);
3921 free_irq(host->core_irqres->start, host);
3922
3923 clk_put(host->clk);
3924 if (!IS_ERR(host->pclk))
3925 clk_put(host->pclk);
3926 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3927 clk_put(host->dfab_pclk);
3928
3929 msmsdcc_vreg_init(host, false);
3930
3931 if (host->is_dma_mode) {
3932 if (host->dmares)
3933 dma_free_coherent(NULL,
3934 sizeof(struct msmsdcc_nc_dmadata),
3935 host->dma.nc, host->dma.nc_busaddr);
3936 }
3937
3938 if (host->is_sps_mode) {
3939 msmsdcc_dml_exit(host);
3940 msmsdcc_sps_exit(host);
3941 }
3942
3943 iounmap(host->base);
3944 mmc_free_host(mmc);
3945
3946#ifdef CONFIG_HAS_EARLYSUSPEND
3947 unregister_early_suspend(&host->early_suspend);
3948#endif
3949 pm_runtime_disable(&(pdev)->dev);
3950 pm_runtime_set_suspended(&(pdev)->dev);
3951
3952 return 0;
3953}
3954
3955#ifdef CONFIG_MSM_SDIO_AL
3956int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
3957{
3958 struct msmsdcc_host *host = mmc_priv(mmc);
3959 unsigned long flags;
3960
3961 spin_lock_irqsave(&host->lock, flags);
3962 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
3963 enable ? "En" : "Dis");
3964
3965 if (enable) {
3966 if (!host->sdcc_irq_disabled) {
3967 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05303968 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003969 host->sdcc_irq_disabled = 1;
3970 }
3971
3972 if (host->clks_on) {
3973 msmsdcc_setup_clocks(host, false);
3974 host->clks_on = 0;
3975 }
3976
3977 if (!host->sdio_gpio_lpm) {
3978 spin_unlock_irqrestore(&host->lock, flags);
3979 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
3980 spin_lock_irqsave(&host->lock, flags);
3981 host->sdio_gpio_lpm = 1;
3982 }
3983
3984 if (host->sdio_irq_disabled) {
3985 msmsdcc_enable_irq_wake(host);
3986 enable_irq(host->plat->sdiowakeup_irq);
3987 host->sdio_irq_disabled = 0;
3988 }
3989 } else {
3990 if (!host->sdio_irq_disabled) {
3991 disable_irq_nosync(host->plat->sdiowakeup_irq);
3992 host->sdio_irq_disabled = 1;
3993 msmsdcc_disable_irq_wake(host);
3994 }
3995
3996 if (host->sdio_gpio_lpm) {
3997 spin_unlock_irqrestore(&host->lock, flags);
3998 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
3999 spin_lock_irqsave(&host->lock, flags);
4000 host->sdio_gpio_lpm = 0;
4001 }
4002
4003 if (!host->clks_on) {
4004 msmsdcc_setup_clocks(host, true);
4005 host->clks_on = 1;
4006 }
4007
4008 if (host->sdcc_irq_disabled) {
4009 writel_relaxed(host->mci_irqenable,
4010 host->base + MMCIMASK0);
4011 mb();
4012 enable_irq(host->core_irqres->start);
4013 host->sdcc_irq_disabled = 0;
4014 }
4015 wake_lock_timeout(&host->sdio_wlock, 1);
4016 }
4017 spin_unlock_irqrestore(&host->lock, flags);
4018 return 0;
4019}
4020#else
4021int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4022{
4023 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004024}
4025#endif
4026
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004027#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07004028static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004029msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004030{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004031 struct mmc_host *mmc = dev_get_drvdata(dev);
4032 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07004033 int rc = 0;
4034
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004035 if (host->plat->is_sdio_al_client)
4036 return 0;
4037
Sahitya Tummala7661a452011-07-18 13:28:35 +05304038 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004039 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004040 host->sdcc_suspending = 1;
4041 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07004042
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004043 /*
4044 * If the clocks are already turned off by SDIO clients (as
4045 * part of LPM), then clocks should be turned on before
4046 * calling mmc_suspend_host() because mmc_suspend_host might
4047 * send some commands to the card. The clocks will be turned
4048 * off again after mmc_suspend_host. Thus for SD/MMC/SDIO
4049 * cards, clocks will be turned on before mmc_suspend_host
4050 * and turned off after mmc_suspend_host.
4051 */
4052 mmc->ios.clock = host->clk_rate;
4053 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07004054
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004055 /*
4056 * MMC core thinks that host is disabled by now since
4057 * runtime suspend is scheduled after msmsdcc_disable()
4058 * is called. Thus, MMC core will try to enable the host
4059 * while suspending it. This results in a synchronous
4060 * runtime resume request while in runtime suspending
4061 * context and hence inorder to complete this resume
4062 * requet, it will wait for suspend to be complete,
4063 * but runtime suspend also can not proceed further
4064 * until the host is resumed. Thus, it leads to a hang.
4065 * Hence, increase the pm usage count before suspending
4066 * the host so that any resume requests after this will
4067 * simple become pm usage counter increment operations.
4068 */
4069 pm_runtime_get_noresume(dev);
4070 rc = mmc_suspend_host(mmc);
4071 pm_runtime_put_noidle(dev);
4072
4073 if (!rc) {
4074 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
4075 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ)) {
4076 disable_irq(host->core_irqres->start);
4077 host->sdcc_irq_disabled = 1;
4078
4079 /*
4080 * If MMC core level suspend is not supported,
4081 * turn off clocks to allow deep sleep (TCXO
4082 * shutdown).
4083 */
4084 mmc->ios.clock = 0;
4085 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4086 enable_irq(host->core_irqres->start);
4087 host->sdcc_irq_disabled = 0;
4088
4089 if (host->plat->sdiowakeup_irq) {
4090 host->sdio_irq_disabled = 0;
4091 msmsdcc_enable_irq_wake(host);
4092 enable_irq(host->plat->sdiowakeup_irq);
4093 }
4094 }
4095 }
4096 host->sdcc_suspending = 0;
4097 mmc->suspend_task = NULL;
4098 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
4099 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004100 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304101 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004102 return rc;
4103}
4104
4105static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004106msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004107{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004108 struct mmc_host *mmc = dev_get_drvdata(dev);
4109 struct msmsdcc_host *host = mmc_priv(mmc);
4110 unsigned long flags;
4111
4112 if (host->plat->is_sdio_al_client)
4113 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07004114
Sahitya Tummala7661a452011-07-18 13:28:35 +05304115 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004116 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004117 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
4118 if (host->sdcc_irq_disabled) {
4119 enable_irq(host->core_irqres->start);
4120 host->sdcc_irq_disabled = 0;
4121 }
4122 }
4123 mmc->ios.clock = host->clk_rate;
4124 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07004125
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004126 spin_lock_irqsave(&host->lock, flags);
4127 writel_relaxed(host->mci_irqenable, host->base + MMCIMASK0);
4128 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07004129
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004130 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
4131 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) &&
4132 !host->sdio_irq_disabled) {
4133 if (host->plat->sdiowakeup_irq) {
4134 disable_irq_nosync(
4135 host->plat->sdiowakeup_irq);
4136 msmsdcc_disable_irq_wake(host);
4137 host->sdio_irq_disabled = 1;
4138 }
4139 }
San Mehat9d2bd732009-09-22 16:44:22 -07004140
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004141 spin_unlock_irqrestore(&host->lock, flags);
4142
4143 mmc_resume_host(mmc);
4144
4145 /*
4146 * FIXME: Clearing of flags must be handled in clients
4147 * resume handler.
4148 */
4149 spin_lock_irqsave(&host->lock, flags);
4150 mmc->pm_flags = 0;
4151 spin_unlock_irqrestore(&host->lock, flags);
4152
4153 /*
4154 * After resuming the host wait for sometime so that
4155 * the SDIO work will be processed.
4156 */
4157 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO)) {
4158 if ((host->plat->cfg_mpm_sdiowakeup ||
4159 host->plat->sdiowakeup_irq) &&
4160 wake_lock_active(&host->sdio_wlock))
4161 wake_lock_timeout(&host->sdio_wlock, 1);
4162 }
4163
4164 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004165 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304166 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004167 return 0;
4168}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004169
4170static int msmsdcc_runtime_idle(struct device *dev)
4171{
4172 struct mmc_host *mmc = dev_get_drvdata(dev);
4173 struct msmsdcc_host *host = mmc_priv(mmc);
4174
4175 if (host->plat->is_sdio_al_client)
4176 return 0;
4177
4178 /* Idle timeout is not configurable for now */
4179 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
4180
4181 return -EAGAIN;
4182}
4183
4184static int msmsdcc_pm_suspend(struct device *dev)
4185{
4186 struct mmc_host *mmc = dev_get_drvdata(dev);
4187 struct msmsdcc_host *host = mmc_priv(mmc);
4188 int rc = 0;
4189
4190 if (host->plat->is_sdio_al_client)
4191 return 0;
4192
4193
4194 if (host->plat->status_irq)
4195 disable_irq(host->plat->status_irq);
4196
4197 if (!pm_runtime_suspended(dev))
4198 rc = msmsdcc_runtime_suspend(dev);
4199
4200 return rc;
4201}
4202
4203static int msmsdcc_pm_resume(struct device *dev)
4204{
4205 struct mmc_host *mmc = dev_get_drvdata(dev);
4206 struct msmsdcc_host *host = mmc_priv(mmc);
4207 int rc = 0;
4208
4209 if (host->plat->is_sdio_al_client)
4210 return 0;
4211
Sahitya Tummalafb486372011-09-02 19:01:49 +05304212 if (!pm_runtime_suspended(dev))
4213 rc = msmsdcc_runtime_resume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004214 if (host->plat->status_irq) {
4215 msmsdcc_check_status((unsigned long)host);
4216 enable_irq(host->plat->status_irq);
4217 }
4218
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004219 return rc;
4220}
4221
Daniel Walker08ecfde2010-06-23 12:32:20 -07004222#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004223#define msmsdcc_runtime_suspend NULL
4224#define msmsdcc_runtime_resume NULL
4225#define msmsdcc_runtime_idle NULL
4226#define msmsdcc_pm_suspend NULL
4227#define msmsdcc_pm_resume NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07004228#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004229
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004230static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
4231 .runtime_suspend = msmsdcc_runtime_suspend,
4232 .runtime_resume = msmsdcc_runtime_resume,
4233 .runtime_idle = msmsdcc_runtime_idle,
4234 .suspend = msmsdcc_pm_suspend,
4235 .resume = msmsdcc_pm_resume,
4236};
4237
San Mehat9d2bd732009-09-22 16:44:22 -07004238static struct platform_driver msmsdcc_driver = {
4239 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004240 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07004241 .driver = {
4242 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004243 .pm = &msmsdcc_dev_pm_ops,
San Mehat9d2bd732009-09-22 16:44:22 -07004244 },
4245};
4246
4247static int __init msmsdcc_init(void)
4248{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004249#if defined(CONFIG_DEBUG_FS)
4250 int ret = 0;
4251 ret = msmsdcc_dbg_init();
4252 if (ret) {
4253 pr_err("Failed to create debug fs dir \n");
4254 return ret;
4255 }
4256#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004257 return platform_driver_register(&msmsdcc_driver);
4258}
4259
4260static void __exit msmsdcc_exit(void)
4261{
4262 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004263
4264#if defined(CONFIG_DEBUG_FS)
4265 debugfs_remove(debugfs_file);
4266 debugfs_remove(debugfs_dir);
4267#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004268}
4269
4270module_init(msmsdcc_init);
4271module_exit(msmsdcc_exit);
4272
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004273MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07004274MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004275
4276#if defined(CONFIG_DEBUG_FS)
4277
4278static int
4279msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
4280{
4281 file->private_data = inode->i_private;
4282 return 0;
4283}
4284
4285static ssize_t
4286msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
4287 size_t count, loff_t *ppos)
4288{
4289 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
4290 char buf[1024];
4291 int max, i;
4292
4293 i = 0;
4294 max = sizeof(buf) - 1;
4295
4296 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
4297 host->curr.cmd, host->curr.data);
4298 if (host->curr.cmd) {
4299 struct mmc_command *cmd = host->curr.cmd;
4300
4301 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
4302 cmd->opcode, cmd->arg, cmd->flags);
4303 }
4304 if (host->curr.data) {
4305 struct mmc_data *data = host->curr.data;
4306 i += scnprintf(buf + i, max - i,
4307 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
4308 data->timeout_ns, data->timeout_clks,
4309 data->blksz, data->blocks, data->error,
4310 data->flags);
4311 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
4312 host->curr.xfer_size, host->curr.xfer_remain,
4313 host->curr.data_xfered, host->dma.sg);
4314 }
4315
4316 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
4317}
4318
4319static const struct file_operations msmsdcc_dbg_state_ops = {
4320 .read = msmsdcc_dbg_state_read,
4321 .open = msmsdcc_dbg_state_open,
4322};
4323
4324static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
4325{
4326 if (debugfs_dir) {
4327 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
4328 0644, debugfs_dir, host,
4329 &msmsdcc_dbg_state_ops);
4330 }
4331}
4332
4333static int __init msmsdcc_dbg_init(void)
4334{
4335 int err;
4336
4337 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
4338 if (IS_ERR(debugfs_dir)) {
4339 err = PTR_ERR(debugfs_dir);
4340 debugfs_dir = NULL;
4341 return err;
4342 }
4343
4344 return 0;
4345}
4346#endif