blob: 5d652272acc920af4d6e35d133cf6b30d791eadf [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();
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +0530340 udelay(host->reg_write_delay);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530341
342 if (host->plat->sdcc_v4_sup &&
343 (readl_relaxed(host->base + MCI_STATUS2) &
344 MCI_MCLK_REG_WR_ACTIVE)) {
345 start = ktime_get();
346 while (readl_relaxed(host->base + MCI_STATUS2) &
347 MCI_MCLK_REG_WR_ACTIVE) {
348 diff = ktime_sub(ktime_get(), start);
349 /* poll for max. 1 ms */
350 if (ktime_to_us(diff) > 1000) {
351 pr_warning("%s: previous reg. write is"
352 " still active\n",
353 mmc_hostname(host->mmc));
354 break;
355 }
356 }
357 }
San Mehat9d2bd732009-09-22 16:44:22 -0700358}
359
San Mehat56a8b5b2009-11-21 12:29:46 -0800360static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700361msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
362{
363 writel_relaxed(arg, host->base + MMCIARGUMENT);
364 msmsdcc_delay(host);
365 writel_relaxed(c, host->base + MMCICOMMAND);
366 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800367}
368
369static void
370msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
371{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700372 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800373
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700374 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
375 writel_relaxed((unsigned int)host->curr.xfer_size,
376 host->base + MMCIDATALENGTH);
377 msmsdcc_delay(host); /* Allow data parms to be applied */
378 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
379 msmsdcc_delay(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800380
San Mehat6ac9ea62009-12-02 17:24:58 -0800381 if (host->cmd_cmd) {
382 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700383 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800384 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800385}
386
San Mehat9d2bd732009-09-22 16:44:22 -0700387static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530388msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700389{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530390 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700391 unsigned long flags;
392 struct mmc_request *mrq;
393
394 spin_lock_irqsave(&host->lock, flags);
395 mrq = host->curr.mrq;
396 BUG_ON(!mrq);
397
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530398 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700399 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700400 goto out;
401 }
402
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530403 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700404 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700405 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700406 } else {
407 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530408 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700409 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530410 mmc_hostname(host->mmc), host->dma.result);
411 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700412 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530413 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530414 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700415 host->dma.err.flush[0], host->dma.err.flush[1],
416 host->dma.err.flush[2], host->dma.err.flush[3],
417 host->dma.err.flush[4],
418 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530419 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700420 if (!mrq->data->error)
421 mrq->data->error = -EIO;
422 }
San Mehat9d2bd732009-09-22 16:44:22 -0700423 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents,
424 host->dma.dir);
425
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700426 if (host->curr.user_pages) {
427 struct scatterlist *sg = host->dma.sg;
428 int i;
429
430 for (i = 0; i < host->dma.num_ents; i++, sg++)
431 flush_dcache_page(sg_page(sg));
432 }
433
San Mehat9d2bd732009-09-22 16:44:22 -0700434 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800435 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700436
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530437 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
438 (host->curr.wait_for_auto_prog_done &&
439 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700440 /*
441 * If we've already gotten our DATAEND / DATABLKEND
442 * for this request, then complete it through here.
443 */
San Mehat9d2bd732009-09-22 16:44:22 -0700444
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700445 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700446 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700447 host->curr.xfer_remain -= host->curr.xfer_size;
448 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700449 if (host->dummy_52_needed) {
450 mrq->data->bytes_xfered = host->curr.data_xfered;
451 host->dummy_52_sent = 1;
452 msmsdcc_start_command(host, &dummy52cmd,
453 MCI_CPSM_PROGENA);
454 goto out;
455 }
456 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530457 if (!mrq->data->stop || mrq->cmd->error ||
458 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700459 host->curr.mrq = NULL;
460 host->curr.cmd = NULL;
461 mrq->data->bytes_xfered = host->curr.data_xfered;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700462 del_timer(&host->req_tout_timer);
San Mehat9d2bd732009-09-22 16:44:22 -0700463 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700464
San Mehat9d2bd732009-09-22 16:44:22 -0700465 mmc_request_done(host->mmc, mrq);
466 return;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530467 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
468 || !mrq->sbc)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700469 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530470 }
San Mehat9d2bd732009-09-22 16:44:22 -0700471 }
472
473out:
474 spin_unlock_irqrestore(&host->lock, flags);
475 return;
476}
477
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700478#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
479/**
480 * Callback notification from SPS driver
481 *
482 * This callback function gets triggered called from
483 * SPS driver when requested SPS data transfer is
484 * completed.
485 *
486 * SPS driver invokes this callback in BAM irq context so
487 * SDCC driver schedule a tasklet for further processing
488 * this callback notification at later point of time in
489 * tasklet context and immediately returns control back
490 * to SPS driver.
491 *
492 * @nofity - Pointer to sps event notify sturcture
493 *
494 */
495static void
496msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
497{
498 struct msmsdcc_host *host =
499 (struct msmsdcc_host *)
500 ((struct sps_event_notify *)notify)->user;
501
502 host->sps.notify = *notify;
503 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
504 mmc_hostname(host->mmc), __func__, notify->event_id,
505 notify->data.transfer.iovec.addr,
506 notify->data.transfer.iovec.size,
507 notify->data.transfer.iovec.flags);
508 /* Schedule a tasklet for completing data transfer */
509 tasklet_schedule(&host->sps.tlet);
510}
511
512/**
513 * Tasklet handler for processing SPS callback event
514 *
515 * This function processing SPS event notification and
516 * checks if the SPS transfer is completed or not and
517 * then accordingly notifies status to MMC core layer.
518 *
519 * This function is called in tasklet context.
520 *
521 * @data - Pointer to sdcc driver data
522 *
523 */
524static void msmsdcc_sps_complete_tlet(unsigned long data)
525{
526 unsigned long flags;
527 int i, rc;
528 u32 data_xfered = 0;
529 struct mmc_request *mrq;
530 struct sps_iovec iovec;
531 struct sps_pipe *sps_pipe_handle;
532 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
533 struct sps_event_notify *notify = &host->sps.notify;
534
535 spin_lock_irqsave(&host->lock, flags);
536 if (host->sps.dir == DMA_FROM_DEVICE)
537 sps_pipe_handle = host->sps.prod.pipe_handle;
538 else
539 sps_pipe_handle = host->sps.cons.pipe_handle;
540 mrq = host->curr.mrq;
541
542 if (!mrq) {
543 spin_unlock_irqrestore(&host->lock, flags);
544 return;
545 }
546
547 pr_debug("%s: %s: sps event_id=%d\n",
548 mmc_hostname(host->mmc), __func__,
549 notify->event_id);
550
551 if (msmsdcc_is_dml_busy(host)) {
552 /* oops !!! this should never happen. */
553 pr_err("%s: %s: Received SPS EOT event"
554 " but DML HW is still busy !!!\n",
555 mmc_hostname(host->mmc), __func__);
556 }
557 /*
558 * Got End of transfer event!!! Check if all of the data
559 * has been transferred?
560 */
561 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
562 rc = sps_get_iovec(sps_pipe_handle, &iovec);
563 if (rc) {
564 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
565 mmc_hostname(host->mmc), __func__, rc, i);
566 break;
567 }
568 data_xfered += iovec.size;
569 }
570
571 if (data_xfered == host->curr.xfer_size) {
572 host->curr.data_xfered = host->curr.xfer_size;
573 host->curr.xfer_remain -= host->curr.xfer_size;
574 pr_debug("%s: Data xfer success. data_xfered=0x%x",
575 mmc_hostname(host->mmc),
576 host->curr.xfer_size);
577 } else {
578 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
579 " xfer_size=%d", mmc_hostname(host->mmc),
580 data_xfered, host->curr.xfer_size);
581 msmsdcc_reset_and_restore(host);
582 if (!mrq->data->error)
583 mrq->data->error = -EIO;
584 }
585
586 /* Unmap sg buffers */
587 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
588 host->sps.dir);
589
590 host->sps.sg = NULL;
591 host->sps.busy = 0;
592
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530593 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
594 (host->curr.wait_for_auto_prog_done &&
595 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700596 /*
597 * If we've already gotten our DATAEND / DATABLKEND
598 * for this request, then complete it through here.
599 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700600
601 if (!mrq->data->error) {
602 host->curr.data_xfered = host->curr.xfer_size;
603 host->curr.xfer_remain -= host->curr.xfer_size;
604 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700605 if (host->dummy_52_needed) {
606 mrq->data->bytes_xfered = host->curr.data_xfered;
607 host->dummy_52_sent = 1;
608 msmsdcc_start_command(host, &dummy52cmd,
609 MCI_CPSM_PROGENA);
610 return;
611 }
612 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530613 if (!mrq->data->stop || mrq->cmd->error ||
614 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700615 host->curr.mrq = NULL;
616 host->curr.cmd = NULL;
617 mrq->data->bytes_xfered = host->curr.data_xfered;
618 del_timer(&host->req_tout_timer);
619 spin_unlock_irqrestore(&host->lock, flags);
620
621 mmc_request_done(host->mmc, mrq);
622 return;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530623 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
624 || !mrq->sbc)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700625 msmsdcc_start_command(host, mrq->data->stop, 0);
626 }
627 }
628 spin_unlock_irqrestore(&host->lock, flags);
629}
630
631/**
632 * Exit from current SPS data transfer
633 *
634 * This function exits from current SPS data transfer.
635 *
636 * This function should be called when error condition
637 * is encountered during data transfer.
638 *
639 * @host - Pointer to sdcc host structure
640 *
641 */
642static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
643{
644 struct mmc_request *mrq;
645
646 mrq = host->curr.mrq;
647 BUG_ON(!mrq);
648
649 msmsdcc_reset_and_restore(host);
650 if (!mrq->data->error)
651 mrq->data->error = -EIO;
652
653 /* Unmap sg buffers */
654 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
655 host->sps.dir);
656
657 host->sps.sg = NULL;
658 host->sps.busy = 0;
659 if (host->curr.data)
660 msmsdcc_stop_data(host);
661
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530662 if (!mrq->data->stop || mrq->cmd->error ||
663 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700664 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530665 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
666 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700667 msmsdcc_start_command(host, mrq->data->stop, 0);
668
669}
670#else
671static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
672static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
673static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
674#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
675
676static void msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
677
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530678static void
679msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
680 unsigned int result,
681 struct msm_dmov_errdata *err)
682{
683 struct msmsdcc_dma_data *dma_data =
684 container_of(cmd, struct msmsdcc_dma_data, hdr);
685 struct msmsdcc_host *host = dma_data->host;
686
687 dma_data->result = result;
688 if (err)
689 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
690
691 tasklet_schedule(&host->dma_tlet);
692}
693
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700694static int msmsdcc_check_dma_op_req(struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700695{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700696 if (((data->blksz * data->blocks) < MCI_FIFOSIZE) ||
697 ((data->blksz * data->blocks) % MCI_FIFOSIZE))
San Mehat9d2bd732009-09-22 16:44:22 -0700698 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700699 else
700 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700701}
702
703static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
704{
705 struct msmsdcc_nc_dmadata *nc;
706 dmov_box *box;
707 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700708 unsigned int n;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700709 int i;
San Mehat9d2bd732009-09-22 16:44:22 -0700710 struct scatterlist *sg = data->sg;
711
Krishna Konda25786ec2011-07-25 16:21:36 -0700712 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700713 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700714
Krishna Konda25786ec2011-07-25 16:21:36 -0700715 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
716
San Mehat9d2bd732009-09-22 16:44:22 -0700717 host->dma.sg = data->sg;
718 host->dma.num_ents = data->sg_len;
719
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700720 BUG_ON(host->dma.num_ents > NR_SG); /* Prevent memory corruption */
San Mehat56a8b5b2009-11-21 12:29:46 -0800721
San Mehat9d2bd732009-09-22 16:44:22 -0700722 nc = host->dma.nc;
723
San Mehat9d2bd732009-09-22 16:44:22 -0700724 if (data->flags & MMC_DATA_READ)
725 host->dma.dir = DMA_FROM_DEVICE;
726 else
727 host->dma.dir = DMA_TO_DEVICE;
728
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700729 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
San Mehat9d2bd732009-09-22 16:44:22 -0700730 host->curr.user_pages = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700731 box = &nc->cmd[0];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700732 for (i = 0; i < host->dma.num_ents; i++) {
San Mehat9d2bd732009-09-22 16:44:22 -0700733 box->cmd = CMD_MODE_BOX;
734
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700735 /* Initialize sg dma address */
736 sg->dma_address = pfn_to_dma(mmc_dev(host->mmc),
737 page_to_pfn(sg_page(sg)))
738 + sg->offset;
739
740 if (i == (host->dma.num_ents - 1))
San Mehat9d2bd732009-09-22 16:44:22 -0700741 box->cmd |= CMD_LC;
742 rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ?
743 (sg_dma_len(sg) / MCI_FIFOSIZE) + 1 :
744 (sg_dma_len(sg) / MCI_FIFOSIZE) ;
745
746 if (data->flags & MMC_DATA_READ) {
747 box->src_row_addr = msmsdcc_fifo_addr(host);
748 box->dst_row_addr = sg_dma_address(sg);
749
750 box->src_dst_len = (MCI_FIFOSIZE << 16) |
751 (MCI_FIFOSIZE);
752 box->row_offset = MCI_FIFOSIZE;
753
754 box->num_rows = rows * ((1 << 16) + 1);
Krishna Konda25786ec2011-07-25 16:21:36 -0700755 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
San Mehat9d2bd732009-09-22 16:44:22 -0700756 } else {
757 box->src_row_addr = sg_dma_address(sg);
758 box->dst_row_addr = msmsdcc_fifo_addr(host);
759
760 box->src_dst_len = (MCI_FIFOSIZE << 16) |
761 (MCI_FIFOSIZE);
762 box->row_offset = (MCI_FIFOSIZE << 16);
763
764 box->num_rows = rows * ((1 << 16) + 1);
Krishna Konda25786ec2011-07-25 16:21:36 -0700765 box->cmd |= CMD_DST_CRCI(host->dma.crci);
San Mehat9d2bd732009-09-22 16:44:22 -0700766 }
767 box++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700768 sg++;
769 }
770
771 /* location of command block must be 64 bit aligned */
772 BUG_ON(host->dma.cmd_busaddr & 0x07);
773
774 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
775 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
776 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
777 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700778
779 n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
780 host->dma.num_ents, host->dma.dir);
781 /* dsb inside dma_map_sg will write nc out to mem as well */
782
783 if (n != host->dma.num_ents) {
784 pr_err("%s: Unable to map in all sg elements\n",
785 mmc_hostname(host->mmc));
786 host->dma.sg = NULL;
787 host->dma.num_ents = 0;
788 return -ENOMEM;
San Mehat56a8b5b2009-11-21 12:29:46 -0800789 }
San Mehat9d2bd732009-09-22 16:44:22 -0700790
791 return 0;
792}
793
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700794#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
795/**
796 * Submits data transfer request to SPS driver
797 *
798 * This function make sg (scatter gather) data buffers
799 * DMA ready and then submits them to SPS driver for
800 * transfer.
801 *
802 * @host - Pointer to sdcc host structure
803 * @data - Pointer to mmc_data structure
804 *
805 * @return 0 if success else negative value
806 */
807static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
808 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -0800809{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700810 int rc = 0;
811 u32 flags;
812 int i;
813 u32 addr, len, data_cnt;
814 struct scatterlist *sg = data->sg;
815 struct sps_pipe *sps_pipe_handle;
816
817 BUG_ON(data->sg_len > NR_SG); /* Prevent memory corruption */
818
819 host->sps.sg = data->sg;
820 host->sps.num_ents = data->sg_len;
821 host->sps.xfer_req_cnt = 0;
822 if (data->flags & MMC_DATA_READ) {
823 host->sps.dir = DMA_FROM_DEVICE;
824 sps_pipe_handle = host->sps.prod.pipe_handle;
825 } else {
826 host->sps.dir = DMA_TO_DEVICE;
827 sps_pipe_handle = host->sps.cons.pipe_handle;
828 }
829
830 /* Make sg buffers DMA ready */
831 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
832 host->sps.dir);
833
834 if (rc != data->sg_len) {
835 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
836 mmc_hostname(host->mmc), rc);
837 host->sps.sg = NULL;
838 host->sps.num_ents = 0;
839 rc = -ENOMEM;
840 goto dma_map_err;
841 }
842
843 pr_debug("%s: %s: %s: pipe=0x%x, total_xfer=0x%x, sg_len=%d\n",
844 mmc_hostname(host->mmc), __func__,
845 host->sps.dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
846 (u32)sps_pipe_handle, host->curr.xfer_size, data->sg_len);
847
848 for (i = 0; i < data->sg_len; i++) {
849 /*
850 * Check if this is the last buffer to transfer?
851 * If yes then set the INT and EOT flags.
852 */
853 len = sg_dma_len(sg);
854 addr = sg_dma_address(sg);
855 flags = 0;
856 while (len > 0) {
857 if (len > SPS_MAX_DESC_SIZE) {
858 data_cnt = SPS_MAX_DESC_SIZE;
859 } else {
860 data_cnt = len;
861 if (i == data->sg_len - 1)
862 flags = SPS_IOVEC_FLAG_INT |
863 SPS_IOVEC_FLAG_EOT;
864 }
865 rc = sps_transfer_one(sps_pipe_handle, addr,
866 data_cnt, host, flags);
867 if (rc) {
868 pr_err("%s: sps_transfer_one() error! rc=%d,"
869 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
870 mmc_hostname(host->mmc), rc,
871 (u32)sps_pipe_handle, (u32)sg, i);
872 goto dma_map_err;
873 }
874 addr += data_cnt;
875 len -= data_cnt;
876 host->sps.xfer_req_cnt++;
877 }
878 sg++;
879 }
880 goto out;
881
882dma_map_err:
883 /* unmap sg buffers */
884 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
885 host->sps.dir);
886out:
887 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -0700888}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700889#else
890static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
891 struct mmc_data *data) { return 0; }
892#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -0700893
894static void
San Mehat56a8b5b2009-11-21 12:29:46 -0800895msmsdcc_start_command_deferred(struct msmsdcc_host *host,
896 struct mmc_command *cmd, u32 *c)
897{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700898 DBG(host, "op %02x arg %08x flags %08x\n",
899 cmd->opcode, cmd->arg, cmd->flags);
900
San Mehat56a8b5b2009-11-21 12:29:46 -0800901 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
902
903 if (cmd->flags & MMC_RSP_PRESENT) {
904 if (cmd->flags & MMC_RSP_136)
905 *c |= MCI_CPSM_LONGRSP;
906 *c |= MCI_CPSM_RESPONSE;
907 }
908
909 if (/*interrupt*/0)
910 *c |= MCI_CPSM_INTERRUPT;
911
912 if ((((cmd->opcode == 17) || (cmd->opcode == 18)) ||
913 ((cmd->opcode == 24) || (cmd->opcode == 25))) ||
914 (cmd->opcode == 53))
915 *c |= MCI_CSPM_DATCMD;
916
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700917 /* Check if AUTO CMD19 is required or not? */
Subhash Jadavani1d6ba602011-09-21 18:10:54 +0530918 if (host->tuning_needed) {
919 /*
920 * For open ended block read operation (without CMD23),
921 * AUTO_CMD19 bit should be set while sending the READ command.
922 * For close ended block read operation (with CMD23),
923 * AUTO_CMD19 bit should be set while sending CMD23.
924 */
925 if ((cmd->opcode == 23 && (host->curr.mrq->cmd->opcode == 17 ||
926 host->curr.mrq->cmd->opcode == 18)) ||
927 (!host->curr.mrq->sbc &&
928 (cmd->opcode == 17 || cmd->opcode == 18))) {
929 msmsdcc_enable_cdr_cm_sdc4_dll(host);
930 *c |= MCI_CSPM_AUTO_CMD19;
931 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700932 }
933
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +0530934 if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +0530935 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700936 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +0530937 }
938
San Mehat56a8b5b2009-11-21 12:29:46 -0800939 if (cmd == cmd->mrq->stop)
940 *c |= MCI_CSPM_MCIABORT;
941
San Mehat56a8b5b2009-11-21 12:29:46 -0800942 if (host->curr.cmd != NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700943 pr_err("%s: Overlapping command requests\n",
944 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -0800945 }
946 host->curr.cmd = cmd;
947}
948
949static void
950msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
951 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -0700952{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +0530953 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -0700954 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700955 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -0700956 unsigned int pio_irqmask = 0;
957
958 host->curr.data = data;
959 host->curr.xfer_size = data->blksz * data->blocks;
960 host->curr.xfer_remain = host->curr.xfer_size;
961 host->curr.data_xfered = 0;
962 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530963 host->curr.got_auto_prog_done = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700964
965 memset(&host->pio, 0, sizeof(host->pio));
966
San Mehat9d2bd732009-09-22 16:44:22 -0700967 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
968
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530969 if (host->curr.wait_for_auto_prog_done)
970 datactrl |= MCI_AUTO_PROG_DONE;
971
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700972 if (!msmsdcc_check_dma_op_req(data)) {
973 if (host->is_dma_mode && !msmsdcc_config_dma(host, data)) {
974 datactrl |= MCI_DPSM_DMAENABLE;
975 } else if (host->is_sps_mode) {
976 if (!msmsdcc_is_dml_busy(host)) {
977 if (!msmsdcc_sps_start_xfer(host, data)) {
978 /* Now kick start DML transfer */
979 mb();
980 msmsdcc_dml_start_xfer(host, data);
981 datactrl |= MCI_DPSM_DMAENABLE;
982 host->sps.busy = 1;
983 }
984 } else {
985 /*
986 * Can't proceed with new transfer as
987 * previous trasnfer is already in progress.
988 * There is no point of going into PIO mode
989 * as well. Is this a time to do kernel panic?
990 */
991 pr_err("%s: %s: DML HW is busy!!!"
992 " Can't perform new SPS transfers"
993 " now\n", mmc_hostname(host->mmc),
994 __func__);
995 }
996 }
997 }
998
999 /* Is data transfer in PIO mode required? */
1000 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001001 host->pio.sg = data->sg;
1002 host->pio.sg_len = data->sg_len;
1003 host->pio.sg_off = 0;
1004
1005 if (data->flags & MMC_DATA_READ) {
1006 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1007 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1008 pio_irqmask |= MCI_RXDATAAVLBLMASK;
1009 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001010 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1011 MCI_TXFIFOEMPTYMASK;
San Mehat9d2bd732009-09-22 16:44:22 -07001012 }
1013
1014 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301015 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
Subhash Jadavanibbf38a32011-10-12 16:47:52 +05301016 else if (data->flags & MMC_DATA_WRITE)
1017 datactrl |= MCI_DATA_PEND;
San Mehat9d2bd732009-09-22 16:44:22 -07001018
San Mehat56a8b5b2009-11-21 12:29:46 -08001019 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001020 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001021 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -07001022
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001023 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
1024 /* Use ADM (Application Data Mover) HW for Data transfer */
1025 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001026 host->cmd_timeout = timeout;
1027 host->cmd_pio_irqmask = pio_irqmask;
1028 host->cmd_datactrl = datactrl;
1029 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001030
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001031 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1032 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001033 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001034
1035 if (cmd) {
1036 msmsdcc_start_command_deferred(host, cmd, &c);
1037 host->cmd_c = c;
1038 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001039 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1040 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1041 host->base + MMCIMASK0);
1042 mb();
1043 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001044 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001045 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001046 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001047
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001048 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001049
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001050 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1051 (~(MCI_IRQ_PIO))) | pio_irqmask,
1052 host->base + MMCIMASK0);
1053 msmsdcc_delay(host); /* Allow parms to be applied */
1054 writel_relaxed(datactrl, base + MMCIDATACTRL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001055
1056 if (cmd) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001057 msmsdcc_delay(host); /* Delay between data/command */
San Mehat56a8b5b2009-11-21 12:29:46 -08001058 /* Daisy-chain the command if requested */
1059 msmsdcc_start_command(host, cmd, c);
1060 }
San Mehat9d2bd732009-09-22 16:44:22 -07001061 }
1062}
1063
1064static void
1065msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1066{
San Mehat56a8b5b2009-11-21 12:29:46 -08001067 msmsdcc_start_command_deferred(host, cmd, &c);
1068 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001069}
1070
1071static void
1072msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1073 unsigned int status)
1074{
1075 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001076 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1077 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1078 pr_err("%s: Data CRC error\n",
1079 mmc_hostname(host->mmc));
1080 pr_err("%s: opcode 0x%.8x\n", __func__,
1081 data->mrq->cmd->opcode);
1082 pr_err("%s: blksz %d, blocks %d\n", __func__,
1083 data->blksz, data->blocks);
1084 data->error = -EILSEQ;
1085 }
San Mehat9d2bd732009-09-22 16:44:22 -07001086 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001087 /* CRC is optional for the bus test commands, not all
1088 * cards respond back with CRC. However controller
1089 * waits for the CRC and times out. Hence ignore the
1090 * data timeouts during the Bustest.
1091 */
1092 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1093 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1094 pr_err("%s: Data timeout\n",
1095 mmc_hostname(host->mmc));
1096 data->error = -ETIMEDOUT;
1097 }
San Mehat9d2bd732009-09-22 16:44:22 -07001098 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001099 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001100 data->error = -EIO;
1101 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001102 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001103 data->error = -EIO;
1104 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001105 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001106 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001107 data->error = -EIO;
1108 }
San Mehat9d2bd732009-09-22 16:44:22 -07001109
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001110 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001111 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001112 host->dummy_52_needed = 0;
1113}
San Mehat9d2bd732009-09-22 16:44:22 -07001114
1115static int
1116msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1117{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001118 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001119 uint32_t *ptr = (uint32_t *) buffer;
1120 int count = 0;
1121
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301122 if (remain % 4)
1123 remain = ((remain >> 2) + 1) << 2;
1124
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001125 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1126
1127 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001128 ptr++;
1129 count += sizeof(uint32_t);
1130
1131 remain -= sizeof(uint32_t);
1132 if (remain == 0)
1133 break;
1134 }
1135 return count;
1136}
1137
1138static int
1139msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001140 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001141{
1142 void __iomem *base = host->base;
1143 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001144 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001145
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001146 while (readl_relaxed(base + MMCISTATUS) &
1147 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1148 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001149
San Mehat9d2bd732009-09-22 16:44:22 -07001150 count = min(remain, maxcnt);
1151
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301152 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1153 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001154 ptr += count;
1155 remain -= count;
1156
1157 if (remain == 0)
1158 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001159 }
1160 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001161
1162 return ptr - buffer;
1163}
1164
San Mehat1cd22962010-02-03 12:59:29 -08001165static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001166msmsdcc_pio_irq(int irq, void *dev_id)
1167{
1168 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001169 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001170 uint32_t status;
1171
Murali Palnati36448a42011-09-02 15:06:18 +05301172 spin_lock(&host->lock);
1173
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001174 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001175
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001176 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301177 (MCI_IRQ_PIO)) == 0) {
1178 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001179 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301180 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001181
1182#if IRQ_DEBUG
1183 msmsdcc_print_status(host, "irq1-r", status);
1184#endif
1185
San Mehat9d2bd732009-09-22 16:44:22 -07001186 do {
1187 unsigned long flags;
1188 unsigned int remain, len;
1189 char *buffer;
1190
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001191 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1192 | MCI_RXDATAAVLBL)))
1193 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001194
1195 /* Map the current scatter buffer */
1196 local_irq_save(flags);
1197 buffer = kmap_atomic(sg_page(host->pio.sg),
1198 KM_BIO_SRC_IRQ) + host->pio.sg->offset;
1199 buffer += host->pio.sg_off;
1200 remain = host->pio.sg->length - host->pio.sg_off;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001201
San Mehat9d2bd732009-09-22 16:44:22 -07001202 len = 0;
1203 if (status & MCI_RXACTIVE)
1204 len = msmsdcc_pio_read(host, buffer, remain);
1205 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001206 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001207
1208 /* Unmap the buffer */
1209 kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
1210 local_irq_restore(flags);
1211
1212 host->pio.sg_off += len;
1213 host->curr.xfer_remain -= len;
1214 host->curr.data_xfered += len;
1215 remain -= len;
1216
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001217 if (remain) /* Done with this page? */
1218 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001219
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001220 if (status & MCI_RXACTIVE && host->curr.user_pages)
1221 flush_dcache_page(sg_page(host->pio.sg));
San Mehat9d2bd732009-09-22 16:44:22 -07001222
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001223 if (!--host->pio.sg_len) {
1224 memset(&host->pio, 0, sizeof(host->pio));
1225 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001226 }
1227
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001228 /* Advance to next sg */
1229 host->pio.sg++;
1230 host->pio.sg_off = 0;
1231
1232 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001233 } while (1);
1234
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001235 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1236 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1237 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1238 host->base + MMCIMASK0);
1239 if (!host->curr.xfer_remain) {
1240 /* Delay needed (same port was just written) */
1241 msmsdcc_delay(host);
1242 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1243 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1244 }
1245 mb();
1246 } else if (!host->curr.xfer_remain) {
1247 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1248 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1249 mb();
1250 }
San Mehat9d2bd732009-09-22 16:44:22 -07001251
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001252 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001253
1254 return IRQ_HANDLED;
1255}
1256
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001257static void
1258msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1259
1260static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1261 struct mmc_data *data)
1262{
1263 u32 loop_cnt = 0;
1264
1265 /*
1266 * For read commands with data less than fifo size, it is possible to
1267 * get DATAEND first and RXDATA_AVAIL might be set later because of
1268 * synchronization delay through the asynchronous RX FIFO. Thus, for
1269 * such cases, even after DATAEND interrupt is received software
1270 * should poll for RXDATA_AVAIL until the requested data is read out
1271 * of FIFO. This change is needed to get around this abnormal but
1272 * sometimes expected behavior of SDCC3 controller.
1273 *
1274 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1275 * after the data is loaded into RX FIFO. This would amount to less
1276 * than a microsecond and thus looping for 1000 times is good enough
1277 * for that delay.
1278 */
1279 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1280 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1281 spin_unlock(&host->lock);
1282 msmsdcc_pio_irq(1, host);
1283 spin_lock(&host->lock);
1284 }
1285 }
1286 if (loop_cnt == 1000) {
1287 pr_info("%s: Timed out while polling for Rx Data\n",
1288 mmc_hostname(host->mmc));
1289 data->error = -ETIMEDOUT;
1290 msmsdcc_reset_and_restore(host);
1291 }
1292}
1293
San Mehat9d2bd732009-09-22 16:44:22 -07001294static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1295{
1296 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001297
1298 host->curr.cmd = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001299 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1300 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1301 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1302 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -07001303
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001304 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Sahitya Tummala5a0ae912011-07-18 13:34:01 +05301305 pr_debug("%s: Command timeout\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001306 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001307 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
1308 !host->cmd19_tuning_in_progress) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001309 pr_err("%s: Command CRC error\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001310 cmd->error = -EILSEQ;
1311 }
1312
1313 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001314 if (host->curr.data && host->dma.sg &&
1315 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001316 msm_dmov_stop_cmd(host->dma.channel,
1317 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001318 else if (host->curr.data && host->sps.sg &&
1319 host->is_sps_mode){
1320 /* Stop current SPS transfer */
1321 msmsdcc_sps_exit_curr_xfer(host);
1322 }
San Mehat9d2bd732009-09-22 16:44:22 -07001323 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301324 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001325 msmsdcc_stop_data(host);
1326 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301327 } else { /* host->data == NULL */
1328 if (!cmd->error && host->prog_enable) {
1329 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001330 host->prog_enable = 0;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301331 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001332 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301333 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301334 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301335 host->prog_enable = 0;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001336 if (host->dummy_52_needed)
1337 host->dummy_52_needed = 0;
1338 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001339 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301340 msmsdcc_request_end(host, cmd->mrq);
1341 }
1342 }
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301343 } else if ((cmd == host->curr.mrq->sbc) && cmd->data) {
1344 if (cmd->data->flags & MMC_DATA_READ)
1345 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1346 else
1347 msmsdcc_request_start(host, host->curr.mrq);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001348 }
1349}
1350
San Mehat9d2bd732009-09-22 16:44:22 -07001351static irqreturn_t
1352msmsdcc_irq(int irq, void *dev_id)
1353{
1354 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001355 u32 status;
1356 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001357 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001358
1359 spin_lock(&host->lock);
1360
1361 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001362 struct mmc_command *cmd;
1363 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001364
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001365 if (timer) {
1366 timer = 0;
1367 msmsdcc_delay(host);
1368 }
San Mehat865c8062009-11-13 13:42:06 -08001369
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001370 if (!host->clks_on) {
1371 pr_debug("%s: %s: SDIO async irq received\n",
1372 mmc_hostname(host->mmc), __func__);
1373 host->mmc->ios.clock = host->clk_rate;
1374 spin_unlock(&host->lock);
1375 host->mmc->ops->set_ios(host->mmc, &host->mmc->ios);
1376 spin_lock(&host->lock);
1377 if (host->plat->cfg_mpm_sdiowakeup &&
1378 (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
1379 wake_lock(&host->sdio_wlock);
1380 /* only ansyc interrupt can come when clocks are off */
1381 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301382 if (host->clk_rate <=
1383 msmsdcc_get_min_sup_clk_rate(host))
1384 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001385 }
1386
1387 status = readl_relaxed(host->base + MMCISTATUS);
1388
1389 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1390 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001391 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001392
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001393#if IRQ_DEBUG
1394 msmsdcc_print_status(host, "irq0-r", status);
1395#endif
1396 status &= readl_relaxed(host->base + MMCIMASK0);
1397 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301398 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301399 if (host->clk_rate <=
1400 msmsdcc_get_min_sup_clk_rate(host))
1401 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001402#if IRQ_DEBUG
1403 msmsdcc_print_status(host, "irq0-p", status);
1404#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001405
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001406#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
1407 if (status & MCI_SDIOINTROPE) {
1408 if (host->sdcc_suspending)
1409 wake_lock(&host->sdio_suspend_wlock);
1410 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001411 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001412#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001413 data = host->curr.data;
1414
1415 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001416 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1417 MCI_CMDTIMEOUT)) {
1418 if (status & MCI_CMDTIMEOUT)
1419 pr_debug("%s: dummy CMD52 timeout\n",
1420 mmc_hostname(host->mmc));
1421 if (status & MCI_CMDCRCFAIL)
1422 pr_debug("%s: dummy CMD52 CRC failed\n",
1423 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001424 host->dummy_52_sent = 0;
1425 host->dummy_52_needed = 0;
1426 if (data) {
1427 msmsdcc_stop_data(host);
1428 msmsdcc_request_end(host, data->mrq);
1429 }
1430 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001431 spin_unlock(&host->lock);
1432 return IRQ_HANDLED;
1433 }
1434 break;
1435 }
1436
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001437 /*
1438 * Check for proper command response
1439 */
1440 cmd = host->curr.cmd;
1441 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1442 MCI_CMDTIMEOUT | MCI_PROGDONE |
1443 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1444 msmsdcc_do_cmdirq(host, status);
1445 }
1446
1447 if (data) {
1448 /* Check for data errors */
1449 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1450 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1451 msmsdcc_data_err(host, data, status);
1452 host->curr.data_xfered = 0;
1453 if (host->dma.sg && host->is_dma_mode)
1454 msm_dmov_stop_cmd(host->dma.channel,
1455 &host->dma.hdr, 0);
1456 else if (host->sps.sg && host->is_sps_mode) {
1457 /* Stop current SPS transfer */
1458 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301459 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001460 msmsdcc_reset_and_restore(host);
1461 if (host->curr.data)
1462 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301463 if (!data->stop || (host->curr.mrq->sbc
1464 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001465 timer |=
1466 msmsdcc_request_end(host,
1467 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301468 else if ((host->curr.mrq->sbc
1469 && data->error) ||
1470 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001471 msmsdcc_start_command(host,
1472 data->stop,
1473 0);
1474 timer = 1;
1475 }
1476 }
1477 }
1478
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301479 /* Check for prog done */
1480 if (host->curr.wait_for_auto_prog_done &&
1481 (status & MCI_PROGDONE))
1482 host->curr.got_auto_prog_done = 1;
1483
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001484 /* Check for data done */
1485 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1486 host->curr.got_dataend = 1;
1487
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301488 if (host->curr.got_dataend &&
1489 (!host->curr.wait_for_auto_prog_done ||
1490 (host->curr.wait_for_auto_prog_done &&
1491 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001492 /*
1493 * If DMA is still in progress, we complete
1494 * via the completion handler
1495 */
1496 if (!host->dma.busy && !host->sps.busy) {
1497 /*
1498 * There appears to be an issue in the
1499 * controller where if you request a
1500 * small block transfer (< fifo size),
1501 * you may get your DATAEND/DATABLKEND
1502 * irq without the PIO data irq.
1503 *
1504 * Check to see if theres still data
1505 * to be read, and simulate a PIO irq.
1506 */
1507 if (data->flags & MMC_DATA_READ)
1508 msmsdcc_wait_for_rxdata(host,
1509 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001510 if (!data->error) {
1511 host->curr.data_xfered =
1512 host->curr.xfer_size;
1513 host->curr.xfer_remain -=
1514 host->curr.xfer_size;
1515 }
1516
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001517 if (!host->dummy_52_needed) {
1518 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301519 if (!data->stop ||
1520 (host->curr.mrq->sbc
1521 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001522 msmsdcc_request_end(
1523 host,
1524 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301525 else if ((host->curr.mrq->sbc
1526 && data->error) ||
1527 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001528 msmsdcc_start_command(
1529 host,
1530 data->stop, 0);
1531 timer = 1;
1532 }
1533 } else {
1534 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001535 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001536 &dummy52cmd,
1537 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001538 }
1539 }
1540 }
1541 }
1542
San Mehat9d2bd732009-09-22 16:44:22 -07001543 ret = 1;
1544 } while (status);
1545
1546 spin_unlock(&host->lock);
1547
San Mehat9d2bd732009-09-22 16:44:22 -07001548 return IRQ_RETVAL(ret);
1549}
1550
1551static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001552msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1553{
Subhash Jadavanibbf38a32011-10-12 16:47:52 +05301554 if (mrq->data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001555 /* Queue/read data, daisy-chain command when data starts */
Subhash Jadavanibbf38a32011-10-12 16:47:52 +05301556 if (mrq->sbc && (mrq->data->flags & MMC_DATA_READ))
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301557 msmsdcc_start_data(host, mrq->data, mrq->sbc, 0);
1558 else
1559 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001560 } else {
1561 msmsdcc_start_command(host, mrq->cmd, 0);
1562 }
1563}
1564
1565static void
San Mehat9d2bd732009-09-22 16:44:22 -07001566msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1567{
1568 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001569 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001570
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001571 /*
1572 * Get the SDIO AL client out of LPM.
1573 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001574 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001575 if (host->plat->is_sdio_al_client)
1576 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001577
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301578 /* check if sps pipe reset is pending? */
1579 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1580 msmsdcc_sps_pipes_reset_and_restore(host);
1581 host->sps.pipe_reset_pending = false;
1582 }
1583
San Mehat9d2bd732009-09-22 16:44:22 -07001584 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001585 WARN(host->curr.mrq, "Request in progress\n");
1586 WARN(!host->pwr, "SDCC power is turned off\n");
1587 WARN(!host->clks_on, "SDCC clocks are turned off\n");
1588 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
San Mehat9d2bd732009-09-22 16:44:22 -07001589
1590 if (host->eject) {
1591 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1592 mrq->cmd->error = 0;
1593 mrq->data->bytes_xfered = mrq->data->blksz *
1594 mrq->data->blocks;
1595 } else
1596 mrq->cmd->error = -ENOMEDIUM;
1597
1598 spin_unlock_irqrestore(&host->lock, flags);
1599 mmc_request_done(mmc, mrq);
1600 return;
1601 }
1602
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301603 /*
1604 * Kick the software command timeout timer here.
1605 * Timer expires in 10 secs.
1606 */
1607 mod_timer(&host->req_tout_timer,
1608 (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
San Mehat9d2bd732009-09-22 16:44:22 -07001609
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301610 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301611 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301612 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
1613 mrq->cmd->opcode == 54) {
1614 if (!host->plat->sdcc_v4_sup)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001615 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301616 else
1617 /*
1618 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
1619 * write operations using CMD53 and CMD54.
1620 * Setting this bit with CMD53 would
1621 * automatically triggers PROG_DONE interrupt
1622 * without the need of sending dummy CMD52.
1623 */
1624 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001625 }
San Mehat9d2bd732009-09-22 16:44:22 -07001626 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301627
Pratibhasagar V00b94332011-10-18 14:57:27 +05301628 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301629 mrq->sbc->mrq = mrq;
1630 mrq->sbc->data = mrq->data;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301631 if (mrq->data->flags & MMC_DATA_WRITE) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301632 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301633 msmsdcc_start_command(host, mrq->sbc, 0);
1634 } else {
1635 msmsdcc_request_start(host, mrq);
1636 }
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301637 } else {
1638 msmsdcc_request_start(host, mrq);
1639 }
1640
San Mehat9d2bd732009-09-22 16:44:22 -07001641 spin_unlock_irqrestore(&host->lock, flags);
1642}
1643
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001644static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1645 int min_uV, int max_uV)
1646{
1647 int rc = 0;
1648
1649 if (vreg->set_voltage_sup) {
1650 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1651 if (rc) {
1652 pr_err("%s: regulator_set_voltage(%s) failed."
1653 " min_uV=%d, max_uV=%d, rc=%d\n",
1654 __func__, vreg->name, min_uV, max_uV, rc);
1655 }
1656 }
1657
1658 return rc;
1659}
1660
1661static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1662 int uA_load)
1663{
1664 int rc = 0;
1665
1666 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1667 if (rc < 0)
1668 pr_err("%s: regulator_set_optimum_mode(reg=%s, uA_load=%d)"
1669 " failed. rc=%d\n", __func__, vreg->name,
1670 uA_load, rc);
1671 else
1672 /* regulator_set_optimum_mode() can return non zero value
1673 * even for success case.
1674 */
1675 rc = 0;
1676
1677 return rc;
1678}
1679
1680static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1681 struct device *dev)
1682{
1683 int rc = 0;
1684
1685 /* check if regulator is already initialized? */
1686 if (vreg->reg)
1687 goto out;
1688
1689 /* Get the regulator handle */
1690 vreg->reg = regulator_get(dev, vreg->name);
1691 if (IS_ERR(vreg->reg)) {
1692 rc = PTR_ERR(vreg->reg);
1693 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
1694 __func__, vreg->name, rc);
1695 }
1696out:
1697 return rc;
1698}
1699
1700static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
1701{
1702 if (vreg->reg)
1703 regulator_put(vreg->reg);
1704}
1705
1706/* This init function should be called only once for each SDCC slot */
1707static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
1708{
1709 int rc = 0;
1710 struct msm_mmc_slot_reg_data *curr_slot;
1711 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1712 struct device *dev = mmc_dev(host->mmc);
1713
1714 curr_slot = host->plat->vreg_data;
1715 if (!curr_slot)
1716 goto out;
1717
1718 curr_vdd_reg = curr_slot->vdd_data;
1719 curr_vccq_reg = curr_slot->vccq_data;
1720 curr_vddp_reg = curr_slot->vddp_data;
1721
1722 if (is_init) {
1723 /*
1724 * Get the regulator handle from voltage regulator framework
1725 * and then try to set the voltage level for the regulator
1726 */
1727 if (curr_vdd_reg) {
1728 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
1729 if (rc)
1730 goto out;
1731 }
1732 if (curr_vccq_reg) {
1733 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
1734 if (rc)
1735 goto vdd_reg_deinit;
1736 }
1737 if (curr_vddp_reg) {
1738 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
1739 if (rc)
1740 goto vccq_reg_deinit;
1741 }
1742 goto out;
1743 } else {
1744 /* Deregister all regulators from regulator framework */
1745 goto vddp_reg_deinit;
1746 }
1747vddp_reg_deinit:
1748 if (curr_vddp_reg)
1749 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
1750vccq_reg_deinit:
1751 if (curr_vccq_reg)
1752 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
1753vdd_reg_deinit:
1754 if (curr_vdd_reg)
1755 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
1756out:
1757 return rc;
1758}
1759
1760static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
1761{
1762 int rc = 0;
1763
Subhash Jadavanicc922692011-08-01 23:05:01 +05301764 /* Put regulator in HPM (high power mode) */
1765 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
1766 if (rc < 0)
1767 goto out;
1768
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001769 if (!vreg->is_enabled) {
1770 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301771 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
1772 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001773 if (rc)
1774 goto out;
1775
1776 rc = regulator_enable(vreg->reg);
1777 if (rc) {
1778 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
1779 __func__, vreg->name, rc);
1780 goto out;
1781 }
1782 vreg->is_enabled = true;
1783 }
1784
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001785out:
1786 return rc;
1787}
1788
1789static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
1790{
1791 int rc = 0;
1792
1793 /* Never disable regulator marked as always_on */
1794 if (vreg->is_enabled && !vreg->always_on) {
1795 rc = regulator_disable(vreg->reg);
1796 if (rc) {
1797 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
1798 __func__, vreg->name, rc);
1799 goto out;
1800 }
1801 vreg->is_enabled = false;
1802
1803 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
1804 if (rc < 0)
1805 goto out;
1806
1807 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301808 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001809 if (rc)
1810 goto out;
1811 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
1812 /* Put always_on regulator in LPM (low power mode) */
1813 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
1814 if (rc < 0)
1815 goto out;
1816 }
1817out:
1818 return rc;
1819}
1820
1821static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
1822{
1823 int rc = 0, i;
1824 struct msm_mmc_slot_reg_data *curr_slot;
1825 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1826 struct msm_mmc_reg_data *vreg_table[3];
1827
1828 curr_slot = host->plat->vreg_data;
1829 if (!curr_slot)
1830 goto out;
1831
1832 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
1833 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
1834 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
1835
1836 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
1837 if (vreg_table[i]) {
1838 if (enable)
1839 rc = msmsdcc_vreg_enable(vreg_table[i]);
1840 else
1841 rc = msmsdcc_vreg_disable(vreg_table[i]);
1842 if (rc)
1843 goto out;
1844 }
1845 }
1846out:
1847 return rc;
1848}
1849
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301850static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001851{
1852 int rc = 0;
1853
1854 if (host->plat->vreg_data) {
1855 struct msm_mmc_reg_data *vddp_reg =
1856 host->plat->vreg_data->vddp_data;
1857
1858 if (vddp_reg && vddp_reg->is_enabled)
1859 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
1860 }
1861
1862 return rc;
1863}
1864
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301865static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
1866{
1867 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1868 int rc = 0;
1869
1870 if (curr_slot && curr_slot->vddp_data) {
1871 rc = msmsdcc_set_vddp_level(host,
1872 curr_slot->vddp_data->low_vol_level);
1873
1874 if (rc)
1875 pr_err("%s: %s: failed to change vddp level to %d",
1876 mmc_hostname(host->mmc), __func__,
1877 curr_slot->vddp_data->low_vol_level);
1878 }
1879
1880 return rc;
1881}
1882
1883static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
1884{
1885 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1886 int rc = 0;
1887
1888 if (curr_slot && curr_slot->vddp_data) {
1889 rc = msmsdcc_set_vddp_level(host,
1890 curr_slot->vddp_data->high_vol_level);
1891
1892 if (rc)
1893 pr_err("%s: %s: failed to change vddp level to %d",
1894 mmc_hostname(host->mmc), __func__,
1895 curr_slot->vddp_data->high_vol_level);
1896 }
1897
1898 return rc;
1899}
1900
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001901static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
1902{
1903 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
1904 return 1;
1905 return 0;
1906}
1907
1908static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
1909{
1910 if (enable) {
1911 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1912 clk_enable(host->dfab_pclk);
1913 if (!IS_ERR(host->pclk))
1914 clk_enable(host->pclk);
1915 clk_enable(host->clk);
1916 } else {
1917 clk_disable(host->clk);
1918 if (!IS_ERR(host->pclk))
1919 clk_disable(host->pclk);
1920 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1921 clk_disable(host->dfab_pclk);
1922 }
1923}
1924
1925static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
1926 unsigned int req_clk)
1927{
1928 unsigned int sel_clk = -1;
1929
1930 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
1931 unsigned char cnt;
1932
1933 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
1934 if (host->plat->sup_clk_table[cnt] > req_clk)
1935 break;
1936 else if (host->plat->sup_clk_table[cnt] == req_clk) {
1937 sel_clk = host->plat->sup_clk_table[cnt];
1938 break;
1939 } else
1940 sel_clk = host->plat->sup_clk_table[cnt];
1941 }
1942 } else {
1943 if ((req_clk < host->plat->msmsdcc_fmax) &&
1944 (req_clk > host->plat->msmsdcc_fmid))
1945 sel_clk = host->plat->msmsdcc_fmid;
1946 else
1947 sel_clk = req_clk;
1948 }
1949
1950 return sel_clk;
1951}
1952
1953static inline unsigned int msmsdcc_get_min_sup_clk_rate(
1954 struct msmsdcc_host *host)
1955{
1956 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
1957 return host->plat->sup_clk_table[0];
1958 else
1959 return host->plat->msmsdcc_fmin;
1960}
1961
1962static inline unsigned int msmsdcc_get_max_sup_clk_rate(
1963 struct msmsdcc_host *host)
1964{
1965 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
1966 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
1967 else
1968 return host->plat->msmsdcc_fmax;
1969}
1970
1971static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05301972{
1973 struct msm_mmc_gpio_data *curr;
1974 int i, rc = 0;
1975
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001976 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301977 for (i = 0; i < curr->size; i++) {
1978 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001979 if (curr->gpio[i].is_always_on &&
1980 curr->gpio[i].is_enabled)
1981 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301982 rc = gpio_request(curr->gpio[i].no,
1983 curr->gpio[i].name);
1984 if (rc) {
1985 pr_err("%s: gpio_request(%d, %s) failed %d\n",
1986 mmc_hostname(host->mmc),
1987 curr->gpio[i].no,
1988 curr->gpio[i].name, rc);
1989 goto free_gpios;
1990 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001991 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301992 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001993 if (curr->gpio[i].is_always_on)
1994 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301995 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001996 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301997 }
1998 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001999 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302000
2001free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002002 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302003 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002004 curr->gpio[i].is_enabled = false;
2005 }
2006out:
2007 return rc;
2008}
2009
2010static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2011{
2012 struct msm_mmc_pad_data *curr;
2013 int i;
2014
2015 curr = host->plat->pin_data->pad_data;
2016 for (i = 0; i < curr->drv->size; i++) {
2017 if (enable)
2018 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2019 curr->drv->on[i].val);
2020 else
2021 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2022 curr->drv->off[i].val);
2023 }
2024
2025 for (i = 0; i < curr->pull->size; i++) {
2026 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002027 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002028 curr->pull->on[i].val);
2029 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002030 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002031 curr->pull->off[i].val);
2032 }
2033
2034 return 0;
2035}
2036
2037static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2038{
2039 int rc = 0;
2040
2041 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2042 return 0;
2043
2044 if (host->plat->pin_data->is_gpio)
2045 rc = msmsdcc_setup_gpio(host, enable);
2046 else
2047 rc = msmsdcc_setup_pad(host, enable);
2048
2049 if (!rc)
2050 host->plat->pin_data->cfg_sts = enable;
2051
2052 return rc;
2053}
2054
2055static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2056{
2057 unsigned int wakeup_irq;
2058
2059 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2060 host->plat->sdiowakeup_irq :
2061 host->core_irqres->start;
2062
2063 if (!host->irq_wake_enabled) {
2064 enable_irq_wake(wakeup_irq);
2065 host->irq_wake_enabled = true;
2066 }
2067}
2068
2069static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2070{
2071 unsigned int wakeup_irq;
2072
2073 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2074 host->plat->sdiowakeup_irq :
2075 host->core_irqres->start;
2076
2077 if (host->irq_wake_enabled) {
2078 disable_irq_wake(wakeup_irq);
2079 host->irq_wake_enabled = false;
2080 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302081}
2082
San Mehat9d2bd732009-09-22 16:44:22 -07002083static void
2084msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2085{
2086 struct msmsdcc_host *host = mmc_priv(mmc);
2087 u32 clk = 0, pwr = 0;
2088 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002089 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002090 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002091
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002092 DBG(host, "ios->clock = %u\n", ios->clock);
Sahitya Tummala7a892482011-01-18 11:22:49 +05302093
San Mehat9d2bd732009-09-22 16:44:22 -07002094 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002095 spin_lock_irqsave(&host->lock, flags);
2096 if (!host->clks_on) {
2097 msmsdcc_setup_clocks(host, true);
2098 host->clks_on = 1;
2099 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2100 if (!host->plat->sdiowakeup_irq) {
2101 writel_relaxed(host->mci_irqenable,
2102 host->base + MMCIMASK0);
2103 mb();
2104 if (host->plat->cfg_mpm_sdiowakeup &&
2105 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2106 host->plat->cfg_mpm_sdiowakeup(
2107 mmc_dev(mmc), SDC_DAT1_DISWAKE);
2108 msmsdcc_disable_irq_wake(host);
2109 } else if (!(mmc->pm_flags &
2110 MMC_PM_WAKE_SDIO_IRQ)) {
2111 writel_relaxed(host->mci_irqenable,
2112 host->base + MMCIMASK0);
2113 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05302114 } else {
2115 writel_relaxed(host->mci_irqenable,
2116 host->base + MMCIMASK0);
2117 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002118 }
San Mehat9d2bd732009-09-22 16:44:22 -07002119 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002120 spin_unlock_irqrestore(&host->lock, flags);
2121
2122 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2123 /*
2124 * For DDR50 mode, controller needs clock rate to be
2125 * double than what is required on the SD card CLK pin.
2126 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302127 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002128 /*
2129 * Make sure that we don't double the clock if
2130 * doubled clock rate is already set
2131 */
2132 if (!host->ddr_doubled_clk_rate ||
2133 (host->ddr_doubled_clk_rate &&
2134 (host->ddr_doubled_clk_rate != ios->clock))) {
2135 host->ddr_doubled_clk_rate =
2136 msmsdcc_get_sup_clk_rate(
2137 host, (ios->clock * 2));
2138 clock = host->ddr_doubled_clk_rate;
2139 }
2140 } else {
2141 host->ddr_doubled_clk_rate = 0;
2142 }
2143
2144 if (clock != host->clk_rate) {
2145 rc = clk_set_rate(host->clk, clock);
2146 if (rc < 0)
2147 pr_debug("%s: failed to set clk rate %u\n",
2148 mmc_hostname(mmc), clock);
2149 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302150 host->reg_write_delay =
2151 (1 + ((3 * USEC_PER_SEC) /
2152 (host->clk_rate ? host->clk_rate :
2153 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002154 }
2155 /*
2156 * give atleast 2 MCLK cycles delay for clocks
2157 * and SDCC core to stabilize
2158 */
2159 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002160 clk |= MCI_CLK_ENABLE;
2161 }
2162
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002163 if (ios->bus_width == MMC_BUS_WIDTH_8)
2164 clk |= MCI_CLK_WIDEBUS_8;
2165 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2166 clk |= MCI_CLK_WIDEBUS_4;
2167 else
2168 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002169
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002170 if (msmsdcc_is_pwrsave(host))
2171 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002172
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002173 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002174
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002175 host->tuning_needed = 0;
2176 /*
2177 * Select the controller timing mode according
2178 * to current bus speed mode
2179 */
2180 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2181 (ios->timing == MMC_TIMING_UHS_SDR50)) {
2182 clk |= (4 << 14);
2183 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302184 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002185 clk |= (3 << 14);
2186 } else {
2187 clk |= (2 << 14); /* feedback clock */
2188 }
2189
2190 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2191 clk |= (2 << 23);
2192
2193 if (host->io_pad_pwr_switch)
2194 clk |= IO_PAD_PWR_SWITCH;
2195
2196 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
San Mehat9d2bd732009-09-22 16:44:22 -07002197 pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002198 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2199 pwr |= msmsdcc_setup_vreg(host, !!ios->vdd);
San Mehat9d2bd732009-09-22 16:44:22 -07002200
2201 switch (ios->power_mode) {
2202 case MMC_POWER_OFF:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002203 htc_pwrsink_set(PWRSINK_SDCARD, 0);
2204 if (!host->sdcc_irq_disabled) {
2205 if (host->plat->cfg_mpm_sdiowakeup)
2206 host->plat->cfg_mpm_sdiowakeup(
2207 mmc_dev(mmc), SDC_DAT1_DISABLE);
2208 disable_irq(host->core_irqres->start);
2209 host->sdcc_irq_disabled = 1;
2210 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302211 /*
2212 * As VDD pad rail is always on, set low voltage for VDD
2213 * pad rail when slot is unused (when card is not present
2214 * or during system suspend).
2215 */
2216 msmsdcc_set_vddp_low_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002217 msmsdcc_setup_pins(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002218 break;
2219 case MMC_POWER_UP:
2220 pwr |= MCI_PWR_UP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002221 if (host->sdcc_irq_disabled) {
2222 if (host->plat->cfg_mpm_sdiowakeup)
2223 host->plat->cfg_mpm_sdiowakeup(
2224 mmc_dev(mmc), SDC_DAT1_ENABLE);
2225 enable_irq(host->core_irqres->start);
2226 host->sdcc_irq_disabled = 0;
2227 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302228 msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002229 msmsdcc_setup_pins(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07002230 break;
2231 case MMC_POWER_ON:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002232 htc_pwrsink_set(PWRSINK_SDCARD, 100);
San Mehat9d2bd732009-09-22 16:44:22 -07002233 pwr |= MCI_PWR_ON;
2234 break;
2235 }
2236
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002237 spin_lock_irqsave(&host->lock, flags);
2238 if (!host->clks_on) {
2239 /* force the clocks to be on */
2240 msmsdcc_setup_clocks(host, true);
2241 /*
2242 * give atleast 2 MCLK cycles delay for clocks
2243 * and SDCC core to stabilize
2244 */
2245 msmsdcc_delay(host);
2246 }
2247 writel_relaxed(clk, host->base + MMCICLOCK);
2248 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002249
2250 if (host->pwr != pwr) {
2251 host->pwr = pwr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002252 writel_relaxed(pwr, host->base + MMCIPOWER);
2253 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07002254 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002255 if (!host->clks_on) {
2256 /* force the clocks to be off */
2257 msmsdcc_setup_clocks(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002258 }
2259
2260 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
2261 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2262 if (!host->plat->sdiowakeup_irq) {
2263 writel_relaxed(MCI_SDIOINTMASK,
2264 host->base + MMCIMASK0);
2265 mb();
2266 if (host->plat->cfg_mpm_sdiowakeup &&
2267 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2268 host->plat->cfg_mpm_sdiowakeup(
2269 mmc_dev(mmc), SDC_DAT1_ENWAKE);
2270 msmsdcc_enable_irq_wake(host);
2271 } else if (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2272 writel_relaxed(0, host->base + MMCIMASK0);
2273 } else {
2274 writel_relaxed(MCI_SDIOINTMASK,
2275 host->base + MMCIMASK0);
2276 }
2277 msmsdcc_delay(host);
2278 }
2279 msmsdcc_setup_clocks(host, false);
2280 host->clks_on = 0;
2281 }
San Mehat4adbbcc2009-11-08 13:00:37 -08002282 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002283}
2284
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002285int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2286{
2287 struct msmsdcc_host *host = mmc_priv(mmc);
2288 u32 clk;
2289
2290 clk = readl_relaxed(host->base + MMCICLOCK);
2291 pr_debug("Changing to pwr_save=%d", pwrsave);
2292 if (pwrsave && msmsdcc_is_pwrsave(host))
2293 clk |= MCI_CLK_PWRSAVE;
2294 else
2295 clk &= ~MCI_CLK_PWRSAVE;
2296 writel_relaxed(clk, host->base + MMCICLOCK);
2297 mb();
2298
2299 return 0;
2300}
2301
2302static int msmsdcc_get_ro(struct mmc_host *mmc)
2303{
2304 int status = -ENOSYS;
2305 struct msmsdcc_host *host = mmc_priv(mmc);
2306
2307 if (host->plat->wpswitch) {
2308 status = host->plat->wpswitch(mmc_dev(mmc));
2309 } else if (host->plat->wpswitch_gpio) {
2310 status = gpio_request(host->plat->wpswitch_gpio,
2311 "SD_WP_Switch");
2312 if (status) {
2313 pr_err("%s: %s: Failed to request GPIO %d\n",
2314 mmc_hostname(mmc), __func__,
2315 host->plat->wpswitch_gpio);
2316 } else {
2317 status = gpio_direction_input(
2318 host->plat->wpswitch_gpio);
2319 if (!status) {
2320 /*
2321 * Wait for atleast 300ms as debounce
2322 * time for GPIO input to stabilize.
2323 */
2324 msleep(300);
2325 status = gpio_get_value_cansleep(
2326 host->plat->wpswitch_gpio);
2327 status ^= !host->plat->wpswitch_polarity;
2328 }
2329 gpio_free(host->plat->wpswitch_gpio);
2330 }
2331 }
2332
2333 if (status < 0)
2334 status = -ENOSYS;
2335 pr_debug("%s: Card read-only status %d\n", __func__, status);
2336
2337 return status;
2338}
2339
2340#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002341static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2342{
2343 struct msmsdcc_host *host = mmc_priv(mmc);
2344 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002345
2346 if (enable) {
2347 spin_lock_irqsave(&host->lock, flags);
2348 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
2349 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
2350 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2351 spin_unlock_irqrestore(&host->lock, flags);
2352 } else {
2353 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
2354 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
2355 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2356 }
2357 mb();
2358}
2359#endif /* CONFIG_MMC_MSM_SDIO_SUPPORT */
2360
2361#ifdef CONFIG_PM_RUNTIME
2362static int msmsdcc_enable(struct mmc_host *mmc)
2363{
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302364 int rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002365 struct device *dev = mmc->parent;
2366
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302367 if (dev->power.runtime_status == RPM_SUSPENDING) {
2368 if (mmc->suspend_task == current) {
2369 pm_runtime_get_noresume(dev);
2370 goto out;
2371 }
2372 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002373
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302374 rc = pm_runtime_get_sync(dev);
2375
2376 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002377 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2378 __func__, rc);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302379 return rc;
2380 }
2381out:
2382 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002383}
2384
2385static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2386{
2387 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302388 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002389
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302390 if (host->plat->disable_runtime_pm)
2391 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002392 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO)
2393 return -ENOTSUPP;
2394
2395 rc = pm_runtime_put_sync(mmc->parent);
2396
2397 if (rc < 0)
2398 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2399 __func__, rc);
2400 return rc;
2401}
2402#else
2403#define msmsdcc_enable NULL
2404#define msmsdcc_disable NULL
2405#endif
2406
2407static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2408 struct mmc_ios *ios)
2409{
2410 struct msmsdcc_host *host = mmc_priv(mmc);
2411 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302412 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002413
2414 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2415 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302416 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002417 goto out;
2418 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2419 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302420 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002421 goto out;
2422 }
San Mehat9d2bd732009-09-22 16:44:22 -07002423
2424 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002425 /*
2426 * If we are here means voltage switch from high voltage to
2427 * low voltage is required
2428 */
2429
2430 /*
2431 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2432 * register until they become all zeros.
2433 */
2434 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302435 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002436 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2437 mmc_hostname(mmc), __func__);
2438 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002439 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002440
2441 /* Stop SD CLK output. */
2442 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2443 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2444
San Mehat9d2bd732009-09-22 16:44:22 -07002445 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002446
2447 /*
2448 * Switch VDDPX from high voltage to low voltage
2449 * to change the VDD of the SD IO pads.
2450 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302451 rc = msmsdcc_set_vddp_low_vol(host);
2452 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002453 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002454
2455 spin_lock_irqsave(&host->lock, flags);
2456 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2457 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
2458 host->io_pad_pwr_switch = 1;
2459 spin_unlock_irqrestore(&host->lock, flags);
2460
2461 /* Wait 5 ms for the voltage regulater in the card to become stable. */
2462 usleep_range(5000, 5500);
2463
2464 spin_lock_irqsave(&host->lock, flags);
2465 /* Start SD CLK output. */
2466 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2467 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2468 spin_unlock_irqrestore(&host->lock, flags);
2469
2470 /*
2471 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
2472 * don't become all ones within 1 ms then a Voltage Switch
2473 * sequence has failed and a power cycle to the card is required.
2474 * Otherwise Voltage Switch sequence is completed successfully.
2475 */
2476 usleep_range(1000, 1500);
2477
2478 spin_lock_irqsave(&host->lock, flags);
2479 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
2480 != (0xF << 1)) {
2481 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
2482 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302483 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002484 goto out_unlock;
2485 }
2486
2487out_unlock:
2488 spin_unlock_irqrestore(&host->lock, flags);
2489out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302490 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002491}
2492
2493static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2494 u8 phase);
2495/* Initialize the DLL (Programmable Delay Line ) */
2496static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
2497{
2498 int rc = 0;
2499 u32 wait_timeout;
2500
2501 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
2502 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2503 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2504
2505 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
2506 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2507 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2508
2509 msmsdcc_delay(host);
2510
2511 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
2512 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2513 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2514
2515 /* Initialize the phase to 0 */
2516 rc = msmsdcc_config_cm_sdc4_dll_phase(host, 0);
2517 if (rc)
2518 goto out;
2519
2520 wait_timeout = 1000;
2521 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
2522 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
2523 /* max. wait for 1 sec for LOCK bit to be set */
2524 if (--wait_timeout == 0) {
2525 pr_err("%s: %s: DLL failed to lock at phase: %d",
2526 mmc_hostname(host->mmc), __func__, 0);
2527 rc = -1;
2528 goto out;
2529 }
2530 /* wait for 1ms */
2531 usleep_range(1000, 1500);
2532 }
2533out:
2534 return rc;
2535}
2536
2537/*
2538 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
2539 * calibration sequence. This function should be called before
2540 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
2541 * commands (CMD17/CMD18).
2542 */
2543static void msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
2544{
2545 /* Set CDR_EN bit to 1. */
2546 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) |
2547 MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2548
2549 /* Set CDR_EXT_EN bit to 0. */
2550 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2551 & ~MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2552
2553 /* Set CK_OUT_EN bit to 0. */
2554 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2555 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2556
2557 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2558 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)
2559 ;
2560
2561 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2562 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2563 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2564
2565 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register is 1. */
2566 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN))
2567 ;
2568}
2569
2570static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2571 u8 phase)
2572{
2573 int rc = 0;
2574 u32 mclk_freq = 0;
2575 u32 wait_timeout;
2576
2577 /* Set CDR_EN bit to 0. */
2578 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2579 & ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2580
2581 /* Set CDR_EXT_EN bit to 1. */
2582 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2583 | MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2584
2585 /* Program the MCLK value to MCLK_FREQ bit field */
2586 if (host->clk_rate <= 112000000)
2587 mclk_freq = 0;
2588 else if (host->clk_rate <= 125000000)
2589 mclk_freq = 1;
2590 else if (host->clk_rate <= 137000000)
2591 mclk_freq = 2;
2592 else if (host->clk_rate <= 150000000)
2593 mclk_freq = 3;
2594 else if (host->clk_rate <= 162000000)
2595 mclk_freq = 4;
2596 else if (host->clk_rate <= 175000000)
2597 mclk_freq = 5;
2598 else if (host->clk_rate <= 187000000)
2599 mclk_freq = 6;
2600 else if (host->clk_rate <= 200000000)
2601 mclk_freq = 7;
2602
2603 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2604 & ~(7 << 24)) | (mclk_freq << 24)),
2605 host->base + MCI_DLL_CONFIG);
2606
2607 /* Set CK_OUT_EN bit to 0. */
2608 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2609 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2610
2611 /* Set DLL_EN bit to 1. */
2612 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2613 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
2614
2615 wait_timeout = 1000;
2616 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2617 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN) {
2618 /* max. wait for 1 sec for LOCK bit for be set */
2619 if (--wait_timeout == 0) {
2620 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 0",
2621 mmc_hostname(host->mmc), __func__, phase);
2622 rc = -1;
2623 goto out;
2624 }
2625 /* wait for 1ms */
2626 usleep_range(1000, 1500);
2627 }
2628
2629 /*
2630 * Write the selected DLL clock output phase (0 ... 15)
2631 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
2632 */
2633 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2634 & ~(0xF << 20)) | (phase << 20)),
2635 host->base + MCI_DLL_CONFIG);
2636
2637 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2638 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2639 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2640
2641 wait_timeout = 1000;
2642 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
2643 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)) {
2644 /* max. wait for 1 sec for LOCK bit for be set */
2645 if (--wait_timeout == 0) {
2646 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 1",
2647 mmc_hostname(host->mmc), __func__, phase);
2648 rc = -1;
2649 goto out;
2650 }
2651 /* wait for 1ms */
2652 usleep_range(1000, 1500);
2653 }
2654out:
2655 return rc;
2656}
2657
2658static int msmsdcc_execute_tuning(struct mmc_host *mmc)
2659{
2660 struct msmsdcc_host *host = mmc_priv(mmc);
2661 u8 phase;
2662 u8 *data_buf;
2663 u8 tuned_phases[16], tuned_phase_cnt = 0;
2664 int rc = 0;
2665
2666 /* Tuning is only required for SDR50 & SDR104 modes */
2667 if (!host->tuning_needed) {
2668 rc = 0;
2669 goto out;
2670 }
2671
2672 host->cmd19_tuning_in_progress = 1;
2673 /*
2674 * Make sure that clock is always enabled when DLL
2675 * tuning is in progress. Keeping PWRSAVE ON may
2676 * turn off the clock. So let's disable the PWRSAVE
2677 * here and re-enable it once tuning is completed.
2678 */
2679 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2680 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2681 /* first of all reset the tuning block */
2682 rc = msmsdcc_init_cm_sdc4_dll(host);
2683 if (rc)
2684 goto out;
2685
2686 data_buf = kmalloc(64, GFP_KERNEL);
2687 if (!data_buf) {
2688 rc = -ENOMEM;
2689 goto out;
2690 }
2691
2692 phase = 0;
2693 do {
2694 struct mmc_command cmd = {0};
2695 struct mmc_data data = {0};
2696 struct mmc_request mrq = {
2697 .cmd = &cmd,
2698 .data = &data
2699 };
2700 struct scatterlist sg;
2701
2702 /* set the phase in delay line hw block */
2703 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2704 if (rc)
2705 goto kfree;
2706
2707 cmd.opcode = MMC_SEND_TUNING_BLOCK;
2708 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
2709
2710 data.blksz = 64;
2711 data.blocks = 1;
2712 data.flags = MMC_DATA_READ;
2713 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
2714
2715 data.sg = &sg;
2716 data.sg_len = 1;
2717 sg_init_one(&sg, data_buf, 64);
2718 memset(data_buf, 0, 64);
2719 mmc_wait_for_req(mmc, &mrq);
2720
2721 if (!cmd.error && !data.error &&
2722 !memcmp(data_buf, cmd19_tuning_block, 64)) {
2723 /* tuning is successful with this tuning point */
2724 tuned_phases[tuned_phase_cnt++] = phase;
2725 }
2726 } while (++phase < 16);
2727
2728 kfree(data_buf);
2729
2730 if (tuned_phase_cnt) {
2731 tuned_phase_cnt--;
2732 tuned_phase_cnt = (tuned_phase_cnt * 3) / 4;
2733 phase = tuned_phases[tuned_phase_cnt];
2734 /*
2735 * Finally set the selected phase in delay
2736 * line hw block.
2737 */
2738 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2739 if (rc)
2740 goto out;
2741 } else {
2742 /* tuning failed */
2743 rc = -EAGAIN;
2744 pr_err("%s: %s: no tuning point found",
2745 mmc_hostname(mmc), __func__);
2746 }
2747 goto out;
2748
2749kfree:
2750 kfree(data_buf);
2751out:
2752 /* re-enable PWESAVE */
2753 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2754 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2755 host->cmd19_tuning_in_progress = 0;
2756 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07002757}
2758
2759static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002760 .enable = msmsdcc_enable,
2761 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07002762 .request = msmsdcc_request,
2763 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002764 .get_ro = msmsdcc_get_ro,
2765#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002766 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002767#endif
2768 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
2769 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07002770};
2771
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002772static unsigned int
2773msmsdcc_slot_status(struct msmsdcc_host *host)
2774{
2775 int status;
2776 unsigned int gpio_no = host->plat->status_gpio;
2777
2778 status = gpio_request(gpio_no, "SD_HW_Detect");
2779 if (status) {
2780 pr_err("%s: %s: Failed to request GPIO %d\n",
2781 mmc_hostname(host->mmc), __func__, gpio_no);
2782 } else {
2783 status = gpio_direction_input(gpio_no);
2784 if (!status)
2785 status = !gpio_get_value_cansleep(gpio_no);
2786 gpio_free(gpio_no);
2787 }
2788 return status;
2789}
2790
San Mehat9d2bd732009-09-22 16:44:22 -07002791static void
2792msmsdcc_check_status(unsigned long data)
2793{
2794 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
2795 unsigned int status;
2796
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002797 if (host->plat->status || host->plat->status_gpio) {
2798 if (host->plat->status)
2799 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07002800 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002801 status = msmsdcc_slot_status(host);
2802
2803 host->eject = !status;
2804 if (status ^ host->oldstat) {
2805 pr_info("%s: Slot status change detected (%d -> %d)\n",
2806 mmc_hostname(host->mmc), host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07002807 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002808 }
2809 host->oldstat = status;
2810 } else {
2811 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07002812 }
San Mehat9d2bd732009-09-22 16:44:22 -07002813}
2814
2815static irqreturn_t
2816msmsdcc_platform_status_irq(int irq, void *dev_id)
2817{
2818 struct msmsdcc_host *host = dev_id;
2819
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002820 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07002821 msmsdcc_check_status((unsigned long) host);
2822 return IRQ_HANDLED;
2823}
2824
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002825static irqreturn_t
2826msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
2827{
2828 struct msmsdcc_host *host = dev_id;
2829
2830 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
2831 spin_lock(&host->lock);
2832 if (!host->sdio_irq_disabled) {
2833 disable_irq_nosync(irq);
2834 if (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2835 wake_lock(&host->sdio_wlock);
2836 msmsdcc_disable_irq_wake(host);
2837 }
2838 host->sdio_irq_disabled = 1;
2839 }
2840 if (host->plat->is_sdio_al_client) {
2841 if (!host->clks_on) {
2842 msmsdcc_setup_clocks(host, true);
2843 host->clks_on = 1;
2844 }
2845 if (host->sdcc_irq_disabled) {
2846 writel_relaxed(host->mci_irqenable,
2847 host->base + MMCIMASK0);
2848 mb();
2849 enable_irq(host->core_irqres->start);
2850 host->sdcc_irq_disabled = 0;
2851 }
2852 wake_lock(&host->sdio_wlock);
2853 }
2854 spin_unlock(&host->lock);
2855
2856 return IRQ_HANDLED;
2857}
2858
San Mehat9d2bd732009-09-22 16:44:22 -07002859static void
2860msmsdcc_status_notify_cb(int card_present, void *dev_id)
2861{
2862 struct msmsdcc_host *host = dev_id;
2863
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002864 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07002865 card_present);
2866 msmsdcc_check_status((unsigned long) host);
2867}
2868
San Mehat9d2bd732009-09-22 16:44:22 -07002869static int
2870msmsdcc_init_dma(struct msmsdcc_host *host)
2871{
2872 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
2873 host->dma.host = host;
2874 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07002875 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07002876
2877 if (!host->dmares)
2878 return -ENODEV;
2879
2880 host->dma.nc = dma_alloc_coherent(NULL,
2881 sizeof(struct msmsdcc_nc_dmadata),
2882 &host->dma.nc_busaddr,
2883 GFP_KERNEL);
2884 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07002885 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07002886 return -ENOMEM;
2887 }
2888 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
2889 host->dma.cmd_busaddr = host->dma.nc_busaddr;
2890 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
2891 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
2892 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07002893 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07002894
2895 return 0;
2896}
2897
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002898#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
2899/**
2900 * Allocate and Connect a SDCC peripheral's SPS endpoint
2901 *
2902 * This function allocates endpoint context and
2903 * connect it with memory endpoint by calling
2904 * appropriate SPS driver APIs.
2905 *
2906 * Also registers a SPS callback function with
2907 * SPS driver
2908 *
2909 * This function should only be called once typically
2910 * during driver probe.
2911 *
2912 * @host - Pointer to sdcc host structure
2913 * @ep - Pointer to sps endpoint data structure
2914 * @is_produce - 1 means Producer endpoint
2915 * 0 means Consumer endpoint
2916 *
2917 * @return - 0 if successful else negative value.
2918 *
2919 */
2920static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
2921 struct msmsdcc_sps_ep_conn_data *ep,
2922 bool is_producer)
2923{
2924 int rc = 0;
2925 struct sps_pipe *sps_pipe_handle;
2926 struct sps_connect *sps_config = &ep->config;
2927 struct sps_register_event *sps_event = &ep->event;
2928
2929 /* Allocate endpoint context */
2930 sps_pipe_handle = sps_alloc_endpoint();
2931 if (!sps_pipe_handle) {
2932 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
2933 mmc_hostname(host->mmc), is_producer);
2934 rc = -ENOMEM;
2935 goto out;
2936 }
2937
2938 /* Get default connection configuration for an endpoint */
2939 rc = sps_get_config(sps_pipe_handle, sps_config);
2940 if (rc) {
2941 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
2942 " rc=%d", mmc_hostname(host->mmc),
2943 (u32)sps_pipe_handle, rc);
2944 goto get_config_err;
2945 }
2946
2947 /* Modify the default connection configuration */
2948 if (is_producer) {
2949 /*
2950 * For SDCC producer transfer, source should be
2951 * SDCC peripheral where as destination should
2952 * be system memory.
2953 */
2954 sps_config->source = host->sps.bam_handle;
2955 sps_config->destination = SPS_DEV_HANDLE_MEM;
2956 /* Producer pipe will handle this connection */
2957 sps_config->mode = SPS_MODE_SRC;
2958 sps_config->options =
2959 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
2960 } else {
2961 /*
2962 * For SDCC consumer transfer, source should be
2963 * system memory where as destination should
2964 * SDCC peripheral
2965 */
2966 sps_config->source = SPS_DEV_HANDLE_MEM;
2967 sps_config->destination = host->sps.bam_handle;
2968 sps_config->mode = SPS_MODE_DEST;
2969 sps_config->options =
2970 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
2971 }
2972
2973 /* Producer pipe index */
2974 sps_config->src_pipe_index = host->sps.src_pipe_index;
2975 /* Consumer pipe index */
2976 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
2977 /*
2978 * This event thresold value is only significant for BAM-to-BAM
2979 * transfer. It's ignored for BAM-to-System mode transfer.
2980 */
2981 sps_config->event_thresh = 0x10;
2982 /*
2983 * Max. no of scatter/gather buffers that can
2984 * be passed by block layer = 32 (NR_SG).
2985 * Each BAM descritor needs 64 bits (8 bytes).
2986 * One BAM descriptor is required per buffer transfer.
2987 * So we would require total 256 (32 * 8) bytes of descriptor FIFO.
2988 * But due to HW limitation we need to allocate atleast one extra
2989 * descriptor memory (256 bytes + 8 bytes). But in order to be
2990 * in power of 2, we are allocating 512 bytes of memory.
2991 */
2992 sps_config->desc.size = 512;
2993 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
2994 sps_config->desc.size,
2995 &sps_config->desc.phys_base,
2996 GFP_KERNEL);
2997
Pratibhasagar V00b94332011-10-18 14:57:27 +05302998 if (!sps_config->desc.base) {
2999 rc = -ENOMEM;
3000 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3001 , mmc_hostname(host->mmc));
3002 goto get_config_err;
3003 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003004 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3005
3006 /* Establish connection between peripheral and memory endpoint */
3007 rc = sps_connect(sps_pipe_handle, sps_config);
3008 if (rc) {
3009 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3010 " rc=%d", mmc_hostname(host->mmc),
3011 (u32)sps_pipe_handle, rc);
3012 goto sps_connect_err;
3013 }
3014
3015 sps_event->mode = SPS_TRIGGER_CALLBACK;
3016 sps_event->options = SPS_O_EOT;
3017 sps_event->callback = msmsdcc_sps_complete_cb;
3018 sps_event->xfer_done = NULL;
3019 sps_event->user = (void *)host;
3020
3021 /* Register callback event for EOT (End of transfer) event. */
3022 rc = sps_register_event(sps_pipe_handle, sps_event);
3023 if (rc) {
3024 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3025 " rc=%d", mmc_hostname(host->mmc),
3026 (u32)sps_pipe_handle, rc);
3027 goto reg_event_err;
3028 }
3029 /* Now save the sps pipe handle */
3030 ep->pipe_handle = sps_pipe_handle;
3031 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3032 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3033 __func__, is_producer ? "READ" : "WRITE",
3034 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3035 goto out;
3036
3037reg_event_err:
3038 sps_disconnect(sps_pipe_handle);
3039sps_connect_err:
3040 dma_free_coherent(mmc_dev(host->mmc),
3041 sps_config->desc.size,
3042 sps_config->desc.base,
3043 sps_config->desc.phys_base);
3044get_config_err:
3045 sps_free_endpoint(sps_pipe_handle);
3046out:
3047 return rc;
3048}
3049
3050/**
3051 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3052 *
3053 * This function disconnect endpoint and deallocates
3054 * endpoint context.
3055 *
3056 * This function should only be called once typically
3057 * during driver remove.
3058 *
3059 * @host - Pointer to sdcc host structure
3060 * @ep - Pointer to sps endpoint data structure
3061 *
3062 */
3063static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3064 struct msmsdcc_sps_ep_conn_data *ep)
3065{
3066 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3067 struct sps_connect *sps_config = &ep->config;
3068 struct sps_register_event *sps_event = &ep->event;
3069
3070 sps_event->xfer_done = NULL;
3071 sps_event->callback = NULL;
3072 sps_register_event(sps_pipe_handle, sps_event);
3073 sps_disconnect(sps_pipe_handle);
3074 dma_free_coherent(mmc_dev(host->mmc),
3075 sps_config->desc.size,
3076 sps_config->desc.base,
3077 sps_config->desc.phys_base);
3078 sps_free_endpoint(sps_pipe_handle);
3079}
3080
3081/**
3082 * Reset SDCC peripheral's SPS endpoint
3083 *
3084 * This function disconnects an endpoint.
3085 *
3086 * This function should be called for reseting
3087 * SPS endpoint when data transfer error is
3088 * encountered during data transfer. This
3089 * can be considered as soft reset to endpoint.
3090 *
3091 * This function should only be called if
3092 * msmsdcc_sps_init() is already called.
3093 *
3094 * @host - Pointer to sdcc host structure
3095 * @ep - Pointer to sps endpoint data structure
3096 *
3097 * @return - 0 if successful else negative value.
3098 */
3099static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3100 struct msmsdcc_sps_ep_conn_data *ep)
3101{
3102 int rc = 0;
3103 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3104
3105 rc = sps_disconnect(sps_pipe_handle);
3106 if (rc) {
3107 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3108 " rc=%d", mmc_hostname(host->mmc), __func__,
3109 (u32)sps_pipe_handle, rc);
3110 goto out;
3111 }
3112 out:
3113 return rc;
3114}
3115
3116/**
3117 * Restore SDCC peripheral's SPS endpoint
3118 *
3119 * This function connects an endpoint.
3120 *
3121 * This function should be called for restoring
3122 * SPS endpoint after data transfer error is
3123 * encountered during data transfer. This
3124 * can be considered as soft reset to endpoint.
3125 *
3126 * This function should only be called if
3127 * msmsdcc_sps_reset_ep() is called before.
3128 *
3129 * @host - Pointer to sdcc host structure
3130 * @ep - Pointer to sps endpoint data structure
3131 *
3132 * @return - 0 if successful else negative value.
3133 */
3134static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3135 struct msmsdcc_sps_ep_conn_data *ep)
3136{
3137 int rc = 0;
3138 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3139 struct sps_connect *sps_config = &ep->config;
3140 struct sps_register_event *sps_event = &ep->event;
3141
3142 /* Establish connection between peripheral and memory endpoint */
3143 rc = sps_connect(sps_pipe_handle, sps_config);
3144 if (rc) {
3145 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3146 " rc=%d", mmc_hostname(host->mmc), __func__,
3147 (u32)sps_pipe_handle, rc);
3148 goto out;
3149 }
3150
3151 /* Register callback event for EOT (End of transfer) event. */
3152 rc = sps_register_event(sps_pipe_handle, sps_event);
3153 if (rc) {
3154 pr_err("%s: %s: sps_register_event() failed!!!"
3155 " pipe_handle=0x%x, rc=%d",
3156 mmc_hostname(host->mmc), __func__,
3157 (u32)sps_pipe_handle, rc);
3158 goto reg_event_err;
3159 }
3160 goto out;
3161
3162reg_event_err:
3163 sps_disconnect(sps_pipe_handle);
3164out:
3165 return rc;
3166}
3167
3168/**
3169 * Initialize SPS HW connected with SDCC core
3170 *
3171 * This function register BAM HW resources with
3172 * SPS driver and then initialize 2 SPS endpoints
3173 *
3174 * This function should only be called once typically
3175 * during driver probe.
3176 *
3177 * @host - Pointer to sdcc host structure
3178 *
3179 * @return - 0 if successful else negative value.
3180 *
3181 */
3182static int msmsdcc_sps_init(struct msmsdcc_host *host)
3183{
3184 int rc = 0;
3185 struct sps_bam_props bam = {0};
3186
3187 host->bam_base = ioremap(host->bam_memres->start,
3188 resource_size(host->bam_memres));
3189 if (!host->bam_base) {
3190 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3191 " size=0x%x", mmc_hostname(host->mmc),
3192 host->bam_memres->start,
3193 (host->bam_memres->end -
3194 host->bam_memres->start));
3195 rc = -ENOMEM;
3196 goto out;
3197 }
3198
3199 bam.phys_addr = host->bam_memres->start;
3200 bam.virt_addr = host->bam_base;
3201 /*
3202 * This event thresold value is only significant for BAM-to-BAM
3203 * transfer. It's ignored for BAM-to-System mode transfer.
3204 */
3205 bam.event_threshold = 0x10; /* Pipe event threshold */
3206 /*
3207 * This threshold controls when the BAM publish
3208 * the descriptor size on the sideband interface.
3209 * SPS HW will only be used when
3210 * data transfer size > MCI_FIFOSIZE (64 bytes).
3211 * PIO mode will be used when
3212 * data transfer size < MCI_FIFOSIZE (64 bytes).
3213 * So set this thresold value to 64 bytes.
3214 */
3215 bam.summing_threshold = 64;
3216 /* SPS driver wll handle the SDCC BAM IRQ */
3217 bam.irq = (u32)host->bam_irqres->start;
3218 bam.manage = SPS_BAM_MGR_LOCAL;
3219
3220 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3221 (u32)bam.phys_addr);
3222 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3223 (u32)bam.virt_addr);
3224
3225 /* Register SDCC Peripheral BAM device to SPS driver */
3226 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3227 if (rc) {
3228 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3229 mmc_hostname(host->mmc), rc);
3230 goto reg_bam_err;
3231 }
3232 pr_info("%s: BAM device registered. bam_handle=0x%x",
3233 mmc_hostname(host->mmc), host->sps.bam_handle);
3234
3235 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3236 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3237
3238 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3239 SPS_PROD_PERIPHERAL);
3240 if (rc)
3241 goto sps_reset_err;
3242 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3243 SPS_CONS_PERIPHERAL);
3244 if (rc)
3245 goto cons_conn_err;
3246
3247 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3248 mmc_hostname(host->mmc),
3249 (unsigned long long)host->bam_memres->start,
3250 (unsigned int)host->bam_irqres->start);
3251 goto out;
3252
3253cons_conn_err:
3254 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3255sps_reset_err:
3256 sps_deregister_bam_device(host->sps.bam_handle);
3257reg_bam_err:
3258 iounmap(host->bam_base);
3259out:
3260 return rc;
3261}
3262
3263/**
3264 * De-initialize SPS HW connected with SDCC core
3265 *
3266 * This function deinitialize SPS endpoints and then
3267 * deregisters BAM resources from SPS driver.
3268 *
3269 * This function should only be called once typically
3270 * during driver remove.
3271 *
3272 * @host - Pointer to sdcc host structure
3273 *
3274 */
3275static void msmsdcc_sps_exit(struct msmsdcc_host *host)
3276{
3277 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
3278 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3279 sps_deregister_bam_device(host->sps.bam_handle);
3280 iounmap(host->bam_base);
3281}
3282#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
3283
3284static ssize_t
3285show_polling(struct device *dev, struct device_attribute *attr, char *buf)
3286{
3287 struct mmc_host *mmc = dev_get_drvdata(dev);
3288 struct msmsdcc_host *host = mmc_priv(mmc);
3289 int poll;
3290 unsigned long flags;
3291
3292 spin_lock_irqsave(&host->lock, flags);
3293 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
3294 spin_unlock_irqrestore(&host->lock, flags);
3295
3296 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
3297}
3298
3299static ssize_t
3300set_polling(struct device *dev, struct device_attribute *attr,
3301 const char *buf, size_t count)
3302{
3303 struct mmc_host *mmc = dev_get_drvdata(dev);
3304 struct msmsdcc_host *host = mmc_priv(mmc);
3305 int value;
3306 unsigned long flags;
3307
3308 sscanf(buf, "%d", &value);
3309
3310 spin_lock_irqsave(&host->lock, flags);
3311 if (value) {
3312 mmc->caps |= MMC_CAP_NEEDS_POLL;
3313 mmc_detect_change(host->mmc, 0);
3314 } else {
3315 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3316 }
3317#ifdef CONFIG_HAS_EARLYSUSPEND
3318 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
3319#endif
3320 spin_unlock_irqrestore(&host->lock, flags);
3321 return count;
3322}
3323
3324static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
3325 show_polling, set_polling);
3326static struct attribute *dev_attrs[] = {
3327 &dev_attr_polling.attr,
3328 NULL,
3329};
3330static struct attribute_group dev_attr_grp = {
3331 .attrs = dev_attrs,
3332};
3333
3334#ifdef CONFIG_HAS_EARLYSUSPEND
3335static void msmsdcc_early_suspend(struct early_suspend *h)
3336{
3337 struct msmsdcc_host *host =
3338 container_of(h, struct msmsdcc_host, early_suspend);
3339 unsigned long flags;
3340
3341 spin_lock_irqsave(&host->lock, flags);
3342 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
3343 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3344 spin_unlock_irqrestore(&host->lock, flags);
3345};
3346static void msmsdcc_late_resume(struct early_suspend *h)
3347{
3348 struct msmsdcc_host *host =
3349 container_of(h, struct msmsdcc_host, early_suspend);
3350 unsigned long flags;
3351
3352 if (host->polling_enabled) {
3353 spin_lock_irqsave(&host->lock, flags);
3354 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
3355 mmc_detect_change(host->mmc, 0);
3356 spin_unlock_irqrestore(&host->lock, flags);
3357 }
3358};
3359#endif
3360
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303361void msmsdcc_print_regs(const char *name, void __iomem *base,
3362 unsigned int no_of_regs)
3363{
3364 unsigned int i;
3365
3366 if (!base)
3367 return;
3368 pr_info("===== %s: Register Dumps @base=0x%x =====\n",
3369 name, (u32)base);
3370 for (i = 0; i < no_of_regs; i = i + 4) {
3371 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x.\n", i*4,
3372 (u32)readl_relaxed(base + i*4),
3373 (u32)readl_relaxed(base + ((i+1)*4)),
3374 (u32)readl_relaxed(base + ((i+2)*4)),
3375 (u32)readl_relaxed(base + ((i+3)*4)));
3376 }
3377}
3378
3379static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
3380{
3381 /* Dump current state of SDCC clocks, power and irq */
3382 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
3383 (host->pwr ? "ON" : "OFF"));
3384 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
3385 mmc_hostname(host->mmc),
3386 (host->clks_on ? "ON" : "OFF"),
3387 (u32)clk_get_rate(host->clk));
3388 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
3389 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
3390
3391 /* Now dump SDCC registers. Don't print FIFO registers */
3392 if (host->clks_on)
3393 msmsdcc_print_regs("SDCC-CORE", host->base, 28);
3394
3395 if (host->curr.data) {
3396 if (msmsdcc_check_dma_op_req(host->curr.data))
3397 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
3398 else if (host->is_dma_mode)
3399 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
3400 mmc_hostname(host->mmc), host->dma.busy,
3401 host->dma.channel, host->dma.crci);
3402 else if (host->is_sps_mode)
3403 pr_info("%s: SPS mode: busy=%d\n",
3404 mmc_hostname(host->mmc), host->sps.busy);
3405
3406 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
3407 mmc_hostname(host->mmc), host->curr.xfer_size,
3408 host->curr.data_xfered, host->curr.xfer_remain);
3409 pr_info("%s: got_dataend=%d, prog_enable=%d,"
3410 " wait_for_auto_prog_done=%d,"
3411 " got_auto_prog_done=%d\n",
3412 mmc_hostname(host->mmc), host->curr.got_dataend,
3413 host->prog_enable, host->curr.wait_for_auto_prog_done,
3414 host->curr.got_auto_prog_done);
3415 }
3416
3417}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003418static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
3419{
3420 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3421 struct mmc_request *mrq;
3422 unsigned long flags;
3423
3424 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003425 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003426 pr_info("%s: %s: dummy CMD52 timeout\n",
3427 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003428 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003429 }
3430
3431 mrq = host->curr.mrq;
3432
3433 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303434 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
3435 mrq->cmd->opcode);
3436 msmsdcc_dump_sdcc_state(host);
3437
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003438 if (!mrq->cmd->error)
3439 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303440 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003441 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003442 if (mrq->data && !mrq->data->error)
3443 mrq->data->error = -ETIMEDOUT;
3444 host->curr.data_xfered = 0;
3445 if (host->dma.sg && host->is_dma_mode) {
3446 msm_dmov_stop_cmd(host->dma.channel,
3447 &host->dma.hdr, 0);
3448 } else if (host->sps.sg && host->is_sps_mode) {
3449 /* Stop current SPS transfer */
3450 msmsdcc_sps_exit_curr_xfer(host);
3451 } else {
3452 msmsdcc_reset_and_restore(host);
3453 msmsdcc_stop_data(host);
3454 if (mrq->data && mrq->data->stop)
3455 msmsdcc_start_command(host,
3456 mrq->data->stop, 0);
3457 else
3458 msmsdcc_request_end(host, mrq);
3459 }
3460 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05303461 host->prog_enable = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003462 msmsdcc_reset_and_restore(host);
3463 msmsdcc_request_end(host, mrq);
3464 }
3465 }
3466 spin_unlock_irqrestore(&host->lock, flags);
3467}
3468
San Mehat9d2bd732009-09-22 16:44:22 -07003469static int
3470msmsdcc_probe(struct platform_device *pdev)
3471{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003472 struct mmc_platform_data *plat = pdev->dev.platform_data;
San Mehat9d2bd732009-09-22 16:44:22 -07003473 struct msmsdcc_host *host;
3474 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003475 unsigned long flags;
3476 struct resource *core_irqres = NULL;
3477 struct resource *bam_irqres = NULL;
3478 struct resource *core_memres = NULL;
3479 struct resource *dml_memres = NULL;
3480 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07003481 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07003482 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05303483 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003484 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07003485
3486 /* must have platform data */
3487 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003488 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003489 ret = -EINVAL;
3490 goto out;
3491 }
3492
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003493 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07003494 return -EINVAL;
3495
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003496 if (plat->is_sdio_al_client)
3497 if (!plat->sdio_lpm_gpio_setup || !plat->sdiowakeup_irq)
3498 return -EINVAL;
3499
San Mehat9d2bd732009-09-22 16:44:22 -07003500 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003501 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003502 return -ENXIO;
3503 }
3504
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003505 for (i = 0; i < pdev->num_resources; i++) {
3506 if (pdev->resource[i].flags & IORESOURCE_MEM) {
3507 if (!strcmp(pdev->resource[i].name,
3508 "sdcc_dml_addr"))
3509 dml_memres = &pdev->resource[i];
3510 else if (!strcmp(pdev->resource[i].name,
3511 "sdcc_bam_addr"))
3512 bam_memres = &pdev->resource[i];
3513 else
3514 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07003515
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003516 }
3517 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
3518 if (!strcmp(pdev->resource[i].name,
3519 "sdcc_bam_irq"))
3520 bam_irqres = &pdev->resource[i];
3521 else
3522 core_irqres = &pdev->resource[i];
3523 }
Krishna Konda25786ec2011-07-25 16:21:36 -07003524 if (pdev->resource[i].flags & IORESOURCE_DMA) {
3525 if (!strncmp(pdev->resource[i].name,
3526 "sdcc_dma_chnl",
3527 sizeof("sdcc_dma_chnl")))
3528 dmares = &pdev->resource[i];
3529 else if (!strncmp(pdev->resource[i].name,
3530 "sdcc_dma_crci",
3531 sizeof("sdcc_dma_crci")))
3532 dma_crci_res = &pdev->resource[i];
3533 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003534 }
3535
3536 if (!core_irqres || !core_memres) {
3537 pr_err("%s: Invalid sdcc core resource\n", __func__);
3538 return -ENXIO;
3539 }
3540
3541 /*
3542 * Both BAM and DML memory resource should be preset.
3543 * BAM IRQ resource should also be present.
3544 */
3545 if ((bam_memres && !dml_memres) ||
3546 (!bam_memres && dml_memres) ||
3547 ((bam_memres && dml_memres) && !bam_irqres)) {
3548 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003549 return -ENXIO;
3550 }
3551
3552 /*
3553 * Setup our host structure
3554 */
San Mehat9d2bd732009-09-22 16:44:22 -07003555 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
3556 if (!mmc) {
3557 ret = -ENOMEM;
3558 goto out;
3559 }
3560
3561 host = mmc_priv(mmc);
3562 host->pdev_id = pdev->id;
3563 host->plat = plat;
3564 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08003565 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05303566
3567 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003568 host->is_sps_mode = 1;
3569 else if (dmares)
3570 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07003571
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003572 host->base = ioremap(core_memres->start,
3573 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07003574 if (!host->base) {
3575 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003576 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003577 }
3578
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003579 host->core_irqres = core_irqres;
3580 host->bam_irqres = bam_irqres;
3581 host->core_memres = core_memres;
3582 host->dml_memres = dml_memres;
3583 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07003584 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07003585 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07003586 spin_lock_init(&host->lock);
3587
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003588#ifdef CONFIG_MMC_EMBEDDED_SDIO
3589 if (plat->embedded_sdio)
3590 mmc_set_embedded_sdio_data(mmc,
3591 &plat->embedded_sdio->cis,
3592 &plat->embedded_sdio->cccr,
3593 plat->embedded_sdio->funcs,
3594 plat->embedded_sdio->num_funcs);
3595#endif
3596
Sahitya Tummala62612cf2010-12-08 15:03:03 +05303597 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
3598 (unsigned long)host);
3599
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003600 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
3601 (unsigned long)host);
3602 if (host->is_dma_mode) {
3603 /* Setup DMA */
3604 ret = msmsdcc_init_dma(host);
3605 if (ret)
3606 goto ioremap_free;
3607 } else {
3608 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003609 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003610 }
3611
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003612 /*
3613 * Setup SDCC clock if derived from Dayatona
3614 * fabric core clock.
3615 */
3616 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07003617 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003618 if (!IS_ERR(host->dfab_pclk)) {
3619 /* Set the clock rate to 64MHz for max. performance */
3620 ret = clk_set_rate(host->dfab_pclk, 64000000);
3621 if (ret)
3622 goto dfab_pclk_put;
3623 ret = clk_enable(host->dfab_pclk);
3624 if (ret)
3625 goto dfab_pclk_put;
3626 } else
3627 goto dma_free;
3628 }
3629
3630 /*
3631 * Setup main peripheral bus clock
3632 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003633 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003634 if (!IS_ERR(host->pclk)) {
3635 ret = clk_enable(host->pclk);
3636 if (ret)
3637 goto pclk_put;
3638
3639 host->pclk_rate = clk_get_rate(host->pclk);
3640 }
3641
3642 /*
3643 * Setup SDC MMC clock
3644 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003645 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07003646 if (IS_ERR(host->clk)) {
3647 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003648 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07003649 }
3650
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003651 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
3652 if (ret) {
3653 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
3654 goto clk_put;
3655 }
3656
3657 ret = clk_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003658 if (ret)
3659 goto clk_put;
3660
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003661 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303662 if (!host->clk_rate)
3663 dev_err(&pdev->dev, "Failed to read MCLK\n");
3664 /*
3665 * Set the register write delay according to min. clock frequency
3666 * supported and update later when the host->clk_rate changes.
3667 */
3668 host->reg_write_delay =
3669 (1 + ((3 * USEC_PER_SEC) /
3670 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003671
3672 host->clks_on = 1;
3673
3674 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07003675 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003676 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07003677 goto clk_disable;
3678 }
3679
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003680
3681 /* Clocks has to be running before accessing SPS/DML HW blocks */
3682 if (host->is_sps_mode) {
3683 /* Initialize SPS */
3684 ret = msmsdcc_sps_init(host);
3685 if (ret)
3686 goto vreg_deinit;
3687 /* Initialize DML */
3688 ret = msmsdcc_dml_init(host);
3689 if (ret)
3690 goto sps_exit;
3691 }
San Mehat9d2bd732009-09-22 16:44:22 -07003692
San Mehat9d2bd732009-09-22 16:44:22 -07003693 /*
3694 * Setup MMC host structure
3695 */
3696 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003697 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
3698 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003699 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003700 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
3701 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07003702
San Mehat9d2bd732009-09-22 16:44:22 -07003703 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05303704 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05303705
3706 /*
3707 * If we send the CMD23 before multi block write/read command
3708 * then we need not to send CMD12 at the end of the transfer.
3709 * If we don't send the CMD12 then only way to detect the PROG_DONE
3710 * status is to use the AUTO_PROG_DONE status provided by SDCC4
3711 * controller. So let's enable the CMD23 for SDCC4 only.
3712 */
Sahitya Tummala85fa0702011-09-15 09:39:37 +05303713 if (!plat->disable_cmd23 && host->plat->sdcc_v4_sup)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05303714 mmc->caps |= MMC_CAP_CMD23;
3715
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003716 mmc->caps |= plat->uhs_caps;
3717 /*
3718 * XPC controls the maximum current in the default speed mode of SDXC
3719 * card. XPC=0 means 100mA (max.) but speed class is not supported.
3720 * XPC=1 means 150mA (max.) and speed class is supported.
3721 */
3722 if (plat->xpc_cap)
3723 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
3724 MMC_CAP_SET_XPC_180);
3725
3726 if (plat->nonremovable)
3727 mmc->caps |= MMC_CAP_NONREMOVABLE;
3728#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
3729 mmc->caps |= MMC_CAP_SDIO_IRQ;
3730#endif
3731
3732 if (plat->is_sdio_al_client)
3733 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07003734
Martin K. Petersena36274e2010-09-10 01:33:59 -04003735 mmc->max_segs = NR_SG;
San Mehat9d2bd732009-09-22 16:44:22 -07003736 mmc->max_blk_size = 4096; /* MCI_DATA_CTL BLOCKSIZE up to 4096 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003737 mmc->max_blk_count = 65535;
San Mehat9d2bd732009-09-22 16:44:22 -07003738
3739 mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */
3740 mmc->max_seg_size = mmc->max_req_size;
3741
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003742 writel_relaxed(0, host->base + MMCIMASK0);
3743 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -07003744
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003745 /* Delay needed (MMCIMASK0 was just written above) */
3746 msmsdcc_delay(host);
3747 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
3748 mb();
3749 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07003750
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003751 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
3752 DRIVER_NAME " (cmd)", host);
3753 if (ret)
3754 goto dml_exit;
3755
3756 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
3757 DRIVER_NAME " (pio)", host);
3758 if (ret)
3759 goto irq_free;
3760
3761 /*
3762 * Enable SDCC IRQ only when host is powered on. Otherwise, this
3763 * IRQ is un-necessarily being monitored by MPM (Modem power
3764 * management block) during idle-power collapse. The MPM will be
3765 * configured to monitor the DATA1 GPIO line with level-low trigger
3766 * and thus depending on the GPIO status, it prevents TCXO shutdown
3767 * during idle-power collapse.
3768 */
3769 disable_irq(core_irqres->start);
3770 host->sdcc_irq_disabled = 1;
3771
3772 if (plat->sdiowakeup_irq) {
3773 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3774 mmc_hostname(mmc));
3775 ret = request_irq(plat->sdiowakeup_irq,
3776 msmsdcc_platform_sdiowakeup_irq,
3777 IRQF_SHARED | IRQF_TRIGGER_LOW,
3778 DRIVER_NAME "sdiowakeup", host);
3779 if (ret) {
3780 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
3781 plat->sdiowakeup_irq, ret);
3782 goto pio_irq_free;
3783 } else {
3784 spin_lock_irqsave(&host->lock, flags);
3785 if (!host->sdio_irq_disabled) {
3786 disable_irq_nosync(plat->sdiowakeup_irq);
3787 host->sdio_irq_disabled = 1;
3788 }
3789 spin_unlock_irqrestore(&host->lock, flags);
3790 }
3791 }
3792
3793 if (plat->cfg_mpm_sdiowakeup) {
3794 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3795 mmc_hostname(mmc));
3796 }
3797
3798 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
3799 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003800 /*
3801 * Setup card detect change
3802 */
3803
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003804 if (plat->status || plat->status_gpio) {
3805 if (plat->status)
3806 host->oldstat = plat->status(mmc_dev(host->mmc));
3807 else
3808 host->oldstat = msmsdcc_slot_status(host);
3809 host->eject = !host->oldstat;
3810 }
San Mehat9d2bd732009-09-22 16:44:22 -07003811
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003812 if (plat->status_irq) {
3813 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07003814 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003815 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07003816 DRIVER_NAME " (slot)",
3817 host);
3818 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003819 pr_err("Unable to get slot IRQ %d (%d)\n",
3820 plat->status_irq, ret);
3821 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003822 }
3823 } else if (plat->register_status_notify) {
3824 plat->register_status_notify(msmsdcc_status_notify_cb, host);
3825 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003826 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07003827 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003828
3829 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003830
3831 ret = pm_runtime_set_active(&(pdev)->dev);
3832 if (ret < 0)
3833 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3834 __func__, ret);
3835 /*
3836 * There is no notion of suspend/resume for SD/MMC/SDIO
3837 * cards. So host can be suspended/resumed with out
3838 * worrying about its children.
3839 */
3840 pm_suspend_ignore_children(&(pdev)->dev, true);
3841
3842 /*
3843 * MMC/SD/SDIO bus suspend/resume operations are defined
3844 * only for the slots that will be used for non-removable
3845 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
3846 * defined. Otherwise, they simply become card removal and
3847 * insertion events during suspend and resume respectively.
3848 * Hence, enable run-time PM only for slots for which bus
3849 * suspend/resume operations are defined.
3850 */
3851#ifdef CONFIG_MMC_UNSAFE_RESUME
3852 /*
3853 * If this capability is set, MMC core will enable/disable host
3854 * for every claim/release operation on a host. We use this
3855 * notification to increment/decrement runtime pm usage count.
3856 */
3857 mmc->caps |= MMC_CAP_DISABLE;
3858 pm_runtime_enable(&(pdev)->dev);
3859#else
3860 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
3861 mmc->caps |= MMC_CAP_DISABLE;
3862 pm_runtime_enable(&(pdev)->dev);
3863 }
3864#endif
3865 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
3866 (unsigned long)host);
3867
San Mehat9d2bd732009-09-22 16:44:22 -07003868 mmc_add_host(mmc);
3869
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003870#ifdef CONFIG_HAS_EARLYSUSPEND
3871 host->early_suspend.suspend = msmsdcc_early_suspend;
3872 host->early_suspend.resume = msmsdcc_late_resume;
3873 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
3874 register_early_suspend(&host->early_suspend);
3875#endif
San Mehat9d2bd732009-09-22 16:44:22 -07003876
Krishna Konda25786ec2011-07-25 16:21:36 -07003877 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
3878 " dmacrcri %d\n", mmc_hostname(mmc),
3879 (unsigned long long)core_memres->start,
3880 (unsigned int) core_irqres->start,
3881 (unsigned int) plat->status_irq, host->dma.channel,
3882 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003883
3884 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
3885 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
3886 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
3887 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
3888 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
3889 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
3890 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
3891 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
3892 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
3893 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
3894 host->eject);
3895 pr_info("%s: Power save feature enable = %d\n",
3896 mmc_hostname(mmc), msmsdcc_pwrsave);
3897
Krishna Konda25786ec2011-07-25 16:21:36 -07003898 if (host->is_dma_mode && host->dma.channel != -1
3899 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003900 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003901 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003902 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003903 mmc_hostname(mmc), host->dma.cmd_busaddr,
3904 host->dma.cmdptr_busaddr);
3905 } else if (host->is_sps_mode) {
3906 pr_info("%s: SPS-BAM data transfer mode available\n",
3907 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003908 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003909 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003910
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003911#if defined(CONFIG_DEBUG_FS)
3912 msmsdcc_dbg_createhost(host);
3913#endif
3914 if (!plat->status_irq) {
3915 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
3916 if (ret)
3917 goto platform_irq_free;
3918 }
San Mehat9d2bd732009-09-22 16:44:22 -07003919 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003920
3921 platform_irq_free:
3922 del_timer_sync(&host->req_tout_timer);
3923 pm_runtime_disable(&(pdev)->dev);
3924 pm_runtime_set_suspended(&(pdev)->dev);
3925
3926 if (plat->status_irq)
3927 free_irq(plat->status_irq, host);
3928 sdiowakeup_irq_free:
3929 wake_lock_destroy(&host->sdio_suspend_wlock);
3930 if (plat->sdiowakeup_irq)
3931 free_irq(plat->sdiowakeup_irq, host);
3932 pio_irq_free:
3933 if (plat->sdiowakeup_irq)
3934 wake_lock_destroy(&host->sdio_wlock);
3935 free_irq(core_irqres->start, host);
3936 irq_free:
3937 free_irq(core_irqres->start, host);
3938 dml_exit:
3939 if (host->is_sps_mode)
3940 msmsdcc_dml_exit(host);
3941 sps_exit:
3942 if (host->is_sps_mode)
3943 msmsdcc_sps_exit(host);
3944 vreg_deinit:
3945 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07003946 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003947 clk_disable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003948 clk_put:
3949 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003950 pclk_disable:
3951 if (!IS_ERR(host->pclk))
3952 clk_disable(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07003953 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003954 if (!IS_ERR(host->pclk))
3955 clk_put(host->pclk);
3956 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3957 clk_disable(host->dfab_pclk);
3958 dfab_pclk_put:
3959 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3960 clk_put(host->dfab_pclk);
3961 dma_free:
3962 if (host->is_dma_mode) {
3963 if (host->dmares)
3964 dma_free_coherent(NULL,
3965 sizeof(struct msmsdcc_nc_dmadata),
3966 host->dma.nc, host->dma.nc_busaddr);
3967 }
3968 ioremap_free:
3969 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07003970 host_free:
3971 mmc_free_host(mmc);
3972 out:
3973 return ret;
3974}
3975
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003976static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07003977{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003978 struct mmc_host *mmc = mmc_get_drvdata(pdev);
3979 struct mmc_platform_data *plat;
3980 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07003981
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003982 if (!mmc)
3983 return -ENXIO;
3984
3985 if (pm_runtime_suspended(&(pdev)->dev))
3986 pm_runtime_resume(&(pdev)->dev);
3987
3988 host = mmc_priv(mmc);
3989
3990 DBG(host, "Removing SDCC device = %d\n", pdev->id);
3991 plat = host->plat;
3992
3993 if (!plat->status_irq)
3994 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
3995
3996 del_timer_sync(&host->req_tout_timer);
3997 tasklet_kill(&host->dma_tlet);
3998 tasklet_kill(&host->sps.tlet);
3999 mmc_remove_host(mmc);
4000
4001 if (plat->status_irq)
4002 free_irq(plat->status_irq, host);
4003
4004 wake_lock_destroy(&host->sdio_suspend_wlock);
4005 if (plat->sdiowakeup_irq) {
4006 wake_lock_destroy(&host->sdio_wlock);
4007 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
4008 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07004009 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004010
4011 free_irq(host->core_irqres->start, host);
4012 free_irq(host->core_irqres->start, host);
4013
4014 clk_put(host->clk);
4015 if (!IS_ERR(host->pclk))
4016 clk_put(host->pclk);
4017 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4018 clk_put(host->dfab_pclk);
4019
4020 msmsdcc_vreg_init(host, false);
4021
4022 if (host->is_dma_mode) {
4023 if (host->dmares)
4024 dma_free_coherent(NULL,
4025 sizeof(struct msmsdcc_nc_dmadata),
4026 host->dma.nc, host->dma.nc_busaddr);
4027 }
4028
4029 if (host->is_sps_mode) {
4030 msmsdcc_dml_exit(host);
4031 msmsdcc_sps_exit(host);
4032 }
4033
4034 iounmap(host->base);
4035 mmc_free_host(mmc);
4036
4037#ifdef CONFIG_HAS_EARLYSUSPEND
4038 unregister_early_suspend(&host->early_suspend);
4039#endif
4040 pm_runtime_disable(&(pdev)->dev);
4041 pm_runtime_set_suspended(&(pdev)->dev);
4042
4043 return 0;
4044}
4045
4046#ifdef CONFIG_MSM_SDIO_AL
4047int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4048{
4049 struct msmsdcc_host *host = mmc_priv(mmc);
4050 unsigned long flags;
4051
4052 spin_lock_irqsave(&host->lock, flags);
4053 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
4054 enable ? "En" : "Dis");
4055
4056 if (enable) {
4057 if (!host->sdcc_irq_disabled) {
4058 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05304059 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004060 host->sdcc_irq_disabled = 1;
4061 }
4062
4063 if (host->clks_on) {
4064 msmsdcc_setup_clocks(host, false);
4065 host->clks_on = 0;
4066 }
4067
4068 if (!host->sdio_gpio_lpm) {
4069 spin_unlock_irqrestore(&host->lock, flags);
4070 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
4071 spin_lock_irqsave(&host->lock, flags);
4072 host->sdio_gpio_lpm = 1;
4073 }
4074
4075 if (host->sdio_irq_disabled) {
4076 msmsdcc_enable_irq_wake(host);
4077 enable_irq(host->plat->sdiowakeup_irq);
4078 host->sdio_irq_disabled = 0;
4079 }
4080 } else {
4081 if (!host->sdio_irq_disabled) {
4082 disable_irq_nosync(host->plat->sdiowakeup_irq);
4083 host->sdio_irq_disabled = 1;
4084 msmsdcc_disable_irq_wake(host);
4085 }
4086
4087 if (host->sdio_gpio_lpm) {
4088 spin_unlock_irqrestore(&host->lock, flags);
4089 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
4090 spin_lock_irqsave(&host->lock, flags);
4091 host->sdio_gpio_lpm = 0;
4092 }
4093
4094 if (!host->clks_on) {
4095 msmsdcc_setup_clocks(host, true);
4096 host->clks_on = 1;
4097 }
4098
4099 if (host->sdcc_irq_disabled) {
4100 writel_relaxed(host->mci_irqenable,
4101 host->base + MMCIMASK0);
4102 mb();
4103 enable_irq(host->core_irqres->start);
4104 host->sdcc_irq_disabled = 0;
4105 }
4106 wake_lock_timeout(&host->sdio_wlock, 1);
4107 }
4108 spin_unlock_irqrestore(&host->lock, flags);
4109 return 0;
4110}
4111#else
4112int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4113{
4114 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004115}
4116#endif
4117
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004118#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07004119static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004120msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004121{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004122 struct mmc_host *mmc = dev_get_drvdata(dev);
4123 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07004124 int rc = 0;
4125
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004126 if (host->plat->is_sdio_al_client)
4127 return 0;
4128
Sahitya Tummala7661a452011-07-18 13:28:35 +05304129 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004130 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004131 host->sdcc_suspending = 1;
4132 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07004133
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004134 /*
4135 * If the clocks are already turned off by SDIO clients (as
4136 * part of LPM), then clocks should be turned on before
4137 * calling mmc_suspend_host() because mmc_suspend_host might
4138 * send some commands to the card. The clocks will be turned
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304139 * off again after mmc_suspend_host. Thus for SDIO
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004140 * cards, clocks will be turned on before mmc_suspend_host
4141 * and turned off after mmc_suspend_host.
4142 */
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304143 if (mmc->card && mmc_card_sdio(mmc->card)) {
4144 mmc->ios.clock = host->clk_rate;
4145 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4146 }
San Mehat9d2bd732009-09-22 16:44:22 -07004147
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004148 /*
4149 * MMC core thinks that host is disabled by now since
4150 * runtime suspend is scheduled after msmsdcc_disable()
4151 * is called. Thus, MMC core will try to enable the host
4152 * while suspending it. This results in a synchronous
4153 * runtime resume request while in runtime suspending
4154 * context and hence inorder to complete this resume
4155 * requet, it will wait for suspend to be complete,
4156 * but runtime suspend also can not proceed further
4157 * until the host is resumed. Thus, it leads to a hang.
4158 * Hence, increase the pm usage count before suspending
4159 * the host so that any resume requests after this will
4160 * simple become pm usage counter increment operations.
4161 */
4162 pm_runtime_get_noresume(dev);
4163 rc = mmc_suspend_host(mmc);
4164 pm_runtime_put_noidle(dev);
4165
4166 if (!rc) {
4167 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
4168 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ)) {
4169 disable_irq(host->core_irqres->start);
4170 host->sdcc_irq_disabled = 1;
4171
4172 /*
4173 * If MMC core level suspend is not supported,
4174 * turn off clocks to allow deep sleep (TCXO
4175 * shutdown).
4176 */
4177 mmc->ios.clock = 0;
4178 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4179 enable_irq(host->core_irqres->start);
4180 host->sdcc_irq_disabled = 0;
4181
4182 if (host->plat->sdiowakeup_irq) {
4183 host->sdio_irq_disabled = 0;
4184 msmsdcc_enable_irq_wake(host);
4185 enable_irq(host->plat->sdiowakeup_irq);
4186 }
4187 }
4188 }
4189 host->sdcc_suspending = 0;
4190 mmc->suspend_task = NULL;
4191 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
4192 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004193 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304194 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004195 return rc;
4196}
4197
4198static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004199msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004200{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004201 struct mmc_host *mmc = dev_get_drvdata(dev);
4202 struct msmsdcc_host *host = mmc_priv(mmc);
4203 unsigned long flags;
4204
4205 if (host->plat->is_sdio_al_client)
4206 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07004207
Sahitya Tummala7661a452011-07-18 13:28:35 +05304208 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004209 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004210 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
4211 if (host->sdcc_irq_disabled) {
4212 enable_irq(host->core_irqres->start);
4213 host->sdcc_irq_disabled = 0;
4214 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304215 mmc->ios.clock = host->clk_rate;
4216 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07004217
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304218 spin_lock_irqsave(&host->lock, flags);
4219 writel_relaxed(host->mci_irqenable,
4220 host->base + MMCIMASK0);
4221 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07004222
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304223 if ((mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) &&
4224 !host->sdio_irq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004225 if (host->plat->sdiowakeup_irq) {
4226 disable_irq_nosync(
4227 host->plat->sdiowakeup_irq);
4228 msmsdcc_disable_irq_wake(host);
4229 host->sdio_irq_disabled = 1;
4230 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304231 }
San Mehat9d2bd732009-09-22 16:44:22 -07004232
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304233 spin_unlock_irqrestore(&host->lock, flags);
4234 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004235
4236 mmc_resume_host(mmc);
4237
4238 /*
4239 * FIXME: Clearing of flags must be handled in clients
4240 * resume handler.
4241 */
4242 spin_lock_irqsave(&host->lock, flags);
4243 mmc->pm_flags = 0;
4244 spin_unlock_irqrestore(&host->lock, flags);
4245
4246 /*
4247 * After resuming the host wait for sometime so that
4248 * the SDIO work will be processed.
4249 */
4250 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO)) {
4251 if ((host->plat->cfg_mpm_sdiowakeup ||
4252 host->plat->sdiowakeup_irq) &&
4253 wake_lock_active(&host->sdio_wlock))
4254 wake_lock_timeout(&host->sdio_wlock, 1);
4255 }
4256
4257 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004258 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304259 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004260 return 0;
4261}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004262
4263static int msmsdcc_runtime_idle(struct device *dev)
4264{
4265 struct mmc_host *mmc = dev_get_drvdata(dev);
4266 struct msmsdcc_host *host = mmc_priv(mmc);
4267
4268 if (host->plat->is_sdio_al_client)
4269 return 0;
4270
4271 /* Idle timeout is not configurable for now */
4272 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
4273
4274 return -EAGAIN;
4275}
4276
4277static int msmsdcc_pm_suspend(struct device *dev)
4278{
4279 struct mmc_host *mmc = dev_get_drvdata(dev);
4280 struct msmsdcc_host *host = mmc_priv(mmc);
4281 int rc = 0;
4282
4283 if (host->plat->is_sdio_al_client)
4284 return 0;
4285
4286
4287 if (host->plat->status_irq)
4288 disable_irq(host->plat->status_irq);
4289
4290 if (!pm_runtime_suspended(dev))
4291 rc = msmsdcc_runtime_suspend(dev);
4292
4293 return rc;
4294}
4295
4296static int msmsdcc_pm_resume(struct device *dev)
4297{
4298 struct mmc_host *mmc = dev_get_drvdata(dev);
4299 struct msmsdcc_host *host = mmc_priv(mmc);
4300 int rc = 0;
4301
4302 if (host->plat->is_sdio_al_client)
4303 return 0;
4304
Sahitya Tummalafb486372011-09-02 19:01:49 +05304305 if (!pm_runtime_suspended(dev))
4306 rc = msmsdcc_runtime_resume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004307 if (host->plat->status_irq) {
4308 msmsdcc_check_status((unsigned long)host);
4309 enable_irq(host->plat->status_irq);
4310 }
4311
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004312 return rc;
4313}
4314
Daniel Walker08ecfde2010-06-23 12:32:20 -07004315#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004316#define msmsdcc_runtime_suspend NULL
4317#define msmsdcc_runtime_resume NULL
4318#define msmsdcc_runtime_idle NULL
4319#define msmsdcc_pm_suspend NULL
4320#define msmsdcc_pm_resume NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07004321#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004322
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004323static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
4324 .runtime_suspend = msmsdcc_runtime_suspend,
4325 .runtime_resume = msmsdcc_runtime_resume,
4326 .runtime_idle = msmsdcc_runtime_idle,
4327 .suspend = msmsdcc_pm_suspend,
4328 .resume = msmsdcc_pm_resume,
4329};
4330
San Mehat9d2bd732009-09-22 16:44:22 -07004331static struct platform_driver msmsdcc_driver = {
4332 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004333 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07004334 .driver = {
4335 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004336 .pm = &msmsdcc_dev_pm_ops,
San Mehat9d2bd732009-09-22 16:44:22 -07004337 },
4338};
4339
4340static int __init msmsdcc_init(void)
4341{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004342#if defined(CONFIG_DEBUG_FS)
4343 int ret = 0;
4344 ret = msmsdcc_dbg_init();
4345 if (ret) {
4346 pr_err("Failed to create debug fs dir \n");
4347 return ret;
4348 }
4349#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004350 return platform_driver_register(&msmsdcc_driver);
4351}
4352
4353static void __exit msmsdcc_exit(void)
4354{
4355 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004356
4357#if defined(CONFIG_DEBUG_FS)
4358 debugfs_remove(debugfs_file);
4359 debugfs_remove(debugfs_dir);
4360#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004361}
4362
4363module_init(msmsdcc_init);
4364module_exit(msmsdcc_exit);
4365
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004366MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07004367MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004368
4369#if defined(CONFIG_DEBUG_FS)
4370
4371static int
4372msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
4373{
4374 file->private_data = inode->i_private;
4375 return 0;
4376}
4377
4378static ssize_t
4379msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
4380 size_t count, loff_t *ppos)
4381{
4382 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
4383 char buf[1024];
4384 int max, i;
4385
4386 i = 0;
4387 max = sizeof(buf) - 1;
4388
4389 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
4390 host->curr.cmd, host->curr.data);
4391 if (host->curr.cmd) {
4392 struct mmc_command *cmd = host->curr.cmd;
4393
4394 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
4395 cmd->opcode, cmd->arg, cmd->flags);
4396 }
4397 if (host->curr.data) {
4398 struct mmc_data *data = host->curr.data;
4399 i += scnprintf(buf + i, max - i,
4400 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
4401 data->timeout_ns, data->timeout_clks,
4402 data->blksz, data->blocks, data->error,
4403 data->flags);
4404 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
4405 host->curr.xfer_size, host->curr.xfer_remain,
4406 host->curr.data_xfered, host->dma.sg);
4407 }
4408
4409 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
4410}
4411
4412static const struct file_operations msmsdcc_dbg_state_ops = {
4413 .read = msmsdcc_dbg_state_read,
4414 .open = msmsdcc_dbg_state_open,
4415};
4416
4417static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
4418{
4419 if (debugfs_dir) {
4420 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
4421 0644, debugfs_dir, host,
4422 &msmsdcc_dbg_state_ops);
4423 }
4424}
4425
4426static int __init msmsdcc_dbg_init(void)
4427{
4428 int err;
4429
4430 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
4431 if (IS_ERR(debugfs_dir)) {
4432 err = PTR_ERR(debugfs_dir);
4433 debugfs_dir = NULL;
4434 return err;
4435 }
4436
4437 return 0;
4438}
4439#endif