blob: 2c4aca7beb17b95ab879bdb4e33ac89b44c617aa [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;
Krishna Konda25786ec2011-07-25 16:21:36 -0700780 host->dma.hdr.crci_mask = msm_dmov_build_crci_mask(1, host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700781
782 n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
783 host->dma.num_ents, host->dma.dir);
784 /* dsb inside dma_map_sg will write nc out to mem as well */
785
786 if (n != host->dma.num_ents) {
787 pr_err("%s: Unable to map in all sg elements\n",
788 mmc_hostname(host->mmc));
789 host->dma.sg = NULL;
790 host->dma.num_ents = 0;
791 return -ENOMEM;
San Mehat56a8b5b2009-11-21 12:29:46 -0800792 }
San Mehat9d2bd732009-09-22 16:44:22 -0700793
794 return 0;
795}
796
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700797#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
798/**
799 * Submits data transfer request to SPS driver
800 *
801 * This function make sg (scatter gather) data buffers
802 * DMA ready and then submits them to SPS driver for
803 * transfer.
804 *
805 * @host - Pointer to sdcc host structure
806 * @data - Pointer to mmc_data structure
807 *
808 * @return 0 if success else negative value
809 */
810static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
811 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -0800812{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700813 int rc = 0;
814 u32 flags;
815 int i;
816 u32 addr, len, data_cnt;
817 struct scatterlist *sg = data->sg;
818 struct sps_pipe *sps_pipe_handle;
819
820 BUG_ON(data->sg_len > NR_SG); /* Prevent memory corruption */
821
822 host->sps.sg = data->sg;
823 host->sps.num_ents = data->sg_len;
824 host->sps.xfer_req_cnt = 0;
825 if (data->flags & MMC_DATA_READ) {
826 host->sps.dir = DMA_FROM_DEVICE;
827 sps_pipe_handle = host->sps.prod.pipe_handle;
828 } else {
829 host->sps.dir = DMA_TO_DEVICE;
830 sps_pipe_handle = host->sps.cons.pipe_handle;
831 }
832
833 /* Make sg buffers DMA ready */
834 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
835 host->sps.dir);
836
837 if (rc != data->sg_len) {
838 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
839 mmc_hostname(host->mmc), rc);
840 host->sps.sg = NULL;
841 host->sps.num_ents = 0;
842 rc = -ENOMEM;
843 goto dma_map_err;
844 }
845
846 pr_debug("%s: %s: %s: pipe=0x%x, total_xfer=0x%x, sg_len=%d\n",
847 mmc_hostname(host->mmc), __func__,
848 host->sps.dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
849 (u32)sps_pipe_handle, host->curr.xfer_size, data->sg_len);
850
851 for (i = 0; i < data->sg_len; i++) {
852 /*
853 * Check if this is the last buffer to transfer?
854 * If yes then set the INT and EOT flags.
855 */
856 len = sg_dma_len(sg);
857 addr = sg_dma_address(sg);
858 flags = 0;
859 while (len > 0) {
860 if (len > SPS_MAX_DESC_SIZE) {
861 data_cnt = SPS_MAX_DESC_SIZE;
862 } else {
863 data_cnt = len;
864 if (i == data->sg_len - 1)
865 flags = SPS_IOVEC_FLAG_INT |
866 SPS_IOVEC_FLAG_EOT;
867 }
868 rc = sps_transfer_one(sps_pipe_handle, addr,
869 data_cnt, host, flags);
870 if (rc) {
871 pr_err("%s: sps_transfer_one() error! rc=%d,"
872 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
873 mmc_hostname(host->mmc), rc,
874 (u32)sps_pipe_handle, (u32)sg, i);
875 goto dma_map_err;
876 }
877 addr += data_cnt;
878 len -= data_cnt;
879 host->sps.xfer_req_cnt++;
880 }
881 sg++;
882 }
883 goto out;
884
885dma_map_err:
886 /* unmap sg buffers */
887 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
888 host->sps.dir);
889out:
890 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -0700891}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700892#else
893static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
894 struct mmc_data *data) { return 0; }
895#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -0700896
897static void
San Mehat56a8b5b2009-11-21 12:29:46 -0800898msmsdcc_start_command_deferred(struct msmsdcc_host *host,
899 struct mmc_command *cmd, u32 *c)
900{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700901 DBG(host, "op %02x arg %08x flags %08x\n",
902 cmd->opcode, cmd->arg, cmd->flags);
903
San Mehat56a8b5b2009-11-21 12:29:46 -0800904 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
905
906 if (cmd->flags & MMC_RSP_PRESENT) {
907 if (cmd->flags & MMC_RSP_136)
908 *c |= MCI_CPSM_LONGRSP;
909 *c |= MCI_CPSM_RESPONSE;
910 }
911
912 if (/*interrupt*/0)
913 *c |= MCI_CPSM_INTERRUPT;
914
915 if ((((cmd->opcode == 17) || (cmd->opcode == 18)) ||
916 ((cmd->opcode == 24) || (cmd->opcode == 25))) ||
917 (cmd->opcode == 53))
918 *c |= MCI_CSPM_DATCMD;
919
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700920 /* Check if AUTO CMD19 is required or not? */
921 if (((cmd->opcode == 17) || (cmd->opcode == 18)) &&
922 host->tuning_needed) {
923 msmsdcc_enable_cdr_cm_sdc4_dll(host);
924 *c |= MCI_CSPM_AUTO_CMD19;
925 }
926
Sahitya Tummalad5137bd2010-12-08 15:03:04 +0530927 if (host->prog_scan && (cmd->opcode == 12)) {
928 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700929 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +0530930 }
931
San Mehat56a8b5b2009-11-21 12:29:46 -0800932 if (cmd == cmd->mrq->stop)
933 *c |= MCI_CSPM_MCIABORT;
934
San Mehat56a8b5b2009-11-21 12:29:46 -0800935 if (host->curr.cmd != NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700936 pr_err("%s: Overlapping command requests\n",
937 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -0800938 }
939 host->curr.cmd = cmd;
940}
941
942static void
943msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
944 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -0700945{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +0530946 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -0700947 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700948 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -0700949 unsigned int pio_irqmask = 0;
950
951 host->curr.data = data;
952 host->curr.xfer_size = data->blksz * data->blocks;
953 host->curr.xfer_remain = host->curr.xfer_size;
954 host->curr.data_xfered = 0;
955 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530956 host->curr.got_auto_prog_done = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700957
958 memset(&host->pio, 0, sizeof(host->pio));
959
San Mehat9d2bd732009-09-22 16:44:22 -0700960 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
961
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530962 if (host->curr.wait_for_auto_prog_done)
963 datactrl |= MCI_AUTO_PROG_DONE;
964
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700965 if (!msmsdcc_check_dma_op_req(data)) {
966 if (host->is_dma_mode && !msmsdcc_config_dma(host, data)) {
967 datactrl |= MCI_DPSM_DMAENABLE;
968 } else if (host->is_sps_mode) {
969 if (!msmsdcc_is_dml_busy(host)) {
970 if (!msmsdcc_sps_start_xfer(host, data)) {
971 /* Now kick start DML transfer */
972 mb();
973 msmsdcc_dml_start_xfer(host, data);
974 datactrl |= MCI_DPSM_DMAENABLE;
975 host->sps.busy = 1;
976 }
977 } else {
978 /*
979 * Can't proceed with new transfer as
980 * previous trasnfer is already in progress.
981 * There is no point of going into PIO mode
982 * as well. Is this a time to do kernel panic?
983 */
984 pr_err("%s: %s: DML HW is busy!!!"
985 " Can't perform new SPS transfers"
986 " now\n", mmc_hostname(host->mmc),
987 __func__);
988 }
989 }
990 }
991
992 /* Is data transfer in PIO mode required? */
993 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700994 host->pio.sg = data->sg;
995 host->pio.sg_len = data->sg_len;
996 host->pio.sg_off = 0;
997
998 if (data->flags & MMC_DATA_READ) {
999 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1000 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1001 pio_irqmask |= MCI_RXDATAAVLBLMASK;
1002 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001003 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1004 MCI_TXFIFOEMPTYMASK;
San Mehat9d2bd732009-09-22 16:44:22 -07001005 }
1006
1007 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301008 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
San Mehat9d2bd732009-09-22 16:44:22 -07001009
San Mehat56a8b5b2009-11-21 12:29:46 -08001010 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001011 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001012 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -07001013
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001014 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
1015 /* Use ADM (Application Data Mover) HW for Data transfer */
1016 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001017 host->cmd_timeout = timeout;
1018 host->cmd_pio_irqmask = pio_irqmask;
1019 host->cmd_datactrl = datactrl;
1020 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001021
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001022 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1023 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001024 host->dma.busy = 1;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301025 if ((data->flags & MMC_DATA_WRITE) && !host->curr.mrq->sbc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001026 host->prog_scan = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001027
1028 if (cmd) {
1029 msmsdcc_start_command_deferred(host, cmd, &c);
1030 host->cmd_c = c;
1031 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001032 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1033 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1034 host->base + MMCIMASK0);
1035 mb();
1036 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001037 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001038 /* SPS-BAM mode or PIO mode */
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301039 if ((data->flags & MMC_DATA_WRITE) && !host->curr.mrq->sbc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001040 host->prog_scan = 1;
1041 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001042
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001043 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001044
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001045 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1046 (~(MCI_IRQ_PIO))) | pio_irqmask,
1047 host->base + MMCIMASK0);
1048 msmsdcc_delay(host); /* Allow parms to be applied */
1049 writel_relaxed(datactrl, base + MMCIDATACTRL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001050
1051 if (cmd) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001052 msmsdcc_delay(host); /* Delay between data/command */
San Mehat56a8b5b2009-11-21 12:29:46 -08001053 /* Daisy-chain the command if requested */
1054 msmsdcc_start_command(host, cmd, c);
1055 }
San Mehat9d2bd732009-09-22 16:44:22 -07001056 }
1057}
1058
1059static void
1060msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1061{
San Mehat56a8b5b2009-11-21 12:29:46 -08001062 msmsdcc_start_command_deferred(host, cmd, &c);
1063 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001064}
1065
1066static void
1067msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1068 unsigned int status)
1069{
1070 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001071 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1072 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1073 pr_err("%s: Data CRC error\n",
1074 mmc_hostname(host->mmc));
1075 pr_err("%s: opcode 0x%.8x\n", __func__,
1076 data->mrq->cmd->opcode);
1077 pr_err("%s: blksz %d, blocks %d\n", __func__,
1078 data->blksz, data->blocks);
1079 data->error = -EILSEQ;
1080 }
San Mehat9d2bd732009-09-22 16:44:22 -07001081 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001082 /* CRC is optional for the bus test commands, not all
1083 * cards respond back with CRC. However controller
1084 * waits for the CRC and times out. Hence ignore the
1085 * data timeouts during the Bustest.
1086 */
1087 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1088 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1089 pr_err("%s: Data timeout\n",
1090 mmc_hostname(host->mmc));
1091 data->error = -ETIMEDOUT;
1092 }
San Mehat9d2bd732009-09-22 16:44:22 -07001093 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001094 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001095 data->error = -EIO;
1096 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001097 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001098 data->error = -EIO;
1099 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001100 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001101 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001102 data->error = -EIO;
1103 }
San Mehat9d2bd732009-09-22 16:44:22 -07001104
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001105 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001106 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001107 host->dummy_52_needed = 0;
1108}
San Mehat9d2bd732009-09-22 16:44:22 -07001109
1110static int
1111msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1112{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001113 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001114 uint32_t *ptr = (uint32_t *) buffer;
1115 int count = 0;
1116
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301117 if (remain % 4)
1118 remain = ((remain >> 2) + 1) << 2;
1119
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001120 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1121
1122 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001123 ptr++;
1124 count += sizeof(uint32_t);
1125
1126 remain -= sizeof(uint32_t);
1127 if (remain == 0)
1128 break;
1129 }
1130 return count;
1131}
1132
1133static int
1134msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001135 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001136{
1137 void __iomem *base = host->base;
1138 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001139 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001140
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001141 while (readl_relaxed(base + MMCISTATUS) &
1142 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1143 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001144
San Mehat9d2bd732009-09-22 16:44:22 -07001145 count = min(remain, maxcnt);
1146
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301147 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1148 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001149 ptr += count;
1150 remain -= count;
1151
1152 if (remain == 0)
1153 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001154 }
1155 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001156
1157 return ptr - buffer;
1158}
1159
San Mehat1cd22962010-02-03 12:59:29 -08001160static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001161msmsdcc_pio_irq(int irq, void *dev_id)
1162{
1163 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001164 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001165 uint32_t status;
1166
Murali Palnati36448a42011-09-02 15:06:18 +05301167 spin_lock(&host->lock);
1168
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001169 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001170
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001171 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301172 (MCI_IRQ_PIO)) == 0) {
1173 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001174 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301175 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001176
1177#if IRQ_DEBUG
1178 msmsdcc_print_status(host, "irq1-r", status);
1179#endif
1180
San Mehat9d2bd732009-09-22 16:44:22 -07001181 do {
1182 unsigned long flags;
1183 unsigned int remain, len;
1184 char *buffer;
1185
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001186 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1187 | MCI_RXDATAAVLBL)))
1188 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001189
1190 /* Map the current scatter buffer */
1191 local_irq_save(flags);
1192 buffer = kmap_atomic(sg_page(host->pio.sg),
1193 KM_BIO_SRC_IRQ) + host->pio.sg->offset;
1194 buffer += host->pio.sg_off;
1195 remain = host->pio.sg->length - host->pio.sg_off;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001196
San Mehat9d2bd732009-09-22 16:44:22 -07001197 len = 0;
1198 if (status & MCI_RXACTIVE)
1199 len = msmsdcc_pio_read(host, buffer, remain);
1200 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001201 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001202
1203 /* Unmap the buffer */
1204 kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
1205 local_irq_restore(flags);
1206
1207 host->pio.sg_off += len;
1208 host->curr.xfer_remain -= len;
1209 host->curr.data_xfered += len;
1210 remain -= len;
1211
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001212 if (remain) /* Done with this page? */
1213 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001214
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001215 if (status & MCI_RXACTIVE && host->curr.user_pages)
1216 flush_dcache_page(sg_page(host->pio.sg));
San Mehat9d2bd732009-09-22 16:44:22 -07001217
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001218 if (!--host->pio.sg_len) {
1219 memset(&host->pio, 0, sizeof(host->pio));
1220 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001221 }
1222
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001223 /* Advance to next sg */
1224 host->pio.sg++;
1225 host->pio.sg_off = 0;
1226
1227 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001228 } while (1);
1229
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001230 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1231 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1232 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1233 host->base + MMCIMASK0);
1234 if (!host->curr.xfer_remain) {
1235 /* Delay needed (same port was just written) */
1236 msmsdcc_delay(host);
1237 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1238 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1239 }
1240 mb();
1241 } else if (!host->curr.xfer_remain) {
1242 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1243 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1244 mb();
1245 }
San Mehat9d2bd732009-09-22 16:44:22 -07001246
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001247 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001248
1249 return IRQ_HANDLED;
1250}
1251
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001252static void
1253msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1254
1255static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1256 struct mmc_data *data)
1257{
1258 u32 loop_cnt = 0;
1259
1260 /*
1261 * For read commands with data less than fifo size, it is possible to
1262 * get DATAEND first and RXDATA_AVAIL might be set later because of
1263 * synchronization delay through the asynchronous RX FIFO. Thus, for
1264 * such cases, even after DATAEND interrupt is received software
1265 * should poll for RXDATA_AVAIL until the requested data is read out
1266 * of FIFO. This change is needed to get around this abnormal but
1267 * sometimes expected behavior of SDCC3 controller.
1268 *
1269 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1270 * after the data is loaded into RX FIFO. This would amount to less
1271 * than a microsecond and thus looping for 1000 times is good enough
1272 * for that delay.
1273 */
1274 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1275 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1276 spin_unlock(&host->lock);
1277 msmsdcc_pio_irq(1, host);
1278 spin_lock(&host->lock);
1279 }
1280 }
1281 if (loop_cnt == 1000) {
1282 pr_info("%s: Timed out while polling for Rx Data\n",
1283 mmc_hostname(host->mmc));
1284 data->error = -ETIMEDOUT;
1285 msmsdcc_reset_and_restore(host);
1286 }
1287}
1288
San Mehat9d2bd732009-09-22 16:44:22 -07001289static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1290{
1291 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001292
1293 host->curr.cmd = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001294 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1295 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1296 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1297 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -07001298
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001299 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Sahitya Tummala5a0ae912011-07-18 13:34:01 +05301300 pr_debug("%s: Command timeout\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001301 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001302 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
1303 !host->cmd19_tuning_in_progress) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001304 pr_err("%s: Command CRC error\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001305 cmd->error = -EILSEQ;
1306 }
1307
1308 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001309 if (host->curr.data && host->dma.sg &&
1310 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001311 msm_dmov_stop_cmd(host->dma.channel,
1312 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001313 else if (host->curr.data && host->sps.sg &&
1314 host->is_sps_mode){
1315 /* Stop current SPS transfer */
1316 msmsdcc_sps_exit_curr_xfer(host);
1317 }
San Mehat9d2bd732009-09-22 16:44:22 -07001318 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301319 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001320 msmsdcc_stop_data(host);
1321 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301322 } else { /* host->data == NULL */
1323 if (!cmd->error && host->prog_enable) {
1324 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001325 host->prog_scan = 0;
1326 host->prog_enable = 0;
1327 msmsdcc_request_end(host, cmd->mrq);
1328 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301329 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301330 } else {
1331 if (host->prog_enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001332 host->prog_scan = 0;
1333 host->prog_enable = 0;
1334 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001335 if (host->dummy_52_needed)
1336 host->dummy_52_needed = 0;
1337 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001338 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301339 msmsdcc_request_end(host, cmd->mrq);
1340 }
1341 }
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301342 } else if (cmd == host->curr.mrq->sbc) {
1343 msmsdcc_request_start(host, host->curr.mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001344 } else if (cmd->data) {
San Mehat56a8b5b2009-11-21 12:29:46 -08001345 if (!(cmd->data->flags & MMC_DATA_READ))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001346 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001347 }
1348}
1349
San Mehat9d2bd732009-09-22 16:44:22 -07001350static irqreturn_t
1351msmsdcc_irq(int irq, void *dev_id)
1352{
1353 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001354 u32 status;
1355 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001356 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001357
1358 spin_lock(&host->lock);
1359
1360 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001361 struct mmc_command *cmd;
1362 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001363
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001364 if (timer) {
1365 timer = 0;
1366 msmsdcc_delay(host);
1367 }
San Mehat865c8062009-11-13 13:42:06 -08001368
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001369 if (!host->clks_on) {
1370 pr_debug("%s: %s: SDIO async irq received\n",
1371 mmc_hostname(host->mmc), __func__);
1372 host->mmc->ios.clock = host->clk_rate;
1373 spin_unlock(&host->lock);
1374 host->mmc->ops->set_ios(host->mmc, &host->mmc->ios);
1375 spin_lock(&host->lock);
1376 if (host->plat->cfg_mpm_sdiowakeup &&
1377 (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
1378 wake_lock(&host->sdio_wlock);
1379 /* only ansyc interrupt can come when clocks are off */
1380 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
1381 }
1382
1383 status = readl_relaxed(host->base + MMCISTATUS);
1384
1385 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1386 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001387 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001388
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001389#if IRQ_DEBUG
1390 msmsdcc_print_status(host, "irq0-r", status);
1391#endif
1392 status &= readl_relaxed(host->base + MMCIMASK0);
1393 writel_relaxed(status, host->base + MMCICLEAR);
1394 mb();
1395#if IRQ_DEBUG
1396 msmsdcc_print_status(host, "irq0-p", status);
1397#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001398
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001399#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
1400 if (status & MCI_SDIOINTROPE) {
1401 if (host->sdcc_suspending)
1402 wake_lock(&host->sdio_suspend_wlock);
1403 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001404 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001405#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001406 data = host->curr.data;
1407
1408 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001409 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1410 MCI_CMDTIMEOUT)) {
1411 if (status & MCI_CMDTIMEOUT)
1412 pr_debug("%s: dummy CMD52 timeout\n",
1413 mmc_hostname(host->mmc));
1414 if (status & MCI_CMDCRCFAIL)
1415 pr_debug("%s: dummy CMD52 CRC failed\n",
1416 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001417 host->dummy_52_sent = 0;
1418 host->dummy_52_needed = 0;
1419 if (data) {
1420 msmsdcc_stop_data(host);
1421 msmsdcc_request_end(host, data->mrq);
1422 }
1423 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001424 spin_unlock(&host->lock);
1425 return IRQ_HANDLED;
1426 }
1427 break;
1428 }
1429
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001430 /*
1431 * Check for proper command response
1432 */
1433 cmd = host->curr.cmd;
1434 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1435 MCI_CMDTIMEOUT | MCI_PROGDONE |
1436 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1437 msmsdcc_do_cmdirq(host, status);
1438 }
1439
1440 if (data) {
1441 /* Check for data errors */
1442 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1443 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1444 msmsdcc_data_err(host, data, status);
1445 host->curr.data_xfered = 0;
1446 if (host->dma.sg && host->is_dma_mode)
1447 msm_dmov_stop_cmd(host->dma.channel,
1448 &host->dma.hdr, 0);
1449 else if (host->sps.sg && host->is_sps_mode) {
1450 /* Stop current SPS transfer */
1451 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301452 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001453 msmsdcc_reset_and_restore(host);
1454 if (host->curr.data)
1455 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301456 if (!data->stop || (host->curr.mrq->sbc
1457 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001458 timer |=
1459 msmsdcc_request_end(host,
1460 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301461 else if ((host->curr.mrq->sbc
1462 && data->error) ||
1463 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001464 msmsdcc_start_command(host,
1465 data->stop,
1466 0);
1467 timer = 1;
1468 }
1469 }
1470 }
1471
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301472 /* Check for prog done */
1473 if (host->curr.wait_for_auto_prog_done &&
1474 (status & MCI_PROGDONE))
1475 host->curr.got_auto_prog_done = 1;
1476
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001477 /* Check for data done */
1478 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1479 host->curr.got_dataend = 1;
1480
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301481 if (host->curr.got_dataend &&
1482 (!host->curr.wait_for_auto_prog_done ||
1483 (host->curr.wait_for_auto_prog_done &&
1484 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001485 /*
1486 * If DMA is still in progress, we complete
1487 * via the completion handler
1488 */
1489 if (!host->dma.busy && !host->sps.busy) {
1490 /*
1491 * There appears to be an issue in the
1492 * controller where if you request a
1493 * small block transfer (< fifo size),
1494 * you may get your DATAEND/DATABLKEND
1495 * irq without the PIO data irq.
1496 *
1497 * Check to see if theres still data
1498 * to be read, and simulate a PIO irq.
1499 */
1500 if (data->flags & MMC_DATA_READ)
1501 msmsdcc_wait_for_rxdata(host,
1502 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001503 if (!data->error) {
1504 host->curr.data_xfered =
1505 host->curr.xfer_size;
1506 host->curr.xfer_remain -=
1507 host->curr.xfer_size;
1508 }
1509
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001510 if (!host->dummy_52_needed) {
1511 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301512 if (!data->stop ||
1513 (host->curr.mrq->sbc
1514 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001515 msmsdcc_request_end(
1516 host,
1517 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301518 else if ((host->curr.mrq->sbc
1519 && data->error) ||
1520 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001521 msmsdcc_start_command(
1522 host,
1523 data->stop, 0);
1524 timer = 1;
1525 }
1526 } else {
1527 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001528 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001529 &dummy52cmd,
1530 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001531 }
1532 }
1533 }
1534 }
1535
San Mehat9d2bd732009-09-22 16:44:22 -07001536 ret = 1;
1537 } while (status);
1538
1539 spin_unlock(&host->lock);
1540
San Mehat9d2bd732009-09-22 16:44:22 -07001541 return IRQ_RETVAL(ret);
1542}
1543
1544static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001545msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1546{
1547 if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
1548 /* Queue/read data, daisy-chain command when data starts */
1549 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
1550 } else {
1551 msmsdcc_start_command(host, mrq->cmd, 0);
1552 }
1553}
1554
1555static void
San Mehat9d2bd732009-09-22 16:44:22 -07001556msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1557{
1558 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001559 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001560
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001561 /*
1562 * Get the SDIO AL client out of LPM.
1563 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001564 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001565 if (host->plat->is_sdio_al_client)
1566 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001567
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301568 /* check if sps pipe reset is pending? */
1569 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1570 msmsdcc_sps_pipes_reset_and_restore(host);
1571 host->sps.pipe_reset_pending = false;
1572 }
1573
San Mehat9d2bd732009-09-22 16:44:22 -07001574 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001575 WARN(host->curr.mrq, "Request in progress\n");
1576 WARN(!host->pwr, "SDCC power is turned off\n");
1577 WARN(!host->clks_on, "SDCC clocks are turned off\n");
1578 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
San Mehat9d2bd732009-09-22 16:44:22 -07001579
1580 if (host->eject) {
1581 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1582 mrq->cmd->error = 0;
1583 mrq->data->bytes_xfered = mrq->data->blksz *
1584 mrq->data->blocks;
1585 } else
1586 mrq->cmd->error = -ENOMEDIUM;
1587
1588 spin_unlock_irqrestore(&host->lock, flags);
1589 mmc_request_done(mmc, mrq);
1590 return;
1591 }
1592
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301593 /*
1594 * Kick the software command timeout timer here.
1595 * Timer expires in 10 secs.
1596 */
1597 mod_timer(&host->req_tout_timer,
1598 (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
San Mehat9d2bd732009-09-22 16:44:22 -07001599
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301600 host->curr.mrq = mrq;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301601 if (mrq->data && mrq->data->flags == MMC_DATA_WRITE) {
1602 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
1603 mrq->cmd->opcode == 54) {
1604 if (!host->plat->sdcc_v4_sup)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001605 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301606 else
1607 /*
1608 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
1609 * write operations using CMD53 and CMD54.
1610 * Setting this bit with CMD53 would
1611 * automatically triggers PROG_DONE interrupt
1612 * without the need of sending dummy CMD52.
1613 */
1614 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001615 }
San Mehat9d2bd732009-09-22 16:44:22 -07001616 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301617
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301618 if (mrq->sbc) {
1619 mrq->sbc->mrq = mrq;
1620 mrq->sbc->data = mrq->data;
1621 if (mrq->data->flags == MMC_DATA_WRITE)
1622 host->curr.wait_for_auto_prog_done = 1;
1623 msmsdcc_start_command(host, mrq->sbc, 0);
1624 } else {
1625 msmsdcc_request_start(host, mrq);
1626 }
1627
San Mehat9d2bd732009-09-22 16:44:22 -07001628 spin_unlock_irqrestore(&host->lock, flags);
1629}
1630
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001631static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1632 int min_uV, int max_uV)
1633{
1634 int rc = 0;
1635
1636 if (vreg->set_voltage_sup) {
1637 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1638 if (rc) {
1639 pr_err("%s: regulator_set_voltage(%s) failed."
1640 " min_uV=%d, max_uV=%d, rc=%d\n",
1641 __func__, vreg->name, min_uV, max_uV, rc);
1642 }
1643 }
1644
1645 return rc;
1646}
1647
1648static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1649 int uA_load)
1650{
1651 int rc = 0;
1652
1653 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1654 if (rc < 0)
1655 pr_err("%s: regulator_set_optimum_mode(reg=%s, uA_load=%d)"
1656 " failed. rc=%d\n", __func__, vreg->name,
1657 uA_load, rc);
1658 else
1659 /* regulator_set_optimum_mode() can return non zero value
1660 * even for success case.
1661 */
1662 rc = 0;
1663
1664 return rc;
1665}
1666
1667static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1668 struct device *dev)
1669{
1670 int rc = 0;
1671
1672 /* check if regulator is already initialized? */
1673 if (vreg->reg)
1674 goto out;
1675
1676 /* Get the regulator handle */
1677 vreg->reg = regulator_get(dev, vreg->name);
1678 if (IS_ERR(vreg->reg)) {
1679 rc = PTR_ERR(vreg->reg);
1680 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
1681 __func__, vreg->name, rc);
1682 }
1683out:
1684 return rc;
1685}
1686
1687static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
1688{
1689 if (vreg->reg)
1690 regulator_put(vreg->reg);
1691}
1692
1693/* This init function should be called only once for each SDCC slot */
1694static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
1695{
1696 int rc = 0;
1697 struct msm_mmc_slot_reg_data *curr_slot;
1698 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1699 struct device *dev = mmc_dev(host->mmc);
1700
1701 curr_slot = host->plat->vreg_data;
1702 if (!curr_slot)
1703 goto out;
1704
1705 curr_vdd_reg = curr_slot->vdd_data;
1706 curr_vccq_reg = curr_slot->vccq_data;
1707 curr_vddp_reg = curr_slot->vddp_data;
1708
1709 if (is_init) {
1710 /*
1711 * Get the regulator handle from voltage regulator framework
1712 * and then try to set the voltage level for the regulator
1713 */
1714 if (curr_vdd_reg) {
1715 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
1716 if (rc)
1717 goto out;
1718 }
1719 if (curr_vccq_reg) {
1720 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
1721 if (rc)
1722 goto vdd_reg_deinit;
1723 }
1724 if (curr_vddp_reg) {
1725 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
1726 if (rc)
1727 goto vccq_reg_deinit;
1728 }
1729 goto out;
1730 } else {
1731 /* Deregister all regulators from regulator framework */
1732 goto vddp_reg_deinit;
1733 }
1734vddp_reg_deinit:
1735 if (curr_vddp_reg)
1736 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
1737vccq_reg_deinit:
1738 if (curr_vccq_reg)
1739 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
1740vdd_reg_deinit:
1741 if (curr_vdd_reg)
1742 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
1743out:
1744 return rc;
1745}
1746
1747static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
1748{
1749 int rc = 0;
1750
Subhash Jadavanicc922692011-08-01 23:05:01 +05301751 /* Put regulator in HPM (high power mode) */
1752 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
1753 if (rc < 0)
1754 goto out;
1755
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001756 if (!vreg->is_enabled) {
1757 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301758 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
1759 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001760 if (rc)
1761 goto out;
1762
1763 rc = regulator_enable(vreg->reg);
1764 if (rc) {
1765 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
1766 __func__, vreg->name, rc);
1767 goto out;
1768 }
1769 vreg->is_enabled = true;
1770 }
1771
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001772out:
1773 return rc;
1774}
1775
1776static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
1777{
1778 int rc = 0;
1779
1780 /* Never disable regulator marked as always_on */
1781 if (vreg->is_enabled && !vreg->always_on) {
1782 rc = regulator_disable(vreg->reg);
1783 if (rc) {
1784 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
1785 __func__, vreg->name, rc);
1786 goto out;
1787 }
1788 vreg->is_enabled = false;
1789
1790 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
1791 if (rc < 0)
1792 goto out;
1793
1794 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301795 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001796 if (rc)
1797 goto out;
1798 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
1799 /* Put always_on regulator in LPM (low power mode) */
1800 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
1801 if (rc < 0)
1802 goto out;
1803 }
1804out:
1805 return rc;
1806}
1807
1808static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
1809{
1810 int rc = 0, i;
1811 struct msm_mmc_slot_reg_data *curr_slot;
1812 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1813 struct msm_mmc_reg_data *vreg_table[3];
1814
1815 curr_slot = host->plat->vreg_data;
1816 if (!curr_slot)
1817 goto out;
1818
1819 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
1820 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
1821 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
1822
1823 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
1824 if (vreg_table[i]) {
1825 if (enable)
1826 rc = msmsdcc_vreg_enable(vreg_table[i]);
1827 else
1828 rc = msmsdcc_vreg_disable(vreg_table[i]);
1829 if (rc)
1830 goto out;
1831 }
1832 }
1833out:
1834 return rc;
1835}
1836
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301837static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001838{
1839 int rc = 0;
1840
1841 if (host->plat->vreg_data) {
1842 struct msm_mmc_reg_data *vddp_reg =
1843 host->plat->vreg_data->vddp_data;
1844
1845 if (vddp_reg && vddp_reg->is_enabled)
1846 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
1847 }
1848
1849 return rc;
1850}
1851
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301852static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
1853{
1854 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1855 int rc = 0;
1856
1857 if (curr_slot && curr_slot->vddp_data) {
1858 rc = msmsdcc_set_vddp_level(host,
1859 curr_slot->vddp_data->low_vol_level);
1860
1861 if (rc)
1862 pr_err("%s: %s: failed to change vddp level to %d",
1863 mmc_hostname(host->mmc), __func__,
1864 curr_slot->vddp_data->low_vol_level);
1865 }
1866
1867 return rc;
1868}
1869
1870static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
1871{
1872 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1873 int rc = 0;
1874
1875 if (curr_slot && curr_slot->vddp_data) {
1876 rc = msmsdcc_set_vddp_level(host,
1877 curr_slot->vddp_data->high_vol_level);
1878
1879 if (rc)
1880 pr_err("%s: %s: failed to change vddp level to %d",
1881 mmc_hostname(host->mmc), __func__,
1882 curr_slot->vddp_data->high_vol_level);
1883 }
1884
1885 return rc;
1886}
1887
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001888static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
1889{
1890 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
1891 return 1;
1892 return 0;
1893}
1894
1895static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
1896{
1897 if (enable) {
1898 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1899 clk_enable(host->dfab_pclk);
1900 if (!IS_ERR(host->pclk))
1901 clk_enable(host->pclk);
1902 clk_enable(host->clk);
1903 } else {
1904 clk_disable(host->clk);
1905 if (!IS_ERR(host->pclk))
1906 clk_disable(host->pclk);
1907 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1908 clk_disable(host->dfab_pclk);
1909 }
1910}
1911
1912static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
1913 unsigned int req_clk)
1914{
1915 unsigned int sel_clk = -1;
1916
1917 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
1918 unsigned char cnt;
1919
1920 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
1921 if (host->plat->sup_clk_table[cnt] > req_clk)
1922 break;
1923 else if (host->plat->sup_clk_table[cnt] == req_clk) {
1924 sel_clk = host->plat->sup_clk_table[cnt];
1925 break;
1926 } else
1927 sel_clk = host->plat->sup_clk_table[cnt];
1928 }
1929 } else {
1930 if ((req_clk < host->plat->msmsdcc_fmax) &&
1931 (req_clk > host->plat->msmsdcc_fmid))
1932 sel_clk = host->plat->msmsdcc_fmid;
1933 else
1934 sel_clk = req_clk;
1935 }
1936
1937 return sel_clk;
1938}
1939
1940static inline unsigned int msmsdcc_get_min_sup_clk_rate(
1941 struct msmsdcc_host *host)
1942{
1943 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
1944 return host->plat->sup_clk_table[0];
1945 else
1946 return host->plat->msmsdcc_fmin;
1947}
1948
1949static inline unsigned int msmsdcc_get_max_sup_clk_rate(
1950 struct msmsdcc_host *host)
1951{
1952 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
1953 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
1954 else
1955 return host->plat->msmsdcc_fmax;
1956}
1957
1958static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05301959{
1960 struct msm_mmc_gpio_data *curr;
1961 int i, rc = 0;
1962
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001963 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301964 for (i = 0; i < curr->size; i++) {
1965 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001966 if (curr->gpio[i].is_always_on &&
1967 curr->gpio[i].is_enabled)
1968 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301969 rc = gpio_request(curr->gpio[i].no,
1970 curr->gpio[i].name);
1971 if (rc) {
1972 pr_err("%s: gpio_request(%d, %s) failed %d\n",
1973 mmc_hostname(host->mmc),
1974 curr->gpio[i].no,
1975 curr->gpio[i].name, rc);
1976 goto free_gpios;
1977 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001978 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301979 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001980 if (curr->gpio[i].is_always_on)
1981 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301982 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001983 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301984 }
1985 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001986 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301987
1988free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001989 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05301990 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001991 curr->gpio[i].is_enabled = false;
1992 }
1993out:
1994 return rc;
1995}
1996
1997static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
1998{
1999 struct msm_mmc_pad_data *curr;
2000 int i;
2001
2002 curr = host->plat->pin_data->pad_data;
2003 for (i = 0; i < curr->drv->size; i++) {
2004 if (enable)
2005 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2006 curr->drv->on[i].val);
2007 else
2008 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2009 curr->drv->off[i].val);
2010 }
2011
2012 for (i = 0; i < curr->pull->size; i++) {
2013 if (enable)
2014 msm_tlmm_set_hdrive(curr->pull->on[i].no,
2015 curr->pull->on[i].val);
2016 else
2017 msm_tlmm_set_hdrive(curr->pull->off[i].no,
2018 curr->pull->off[i].val);
2019 }
2020
2021 return 0;
2022}
2023
2024static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2025{
2026 int rc = 0;
2027
2028 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2029 return 0;
2030
2031 if (host->plat->pin_data->is_gpio)
2032 rc = msmsdcc_setup_gpio(host, enable);
2033 else
2034 rc = msmsdcc_setup_pad(host, enable);
2035
2036 if (!rc)
2037 host->plat->pin_data->cfg_sts = enable;
2038
2039 return rc;
2040}
2041
2042static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2043{
2044 unsigned int wakeup_irq;
2045
2046 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2047 host->plat->sdiowakeup_irq :
2048 host->core_irqres->start;
2049
2050 if (!host->irq_wake_enabled) {
2051 enable_irq_wake(wakeup_irq);
2052 host->irq_wake_enabled = true;
2053 }
2054}
2055
2056static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2057{
2058 unsigned int wakeup_irq;
2059
2060 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2061 host->plat->sdiowakeup_irq :
2062 host->core_irqres->start;
2063
2064 if (host->irq_wake_enabled) {
2065 disable_irq_wake(wakeup_irq);
2066 host->irq_wake_enabled = false;
2067 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302068}
2069
San Mehat9d2bd732009-09-22 16:44:22 -07002070static void
2071msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2072{
2073 struct msmsdcc_host *host = mmc_priv(mmc);
2074 u32 clk = 0, pwr = 0;
2075 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002076 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002077 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002078
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002079 DBG(host, "ios->clock = %u\n", ios->clock);
Sahitya Tummala7a892482011-01-18 11:22:49 +05302080
San Mehat9d2bd732009-09-22 16:44:22 -07002081 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002082 spin_lock_irqsave(&host->lock, flags);
2083 if (!host->clks_on) {
2084 msmsdcc_setup_clocks(host, true);
2085 host->clks_on = 1;
2086 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2087 if (!host->plat->sdiowakeup_irq) {
2088 writel_relaxed(host->mci_irqenable,
2089 host->base + MMCIMASK0);
2090 mb();
2091 if (host->plat->cfg_mpm_sdiowakeup &&
2092 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2093 host->plat->cfg_mpm_sdiowakeup(
2094 mmc_dev(mmc), SDC_DAT1_DISWAKE);
2095 msmsdcc_disable_irq_wake(host);
2096 } else if (!(mmc->pm_flags &
2097 MMC_PM_WAKE_SDIO_IRQ)) {
2098 writel_relaxed(host->mci_irqenable,
2099 host->base + MMCIMASK0);
2100 }
2101 }
San Mehat9d2bd732009-09-22 16:44:22 -07002102 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002103 spin_unlock_irqrestore(&host->lock, flags);
2104
2105 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2106 /*
2107 * For DDR50 mode, controller needs clock rate to be
2108 * double than what is required on the SD card CLK pin.
2109 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302110 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002111 /*
2112 * Make sure that we don't double the clock if
2113 * doubled clock rate is already set
2114 */
2115 if (!host->ddr_doubled_clk_rate ||
2116 (host->ddr_doubled_clk_rate &&
2117 (host->ddr_doubled_clk_rate != ios->clock))) {
2118 host->ddr_doubled_clk_rate =
2119 msmsdcc_get_sup_clk_rate(
2120 host, (ios->clock * 2));
2121 clock = host->ddr_doubled_clk_rate;
2122 }
2123 } else {
2124 host->ddr_doubled_clk_rate = 0;
2125 }
2126
2127 if (clock != host->clk_rate) {
2128 rc = clk_set_rate(host->clk, clock);
2129 if (rc < 0)
2130 pr_debug("%s: failed to set clk rate %u\n",
2131 mmc_hostname(mmc), clock);
2132 host->clk_rate = clock;
2133 }
2134 /*
2135 * give atleast 2 MCLK cycles delay for clocks
2136 * and SDCC core to stabilize
2137 */
2138 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002139 clk |= MCI_CLK_ENABLE;
2140 }
2141
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002142 if (ios->bus_width == MMC_BUS_WIDTH_8)
2143 clk |= MCI_CLK_WIDEBUS_8;
2144 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2145 clk |= MCI_CLK_WIDEBUS_4;
2146 else
2147 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002148
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002149 if (msmsdcc_is_pwrsave(host))
2150 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002151
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002152 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002153
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002154 host->tuning_needed = 0;
2155 /*
2156 * Select the controller timing mode according
2157 * to current bus speed mode
2158 */
2159 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2160 (ios->timing == MMC_TIMING_UHS_SDR50)) {
2161 clk |= (4 << 14);
2162 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302163 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002164 clk |= (3 << 14);
2165 } else {
2166 clk |= (2 << 14); /* feedback clock */
2167 }
2168
2169 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2170 clk |= (2 << 23);
2171
2172 if (host->io_pad_pwr_switch)
2173 clk |= IO_PAD_PWR_SWITCH;
2174
2175 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
San Mehat9d2bd732009-09-22 16:44:22 -07002176 pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002177 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2178 pwr |= msmsdcc_setup_vreg(host, !!ios->vdd);
San Mehat9d2bd732009-09-22 16:44:22 -07002179
2180 switch (ios->power_mode) {
2181 case MMC_POWER_OFF:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002182 htc_pwrsink_set(PWRSINK_SDCARD, 0);
2183 if (!host->sdcc_irq_disabled) {
2184 if (host->plat->cfg_mpm_sdiowakeup)
2185 host->plat->cfg_mpm_sdiowakeup(
2186 mmc_dev(mmc), SDC_DAT1_DISABLE);
2187 disable_irq(host->core_irqres->start);
2188 host->sdcc_irq_disabled = 1;
2189 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302190 /*
2191 * As VDD pad rail is always on, set low voltage for VDD
2192 * pad rail when slot is unused (when card is not present
2193 * or during system suspend).
2194 */
2195 msmsdcc_set_vddp_low_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002196 msmsdcc_setup_pins(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002197 break;
2198 case MMC_POWER_UP:
2199 pwr |= MCI_PWR_UP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002200 if (host->sdcc_irq_disabled) {
2201 if (host->plat->cfg_mpm_sdiowakeup)
2202 host->plat->cfg_mpm_sdiowakeup(
2203 mmc_dev(mmc), SDC_DAT1_ENABLE);
2204 enable_irq(host->core_irqres->start);
2205 host->sdcc_irq_disabled = 0;
2206 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302207 msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002208 msmsdcc_setup_pins(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07002209 break;
2210 case MMC_POWER_ON:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002211 htc_pwrsink_set(PWRSINK_SDCARD, 100);
San Mehat9d2bd732009-09-22 16:44:22 -07002212 pwr |= MCI_PWR_ON;
2213 break;
2214 }
2215
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002216 spin_lock_irqsave(&host->lock, flags);
2217 if (!host->clks_on) {
2218 /* force the clocks to be on */
2219 msmsdcc_setup_clocks(host, true);
2220 /*
2221 * give atleast 2 MCLK cycles delay for clocks
2222 * and SDCC core to stabilize
2223 */
2224 msmsdcc_delay(host);
2225 }
2226 writel_relaxed(clk, host->base + MMCICLOCK);
2227 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002228
2229 if (host->pwr != pwr) {
2230 host->pwr = pwr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002231 writel_relaxed(pwr, host->base + MMCIPOWER);
2232 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07002233 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002234 if (!host->clks_on) {
2235 /* force the clocks to be off */
2236 msmsdcc_setup_clocks(host, false);
2237 /*
2238 * give atleast 2 MCLK cycles delay for clocks
2239 * and SDCC core to stabilize
2240 */
2241 msmsdcc_delay(host);
2242 }
2243
2244 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
2245 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2246 if (!host->plat->sdiowakeup_irq) {
2247 writel_relaxed(MCI_SDIOINTMASK,
2248 host->base + MMCIMASK0);
2249 mb();
2250 if (host->plat->cfg_mpm_sdiowakeup &&
2251 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2252 host->plat->cfg_mpm_sdiowakeup(
2253 mmc_dev(mmc), SDC_DAT1_ENWAKE);
2254 msmsdcc_enable_irq_wake(host);
2255 } else if (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2256 writel_relaxed(0, host->base + MMCIMASK0);
2257 } else {
2258 writel_relaxed(MCI_SDIOINTMASK,
2259 host->base + MMCIMASK0);
2260 }
2261 msmsdcc_delay(host);
2262 }
2263 msmsdcc_setup_clocks(host, false);
2264 host->clks_on = 0;
2265 }
San Mehat4adbbcc2009-11-08 13:00:37 -08002266 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002267}
2268
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002269int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2270{
2271 struct msmsdcc_host *host = mmc_priv(mmc);
2272 u32 clk;
2273
2274 clk = readl_relaxed(host->base + MMCICLOCK);
2275 pr_debug("Changing to pwr_save=%d", pwrsave);
2276 if (pwrsave && msmsdcc_is_pwrsave(host))
2277 clk |= MCI_CLK_PWRSAVE;
2278 else
2279 clk &= ~MCI_CLK_PWRSAVE;
2280 writel_relaxed(clk, host->base + MMCICLOCK);
2281 mb();
2282
2283 return 0;
2284}
2285
2286static int msmsdcc_get_ro(struct mmc_host *mmc)
2287{
2288 int status = -ENOSYS;
2289 struct msmsdcc_host *host = mmc_priv(mmc);
2290
2291 if (host->plat->wpswitch) {
2292 status = host->plat->wpswitch(mmc_dev(mmc));
2293 } else if (host->plat->wpswitch_gpio) {
2294 status = gpio_request(host->plat->wpswitch_gpio,
2295 "SD_WP_Switch");
2296 if (status) {
2297 pr_err("%s: %s: Failed to request GPIO %d\n",
2298 mmc_hostname(mmc), __func__,
2299 host->plat->wpswitch_gpio);
2300 } else {
2301 status = gpio_direction_input(
2302 host->plat->wpswitch_gpio);
2303 if (!status) {
2304 /*
2305 * Wait for atleast 300ms as debounce
2306 * time for GPIO input to stabilize.
2307 */
2308 msleep(300);
2309 status = gpio_get_value_cansleep(
2310 host->plat->wpswitch_gpio);
2311 status ^= !host->plat->wpswitch_polarity;
2312 }
2313 gpio_free(host->plat->wpswitch_gpio);
2314 }
2315 }
2316
2317 if (status < 0)
2318 status = -ENOSYS;
2319 pr_debug("%s: Card read-only status %d\n", __func__, status);
2320
2321 return status;
2322}
2323
2324#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002325static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2326{
2327 struct msmsdcc_host *host = mmc_priv(mmc);
2328 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002329
2330 if (enable) {
2331 spin_lock_irqsave(&host->lock, flags);
2332 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
2333 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
2334 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2335 spin_unlock_irqrestore(&host->lock, flags);
2336 } else {
2337 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
2338 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
2339 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2340 }
2341 mb();
2342}
2343#endif /* CONFIG_MMC_MSM_SDIO_SUPPORT */
2344
2345#ifdef CONFIG_PM_RUNTIME
2346static int msmsdcc_enable(struct mmc_host *mmc)
2347{
Sahitya Tummala8605fca2011-08-22 15:39:19 +05302348 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002349 struct device *dev = mmc->parent;
2350
Sahitya Tummala8605fca2011-08-22 15:39:19 +05302351 if (pm_runtime_suspended(dev))
2352 rc = pm_runtime_get_sync(dev);
2353 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002354 pm_runtime_get_noresume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002355
Sahitya Tummala8605fca2011-08-22 15:39:19 +05302356 if (rc < 0)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002357 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2358 __func__, rc);
Sahitya Tummala8605fca2011-08-22 15:39:19 +05302359 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002360}
2361
2362static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2363{
2364 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302365 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002366
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302367 if (host->plat->disable_runtime_pm)
2368 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002369 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO)
2370 return -ENOTSUPP;
2371
2372 rc = pm_runtime_put_sync(mmc->parent);
2373
2374 if (rc < 0)
2375 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2376 __func__, rc);
2377 return rc;
2378}
2379#else
2380#define msmsdcc_enable NULL
2381#define msmsdcc_disable NULL
2382#endif
2383
2384static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2385 struct mmc_ios *ios)
2386{
2387 struct msmsdcc_host *host = mmc_priv(mmc);
2388 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302389 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002390
2391 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2392 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302393 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002394 goto out;
2395 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2396 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302397 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002398 goto out;
2399 }
San Mehat9d2bd732009-09-22 16:44:22 -07002400
2401 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002402 /*
2403 * If we are here means voltage switch from high voltage to
2404 * low voltage is required
2405 */
2406
2407 /*
2408 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2409 * register until they become all zeros.
2410 */
2411 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302412 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002413 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2414 mmc_hostname(mmc), __func__);
2415 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002416 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002417
2418 /* Stop SD CLK output. */
2419 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2420 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2421
San Mehat9d2bd732009-09-22 16:44:22 -07002422 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002423
2424 /*
2425 * Switch VDDPX from high voltage to low voltage
2426 * to change the VDD of the SD IO pads.
2427 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302428 rc = msmsdcc_set_vddp_low_vol(host);
2429 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002430 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002431
2432 spin_lock_irqsave(&host->lock, flags);
2433 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2434 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
2435 host->io_pad_pwr_switch = 1;
2436 spin_unlock_irqrestore(&host->lock, flags);
2437
2438 /* Wait 5 ms for the voltage regulater in the card to become stable. */
2439 usleep_range(5000, 5500);
2440
2441 spin_lock_irqsave(&host->lock, flags);
2442 /* Start SD CLK output. */
2443 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2444 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2445 spin_unlock_irqrestore(&host->lock, flags);
2446
2447 /*
2448 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
2449 * don't become all ones within 1 ms then a Voltage Switch
2450 * sequence has failed and a power cycle to the card is required.
2451 * Otherwise Voltage Switch sequence is completed successfully.
2452 */
2453 usleep_range(1000, 1500);
2454
2455 spin_lock_irqsave(&host->lock, flags);
2456 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
2457 != (0xF << 1)) {
2458 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
2459 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302460 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002461 goto out_unlock;
2462 }
2463
2464out_unlock:
2465 spin_unlock_irqrestore(&host->lock, flags);
2466out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302467 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002468}
2469
2470static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2471 u8 phase);
2472/* Initialize the DLL (Programmable Delay Line ) */
2473static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
2474{
2475 int rc = 0;
2476 u32 wait_timeout;
2477
2478 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
2479 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2480 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2481
2482 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
2483 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2484 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2485
2486 msmsdcc_delay(host);
2487
2488 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
2489 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2490 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2491
2492 /* Initialize the phase to 0 */
2493 rc = msmsdcc_config_cm_sdc4_dll_phase(host, 0);
2494 if (rc)
2495 goto out;
2496
2497 wait_timeout = 1000;
2498 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
2499 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
2500 /* max. wait for 1 sec for LOCK bit to be set */
2501 if (--wait_timeout == 0) {
2502 pr_err("%s: %s: DLL failed to lock at phase: %d",
2503 mmc_hostname(host->mmc), __func__, 0);
2504 rc = -1;
2505 goto out;
2506 }
2507 /* wait for 1ms */
2508 usleep_range(1000, 1500);
2509 }
2510out:
2511 return rc;
2512}
2513
2514/*
2515 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
2516 * calibration sequence. This function should be called before
2517 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
2518 * commands (CMD17/CMD18).
2519 */
2520static void msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
2521{
2522 /* Set CDR_EN bit to 1. */
2523 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) |
2524 MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2525
2526 /* Set CDR_EXT_EN bit to 0. */
2527 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2528 & ~MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2529
2530 /* Set CK_OUT_EN bit to 0. */
2531 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2532 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2533
2534 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2535 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)
2536 ;
2537
2538 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2539 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2540 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2541
2542 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register is 1. */
2543 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN))
2544 ;
2545}
2546
2547static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2548 u8 phase)
2549{
2550 int rc = 0;
2551 u32 mclk_freq = 0;
2552 u32 wait_timeout;
2553
2554 /* Set CDR_EN bit to 0. */
2555 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2556 & ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2557
2558 /* Set CDR_EXT_EN bit to 1. */
2559 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2560 | MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2561
2562 /* Program the MCLK value to MCLK_FREQ bit field */
2563 if (host->clk_rate <= 112000000)
2564 mclk_freq = 0;
2565 else if (host->clk_rate <= 125000000)
2566 mclk_freq = 1;
2567 else if (host->clk_rate <= 137000000)
2568 mclk_freq = 2;
2569 else if (host->clk_rate <= 150000000)
2570 mclk_freq = 3;
2571 else if (host->clk_rate <= 162000000)
2572 mclk_freq = 4;
2573 else if (host->clk_rate <= 175000000)
2574 mclk_freq = 5;
2575 else if (host->clk_rate <= 187000000)
2576 mclk_freq = 6;
2577 else if (host->clk_rate <= 200000000)
2578 mclk_freq = 7;
2579
2580 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2581 & ~(7 << 24)) | (mclk_freq << 24)),
2582 host->base + MCI_DLL_CONFIG);
2583
2584 /* Set CK_OUT_EN bit to 0. */
2585 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2586 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2587
2588 /* Set DLL_EN bit to 1. */
2589 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2590 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
2591
2592 wait_timeout = 1000;
2593 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2594 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN) {
2595 /* max. wait for 1 sec for LOCK bit for be set */
2596 if (--wait_timeout == 0) {
2597 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 0",
2598 mmc_hostname(host->mmc), __func__, phase);
2599 rc = -1;
2600 goto out;
2601 }
2602 /* wait for 1ms */
2603 usleep_range(1000, 1500);
2604 }
2605
2606 /*
2607 * Write the selected DLL clock output phase (0 ... 15)
2608 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
2609 */
2610 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2611 & ~(0xF << 20)) | (phase << 20)),
2612 host->base + MCI_DLL_CONFIG);
2613
2614 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2615 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2616 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2617
2618 wait_timeout = 1000;
2619 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
2620 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)) {
2621 /* max. wait for 1 sec for LOCK bit for be set */
2622 if (--wait_timeout == 0) {
2623 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 1",
2624 mmc_hostname(host->mmc), __func__, phase);
2625 rc = -1;
2626 goto out;
2627 }
2628 /* wait for 1ms */
2629 usleep_range(1000, 1500);
2630 }
2631out:
2632 return rc;
2633}
2634
2635static int msmsdcc_execute_tuning(struct mmc_host *mmc)
2636{
2637 struct msmsdcc_host *host = mmc_priv(mmc);
2638 u8 phase;
2639 u8 *data_buf;
2640 u8 tuned_phases[16], tuned_phase_cnt = 0;
2641 int rc = 0;
2642
2643 /* Tuning is only required for SDR50 & SDR104 modes */
2644 if (!host->tuning_needed) {
2645 rc = 0;
2646 goto out;
2647 }
2648
2649 host->cmd19_tuning_in_progress = 1;
2650 /*
2651 * Make sure that clock is always enabled when DLL
2652 * tuning is in progress. Keeping PWRSAVE ON may
2653 * turn off the clock. So let's disable the PWRSAVE
2654 * here and re-enable it once tuning is completed.
2655 */
2656 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2657 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2658 /* first of all reset the tuning block */
2659 rc = msmsdcc_init_cm_sdc4_dll(host);
2660 if (rc)
2661 goto out;
2662
2663 data_buf = kmalloc(64, GFP_KERNEL);
2664 if (!data_buf) {
2665 rc = -ENOMEM;
2666 goto out;
2667 }
2668
2669 phase = 0;
2670 do {
2671 struct mmc_command cmd = {0};
2672 struct mmc_data data = {0};
2673 struct mmc_request mrq = {
2674 .cmd = &cmd,
2675 .data = &data
2676 };
2677 struct scatterlist sg;
2678
2679 /* set the phase in delay line hw block */
2680 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2681 if (rc)
2682 goto kfree;
2683
2684 cmd.opcode = MMC_SEND_TUNING_BLOCK;
2685 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
2686
2687 data.blksz = 64;
2688 data.blocks = 1;
2689 data.flags = MMC_DATA_READ;
2690 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
2691
2692 data.sg = &sg;
2693 data.sg_len = 1;
2694 sg_init_one(&sg, data_buf, 64);
2695 memset(data_buf, 0, 64);
2696 mmc_wait_for_req(mmc, &mrq);
2697
2698 if (!cmd.error && !data.error &&
2699 !memcmp(data_buf, cmd19_tuning_block, 64)) {
2700 /* tuning is successful with this tuning point */
2701 tuned_phases[tuned_phase_cnt++] = phase;
2702 }
2703 } while (++phase < 16);
2704
2705 kfree(data_buf);
2706
2707 if (tuned_phase_cnt) {
2708 tuned_phase_cnt--;
2709 tuned_phase_cnt = (tuned_phase_cnt * 3) / 4;
2710 phase = tuned_phases[tuned_phase_cnt];
2711 /*
2712 * Finally set the selected phase in delay
2713 * line hw block.
2714 */
2715 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2716 if (rc)
2717 goto out;
2718 } else {
2719 /* tuning failed */
2720 rc = -EAGAIN;
2721 pr_err("%s: %s: no tuning point found",
2722 mmc_hostname(mmc), __func__);
2723 }
2724 goto out;
2725
2726kfree:
2727 kfree(data_buf);
2728out:
2729 /* re-enable PWESAVE */
2730 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2731 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2732 host->cmd19_tuning_in_progress = 0;
2733 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07002734}
2735
2736static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002737 .enable = msmsdcc_enable,
2738 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07002739 .request = msmsdcc_request,
2740 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002741 .get_ro = msmsdcc_get_ro,
2742#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002743 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002744#endif
2745 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
2746 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07002747};
2748
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002749static unsigned int
2750msmsdcc_slot_status(struct msmsdcc_host *host)
2751{
2752 int status;
2753 unsigned int gpio_no = host->plat->status_gpio;
2754
2755 status = gpio_request(gpio_no, "SD_HW_Detect");
2756 if (status) {
2757 pr_err("%s: %s: Failed to request GPIO %d\n",
2758 mmc_hostname(host->mmc), __func__, gpio_no);
2759 } else {
2760 status = gpio_direction_input(gpio_no);
2761 if (!status)
2762 status = !gpio_get_value_cansleep(gpio_no);
2763 gpio_free(gpio_no);
2764 }
2765 return status;
2766}
2767
San Mehat9d2bd732009-09-22 16:44:22 -07002768static void
2769msmsdcc_check_status(unsigned long data)
2770{
2771 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
2772 unsigned int status;
2773
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002774 if (host->plat->status || host->plat->status_gpio) {
2775 if (host->plat->status)
2776 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07002777 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002778 status = msmsdcc_slot_status(host);
2779
2780 host->eject = !status;
2781 if (status ^ host->oldstat) {
2782 pr_info("%s: Slot status change detected (%d -> %d)\n",
2783 mmc_hostname(host->mmc), host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07002784 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002785 }
2786 host->oldstat = status;
2787 } else {
2788 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07002789 }
San Mehat9d2bd732009-09-22 16:44:22 -07002790}
2791
2792static irqreturn_t
2793msmsdcc_platform_status_irq(int irq, void *dev_id)
2794{
2795 struct msmsdcc_host *host = dev_id;
2796
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002797 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07002798 msmsdcc_check_status((unsigned long) host);
2799 return IRQ_HANDLED;
2800}
2801
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002802static irqreturn_t
2803msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
2804{
2805 struct msmsdcc_host *host = dev_id;
2806
2807 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
2808 spin_lock(&host->lock);
2809 if (!host->sdio_irq_disabled) {
2810 disable_irq_nosync(irq);
2811 if (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2812 wake_lock(&host->sdio_wlock);
2813 msmsdcc_disable_irq_wake(host);
2814 }
2815 host->sdio_irq_disabled = 1;
2816 }
2817 if (host->plat->is_sdio_al_client) {
2818 if (!host->clks_on) {
2819 msmsdcc_setup_clocks(host, true);
2820 host->clks_on = 1;
2821 }
2822 if (host->sdcc_irq_disabled) {
2823 writel_relaxed(host->mci_irqenable,
2824 host->base + MMCIMASK0);
2825 mb();
2826 enable_irq(host->core_irqres->start);
2827 host->sdcc_irq_disabled = 0;
2828 }
2829 wake_lock(&host->sdio_wlock);
2830 }
2831 spin_unlock(&host->lock);
2832
2833 return IRQ_HANDLED;
2834}
2835
San Mehat9d2bd732009-09-22 16:44:22 -07002836static void
2837msmsdcc_status_notify_cb(int card_present, void *dev_id)
2838{
2839 struct msmsdcc_host *host = dev_id;
2840
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002841 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07002842 card_present);
2843 msmsdcc_check_status((unsigned long) host);
2844}
2845
San Mehat9d2bd732009-09-22 16:44:22 -07002846static int
2847msmsdcc_init_dma(struct msmsdcc_host *host)
2848{
2849 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
2850 host->dma.host = host;
2851 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07002852 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07002853
2854 if (!host->dmares)
2855 return -ENODEV;
2856
2857 host->dma.nc = dma_alloc_coherent(NULL,
2858 sizeof(struct msmsdcc_nc_dmadata),
2859 &host->dma.nc_busaddr,
2860 GFP_KERNEL);
2861 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07002862 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07002863 return -ENOMEM;
2864 }
2865 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
2866 host->dma.cmd_busaddr = host->dma.nc_busaddr;
2867 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
2868 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
2869 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07002870 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07002871
2872 return 0;
2873}
2874
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002875#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
2876/**
2877 * Allocate and Connect a SDCC peripheral's SPS endpoint
2878 *
2879 * This function allocates endpoint context and
2880 * connect it with memory endpoint by calling
2881 * appropriate SPS driver APIs.
2882 *
2883 * Also registers a SPS callback function with
2884 * SPS driver
2885 *
2886 * This function should only be called once typically
2887 * during driver probe.
2888 *
2889 * @host - Pointer to sdcc host structure
2890 * @ep - Pointer to sps endpoint data structure
2891 * @is_produce - 1 means Producer endpoint
2892 * 0 means Consumer endpoint
2893 *
2894 * @return - 0 if successful else negative value.
2895 *
2896 */
2897static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
2898 struct msmsdcc_sps_ep_conn_data *ep,
2899 bool is_producer)
2900{
2901 int rc = 0;
2902 struct sps_pipe *sps_pipe_handle;
2903 struct sps_connect *sps_config = &ep->config;
2904 struct sps_register_event *sps_event = &ep->event;
2905
2906 /* Allocate endpoint context */
2907 sps_pipe_handle = sps_alloc_endpoint();
2908 if (!sps_pipe_handle) {
2909 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
2910 mmc_hostname(host->mmc), is_producer);
2911 rc = -ENOMEM;
2912 goto out;
2913 }
2914
2915 /* Get default connection configuration for an endpoint */
2916 rc = sps_get_config(sps_pipe_handle, sps_config);
2917 if (rc) {
2918 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
2919 " rc=%d", mmc_hostname(host->mmc),
2920 (u32)sps_pipe_handle, rc);
2921 goto get_config_err;
2922 }
2923
2924 /* Modify the default connection configuration */
2925 if (is_producer) {
2926 /*
2927 * For SDCC producer transfer, source should be
2928 * SDCC peripheral where as destination should
2929 * be system memory.
2930 */
2931 sps_config->source = host->sps.bam_handle;
2932 sps_config->destination = SPS_DEV_HANDLE_MEM;
2933 /* Producer pipe will handle this connection */
2934 sps_config->mode = SPS_MODE_SRC;
2935 sps_config->options =
2936 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
2937 } else {
2938 /*
2939 * For SDCC consumer transfer, source should be
2940 * system memory where as destination should
2941 * SDCC peripheral
2942 */
2943 sps_config->source = SPS_DEV_HANDLE_MEM;
2944 sps_config->destination = host->sps.bam_handle;
2945 sps_config->mode = SPS_MODE_DEST;
2946 sps_config->options =
2947 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
2948 }
2949
2950 /* Producer pipe index */
2951 sps_config->src_pipe_index = host->sps.src_pipe_index;
2952 /* Consumer pipe index */
2953 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
2954 /*
2955 * This event thresold value is only significant for BAM-to-BAM
2956 * transfer. It's ignored for BAM-to-System mode transfer.
2957 */
2958 sps_config->event_thresh = 0x10;
2959 /*
2960 * Max. no of scatter/gather buffers that can
2961 * be passed by block layer = 32 (NR_SG).
2962 * Each BAM descritor needs 64 bits (8 bytes).
2963 * One BAM descriptor is required per buffer transfer.
2964 * So we would require total 256 (32 * 8) bytes of descriptor FIFO.
2965 * But due to HW limitation we need to allocate atleast one extra
2966 * descriptor memory (256 bytes + 8 bytes). But in order to be
2967 * in power of 2, we are allocating 512 bytes of memory.
2968 */
2969 sps_config->desc.size = 512;
2970 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
2971 sps_config->desc.size,
2972 &sps_config->desc.phys_base,
2973 GFP_KERNEL);
2974
2975 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
2976
2977 /* Establish connection between peripheral and memory endpoint */
2978 rc = sps_connect(sps_pipe_handle, sps_config);
2979 if (rc) {
2980 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
2981 " rc=%d", mmc_hostname(host->mmc),
2982 (u32)sps_pipe_handle, rc);
2983 goto sps_connect_err;
2984 }
2985
2986 sps_event->mode = SPS_TRIGGER_CALLBACK;
2987 sps_event->options = SPS_O_EOT;
2988 sps_event->callback = msmsdcc_sps_complete_cb;
2989 sps_event->xfer_done = NULL;
2990 sps_event->user = (void *)host;
2991
2992 /* Register callback event for EOT (End of transfer) event. */
2993 rc = sps_register_event(sps_pipe_handle, sps_event);
2994 if (rc) {
2995 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
2996 " rc=%d", mmc_hostname(host->mmc),
2997 (u32)sps_pipe_handle, rc);
2998 goto reg_event_err;
2999 }
3000 /* Now save the sps pipe handle */
3001 ep->pipe_handle = sps_pipe_handle;
3002 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3003 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3004 __func__, is_producer ? "READ" : "WRITE",
3005 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3006 goto out;
3007
3008reg_event_err:
3009 sps_disconnect(sps_pipe_handle);
3010sps_connect_err:
3011 dma_free_coherent(mmc_dev(host->mmc),
3012 sps_config->desc.size,
3013 sps_config->desc.base,
3014 sps_config->desc.phys_base);
3015get_config_err:
3016 sps_free_endpoint(sps_pipe_handle);
3017out:
3018 return rc;
3019}
3020
3021/**
3022 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3023 *
3024 * This function disconnect endpoint and deallocates
3025 * endpoint context.
3026 *
3027 * This function should only be called once typically
3028 * during driver remove.
3029 *
3030 * @host - Pointer to sdcc host structure
3031 * @ep - Pointer to sps endpoint data structure
3032 *
3033 */
3034static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3035 struct msmsdcc_sps_ep_conn_data *ep)
3036{
3037 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3038 struct sps_connect *sps_config = &ep->config;
3039 struct sps_register_event *sps_event = &ep->event;
3040
3041 sps_event->xfer_done = NULL;
3042 sps_event->callback = NULL;
3043 sps_register_event(sps_pipe_handle, sps_event);
3044 sps_disconnect(sps_pipe_handle);
3045 dma_free_coherent(mmc_dev(host->mmc),
3046 sps_config->desc.size,
3047 sps_config->desc.base,
3048 sps_config->desc.phys_base);
3049 sps_free_endpoint(sps_pipe_handle);
3050}
3051
3052/**
3053 * Reset SDCC peripheral's SPS endpoint
3054 *
3055 * This function disconnects an endpoint.
3056 *
3057 * This function should be called for reseting
3058 * SPS endpoint when data transfer error is
3059 * encountered during data transfer. This
3060 * can be considered as soft reset to endpoint.
3061 *
3062 * This function should only be called if
3063 * msmsdcc_sps_init() is already called.
3064 *
3065 * @host - Pointer to sdcc host structure
3066 * @ep - Pointer to sps endpoint data structure
3067 *
3068 * @return - 0 if successful else negative value.
3069 */
3070static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3071 struct msmsdcc_sps_ep_conn_data *ep)
3072{
3073 int rc = 0;
3074 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3075
3076 rc = sps_disconnect(sps_pipe_handle);
3077 if (rc) {
3078 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3079 " rc=%d", mmc_hostname(host->mmc), __func__,
3080 (u32)sps_pipe_handle, rc);
3081 goto out;
3082 }
3083 out:
3084 return rc;
3085}
3086
3087/**
3088 * Restore SDCC peripheral's SPS endpoint
3089 *
3090 * This function connects an endpoint.
3091 *
3092 * This function should be called for restoring
3093 * SPS endpoint after data transfer error is
3094 * encountered during data transfer. This
3095 * can be considered as soft reset to endpoint.
3096 *
3097 * This function should only be called if
3098 * msmsdcc_sps_reset_ep() is called before.
3099 *
3100 * @host - Pointer to sdcc host structure
3101 * @ep - Pointer to sps endpoint data structure
3102 *
3103 * @return - 0 if successful else negative value.
3104 */
3105static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3106 struct msmsdcc_sps_ep_conn_data *ep)
3107{
3108 int rc = 0;
3109 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3110 struct sps_connect *sps_config = &ep->config;
3111 struct sps_register_event *sps_event = &ep->event;
3112
3113 /* Establish connection between peripheral and memory endpoint */
3114 rc = sps_connect(sps_pipe_handle, sps_config);
3115 if (rc) {
3116 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3117 " rc=%d", mmc_hostname(host->mmc), __func__,
3118 (u32)sps_pipe_handle, rc);
3119 goto out;
3120 }
3121
3122 /* Register callback event for EOT (End of transfer) event. */
3123 rc = sps_register_event(sps_pipe_handle, sps_event);
3124 if (rc) {
3125 pr_err("%s: %s: sps_register_event() failed!!!"
3126 " pipe_handle=0x%x, rc=%d",
3127 mmc_hostname(host->mmc), __func__,
3128 (u32)sps_pipe_handle, rc);
3129 goto reg_event_err;
3130 }
3131 goto out;
3132
3133reg_event_err:
3134 sps_disconnect(sps_pipe_handle);
3135out:
3136 return rc;
3137}
3138
3139/**
3140 * Initialize SPS HW connected with SDCC core
3141 *
3142 * This function register BAM HW resources with
3143 * SPS driver and then initialize 2 SPS endpoints
3144 *
3145 * This function should only be called once typically
3146 * during driver probe.
3147 *
3148 * @host - Pointer to sdcc host structure
3149 *
3150 * @return - 0 if successful else negative value.
3151 *
3152 */
3153static int msmsdcc_sps_init(struct msmsdcc_host *host)
3154{
3155 int rc = 0;
3156 struct sps_bam_props bam = {0};
3157
3158 host->bam_base = ioremap(host->bam_memres->start,
3159 resource_size(host->bam_memres));
3160 if (!host->bam_base) {
3161 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3162 " size=0x%x", mmc_hostname(host->mmc),
3163 host->bam_memres->start,
3164 (host->bam_memres->end -
3165 host->bam_memres->start));
3166 rc = -ENOMEM;
3167 goto out;
3168 }
3169
3170 bam.phys_addr = host->bam_memres->start;
3171 bam.virt_addr = host->bam_base;
3172 /*
3173 * This event thresold value is only significant for BAM-to-BAM
3174 * transfer. It's ignored for BAM-to-System mode transfer.
3175 */
3176 bam.event_threshold = 0x10; /* Pipe event threshold */
3177 /*
3178 * This threshold controls when the BAM publish
3179 * the descriptor size on the sideband interface.
3180 * SPS HW will only be used when
3181 * data transfer size > MCI_FIFOSIZE (64 bytes).
3182 * PIO mode will be used when
3183 * data transfer size < MCI_FIFOSIZE (64 bytes).
3184 * So set this thresold value to 64 bytes.
3185 */
3186 bam.summing_threshold = 64;
3187 /* SPS driver wll handle the SDCC BAM IRQ */
3188 bam.irq = (u32)host->bam_irqres->start;
3189 bam.manage = SPS_BAM_MGR_LOCAL;
3190
3191 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3192 (u32)bam.phys_addr);
3193 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3194 (u32)bam.virt_addr);
3195
3196 /* Register SDCC Peripheral BAM device to SPS driver */
3197 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3198 if (rc) {
3199 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3200 mmc_hostname(host->mmc), rc);
3201 goto reg_bam_err;
3202 }
3203 pr_info("%s: BAM device registered. bam_handle=0x%x",
3204 mmc_hostname(host->mmc), host->sps.bam_handle);
3205
3206 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3207 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3208
3209 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3210 SPS_PROD_PERIPHERAL);
3211 if (rc)
3212 goto sps_reset_err;
3213 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3214 SPS_CONS_PERIPHERAL);
3215 if (rc)
3216 goto cons_conn_err;
3217
3218 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3219 mmc_hostname(host->mmc),
3220 (unsigned long long)host->bam_memres->start,
3221 (unsigned int)host->bam_irqres->start);
3222 goto out;
3223
3224cons_conn_err:
3225 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3226sps_reset_err:
3227 sps_deregister_bam_device(host->sps.bam_handle);
3228reg_bam_err:
3229 iounmap(host->bam_base);
3230out:
3231 return rc;
3232}
3233
3234/**
3235 * De-initialize SPS HW connected with SDCC core
3236 *
3237 * This function deinitialize SPS endpoints and then
3238 * deregisters BAM resources from SPS driver.
3239 *
3240 * This function should only be called once typically
3241 * during driver remove.
3242 *
3243 * @host - Pointer to sdcc host structure
3244 *
3245 */
3246static void msmsdcc_sps_exit(struct msmsdcc_host *host)
3247{
3248 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
3249 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3250 sps_deregister_bam_device(host->sps.bam_handle);
3251 iounmap(host->bam_base);
3252}
3253#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
3254
3255static ssize_t
3256show_polling(struct device *dev, struct device_attribute *attr, char *buf)
3257{
3258 struct mmc_host *mmc = dev_get_drvdata(dev);
3259 struct msmsdcc_host *host = mmc_priv(mmc);
3260 int poll;
3261 unsigned long flags;
3262
3263 spin_lock_irqsave(&host->lock, flags);
3264 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
3265 spin_unlock_irqrestore(&host->lock, flags);
3266
3267 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
3268}
3269
3270static ssize_t
3271set_polling(struct device *dev, struct device_attribute *attr,
3272 const char *buf, size_t count)
3273{
3274 struct mmc_host *mmc = dev_get_drvdata(dev);
3275 struct msmsdcc_host *host = mmc_priv(mmc);
3276 int value;
3277 unsigned long flags;
3278
3279 sscanf(buf, "%d", &value);
3280
3281 spin_lock_irqsave(&host->lock, flags);
3282 if (value) {
3283 mmc->caps |= MMC_CAP_NEEDS_POLL;
3284 mmc_detect_change(host->mmc, 0);
3285 } else {
3286 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3287 }
3288#ifdef CONFIG_HAS_EARLYSUSPEND
3289 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
3290#endif
3291 spin_unlock_irqrestore(&host->lock, flags);
3292 return count;
3293}
3294
3295static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
3296 show_polling, set_polling);
3297static struct attribute *dev_attrs[] = {
3298 &dev_attr_polling.attr,
3299 NULL,
3300};
3301static struct attribute_group dev_attr_grp = {
3302 .attrs = dev_attrs,
3303};
3304
3305#ifdef CONFIG_HAS_EARLYSUSPEND
3306static void msmsdcc_early_suspend(struct early_suspend *h)
3307{
3308 struct msmsdcc_host *host =
3309 container_of(h, struct msmsdcc_host, early_suspend);
3310 unsigned long flags;
3311
3312 spin_lock_irqsave(&host->lock, flags);
3313 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
3314 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3315 spin_unlock_irqrestore(&host->lock, flags);
3316};
3317static void msmsdcc_late_resume(struct early_suspend *h)
3318{
3319 struct msmsdcc_host *host =
3320 container_of(h, struct msmsdcc_host, early_suspend);
3321 unsigned long flags;
3322
3323 if (host->polling_enabled) {
3324 spin_lock_irqsave(&host->lock, flags);
3325 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
3326 mmc_detect_change(host->mmc, 0);
3327 spin_unlock_irqrestore(&host->lock, flags);
3328 }
3329};
3330#endif
3331
3332static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
3333{
3334 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3335 struct mmc_request *mrq;
3336 unsigned long flags;
3337
3338 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003339 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003340 pr_info("%s: %s: dummy CMD52 timeout\n",
3341 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003342 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003343 }
3344
3345 mrq = host->curr.mrq;
3346
3347 if (mrq && mrq->cmd) {
3348 pr_info("%s: %s CMD%d\n", mmc_hostname(host->mmc),
3349 __func__, mrq->cmd->opcode);
3350 if (!mrq->cmd->error)
3351 mrq->cmd->error = -ETIMEDOUT;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003352 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003353 host->dummy_52_needed = 0;
3354 if (host->curr.data) {
3355 pr_info("%s: %s Request timeout\n",
3356 mmc_hostname(host->mmc), __func__);
3357 if (mrq->data && !mrq->data->error)
3358 mrq->data->error = -ETIMEDOUT;
3359 host->curr.data_xfered = 0;
3360 if (host->dma.sg && host->is_dma_mode) {
3361 msm_dmov_stop_cmd(host->dma.channel,
3362 &host->dma.hdr, 0);
3363 } else if (host->sps.sg && host->is_sps_mode) {
3364 /* Stop current SPS transfer */
3365 msmsdcc_sps_exit_curr_xfer(host);
3366 } else {
3367 msmsdcc_reset_and_restore(host);
3368 msmsdcc_stop_data(host);
3369 if (mrq->data && mrq->data->stop)
3370 msmsdcc_start_command(host,
3371 mrq->data->stop, 0);
3372 else
3373 msmsdcc_request_end(host, mrq);
3374 }
3375 } else {
3376 if (host->prog_enable) {
3377 host->prog_scan = 0;
3378 host->prog_enable = 0;
3379 }
3380 msmsdcc_reset_and_restore(host);
3381 msmsdcc_request_end(host, mrq);
3382 }
3383 }
3384 spin_unlock_irqrestore(&host->lock, flags);
3385}
3386
San Mehat9d2bd732009-09-22 16:44:22 -07003387static int
3388msmsdcc_probe(struct platform_device *pdev)
3389{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003390 struct mmc_platform_data *plat = pdev->dev.platform_data;
San Mehat9d2bd732009-09-22 16:44:22 -07003391 struct msmsdcc_host *host;
3392 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003393 unsigned long flags;
3394 struct resource *core_irqres = NULL;
3395 struct resource *bam_irqres = NULL;
3396 struct resource *core_memres = NULL;
3397 struct resource *dml_memres = NULL;
3398 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07003399 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07003400 struct resource *dma_crci_res = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07003401 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003402 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07003403
3404 /* must have platform data */
3405 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003406 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003407 ret = -EINVAL;
3408 goto out;
3409 }
3410
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003411 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07003412 return -EINVAL;
3413
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003414 if (plat->is_sdio_al_client)
3415 if (!plat->sdio_lpm_gpio_setup || !plat->sdiowakeup_irq)
3416 return -EINVAL;
3417
San Mehat9d2bd732009-09-22 16:44:22 -07003418 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003419 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003420 return -ENXIO;
3421 }
3422
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003423 for (i = 0; i < pdev->num_resources; i++) {
3424 if (pdev->resource[i].flags & IORESOURCE_MEM) {
3425 if (!strcmp(pdev->resource[i].name,
3426 "sdcc_dml_addr"))
3427 dml_memres = &pdev->resource[i];
3428 else if (!strcmp(pdev->resource[i].name,
3429 "sdcc_bam_addr"))
3430 bam_memres = &pdev->resource[i];
3431 else
3432 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07003433
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003434 }
3435 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
3436 if (!strcmp(pdev->resource[i].name,
3437 "sdcc_bam_irq"))
3438 bam_irqres = &pdev->resource[i];
3439 else
3440 core_irqres = &pdev->resource[i];
3441 }
Krishna Konda25786ec2011-07-25 16:21:36 -07003442 if (pdev->resource[i].flags & IORESOURCE_DMA) {
3443 if (!strncmp(pdev->resource[i].name,
3444 "sdcc_dma_chnl",
3445 sizeof("sdcc_dma_chnl")))
3446 dmares = &pdev->resource[i];
3447 else if (!strncmp(pdev->resource[i].name,
3448 "sdcc_dma_crci",
3449 sizeof("sdcc_dma_crci")))
3450 dma_crci_res = &pdev->resource[i];
3451 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003452 }
3453
3454 if (!core_irqres || !core_memres) {
3455 pr_err("%s: Invalid sdcc core resource\n", __func__);
3456 return -ENXIO;
3457 }
3458
3459 /*
3460 * Both BAM and DML memory resource should be preset.
3461 * BAM IRQ resource should also be present.
3462 */
3463 if ((bam_memres && !dml_memres) ||
3464 (!bam_memres && dml_memres) ||
3465 ((bam_memres && dml_memres) && !bam_irqres)) {
3466 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003467 return -ENXIO;
3468 }
3469
3470 /*
3471 * Setup our host structure
3472 */
San Mehat9d2bd732009-09-22 16:44:22 -07003473 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
3474 if (!mmc) {
3475 ret = -ENOMEM;
3476 goto out;
3477 }
3478
3479 host = mmc_priv(mmc);
3480 host->pdev_id = pdev->id;
3481 host->plat = plat;
3482 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08003483 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05303484
3485 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003486 host->is_sps_mode = 1;
3487 else if (dmares)
3488 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07003489
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003490 host->base = ioremap(core_memres->start,
3491 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07003492 if (!host->base) {
3493 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003494 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003495 }
3496
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003497 host->core_irqres = core_irqres;
3498 host->bam_irqres = bam_irqres;
3499 host->core_memres = core_memres;
3500 host->dml_memres = dml_memres;
3501 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07003502 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07003503 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07003504 spin_lock_init(&host->lock);
3505
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003506#ifdef CONFIG_MMC_EMBEDDED_SDIO
3507 if (plat->embedded_sdio)
3508 mmc_set_embedded_sdio_data(mmc,
3509 &plat->embedded_sdio->cis,
3510 &plat->embedded_sdio->cccr,
3511 plat->embedded_sdio->funcs,
3512 plat->embedded_sdio->num_funcs);
3513#endif
3514
Sahitya Tummala62612cf2010-12-08 15:03:03 +05303515 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
3516 (unsigned long)host);
3517
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003518 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
3519 (unsigned long)host);
3520 if (host->is_dma_mode) {
3521 /* Setup DMA */
3522 ret = msmsdcc_init_dma(host);
3523 if (ret)
3524 goto ioremap_free;
3525 } else {
3526 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003527 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003528 }
3529
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003530 /*
3531 * Setup SDCC clock if derived from Dayatona
3532 * fabric core clock.
3533 */
3534 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07003535 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003536 if (!IS_ERR(host->dfab_pclk)) {
3537 /* Set the clock rate to 64MHz for max. performance */
3538 ret = clk_set_rate(host->dfab_pclk, 64000000);
3539 if (ret)
3540 goto dfab_pclk_put;
3541 ret = clk_enable(host->dfab_pclk);
3542 if (ret)
3543 goto dfab_pclk_put;
3544 } else
3545 goto dma_free;
3546 }
3547
3548 /*
3549 * Setup main peripheral bus clock
3550 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003551 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003552 if (!IS_ERR(host->pclk)) {
3553 ret = clk_enable(host->pclk);
3554 if (ret)
3555 goto pclk_put;
3556
3557 host->pclk_rate = clk_get_rate(host->pclk);
3558 }
3559
3560 /*
3561 * Setup SDC MMC clock
3562 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003563 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07003564 if (IS_ERR(host->clk)) {
3565 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003566 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07003567 }
3568
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003569 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
3570 if (ret) {
3571 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
3572 goto clk_put;
3573 }
3574
3575 ret = clk_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003576 if (ret)
3577 goto clk_put;
3578
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003579 host->clk_rate = clk_get_rate(host->clk);
3580
3581 host->clks_on = 1;
3582
3583 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07003584 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003585 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07003586 goto clk_disable;
3587 }
3588
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003589
3590 /* Clocks has to be running before accessing SPS/DML HW blocks */
3591 if (host->is_sps_mode) {
3592 /* Initialize SPS */
3593 ret = msmsdcc_sps_init(host);
3594 if (ret)
3595 goto vreg_deinit;
3596 /* Initialize DML */
3597 ret = msmsdcc_dml_init(host);
3598 if (ret)
3599 goto sps_exit;
3600 }
San Mehat9d2bd732009-09-22 16:44:22 -07003601
San Mehat9d2bd732009-09-22 16:44:22 -07003602 /*
3603 * Setup MMC host structure
3604 */
3605 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003606 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
3607 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003608 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003609 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
3610 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07003611
San Mehat9d2bd732009-09-22 16:44:22 -07003612 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05303613
3614 /*
3615 * If we send the CMD23 before multi block write/read command
3616 * then we need not to send CMD12 at the end of the transfer.
3617 * If we don't send the CMD12 then only way to detect the PROG_DONE
3618 * status is to use the AUTO_PROG_DONE status provided by SDCC4
3619 * controller. So let's enable the CMD23 for SDCC4 only.
3620 */
3621 if (host->plat->sdcc_v4_sup)
3622 mmc->caps |= MMC_CAP_CMD23;
3623
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003624 mmc->caps |= plat->uhs_caps;
3625 /*
3626 * XPC controls the maximum current in the default speed mode of SDXC
3627 * card. XPC=0 means 100mA (max.) but speed class is not supported.
3628 * XPC=1 means 150mA (max.) and speed class is supported.
3629 */
3630 if (plat->xpc_cap)
3631 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
3632 MMC_CAP_SET_XPC_180);
3633
3634 if (plat->nonremovable)
3635 mmc->caps |= MMC_CAP_NONREMOVABLE;
3636#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
3637 mmc->caps |= MMC_CAP_SDIO_IRQ;
3638#endif
3639
3640 if (plat->is_sdio_al_client)
3641 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07003642
Martin K. Petersena36274e2010-09-10 01:33:59 -04003643 mmc->max_segs = NR_SG;
San Mehat9d2bd732009-09-22 16:44:22 -07003644 mmc->max_blk_size = 4096; /* MCI_DATA_CTL BLOCKSIZE up to 4096 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003645 mmc->max_blk_count = 65535;
San Mehat9d2bd732009-09-22 16:44:22 -07003646
3647 mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */
3648 mmc->max_seg_size = mmc->max_req_size;
3649
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003650 writel_relaxed(0, host->base + MMCIMASK0);
3651 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -07003652
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003653 /* Delay needed (MMCIMASK0 was just written above) */
3654 msmsdcc_delay(host);
3655 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
3656 mb();
3657 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07003658
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003659 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
3660 DRIVER_NAME " (cmd)", host);
3661 if (ret)
3662 goto dml_exit;
3663
3664 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
3665 DRIVER_NAME " (pio)", host);
3666 if (ret)
3667 goto irq_free;
3668
3669 /*
3670 * Enable SDCC IRQ only when host is powered on. Otherwise, this
3671 * IRQ is un-necessarily being monitored by MPM (Modem power
3672 * management block) during idle-power collapse. The MPM will be
3673 * configured to monitor the DATA1 GPIO line with level-low trigger
3674 * and thus depending on the GPIO status, it prevents TCXO shutdown
3675 * during idle-power collapse.
3676 */
3677 disable_irq(core_irqres->start);
3678 host->sdcc_irq_disabled = 1;
3679
3680 if (plat->sdiowakeup_irq) {
3681 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3682 mmc_hostname(mmc));
3683 ret = request_irq(plat->sdiowakeup_irq,
3684 msmsdcc_platform_sdiowakeup_irq,
3685 IRQF_SHARED | IRQF_TRIGGER_LOW,
3686 DRIVER_NAME "sdiowakeup", host);
3687 if (ret) {
3688 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
3689 plat->sdiowakeup_irq, ret);
3690 goto pio_irq_free;
3691 } else {
3692 spin_lock_irqsave(&host->lock, flags);
3693 if (!host->sdio_irq_disabled) {
3694 disable_irq_nosync(plat->sdiowakeup_irq);
3695 host->sdio_irq_disabled = 1;
3696 }
3697 spin_unlock_irqrestore(&host->lock, flags);
3698 }
3699 }
3700
3701 if (plat->cfg_mpm_sdiowakeup) {
3702 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3703 mmc_hostname(mmc));
3704 }
3705
3706 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
3707 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003708 /*
3709 * Setup card detect change
3710 */
3711
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003712 if (plat->status || plat->status_gpio) {
3713 if (plat->status)
3714 host->oldstat = plat->status(mmc_dev(host->mmc));
3715 else
3716 host->oldstat = msmsdcc_slot_status(host);
3717 host->eject = !host->oldstat;
3718 }
San Mehat9d2bd732009-09-22 16:44:22 -07003719
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003720 if (plat->status_irq) {
3721 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07003722 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003723 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07003724 DRIVER_NAME " (slot)",
3725 host);
3726 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003727 pr_err("Unable to get slot IRQ %d (%d)\n",
3728 plat->status_irq, ret);
3729 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003730 }
3731 } else if (plat->register_status_notify) {
3732 plat->register_status_notify(msmsdcc_status_notify_cb, host);
3733 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003734 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07003735 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003736
3737 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003738
3739 ret = pm_runtime_set_active(&(pdev)->dev);
3740 if (ret < 0)
3741 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3742 __func__, ret);
3743 /*
3744 * There is no notion of suspend/resume for SD/MMC/SDIO
3745 * cards. So host can be suspended/resumed with out
3746 * worrying about its children.
3747 */
3748 pm_suspend_ignore_children(&(pdev)->dev, true);
3749
3750 /*
3751 * MMC/SD/SDIO bus suspend/resume operations are defined
3752 * only for the slots that will be used for non-removable
3753 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
3754 * defined. Otherwise, they simply become card removal and
3755 * insertion events during suspend and resume respectively.
3756 * Hence, enable run-time PM only for slots for which bus
3757 * suspend/resume operations are defined.
3758 */
3759#ifdef CONFIG_MMC_UNSAFE_RESUME
3760 /*
3761 * If this capability is set, MMC core will enable/disable host
3762 * for every claim/release operation on a host. We use this
3763 * notification to increment/decrement runtime pm usage count.
3764 */
3765 mmc->caps |= MMC_CAP_DISABLE;
3766 pm_runtime_enable(&(pdev)->dev);
3767#else
3768 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
3769 mmc->caps |= MMC_CAP_DISABLE;
3770 pm_runtime_enable(&(pdev)->dev);
3771 }
3772#endif
3773 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
3774 (unsigned long)host);
3775
San Mehat9d2bd732009-09-22 16:44:22 -07003776 mmc_add_host(mmc);
3777
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003778#ifdef CONFIG_HAS_EARLYSUSPEND
3779 host->early_suspend.suspend = msmsdcc_early_suspend;
3780 host->early_suspend.resume = msmsdcc_late_resume;
3781 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
3782 register_early_suspend(&host->early_suspend);
3783#endif
San Mehat9d2bd732009-09-22 16:44:22 -07003784
Krishna Konda25786ec2011-07-25 16:21:36 -07003785 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
3786 " dmacrcri %d\n", mmc_hostname(mmc),
3787 (unsigned long long)core_memres->start,
3788 (unsigned int) core_irqres->start,
3789 (unsigned int) plat->status_irq, host->dma.channel,
3790 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003791
3792 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
3793 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
3794 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
3795 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
3796 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
3797 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
3798 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
3799 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
3800 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
3801 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
3802 host->eject);
3803 pr_info("%s: Power save feature enable = %d\n",
3804 mmc_hostname(mmc), msmsdcc_pwrsave);
3805
Krishna Konda25786ec2011-07-25 16:21:36 -07003806 if (host->is_dma_mode && host->dma.channel != -1
3807 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003808 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003809 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003810 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003811 mmc_hostname(mmc), host->dma.cmd_busaddr,
3812 host->dma.cmdptr_busaddr);
3813 } else if (host->is_sps_mode) {
3814 pr_info("%s: SPS-BAM data transfer mode available\n",
3815 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003816 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003817 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003818
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003819#if defined(CONFIG_DEBUG_FS)
3820 msmsdcc_dbg_createhost(host);
3821#endif
3822 if (!plat->status_irq) {
3823 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
3824 if (ret)
3825 goto platform_irq_free;
3826 }
San Mehat9d2bd732009-09-22 16:44:22 -07003827 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003828
3829 platform_irq_free:
3830 del_timer_sync(&host->req_tout_timer);
3831 pm_runtime_disable(&(pdev)->dev);
3832 pm_runtime_set_suspended(&(pdev)->dev);
3833
3834 if (plat->status_irq)
3835 free_irq(plat->status_irq, host);
3836 sdiowakeup_irq_free:
3837 wake_lock_destroy(&host->sdio_suspend_wlock);
3838 if (plat->sdiowakeup_irq)
3839 free_irq(plat->sdiowakeup_irq, host);
3840 pio_irq_free:
3841 if (plat->sdiowakeup_irq)
3842 wake_lock_destroy(&host->sdio_wlock);
3843 free_irq(core_irqres->start, host);
3844 irq_free:
3845 free_irq(core_irqres->start, host);
3846 dml_exit:
3847 if (host->is_sps_mode)
3848 msmsdcc_dml_exit(host);
3849 sps_exit:
3850 if (host->is_sps_mode)
3851 msmsdcc_sps_exit(host);
3852 vreg_deinit:
3853 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07003854 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003855 clk_disable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003856 clk_put:
3857 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003858 pclk_disable:
3859 if (!IS_ERR(host->pclk))
3860 clk_disable(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07003861 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003862 if (!IS_ERR(host->pclk))
3863 clk_put(host->pclk);
3864 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3865 clk_disable(host->dfab_pclk);
3866 dfab_pclk_put:
3867 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3868 clk_put(host->dfab_pclk);
3869 dma_free:
3870 if (host->is_dma_mode) {
3871 if (host->dmares)
3872 dma_free_coherent(NULL,
3873 sizeof(struct msmsdcc_nc_dmadata),
3874 host->dma.nc, host->dma.nc_busaddr);
3875 }
3876 ioremap_free:
3877 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07003878 host_free:
3879 mmc_free_host(mmc);
3880 out:
3881 return ret;
3882}
3883
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003884static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07003885{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003886 struct mmc_host *mmc = mmc_get_drvdata(pdev);
3887 struct mmc_platform_data *plat;
3888 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07003889
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003890 if (!mmc)
3891 return -ENXIO;
3892
3893 if (pm_runtime_suspended(&(pdev)->dev))
3894 pm_runtime_resume(&(pdev)->dev);
3895
3896 host = mmc_priv(mmc);
3897
3898 DBG(host, "Removing SDCC device = %d\n", pdev->id);
3899 plat = host->plat;
3900
3901 if (!plat->status_irq)
3902 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
3903
3904 del_timer_sync(&host->req_tout_timer);
3905 tasklet_kill(&host->dma_tlet);
3906 tasklet_kill(&host->sps.tlet);
3907 mmc_remove_host(mmc);
3908
3909 if (plat->status_irq)
3910 free_irq(plat->status_irq, host);
3911
3912 wake_lock_destroy(&host->sdio_suspend_wlock);
3913 if (plat->sdiowakeup_irq) {
3914 wake_lock_destroy(&host->sdio_wlock);
3915 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
3916 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07003917 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003918
3919 free_irq(host->core_irqres->start, host);
3920 free_irq(host->core_irqres->start, host);
3921
3922 clk_put(host->clk);
3923 if (!IS_ERR(host->pclk))
3924 clk_put(host->pclk);
3925 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3926 clk_put(host->dfab_pclk);
3927
3928 msmsdcc_vreg_init(host, false);
3929
3930 if (host->is_dma_mode) {
3931 if (host->dmares)
3932 dma_free_coherent(NULL,
3933 sizeof(struct msmsdcc_nc_dmadata),
3934 host->dma.nc, host->dma.nc_busaddr);
3935 }
3936
3937 if (host->is_sps_mode) {
3938 msmsdcc_dml_exit(host);
3939 msmsdcc_sps_exit(host);
3940 }
3941
3942 iounmap(host->base);
3943 mmc_free_host(mmc);
3944
3945#ifdef CONFIG_HAS_EARLYSUSPEND
3946 unregister_early_suspend(&host->early_suspend);
3947#endif
3948 pm_runtime_disable(&(pdev)->dev);
3949 pm_runtime_set_suspended(&(pdev)->dev);
3950
3951 return 0;
3952}
3953
3954#ifdef CONFIG_MSM_SDIO_AL
3955int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
3956{
3957 struct msmsdcc_host *host = mmc_priv(mmc);
3958 unsigned long flags;
3959
3960 spin_lock_irqsave(&host->lock, flags);
3961 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
3962 enable ? "En" : "Dis");
3963
3964 if (enable) {
3965 if (!host->sdcc_irq_disabled) {
3966 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05303967 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003968 host->sdcc_irq_disabled = 1;
3969 }
3970
3971 if (host->clks_on) {
3972 msmsdcc_setup_clocks(host, false);
3973 host->clks_on = 0;
3974 }
3975
3976 if (!host->sdio_gpio_lpm) {
3977 spin_unlock_irqrestore(&host->lock, flags);
3978 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
3979 spin_lock_irqsave(&host->lock, flags);
3980 host->sdio_gpio_lpm = 1;
3981 }
3982
3983 if (host->sdio_irq_disabled) {
3984 msmsdcc_enable_irq_wake(host);
3985 enable_irq(host->plat->sdiowakeup_irq);
3986 host->sdio_irq_disabled = 0;
3987 }
3988 } else {
3989 if (!host->sdio_irq_disabled) {
3990 disable_irq_nosync(host->plat->sdiowakeup_irq);
3991 host->sdio_irq_disabled = 1;
3992 msmsdcc_disable_irq_wake(host);
3993 }
3994
3995 if (host->sdio_gpio_lpm) {
3996 spin_unlock_irqrestore(&host->lock, flags);
3997 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
3998 spin_lock_irqsave(&host->lock, flags);
3999 host->sdio_gpio_lpm = 0;
4000 }
4001
4002 if (!host->clks_on) {
4003 msmsdcc_setup_clocks(host, true);
4004 host->clks_on = 1;
4005 }
4006
4007 if (host->sdcc_irq_disabled) {
4008 writel_relaxed(host->mci_irqenable,
4009 host->base + MMCIMASK0);
4010 mb();
4011 enable_irq(host->core_irqres->start);
4012 host->sdcc_irq_disabled = 0;
4013 }
4014 wake_lock_timeout(&host->sdio_wlock, 1);
4015 }
4016 spin_unlock_irqrestore(&host->lock, flags);
4017 return 0;
4018}
4019#else
4020int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4021{
4022 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004023}
4024#endif
4025
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004026#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07004027static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004028msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004029{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004030 struct mmc_host *mmc = dev_get_drvdata(dev);
4031 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07004032 int rc = 0;
4033
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004034 if (host->plat->is_sdio_al_client)
4035 return 0;
4036
Sahitya Tummala7661a452011-07-18 13:28:35 +05304037 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004038 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004039 host->sdcc_suspending = 1;
4040 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07004041
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004042 /*
4043 * If the clocks are already turned off by SDIO clients (as
4044 * part of LPM), then clocks should be turned on before
4045 * calling mmc_suspend_host() because mmc_suspend_host might
4046 * send some commands to the card. The clocks will be turned
4047 * off again after mmc_suspend_host. Thus for SD/MMC/SDIO
4048 * cards, clocks will be turned on before mmc_suspend_host
4049 * and turned off after mmc_suspend_host.
4050 */
4051 mmc->ios.clock = host->clk_rate;
4052 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07004053
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004054 /*
4055 * MMC core thinks that host is disabled by now since
4056 * runtime suspend is scheduled after msmsdcc_disable()
4057 * is called. Thus, MMC core will try to enable the host
4058 * while suspending it. This results in a synchronous
4059 * runtime resume request while in runtime suspending
4060 * context and hence inorder to complete this resume
4061 * requet, it will wait for suspend to be complete,
4062 * but runtime suspend also can not proceed further
4063 * until the host is resumed. Thus, it leads to a hang.
4064 * Hence, increase the pm usage count before suspending
4065 * the host so that any resume requests after this will
4066 * simple become pm usage counter increment operations.
4067 */
4068 pm_runtime_get_noresume(dev);
4069 rc = mmc_suspend_host(mmc);
4070 pm_runtime_put_noidle(dev);
4071
4072 if (!rc) {
4073 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
4074 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ)) {
4075 disable_irq(host->core_irqres->start);
4076 host->sdcc_irq_disabled = 1;
4077
4078 /*
4079 * If MMC core level suspend is not supported,
4080 * turn off clocks to allow deep sleep (TCXO
4081 * shutdown).
4082 */
4083 mmc->ios.clock = 0;
4084 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4085 enable_irq(host->core_irqres->start);
4086 host->sdcc_irq_disabled = 0;
4087
4088 if (host->plat->sdiowakeup_irq) {
4089 host->sdio_irq_disabled = 0;
4090 msmsdcc_enable_irq_wake(host);
4091 enable_irq(host->plat->sdiowakeup_irq);
4092 }
4093 }
4094 }
4095 host->sdcc_suspending = 0;
4096 mmc->suspend_task = NULL;
4097 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
4098 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004099 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304100 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004101 return rc;
4102}
4103
4104static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004105msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004106{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004107 struct mmc_host *mmc = dev_get_drvdata(dev);
4108 struct msmsdcc_host *host = mmc_priv(mmc);
4109 unsigned long flags;
4110
4111 if (host->plat->is_sdio_al_client)
4112 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07004113
Sahitya Tummala7661a452011-07-18 13:28:35 +05304114 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004115 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004116 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
4117 if (host->sdcc_irq_disabled) {
4118 enable_irq(host->core_irqres->start);
4119 host->sdcc_irq_disabled = 0;
4120 }
4121 }
4122 mmc->ios.clock = host->clk_rate;
4123 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07004124
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004125 spin_lock_irqsave(&host->lock, flags);
4126 writel_relaxed(host->mci_irqenable, host->base + MMCIMASK0);
4127 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07004128
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004129 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
4130 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) &&
4131 !host->sdio_irq_disabled) {
4132 if (host->plat->sdiowakeup_irq) {
4133 disable_irq_nosync(
4134 host->plat->sdiowakeup_irq);
4135 msmsdcc_disable_irq_wake(host);
4136 host->sdio_irq_disabled = 1;
4137 }
4138 }
San Mehat9d2bd732009-09-22 16:44:22 -07004139
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004140 spin_unlock_irqrestore(&host->lock, flags);
4141
4142 mmc_resume_host(mmc);
4143
4144 /*
4145 * FIXME: Clearing of flags must be handled in clients
4146 * resume handler.
4147 */
4148 spin_lock_irqsave(&host->lock, flags);
4149 mmc->pm_flags = 0;
4150 spin_unlock_irqrestore(&host->lock, flags);
4151
4152 /*
4153 * After resuming the host wait for sometime so that
4154 * the SDIO work will be processed.
4155 */
4156 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO)) {
4157 if ((host->plat->cfg_mpm_sdiowakeup ||
4158 host->plat->sdiowakeup_irq) &&
4159 wake_lock_active(&host->sdio_wlock))
4160 wake_lock_timeout(&host->sdio_wlock, 1);
4161 }
4162
4163 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004164 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304165 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004166 return 0;
4167}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004168
4169static int msmsdcc_runtime_idle(struct device *dev)
4170{
4171 struct mmc_host *mmc = dev_get_drvdata(dev);
4172 struct msmsdcc_host *host = mmc_priv(mmc);
4173
4174 if (host->plat->is_sdio_al_client)
4175 return 0;
4176
4177 /* Idle timeout is not configurable for now */
4178 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
4179
4180 return -EAGAIN;
4181}
4182
4183static int msmsdcc_pm_suspend(struct device *dev)
4184{
4185 struct mmc_host *mmc = dev_get_drvdata(dev);
4186 struct msmsdcc_host *host = mmc_priv(mmc);
4187 int rc = 0;
4188
4189 if (host->plat->is_sdio_al_client)
4190 return 0;
4191
4192
4193 if (host->plat->status_irq)
4194 disable_irq(host->plat->status_irq);
4195
4196 if (!pm_runtime_suspended(dev))
4197 rc = msmsdcc_runtime_suspend(dev);
4198
4199 return rc;
4200}
4201
4202static int msmsdcc_pm_resume(struct device *dev)
4203{
4204 struct mmc_host *mmc = dev_get_drvdata(dev);
4205 struct msmsdcc_host *host = mmc_priv(mmc);
4206 int rc = 0;
4207
4208 if (host->plat->is_sdio_al_client)
4209 return 0;
4210
Sahitya Tummalafb486372011-09-02 19:01:49 +05304211 if (!pm_runtime_suspended(dev))
4212 rc = msmsdcc_runtime_resume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004213 if (host->plat->status_irq) {
4214 msmsdcc_check_status((unsigned long)host);
4215 enable_irq(host->plat->status_irq);
4216 }
4217
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004218 return rc;
4219}
4220
Daniel Walker08ecfde2010-06-23 12:32:20 -07004221#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004222#define msmsdcc_runtime_suspend NULL
4223#define msmsdcc_runtime_resume NULL
4224#define msmsdcc_runtime_idle NULL
4225#define msmsdcc_pm_suspend NULL
4226#define msmsdcc_pm_resume NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07004227#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004228
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004229static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
4230 .runtime_suspend = msmsdcc_runtime_suspend,
4231 .runtime_resume = msmsdcc_runtime_resume,
4232 .runtime_idle = msmsdcc_runtime_idle,
4233 .suspend = msmsdcc_pm_suspend,
4234 .resume = msmsdcc_pm_resume,
4235};
4236
San Mehat9d2bd732009-09-22 16:44:22 -07004237static struct platform_driver msmsdcc_driver = {
4238 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004239 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07004240 .driver = {
4241 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004242 .pm = &msmsdcc_dev_pm_ops,
San Mehat9d2bd732009-09-22 16:44:22 -07004243 },
4244};
4245
4246static int __init msmsdcc_init(void)
4247{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004248#if defined(CONFIG_DEBUG_FS)
4249 int ret = 0;
4250 ret = msmsdcc_dbg_init();
4251 if (ret) {
4252 pr_err("Failed to create debug fs dir \n");
4253 return ret;
4254 }
4255#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004256 return platform_driver_register(&msmsdcc_driver);
4257}
4258
4259static void __exit msmsdcc_exit(void)
4260{
4261 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004262
4263#if defined(CONFIG_DEBUG_FS)
4264 debugfs_remove(debugfs_file);
4265 debugfs_remove(debugfs_dir);
4266#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004267}
4268
4269module_init(msmsdcc_init);
4270module_exit(msmsdcc_exit);
4271
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004272MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07004273MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004274
4275#if defined(CONFIG_DEBUG_FS)
4276
4277static int
4278msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
4279{
4280 file->private_data = inode->i_private;
4281 return 0;
4282}
4283
4284static ssize_t
4285msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
4286 size_t count, loff_t *ppos)
4287{
4288 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
4289 char buf[1024];
4290 int max, i;
4291
4292 i = 0;
4293 max = sizeof(buf) - 1;
4294
4295 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
4296 host->curr.cmd, host->curr.data);
4297 if (host->curr.cmd) {
4298 struct mmc_command *cmd = host->curr.cmd;
4299
4300 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
4301 cmd->opcode, cmd->arg, cmd->flags);
4302 }
4303 if (host->curr.data) {
4304 struct mmc_data *data = host->curr.data;
4305 i += scnprintf(buf + i, max - i,
4306 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
4307 data->timeout_ns, data->timeout_clks,
4308 data->blksz, data->blocks, data->error,
4309 data->flags);
4310 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
4311 host->curr.xfer_size, host->curr.xfer_remain,
4312 host->curr.data_xfered, host->dma.sg);
4313 }
4314
4315 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
4316}
4317
4318static const struct file_operations msmsdcc_dbg_state_ops = {
4319 .read = msmsdcc_dbg_state_read,
4320 .open = msmsdcc_dbg_state_open,
4321};
4322
4323static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
4324{
4325 if (debugfs_dir) {
4326 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
4327 0644, debugfs_dir, host,
4328 &msmsdcc_dbg_state_ops);
4329 }
4330}
4331
4332static int __init msmsdcc_dbg_init(void)
4333{
4334 int err;
4335
4336 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
4337 if (IS_ERR(debugfs_dir)) {
4338 err = PTR_ERR(debugfs_dir);
4339 debugfs_dir = NULL;
4340 return err;
4341 }
4342
4343 return 0;
4344}
4345#endif