blob: 102b27dfb0c4d744bb3961063535a98a775a8485 [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
Sahitya Tummalad5137bd2010-12-08 15:03:04 +0530934 if (host->prog_scan && (cmd->opcode == 12)) {
935 *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;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301034 if ((data->flags & MMC_DATA_WRITE) && !host->curr.mrq->sbc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001035 host->prog_scan = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001036
1037 if (cmd) {
1038 msmsdcc_start_command_deferred(host, cmd, &c);
1039 host->cmd_c = c;
1040 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001041 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1042 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1043 host->base + MMCIMASK0);
1044 mb();
1045 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001046 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001047 /* SPS-BAM mode or PIO mode */
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301048 if ((data->flags & MMC_DATA_WRITE) && !host->curr.mrq->sbc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001049 host->prog_scan = 1;
1050 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001051
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001052 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001053
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001054 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1055 (~(MCI_IRQ_PIO))) | pio_irqmask,
1056 host->base + MMCIMASK0);
1057 msmsdcc_delay(host); /* Allow parms to be applied */
1058 writel_relaxed(datactrl, base + MMCIDATACTRL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001059
1060 if (cmd) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001061 msmsdcc_delay(host); /* Delay between data/command */
San Mehat56a8b5b2009-11-21 12:29:46 -08001062 /* Daisy-chain the command if requested */
1063 msmsdcc_start_command(host, cmd, c);
1064 }
San Mehat9d2bd732009-09-22 16:44:22 -07001065 }
1066}
1067
1068static void
1069msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1070{
San Mehat56a8b5b2009-11-21 12:29:46 -08001071 msmsdcc_start_command_deferred(host, cmd, &c);
1072 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001073}
1074
1075static void
1076msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1077 unsigned int status)
1078{
1079 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001080 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1081 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1082 pr_err("%s: Data CRC error\n",
1083 mmc_hostname(host->mmc));
1084 pr_err("%s: opcode 0x%.8x\n", __func__,
1085 data->mrq->cmd->opcode);
1086 pr_err("%s: blksz %d, blocks %d\n", __func__,
1087 data->blksz, data->blocks);
1088 data->error = -EILSEQ;
1089 }
San Mehat9d2bd732009-09-22 16:44:22 -07001090 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001091 /* CRC is optional for the bus test commands, not all
1092 * cards respond back with CRC. However controller
1093 * waits for the CRC and times out. Hence ignore the
1094 * data timeouts during the Bustest.
1095 */
1096 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1097 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1098 pr_err("%s: Data timeout\n",
1099 mmc_hostname(host->mmc));
1100 data->error = -ETIMEDOUT;
1101 }
San Mehat9d2bd732009-09-22 16:44:22 -07001102 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001103 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001104 data->error = -EIO;
1105 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001106 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001107 data->error = -EIO;
1108 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001109 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001110 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001111 data->error = -EIO;
1112 }
San Mehat9d2bd732009-09-22 16:44:22 -07001113
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001114 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001115 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001116 host->dummy_52_needed = 0;
1117}
San Mehat9d2bd732009-09-22 16:44:22 -07001118
1119static int
1120msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1121{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001122 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001123 uint32_t *ptr = (uint32_t *) buffer;
1124 int count = 0;
1125
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301126 if (remain % 4)
1127 remain = ((remain >> 2) + 1) << 2;
1128
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001129 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1130
1131 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001132 ptr++;
1133 count += sizeof(uint32_t);
1134
1135 remain -= sizeof(uint32_t);
1136 if (remain == 0)
1137 break;
1138 }
1139 return count;
1140}
1141
1142static int
1143msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001144 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001145{
1146 void __iomem *base = host->base;
1147 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001148 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001149
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001150 while (readl_relaxed(base + MMCISTATUS) &
1151 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1152 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001153
San Mehat9d2bd732009-09-22 16:44:22 -07001154 count = min(remain, maxcnt);
1155
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301156 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1157 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001158 ptr += count;
1159 remain -= count;
1160
1161 if (remain == 0)
1162 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001163 }
1164 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001165
1166 return ptr - buffer;
1167}
1168
San Mehat1cd22962010-02-03 12:59:29 -08001169static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001170msmsdcc_pio_irq(int irq, void *dev_id)
1171{
1172 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001173 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001174 uint32_t status;
1175
Murali Palnati36448a42011-09-02 15:06:18 +05301176 spin_lock(&host->lock);
1177
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001178 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001179
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001180 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301181 (MCI_IRQ_PIO)) == 0) {
1182 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001183 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301184 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001185
1186#if IRQ_DEBUG
1187 msmsdcc_print_status(host, "irq1-r", status);
1188#endif
1189
San Mehat9d2bd732009-09-22 16:44:22 -07001190 do {
1191 unsigned long flags;
1192 unsigned int remain, len;
1193 char *buffer;
1194
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001195 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1196 | MCI_RXDATAAVLBL)))
1197 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001198
1199 /* Map the current scatter buffer */
1200 local_irq_save(flags);
1201 buffer = kmap_atomic(sg_page(host->pio.sg),
1202 KM_BIO_SRC_IRQ) + host->pio.sg->offset;
1203 buffer += host->pio.sg_off;
1204 remain = host->pio.sg->length - host->pio.sg_off;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001205
San Mehat9d2bd732009-09-22 16:44:22 -07001206 len = 0;
1207 if (status & MCI_RXACTIVE)
1208 len = msmsdcc_pio_read(host, buffer, remain);
1209 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001210 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001211
1212 /* Unmap the buffer */
1213 kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
1214 local_irq_restore(flags);
1215
1216 host->pio.sg_off += len;
1217 host->curr.xfer_remain -= len;
1218 host->curr.data_xfered += len;
1219 remain -= len;
1220
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001221 if (remain) /* Done with this page? */
1222 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001223
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001224 if (status & MCI_RXACTIVE && host->curr.user_pages)
1225 flush_dcache_page(sg_page(host->pio.sg));
San Mehat9d2bd732009-09-22 16:44:22 -07001226
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001227 if (!--host->pio.sg_len) {
1228 memset(&host->pio, 0, sizeof(host->pio));
1229 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001230 }
1231
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001232 /* Advance to next sg */
1233 host->pio.sg++;
1234 host->pio.sg_off = 0;
1235
1236 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001237 } while (1);
1238
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001239 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1240 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1241 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1242 host->base + MMCIMASK0);
1243 if (!host->curr.xfer_remain) {
1244 /* Delay needed (same port was just written) */
1245 msmsdcc_delay(host);
1246 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1247 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1248 }
1249 mb();
1250 } else if (!host->curr.xfer_remain) {
1251 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1252 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1253 mb();
1254 }
San Mehat9d2bd732009-09-22 16:44:22 -07001255
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001256 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001257
1258 return IRQ_HANDLED;
1259}
1260
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001261static void
1262msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1263
1264static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1265 struct mmc_data *data)
1266{
1267 u32 loop_cnt = 0;
1268
1269 /*
1270 * For read commands with data less than fifo size, it is possible to
1271 * get DATAEND first and RXDATA_AVAIL might be set later because of
1272 * synchronization delay through the asynchronous RX FIFO. Thus, for
1273 * such cases, even after DATAEND interrupt is received software
1274 * should poll for RXDATA_AVAIL until the requested data is read out
1275 * of FIFO. This change is needed to get around this abnormal but
1276 * sometimes expected behavior of SDCC3 controller.
1277 *
1278 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1279 * after the data is loaded into RX FIFO. This would amount to less
1280 * than a microsecond and thus looping for 1000 times is good enough
1281 * for that delay.
1282 */
1283 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1284 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1285 spin_unlock(&host->lock);
1286 msmsdcc_pio_irq(1, host);
1287 spin_lock(&host->lock);
1288 }
1289 }
1290 if (loop_cnt == 1000) {
1291 pr_info("%s: Timed out while polling for Rx Data\n",
1292 mmc_hostname(host->mmc));
1293 data->error = -ETIMEDOUT;
1294 msmsdcc_reset_and_restore(host);
1295 }
1296}
1297
San Mehat9d2bd732009-09-22 16:44:22 -07001298static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1299{
1300 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001301
1302 host->curr.cmd = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001303 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1304 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1305 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1306 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -07001307
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001308 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Sahitya Tummala5a0ae912011-07-18 13:34:01 +05301309 pr_debug("%s: Command timeout\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001310 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001311 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
1312 !host->cmd19_tuning_in_progress) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001313 pr_err("%s: Command CRC error\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001314 cmd->error = -EILSEQ;
1315 }
1316
1317 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001318 if (host->curr.data && host->dma.sg &&
1319 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001320 msm_dmov_stop_cmd(host->dma.channel,
1321 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001322 else if (host->curr.data && host->sps.sg &&
1323 host->is_sps_mode){
1324 /* Stop current SPS transfer */
1325 msmsdcc_sps_exit_curr_xfer(host);
1326 }
San Mehat9d2bd732009-09-22 16:44:22 -07001327 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301328 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001329 msmsdcc_stop_data(host);
1330 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301331 } else { /* host->data == NULL */
1332 if (!cmd->error && host->prog_enable) {
1333 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001334 host->prog_scan = 0;
1335 host->prog_enable = 0;
1336 msmsdcc_request_end(host, cmd->mrq);
1337 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301338 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301339 } else {
1340 if (host->prog_enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001341 host->prog_scan = 0;
1342 host->prog_enable = 0;
1343 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001344 if (host->dummy_52_needed)
1345 host->dummy_52_needed = 0;
1346 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001347 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301348 msmsdcc_request_end(host, cmd->mrq);
1349 }
1350 }
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301351 } else if ((cmd == host->curr.mrq->sbc) && cmd->data) {
1352 if (cmd->data->flags & MMC_DATA_READ)
1353 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1354 else
1355 msmsdcc_request_start(host, host->curr.mrq);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001356 }
1357}
1358
San Mehat9d2bd732009-09-22 16:44:22 -07001359static irqreturn_t
1360msmsdcc_irq(int irq, void *dev_id)
1361{
1362 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001363 u32 status;
1364 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001365 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001366
1367 spin_lock(&host->lock);
1368
1369 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001370 struct mmc_command *cmd;
1371 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001372
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001373 if (timer) {
1374 timer = 0;
1375 msmsdcc_delay(host);
1376 }
San Mehat865c8062009-11-13 13:42:06 -08001377
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001378 if (!host->clks_on) {
1379 pr_debug("%s: %s: SDIO async irq received\n",
1380 mmc_hostname(host->mmc), __func__);
1381 host->mmc->ios.clock = host->clk_rate;
1382 spin_unlock(&host->lock);
1383 host->mmc->ops->set_ios(host->mmc, &host->mmc->ios);
1384 spin_lock(&host->lock);
1385 if (host->plat->cfg_mpm_sdiowakeup &&
1386 (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
1387 wake_lock(&host->sdio_wlock);
1388 /* only ansyc interrupt can come when clocks are off */
1389 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301390 if (host->clk_rate <=
1391 msmsdcc_get_min_sup_clk_rate(host))
1392 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001393 }
1394
1395 status = readl_relaxed(host->base + MMCISTATUS);
1396
1397 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1398 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001399 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001400
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001401#if IRQ_DEBUG
1402 msmsdcc_print_status(host, "irq0-r", status);
1403#endif
1404 status &= readl_relaxed(host->base + MMCIMASK0);
1405 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301406 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301407 if (host->clk_rate <=
1408 msmsdcc_get_min_sup_clk_rate(host))
1409 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001410#if IRQ_DEBUG
1411 msmsdcc_print_status(host, "irq0-p", status);
1412#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001413
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001414#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
1415 if (status & MCI_SDIOINTROPE) {
1416 if (host->sdcc_suspending)
1417 wake_lock(&host->sdio_suspend_wlock);
1418 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001419 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001420#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001421 data = host->curr.data;
1422
1423 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001424 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1425 MCI_CMDTIMEOUT)) {
1426 if (status & MCI_CMDTIMEOUT)
1427 pr_debug("%s: dummy CMD52 timeout\n",
1428 mmc_hostname(host->mmc));
1429 if (status & MCI_CMDCRCFAIL)
1430 pr_debug("%s: dummy CMD52 CRC failed\n",
1431 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001432 host->dummy_52_sent = 0;
1433 host->dummy_52_needed = 0;
1434 if (data) {
1435 msmsdcc_stop_data(host);
1436 msmsdcc_request_end(host, data->mrq);
1437 }
1438 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001439 spin_unlock(&host->lock);
1440 return IRQ_HANDLED;
1441 }
1442 break;
1443 }
1444
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001445 /*
1446 * Check for proper command response
1447 */
1448 cmd = host->curr.cmd;
1449 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1450 MCI_CMDTIMEOUT | MCI_PROGDONE |
1451 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1452 msmsdcc_do_cmdirq(host, status);
1453 }
1454
1455 if (data) {
1456 /* Check for data errors */
1457 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1458 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1459 msmsdcc_data_err(host, data, status);
1460 host->curr.data_xfered = 0;
1461 if (host->dma.sg && host->is_dma_mode)
1462 msm_dmov_stop_cmd(host->dma.channel,
1463 &host->dma.hdr, 0);
1464 else if (host->sps.sg && host->is_sps_mode) {
1465 /* Stop current SPS transfer */
1466 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301467 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001468 msmsdcc_reset_and_restore(host);
1469 if (host->curr.data)
1470 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301471 if (!data->stop || (host->curr.mrq->sbc
1472 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001473 timer |=
1474 msmsdcc_request_end(host,
1475 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301476 else if ((host->curr.mrq->sbc
1477 && data->error) ||
1478 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001479 msmsdcc_start_command(host,
1480 data->stop,
1481 0);
1482 timer = 1;
1483 }
1484 }
1485 }
1486
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301487 /* Check for prog done */
1488 if (host->curr.wait_for_auto_prog_done &&
1489 (status & MCI_PROGDONE))
1490 host->curr.got_auto_prog_done = 1;
1491
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001492 /* Check for data done */
1493 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1494 host->curr.got_dataend = 1;
1495
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301496 if (host->curr.got_dataend &&
1497 (!host->curr.wait_for_auto_prog_done ||
1498 (host->curr.wait_for_auto_prog_done &&
1499 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001500 /*
1501 * If DMA is still in progress, we complete
1502 * via the completion handler
1503 */
1504 if (!host->dma.busy && !host->sps.busy) {
1505 /*
1506 * There appears to be an issue in the
1507 * controller where if you request a
1508 * small block transfer (< fifo size),
1509 * you may get your DATAEND/DATABLKEND
1510 * irq without the PIO data irq.
1511 *
1512 * Check to see if theres still data
1513 * to be read, and simulate a PIO irq.
1514 */
1515 if (data->flags & MMC_DATA_READ)
1516 msmsdcc_wait_for_rxdata(host,
1517 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001518 if (!data->error) {
1519 host->curr.data_xfered =
1520 host->curr.xfer_size;
1521 host->curr.xfer_remain -=
1522 host->curr.xfer_size;
1523 }
1524
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001525 if (!host->dummy_52_needed) {
1526 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301527 if (!data->stop ||
1528 (host->curr.mrq->sbc
1529 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001530 msmsdcc_request_end(
1531 host,
1532 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301533 else if ((host->curr.mrq->sbc
1534 && data->error) ||
1535 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001536 msmsdcc_start_command(
1537 host,
1538 data->stop, 0);
1539 timer = 1;
1540 }
1541 } else {
1542 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001543 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001544 &dummy52cmd,
1545 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001546 }
1547 }
1548 }
1549 }
1550
San Mehat9d2bd732009-09-22 16:44:22 -07001551 ret = 1;
1552 } while (status);
1553
1554 spin_unlock(&host->lock);
1555
San Mehat9d2bd732009-09-22 16:44:22 -07001556 return IRQ_RETVAL(ret);
1557}
1558
1559static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001560msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1561{
Subhash Jadavanibbf38a32011-10-12 16:47:52 +05301562 if (mrq->data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001563 /* Queue/read data, daisy-chain command when data starts */
Subhash Jadavanibbf38a32011-10-12 16:47:52 +05301564 if (mrq->sbc && (mrq->data->flags & MMC_DATA_READ))
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301565 msmsdcc_start_data(host, mrq->data, mrq->sbc, 0);
1566 else
1567 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001568 } else {
1569 msmsdcc_start_command(host, mrq->cmd, 0);
1570 }
1571}
1572
1573static void
San Mehat9d2bd732009-09-22 16:44:22 -07001574msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1575{
1576 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001577 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001578
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001579 /*
1580 * Get the SDIO AL client out of LPM.
1581 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001582 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001583 if (host->plat->is_sdio_al_client)
1584 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001585
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301586 /* check if sps pipe reset is pending? */
1587 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1588 msmsdcc_sps_pipes_reset_and_restore(host);
1589 host->sps.pipe_reset_pending = false;
1590 }
1591
San Mehat9d2bd732009-09-22 16:44:22 -07001592 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001593 WARN(host->curr.mrq, "Request in progress\n");
1594 WARN(!host->pwr, "SDCC power is turned off\n");
1595 WARN(!host->clks_on, "SDCC clocks are turned off\n");
1596 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
San Mehat9d2bd732009-09-22 16:44:22 -07001597
1598 if (host->eject) {
1599 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1600 mrq->cmd->error = 0;
1601 mrq->data->bytes_xfered = mrq->data->blksz *
1602 mrq->data->blocks;
1603 } else
1604 mrq->cmd->error = -ENOMEDIUM;
1605
1606 spin_unlock_irqrestore(&host->lock, flags);
1607 mmc_request_done(mmc, mrq);
1608 return;
1609 }
1610
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301611 /*
1612 * Kick the software command timeout timer here.
1613 * Timer expires in 10 secs.
1614 */
1615 mod_timer(&host->req_tout_timer,
1616 (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
San Mehat9d2bd732009-09-22 16:44:22 -07001617
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301618 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301619 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301620 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
1621 mrq->cmd->opcode == 54) {
1622 if (!host->plat->sdcc_v4_sup)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001623 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301624 else
1625 /*
1626 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
1627 * write operations using CMD53 and CMD54.
1628 * Setting this bit with CMD53 would
1629 * automatically triggers PROG_DONE interrupt
1630 * without the need of sending dummy CMD52.
1631 */
1632 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001633 }
San Mehat9d2bd732009-09-22 16:44:22 -07001634 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301635
Pratibhasagar V00b94332011-10-18 14:57:27 +05301636 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301637 mrq->sbc->mrq = mrq;
1638 mrq->sbc->data = mrq->data;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301639 if (mrq->data->flags & MMC_DATA_WRITE) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301640 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301641 msmsdcc_start_command(host, mrq->sbc, 0);
1642 } else {
1643 msmsdcc_request_start(host, mrq);
1644 }
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301645 } else {
1646 msmsdcc_request_start(host, mrq);
1647 }
1648
San Mehat9d2bd732009-09-22 16:44:22 -07001649 spin_unlock_irqrestore(&host->lock, flags);
1650}
1651
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001652static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1653 int min_uV, int max_uV)
1654{
1655 int rc = 0;
1656
1657 if (vreg->set_voltage_sup) {
1658 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1659 if (rc) {
1660 pr_err("%s: regulator_set_voltage(%s) failed."
1661 " min_uV=%d, max_uV=%d, rc=%d\n",
1662 __func__, vreg->name, min_uV, max_uV, rc);
1663 }
1664 }
1665
1666 return rc;
1667}
1668
1669static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1670 int uA_load)
1671{
1672 int rc = 0;
1673
1674 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1675 if (rc < 0)
1676 pr_err("%s: regulator_set_optimum_mode(reg=%s, uA_load=%d)"
1677 " failed. rc=%d\n", __func__, vreg->name,
1678 uA_load, rc);
1679 else
1680 /* regulator_set_optimum_mode() can return non zero value
1681 * even for success case.
1682 */
1683 rc = 0;
1684
1685 return rc;
1686}
1687
1688static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1689 struct device *dev)
1690{
1691 int rc = 0;
1692
1693 /* check if regulator is already initialized? */
1694 if (vreg->reg)
1695 goto out;
1696
1697 /* Get the regulator handle */
1698 vreg->reg = regulator_get(dev, vreg->name);
1699 if (IS_ERR(vreg->reg)) {
1700 rc = PTR_ERR(vreg->reg);
1701 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
1702 __func__, vreg->name, rc);
1703 }
1704out:
1705 return rc;
1706}
1707
1708static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
1709{
1710 if (vreg->reg)
1711 regulator_put(vreg->reg);
1712}
1713
1714/* This init function should be called only once for each SDCC slot */
1715static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
1716{
1717 int rc = 0;
1718 struct msm_mmc_slot_reg_data *curr_slot;
1719 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1720 struct device *dev = mmc_dev(host->mmc);
1721
1722 curr_slot = host->plat->vreg_data;
1723 if (!curr_slot)
1724 goto out;
1725
1726 curr_vdd_reg = curr_slot->vdd_data;
1727 curr_vccq_reg = curr_slot->vccq_data;
1728 curr_vddp_reg = curr_slot->vddp_data;
1729
1730 if (is_init) {
1731 /*
1732 * Get the regulator handle from voltage regulator framework
1733 * and then try to set the voltage level for the regulator
1734 */
1735 if (curr_vdd_reg) {
1736 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
1737 if (rc)
1738 goto out;
1739 }
1740 if (curr_vccq_reg) {
1741 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
1742 if (rc)
1743 goto vdd_reg_deinit;
1744 }
1745 if (curr_vddp_reg) {
1746 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
1747 if (rc)
1748 goto vccq_reg_deinit;
1749 }
1750 goto out;
1751 } else {
1752 /* Deregister all regulators from regulator framework */
1753 goto vddp_reg_deinit;
1754 }
1755vddp_reg_deinit:
1756 if (curr_vddp_reg)
1757 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
1758vccq_reg_deinit:
1759 if (curr_vccq_reg)
1760 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
1761vdd_reg_deinit:
1762 if (curr_vdd_reg)
1763 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
1764out:
1765 return rc;
1766}
1767
1768static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
1769{
1770 int rc = 0;
1771
Subhash Jadavanicc922692011-08-01 23:05:01 +05301772 /* Put regulator in HPM (high power mode) */
1773 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
1774 if (rc < 0)
1775 goto out;
1776
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001777 if (!vreg->is_enabled) {
1778 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301779 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
1780 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001781 if (rc)
1782 goto out;
1783
1784 rc = regulator_enable(vreg->reg);
1785 if (rc) {
1786 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
1787 __func__, vreg->name, rc);
1788 goto out;
1789 }
1790 vreg->is_enabled = true;
1791 }
1792
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001793out:
1794 return rc;
1795}
1796
1797static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
1798{
1799 int rc = 0;
1800
1801 /* Never disable regulator marked as always_on */
1802 if (vreg->is_enabled && !vreg->always_on) {
1803 rc = regulator_disable(vreg->reg);
1804 if (rc) {
1805 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
1806 __func__, vreg->name, rc);
1807 goto out;
1808 }
1809 vreg->is_enabled = false;
1810
1811 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
1812 if (rc < 0)
1813 goto out;
1814
1815 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301816 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001817 if (rc)
1818 goto out;
1819 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
1820 /* Put always_on regulator in LPM (low power mode) */
1821 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
1822 if (rc < 0)
1823 goto out;
1824 }
1825out:
1826 return rc;
1827}
1828
1829static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
1830{
1831 int rc = 0, i;
1832 struct msm_mmc_slot_reg_data *curr_slot;
1833 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1834 struct msm_mmc_reg_data *vreg_table[3];
1835
1836 curr_slot = host->plat->vreg_data;
1837 if (!curr_slot)
1838 goto out;
1839
1840 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
1841 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
1842 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
1843
1844 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
1845 if (vreg_table[i]) {
1846 if (enable)
1847 rc = msmsdcc_vreg_enable(vreg_table[i]);
1848 else
1849 rc = msmsdcc_vreg_disable(vreg_table[i]);
1850 if (rc)
1851 goto out;
1852 }
1853 }
1854out:
1855 return rc;
1856}
1857
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301858static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001859{
1860 int rc = 0;
1861
1862 if (host->plat->vreg_data) {
1863 struct msm_mmc_reg_data *vddp_reg =
1864 host->plat->vreg_data->vddp_data;
1865
1866 if (vddp_reg && vddp_reg->is_enabled)
1867 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
1868 }
1869
1870 return rc;
1871}
1872
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301873static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
1874{
1875 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1876 int rc = 0;
1877
1878 if (curr_slot && curr_slot->vddp_data) {
1879 rc = msmsdcc_set_vddp_level(host,
1880 curr_slot->vddp_data->low_vol_level);
1881
1882 if (rc)
1883 pr_err("%s: %s: failed to change vddp level to %d",
1884 mmc_hostname(host->mmc), __func__,
1885 curr_slot->vddp_data->low_vol_level);
1886 }
1887
1888 return rc;
1889}
1890
1891static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
1892{
1893 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1894 int rc = 0;
1895
1896 if (curr_slot && curr_slot->vddp_data) {
1897 rc = msmsdcc_set_vddp_level(host,
1898 curr_slot->vddp_data->high_vol_level);
1899
1900 if (rc)
1901 pr_err("%s: %s: failed to change vddp level to %d",
1902 mmc_hostname(host->mmc), __func__,
1903 curr_slot->vddp_data->high_vol_level);
1904 }
1905
1906 return rc;
1907}
1908
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001909static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
1910{
1911 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
1912 return 1;
1913 return 0;
1914}
1915
1916static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
1917{
1918 if (enable) {
1919 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1920 clk_enable(host->dfab_pclk);
1921 if (!IS_ERR(host->pclk))
1922 clk_enable(host->pclk);
1923 clk_enable(host->clk);
1924 } else {
1925 clk_disable(host->clk);
1926 if (!IS_ERR(host->pclk))
1927 clk_disable(host->pclk);
1928 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1929 clk_disable(host->dfab_pclk);
1930 }
1931}
1932
1933static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
1934 unsigned int req_clk)
1935{
1936 unsigned int sel_clk = -1;
1937
1938 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
1939 unsigned char cnt;
1940
1941 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
1942 if (host->plat->sup_clk_table[cnt] > req_clk)
1943 break;
1944 else if (host->plat->sup_clk_table[cnt] == req_clk) {
1945 sel_clk = host->plat->sup_clk_table[cnt];
1946 break;
1947 } else
1948 sel_clk = host->plat->sup_clk_table[cnt];
1949 }
1950 } else {
1951 if ((req_clk < host->plat->msmsdcc_fmax) &&
1952 (req_clk > host->plat->msmsdcc_fmid))
1953 sel_clk = host->plat->msmsdcc_fmid;
1954 else
1955 sel_clk = req_clk;
1956 }
1957
1958 return sel_clk;
1959}
1960
1961static inline unsigned int msmsdcc_get_min_sup_clk_rate(
1962 struct msmsdcc_host *host)
1963{
1964 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
1965 return host->plat->sup_clk_table[0];
1966 else
1967 return host->plat->msmsdcc_fmin;
1968}
1969
1970static inline unsigned int msmsdcc_get_max_sup_clk_rate(
1971 struct msmsdcc_host *host)
1972{
1973 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
1974 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
1975 else
1976 return host->plat->msmsdcc_fmax;
1977}
1978
1979static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05301980{
1981 struct msm_mmc_gpio_data *curr;
1982 int i, rc = 0;
1983
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001984 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301985 for (i = 0; i < curr->size; i++) {
1986 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001987 if (curr->gpio[i].is_always_on &&
1988 curr->gpio[i].is_enabled)
1989 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301990 rc = gpio_request(curr->gpio[i].no,
1991 curr->gpio[i].name);
1992 if (rc) {
1993 pr_err("%s: gpio_request(%d, %s) failed %d\n",
1994 mmc_hostname(host->mmc),
1995 curr->gpio[i].no,
1996 curr->gpio[i].name, rc);
1997 goto free_gpios;
1998 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001999 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302000 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002001 if (curr->gpio[i].is_always_on)
2002 continue;
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;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302005 }
2006 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002007 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302008
2009free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002010 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302011 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002012 curr->gpio[i].is_enabled = false;
2013 }
2014out:
2015 return rc;
2016}
2017
2018static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2019{
2020 struct msm_mmc_pad_data *curr;
2021 int i;
2022
2023 curr = host->plat->pin_data->pad_data;
2024 for (i = 0; i < curr->drv->size; i++) {
2025 if (enable)
2026 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2027 curr->drv->on[i].val);
2028 else
2029 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2030 curr->drv->off[i].val);
2031 }
2032
2033 for (i = 0; i < curr->pull->size; i++) {
2034 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002035 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002036 curr->pull->on[i].val);
2037 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002038 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002039 curr->pull->off[i].val);
2040 }
2041
2042 return 0;
2043}
2044
2045static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2046{
2047 int rc = 0;
2048
2049 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2050 return 0;
2051
2052 if (host->plat->pin_data->is_gpio)
2053 rc = msmsdcc_setup_gpio(host, enable);
2054 else
2055 rc = msmsdcc_setup_pad(host, enable);
2056
2057 if (!rc)
2058 host->plat->pin_data->cfg_sts = enable;
2059
2060 return rc;
2061}
2062
2063static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2064{
2065 unsigned int wakeup_irq;
2066
2067 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2068 host->plat->sdiowakeup_irq :
2069 host->core_irqres->start;
2070
2071 if (!host->irq_wake_enabled) {
2072 enable_irq_wake(wakeup_irq);
2073 host->irq_wake_enabled = true;
2074 }
2075}
2076
2077static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2078{
2079 unsigned int wakeup_irq;
2080
2081 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2082 host->plat->sdiowakeup_irq :
2083 host->core_irqres->start;
2084
2085 if (host->irq_wake_enabled) {
2086 disable_irq_wake(wakeup_irq);
2087 host->irq_wake_enabled = false;
2088 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302089}
2090
San Mehat9d2bd732009-09-22 16:44:22 -07002091static void
2092msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2093{
2094 struct msmsdcc_host *host = mmc_priv(mmc);
2095 u32 clk = 0, pwr = 0;
2096 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002097 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002098 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002099
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002100 DBG(host, "ios->clock = %u\n", ios->clock);
Sahitya Tummala7a892482011-01-18 11:22:49 +05302101
San Mehat9d2bd732009-09-22 16:44:22 -07002102 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002103 spin_lock_irqsave(&host->lock, flags);
2104 if (!host->clks_on) {
2105 msmsdcc_setup_clocks(host, true);
2106 host->clks_on = 1;
2107 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2108 if (!host->plat->sdiowakeup_irq) {
2109 writel_relaxed(host->mci_irqenable,
2110 host->base + MMCIMASK0);
2111 mb();
2112 if (host->plat->cfg_mpm_sdiowakeup &&
2113 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2114 host->plat->cfg_mpm_sdiowakeup(
2115 mmc_dev(mmc), SDC_DAT1_DISWAKE);
2116 msmsdcc_disable_irq_wake(host);
2117 } else if (!(mmc->pm_flags &
2118 MMC_PM_WAKE_SDIO_IRQ)) {
2119 writel_relaxed(host->mci_irqenable,
2120 host->base + MMCIMASK0);
2121 }
2122 }
San Mehat9d2bd732009-09-22 16:44:22 -07002123 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002124 spin_unlock_irqrestore(&host->lock, flags);
2125
2126 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2127 /*
2128 * For DDR50 mode, controller needs clock rate to be
2129 * double than what is required on the SD card CLK pin.
2130 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302131 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002132 /*
2133 * Make sure that we don't double the clock if
2134 * doubled clock rate is already set
2135 */
2136 if (!host->ddr_doubled_clk_rate ||
2137 (host->ddr_doubled_clk_rate &&
2138 (host->ddr_doubled_clk_rate != ios->clock))) {
2139 host->ddr_doubled_clk_rate =
2140 msmsdcc_get_sup_clk_rate(
2141 host, (ios->clock * 2));
2142 clock = host->ddr_doubled_clk_rate;
2143 }
2144 } else {
2145 host->ddr_doubled_clk_rate = 0;
2146 }
2147
2148 if (clock != host->clk_rate) {
2149 rc = clk_set_rate(host->clk, clock);
2150 if (rc < 0)
2151 pr_debug("%s: failed to set clk rate %u\n",
2152 mmc_hostname(mmc), clock);
2153 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302154 host->reg_write_delay =
2155 (1 + ((3 * USEC_PER_SEC) /
2156 (host->clk_rate ? host->clk_rate :
2157 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002158 }
2159 /*
2160 * give atleast 2 MCLK cycles delay for clocks
2161 * and SDCC core to stabilize
2162 */
2163 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002164 clk |= MCI_CLK_ENABLE;
2165 }
2166
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002167 if (ios->bus_width == MMC_BUS_WIDTH_8)
2168 clk |= MCI_CLK_WIDEBUS_8;
2169 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2170 clk |= MCI_CLK_WIDEBUS_4;
2171 else
2172 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002173
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002174 if (msmsdcc_is_pwrsave(host))
2175 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002176
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002177 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002178
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002179 host->tuning_needed = 0;
2180 /*
2181 * Select the controller timing mode according
2182 * to current bus speed mode
2183 */
2184 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2185 (ios->timing == MMC_TIMING_UHS_SDR50)) {
2186 clk |= (4 << 14);
2187 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302188 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002189 clk |= (3 << 14);
2190 } else {
2191 clk |= (2 << 14); /* feedback clock */
2192 }
2193
2194 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2195 clk |= (2 << 23);
2196
2197 if (host->io_pad_pwr_switch)
2198 clk |= IO_PAD_PWR_SWITCH;
2199
2200 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
San Mehat9d2bd732009-09-22 16:44:22 -07002201 pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002202 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2203 pwr |= msmsdcc_setup_vreg(host, !!ios->vdd);
San Mehat9d2bd732009-09-22 16:44:22 -07002204
2205 switch (ios->power_mode) {
2206 case MMC_POWER_OFF:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002207 htc_pwrsink_set(PWRSINK_SDCARD, 0);
2208 if (!host->sdcc_irq_disabled) {
2209 if (host->plat->cfg_mpm_sdiowakeup)
2210 host->plat->cfg_mpm_sdiowakeup(
2211 mmc_dev(mmc), SDC_DAT1_DISABLE);
2212 disable_irq(host->core_irqres->start);
2213 host->sdcc_irq_disabled = 1;
2214 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302215 /*
2216 * As VDD pad rail is always on, set low voltage for VDD
2217 * pad rail when slot is unused (when card is not present
2218 * or during system suspend).
2219 */
2220 msmsdcc_set_vddp_low_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002221 msmsdcc_setup_pins(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002222 break;
2223 case MMC_POWER_UP:
2224 pwr |= MCI_PWR_UP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002225 if (host->sdcc_irq_disabled) {
2226 if (host->plat->cfg_mpm_sdiowakeup)
2227 host->plat->cfg_mpm_sdiowakeup(
2228 mmc_dev(mmc), SDC_DAT1_ENABLE);
2229 enable_irq(host->core_irqres->start);
2230 host->sdcc_irq_disabled = 0;
2231 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302232 msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002233 msmsdcc_setup_pins(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07002234 break;
2235 case MMC_POWER_ON:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002236 htc_pwrsink_set(PWRSINK_SDCARD, 100);
San Mehat9d2bd732009-09-22 16:44:22 -07002237 pwr |= MCI_PWR_ON;
2238 break;
2239 }
2240
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002241 spin_lock_irqsave(&host->lock, flags);
2242 if (!host->clks_on) {
2243 /* force the clocks to be on */
2244 msmsdcc_setup_clocks(host, true);
2245 /*
2246 * give atleast 2 MCLK cycles delay for clocks
2247 * and SDCC core to stabilize
2248 */
2249 msmsdcc_delay(host);
2250 }
2251 writel_relaxed(clk, host->base + MMCICLOCK);
2252 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002253
2254 if (host->pwr != pwr) {
2255 host->pwr = pwr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002256 writel_relaxed(pwr, host->base + MMCIPOWER);
2257 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07002258 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002259 if (!host->clks_on) {
2260 /* force the clocks to be off */
2261 msmsdcc_setup_clocks(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002262 }
2263
2264 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
2265 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2266 if (!host->plat->sdiowakeup_irq) {
2267 writel_relaxed(MCI_SDIOINTMASK,
2268 host->base + MMCIMASK0);
2269 mb();
2270 if (host->plat->cfg_mpm_sdiowakeup &&
2271 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2272 host->plat->cfg_mpm_sdiowakeup(
2273 mmc_dev(mmc), SDC_DAT1_ENWAKE);
2274 msmsdcc_enable_irq_wake(host);
2275 } else if (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2276 writel_relaxed(0, host->base + MMCIMASK0);
2277 } else {
2278 writel_relaxed(MCI_SDIOINTMASK,
2279 host->base + MMCIMASK0);
2280 }
2281 msmsdcc_delay(host);
2282 }
2283 msmsdcc_setup_clocks(host, false);
2284 host->clks_on = 0;
2285 }
San Mehat4adbbcc2009-11-08 13:00:37 -08002286 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002287}
2288
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002289int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2290{
2291 struct msmsdcc_host *host = mmc_priv(mmc);
2292 u32 clk;
2293
2294 clk = readl_relaxed(host->base + MMCICLOCK);
2295 pr_debug("Changing to pwr_save=%d", pwrsave);
2296 if (pwrsave && msmsdcc_is_pwrsave(host))
2297 clk |= MCI_CLK_PWRSAVE;
2298 else
2299 clk &= ~MCI_CLK_PWRSAVE;
2300 writel_relaxed(clk, host->base + MMCICLOCK);
2301 mb();
2302
2303 return 0;
2304}
2305
2306static int msmsdcc_get_ro(struct mmc_host *mmc)
2307{
2308 int status = -ENOSYS;
2309 struct msmsdcc_host *host = mmc_priv(mmc);
2310
2311 if (host->plat->wpswitch) {
2312 status = host->plat->wpswitch(mmc_dev(mmc));
2313 } else if (host->plat->wpswitch_gpio) {
2314 status = gpio_request(host->plat->wpswitch_gpio,
2315 "SD_WP_Switch");
2316 if (status) {
2317 pr_err("%s: %s: Failed to request GPIO %d\n",
2318 mmc_hostname(mmc), __func__,
2319 host->plat->wpswitch_gpio);
2320 } else {
2321 status = gpio_direction_input(
2322 host->plat->wpswitch_gpio);
2323 if (!status) {
2324 /*
2325 * Wait for atleast 300ms as debounce
2326 * time for GPIO input to stabilize.
2327 */
2328 msleep(300);
2329 status = gpio_get_value_cansleep(
2330 host->plat->wpswitch_gpio);
2331 status ^= !host->plat->wpswitch_polarity;
2332 }
2333 gpio_free(host->plat->wpswitch_gpio);
2334 }
2335 }
2336
2337 if (status < 0)
2338 status = -ENOSYS;
2339 pr_debug("%s: Card read-only status %d\n", __func__, status);
2340
2341 return status;
2342}
2343
2344#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002345static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2346{
2347 struct msmsdcc_host *host = mmc_priv(mmc);
2348 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002349
2350 if (enable) {
2351 spin_lock_irqsave(&host->lock, flags);
2352 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
2353 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
2354 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2355 spin_unlock_irqrestore(&host->lock, flags);
2356 } else {
2357 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
2358 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
2359 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2360 }
2361 mb();
2362}
2363#endif /* CONFIG_MMC_MSM_SDIO_SUPPORT */
2364
2365#ifdef CONFIG_PM_RUNTIME
2366static int msmsdcc_enable(struct mmc_host *mmc)
2367{
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302368 int rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002369 struct device *dev = mmc->parent;
2370
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302371 if (dev->power.runtime_status == RPM_SUSPENDING) {
2372 if (mmc->suspend_task == current) {
2373 pm_runtime_get_noresume(dev);
2374 goto out;
2375 }
2376 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002377
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302378 rc = pm_runtime_get_sync(dev);
2379
2380 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002381 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2382 __func__, rc);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302383 return rc;
2384 }
2385out:
2386 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002387}
2388
2389static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2390{
2391 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302392 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002393
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302394 if (host->plat->disable_runtime_pm)
2395 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002396 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO)
2397 return -ENOTSUPP;
2398
2399 rc = pm_runtime_put_sync(mmc->parent);
2400
2401 if (rc < 0)
2402 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2403 __func__, rc);
2404 return rc;
2405}
2406#else
2407#define msmsdcc_enable NULL
2408#define msmsdcc_disable NULL
2409#endif
2410
2411static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2412 struct mmc_ios *ios)
2413{
2414 struct msmsdcc_host *host = mmc_priv(mmc);
2415 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302416 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002417
2418 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2419 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302420 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002421 goto out;
2422 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2423 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302424 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002425 goto out;
2426 }
San Mehat9d2bd732009-09-22 16:44:22 -07002427
2428 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002429 /*
2430 * If we are here means voltage switch from high voltage to
2431 * low voltage is required
2432 */
2433
2434 /*
2435 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2436 * register until they become all zeros.
2437 */
2438 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302439 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002440 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2441 mmc_hostname(mmc), __func__);
2442 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002443 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002444
2445 /* Stop SD CLK output. */
2446 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2447 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2448
San Mehat9d2bd732009-09-22 16:44:22 -07002449 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002450
2451 /*
2452 * Switch VDDPX from high voltage to low voltage
2453 * to change the VDD of the SD IO pads.
2454 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302455 rc = msmsdcc_set_vddp_low_vol(host);
2456 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002457 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002458
2459 spin_lock_irqsave(&host->lock, flags);
2460 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2461 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
2462 host->io_pad_pwr_switch = 1;
2463 spin_unlock_irqrestore(&host->lock, flags);
2464
2465 /* Wait 5 ms for the voltage regulater in the card to become stable. */
2466 usleep_range(5000, 5500);
2467
2468 spin_lock_irqsave(&host->lock, flags);
2469 /* Start SD CLK output. */
2470 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2471 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2472 spin_unlock_irqrestore(&host->lock, flags);
2473
2474 /*
2475 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
2476 * don't become all ones within 1 ms then a Voltage Switch
2477 * sequence has failed and a power cycle to the card is required.
2478 * Otherwise Voltage Switch sequence is completed successfully.
2479 */
2480 usleep_range(1000, 1500);
2481
2482 spin_lock_irqsave(&host->lock, flags);
2483 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
2484 != (0xF << 1)) {
2485 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
2486 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302487 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002488 goto out_unlock;
2489 }
2490
2491out_unlock:
2492 spin_unlock_irqrestore(&host->lock, flags);
2493out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302494 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002495}
2496
2497static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2498 u8 phase);
2499/* Initialize the DLL (Programmable Delay Line ) */
2500static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
2501{
2502 int rc = 0;
2503 u32 wait_timeout;
2504
2505 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
2506 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2507 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2508
2509 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
2510 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2511 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2512
2513 msmsdcc_delay(host);
2514
2515 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
2516 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2517 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2518
2519 /* Initialize the phase to 0 */
2520 rc = msmsdcc_config_cm_sdc4_dll_phase(host, 0);
2521 if (rc)
2522 goto out;
2523
2524 wait_timeout = 1000;
2525 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
2526 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
2527 /* max. wait for 1 sec for LOCK bit to be set */
2528 if (--wait_timeout == 0) {
2529 pr_err("%s: %s: DLL failed to lock at phase: %d",
2530 mmc_hostname(host->mmc), __func__, 0);
2531 rc = -1;
2532 goto out;
2533 }
2534 /* wait for 1ms */
2535 usleep_range(1000, 1500);
2536 }
2537out:
2538 return rc;
2539}
2540
2541/*
2542 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
2543 * calibration sequence. This function should be called before
2544 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
2545 * commands (CMD17/CMD18).
2546 */
2547static void msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
2548{
2549 /* Set CDR_EN bit to 1. */
2550 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) |
2551 MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2552
2553 /* Set CDR_EXT_EN bit to 0. */
2554 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2555 & ~MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2556
2557 /* Set CK_OUT_EN bit to 0. */
2558 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2559 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2560
2561 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2562 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)
2563 ;
2564
2565 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2566 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2567 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2568
2569 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register is 1. */
2570 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN))
2571 ;
2572}
2573
2574static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2575 u8 phase)
2576{
2577 int rc = 0;
2578 u32 mclk_freq = 0;
2579 u32 wait_timeout;
2580
2581 /* Set CDR_EN bit to 0. */
2582 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2583 & ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2584
2585 /* Set CDR_EXT_EN bit to 1. */
2586 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2587 | MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2588
2589 /* Program the MCLK value to MCLK_FREQ bit field */
2590 if (host->clk_rate <= 112000000)
2591 mclk_freq = 0;
2592 else if (host->clk_rate <= 125000000)
2593 mclk_freq = 1;
2594 else if (host->clk_rate <= 137000000)
2595 mclk_freq = 2;
2596 else if (host->clk_rate <= 150000000)
2597 mclk_freq = 3;
2598 else if (host->clk_rate <= 162000000)
2599 mclk_freq = 4;
2600 else if (host->clk_rate <= 175000000)
2601 mclk_freq = 5;
2602 else if (host->clk_rate <= 187000000)
2603 mclk_freq = 6;
2604 else if (host->clk_rate <= 200000000)
2605 mclk_freq = 7;
2606
2607 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2608 & ~(7 << 24)) | (mclk_freq << 24)),
2609 host->base + MCI_DLL_CONFIG);
2610
2611 /* Set CK_OUT_EN bit to 0. */
2612 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2613 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2614
2615 /* Set DLL_EN bit to 1. */
2616 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2617 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
2618
2619 wait_timeout = 1000;
2620 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2621 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN) {
2622 /* max. wait for 1 sec for LOCK bit for be set */
2623 if (--wait_timeout == 0) {
2624 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 0",
2625 mmc_hostname(host->mmc), __func__, phase);
2626 rc = -1;
2627 goto out;
2628 }
2629 /* wait for 1ms */
2630 usleep_range(1000, 1500);
2631 }
2632
2633 /*
2634 * Write the selected DLL clock output phase (0 ... 15)
2635 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
2636 */
2637 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2638 & ~(0xF << 20)) | (phase << 20)),
2639 host->base + MCI_DLL_CONFIG);
2640
2641 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2642 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2643 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2644
2645 wait_timeout = 1000;
2646 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
2647 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)) {
2648 /* max. wait for 1 sec for LOCK bit for be set */
2649 if (--wait_timeout == 0) {
2650 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 1",
2651 mmc_hostname(host->mmc), __func__, phase);
2652 rc = -1;
2653 goto out;
2654 }
2655 /* wait for 1ms */
2656 usleep_range(1000, 1500);
2657 }
2658out:
2659 return rc;
2660}
2661
2662static int msmsdcc_execute_tuning(struct mmc_host *mmc)
2663{
2664 struct msmsdcc_host *host = mmc_priv(mmc);
2665 u8 phase;
2666 u8 *data_buf;
2667 u8 tuned_phases[16], tuned_phase_cnt = 0;
2668 int rc = 0;
2669
2670 /* Tuning is only required for SDR50 & SDR104 modes */
2671 if (!host->tuning_needed) {
2672 rc = 0;
2673 goto out;
2674 }
2675
2676 host->cmd19_tuning_in_progress = 1;
2677 /*
2678 * Make sure that clock is always enabled when DLL
2679 * tuning is in progress. Keeping PWRSAVE ON may
2680 * turn off the clock. So let's disable the PWRSAVE
2681 * here and re-enable it once tuning is completed.
2682 */
2683 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2684 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2685 /* first of all reset the tuning block */
2686 rc = msmsdcc_init_cm_sdc4_dll(host);
2687 if (rc)
2688 goto out;
2689
2690 data_buf = kmalloc(64, GFP_KERNEL);
2691 if (!data_buf) {
2692 rc = -ENOMEM;
2693 goto out;
2694 }
2695
2696 phase = 0;
2697 do {
2698 struct mmc_command cmd = {0};
2699 struct mmc_data data = {0};
2700 struct mmc_request mrq = {
2701 .cmd = &cmd,
2702 .data = &data
2703 };
2704 struct scatterlist sg;
2705
2706 /* set the phase in delay line hw block */
2707 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2708 if (rc)
2709 goto kfree;
2710
2711 cmd.opcode = MMC_SEND_TUNING_BLOCK;
2712 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
2713
2714 data.blksz = 64;
2715 data.blocks = 1;
2716 data.flags = MMC_DATA_READ;
2717 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
2718
2719 data.sg = &sg;
2720 data.sg_len = 1;
2721 sg_init_one(&sg, data_buf, 64);
2722 memset(data_buf, 0, 64);
2723 mmc_wait_for_req(mmc, &mrq);
2724
2725 if (!cmd.error && !data.error &&
2726 !memcmp(data_buf, cmd19_tuning_block, 64)) {
2727 /* tuning is successful with this tuning point */
2728 tuned_phases[tuned_phase_cnt++] = phase;
2729 }
2730 } while (++phase < 16);
2731
2732 kfree(data_buf);
2733
2734 if (tuned_phase_cnt) {
2735 tuned_phase_cnt--;
2736 tuned_phase_cnt = (tuned_phase_cnt * 3) / 4;
2737 phase = tuned_phases[tuned_phase_cnt];
2738 /*
2739 * Finally set the selected phase in delay
2740 * line hw block.
2741 */
2742 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2743 if (rc)
2744 goto out;
2745 } else {
2746 /* tuning failed */
2747 rc = -EAGAIN;
2748 pr_err("%s: %s: no tuning point found",
2749 mmc_hostname(mmc), __func__);
2750 }
2751 goto out;
2752
2753kfree:
2754 kfree(data_buf);
2755out:
2756 /* re-enable PWESAVE */
2757 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2758 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2759 host->cmd19_tuning_in_progress = 0;
2760 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07002761}
2762
2763static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002764 .enable = msmsdcc_enable,
2765 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07002766 .request = msmsdcc_request,
2767 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002768 .get_ro = msmsdcc_get_ro,
2769#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002770 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002771#endif
2772 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
2773 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07002774};
2775
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002776static unsigned int
2777msmsdcc_slot_status(struct msmsdcc_host *host)
2778{
2779 int status;
2780 unsigned int gpio_no = host->plat->status_gpio;
2781
2782 status = gpio_request(gpio_no, "SD_HW_Detect");
2783 if (status) {
2784 pr_err("%s: %s: Failed to request GPIO %d\n",
2785 mmc_hostname(host->mmc), __func__, gpio_no);
2786 } else {
2787 status = gpio_direction_input(gpio_no);
2788 if (!status)
2789 status = !gpio_get_value_cansleep(gpio_no);
2790 gpio_free(gpio_no);
2791 }
2792 return status;
2793}
2794
San Mehat9d2bd732009-09-22 16:44:22 -07002795static void
2796msmsdcc_check_status(unsigned long data)
2797{
2798 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
2799 unsigned int status;
2800
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002801 if (host->plat->status || host->plat->status_gpio) {
2802 if (host->plat->status)
2803 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07002804 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002805 status = msmsdcc_slot_status(host);
2806
2807 host->eject = !status;
2808 if (status ^ host->oldstat) {
2809 pr_info("%s: Slot status change detected (%d -> %d)\n",
2810 mmc_hostname(host->mmc), host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07002811 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002812 }
2813 host->oldstat = status;
2814 } else {
2815 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07002816 }
San Mehat9d2bd732009-09-22 16:44:22 -07002817}
2818
2819static irqreturn_t
2820msmsdcc_platform_status_irq(int irq, void *dev_id)
2821{
2822 struct msmsdcc_host *host = dev_id;
2823
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002824 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07002825 msmsdcc_check_status((unsigned long) host);
2826 return IRQ_HANDLED;
2827}
2828
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002829static irqreturn_t
2830msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
2831{
2832 struct msmsdcc_host *host = dev_id;
2833
2834 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
2835 spin_lock(&host->lock);
2836 if (!host->sdio_irq_disabled) {
2837 disable_irq_nosync(irq);
2838 if (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2839 wake_lock(&host->sdio_wlock);
2840 msmsdcc_disable_irq_wake(host);
2841 }
2842 host->sdio_irq_disabled = 1;
2843 }
2844 if (host->plat->is_sdio_al_client) {
2845 if (!host->clks_on) {
2846 msmsdcc_setup_clocks(host, true);
2847 host->clks_on = 1;
2848 }
2849 if (host->sdcc_irq_disabled) {
2850 writel_relaxed(host->mci_irqenable,
2851 host->base + MMCIMASK0);
2852 mb();
2853 enable_irq(host->core_irqres->start);
2854 host->sdcc_irq_disabled = 0;
2855 }
2856 wake_lock(&host->sdio_wlock);
2857 }
2858 spin_unlock(&host->lock);
2859
2860 return IRQ_HANDLED;
2861}
2862
San Mehat9d2bd732009-09-22 16:44:22 -07002863static void
2864msmsdcc_status_notify_cb(int card_present, void *dev_id)
2865{
2866 struct msmsdcc_host *host = dev_id;
2867
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002868 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07002869 card_present);
2870 msmsdcc_check_status((unsigned long) host);
2871}
2872
San Mehat9d2bd732009-09-22 16:44:22 -07002873static int
2874msmsdcc_init_dma(struct msmsdcc_host *host)
2875{
2876 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
2877 host->dma.host = host;
2878 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07002879 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07002880
2881 if (!host->dmares)
2882 return -ENODEV;
2883
2884 host->dma.nc = dma_alloc_coherent(NULL,
2885 sizeof(struct msmsdcc_nc_dmadata),
2886 &host->dma.nc_busaddr,
2887 GFP_KERNEL);
2888 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07002889 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07002890 return -ENOMEM;
2891 }
2892 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
2893 host->dma.cmd_busaddr = host->dma.nc_busaddr;
2894 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
2895 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
2896 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07002897 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07002898
2899 return 0;
2900}
2901
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002902#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
2903/**
2904 * Allocate and Connect a SDCC peripheral's SPS endpoint
2905 *
2906 * This function allocates endpoint context and
2907 * connect it with memory endpoint by calling
2908 * appropriate SPS driver APIs.
2909 *
2910 * Also registers a SPS callback function with
2911 * SPS driver
2912 *
2913 * This function should only be called once typically
2914 * during driver probe.
2915 *
2916 * @host - Pointer to sdcc host structure
2917 * @ep - Pointer to sps endpoint data structure
2918 * @is_produce - 1 means Producer endpoint
2919 * 0 means Consumer endpoint
2920 *
2921 * @return - 0 if successful else negative value.
2922 *
2923 */
2924static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
2925 struct msmsdcc_sps_ep_conn_data *ep,
2926 bool is_producer)
2927{
2928 int rc = 0;
2929 struct sps_pipe *sps_pipe_handle;
2930 struct sps_connect *sps_config = &ep->config;
2931 struct sps_register_event *sps_event = &ep->event;
2932
2933 /* Allocate endpoint context */
2934 sps_pipe_handle = sps_alloc_endpoint();
2935 if (!sps_pipe_handle) {
2936 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
2937 mmc_hostname(host->mmc), is_producer);
2938 rc = -ENOMEM;
2939 goto out;
2940 }
2941
2942 /* Get default connection configuration for an endpoint */
2943 rc = sps_get_config(sps_pipe_handle, sps_config);
2944 if (rc) {
2945 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
2946 " rc=%d", mmc_hostname(host->mmc),
2947 (u32)sps_pipe_handle, rc);
2948 goto get_config_err;
2949 }
2950
2951 /* Modify the default connection configuration */
2952 if (is_producer) {
2953 /*
2954 * For SDCC producer transfer, source should be
2955 * SDCC peripheral where as destination should
2956 * be system memory.
2957 */
2958 sps_config->source = host->sps.bam_handle;
2959 sps_config->destination = SPS_DEV_HANDLE_MEM;
2960 /* Producer pipe will handle this connection */
2961 sps_config->mode = SPS_MODE_SRC;
2962 sps_config->options =
2963 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
2964 } else {
2965 /*
2966 * For SDCC consumer transfer, source should be
2967 * system memory where as destination should
2968 * SDCC peripheral
2969 */
2970 sps_config->source = SPS_DEV_HANDLE_MEM;
2971 sps_config->destination = host->sps.bam_handle;
2972 sps_config->mode = SPS_MODE_DEST;
2973 sps_config->options =
2974 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
2975 }
2976
2977 /* Producer pipe index */
2978 sps_config->src_pipe_index = host->sps.src_pipe_index;
2979 /* Consumer pipe index */
2980 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
2981 /*
2982 * This event thresold value is only significant for BAM-to-BAM
2983 * transfer. It's ignored for BAM-to-System mode transfer.
2984 */
2985 sps_config->event_thresh = 0x10;
2986 /*
2987 * Max. no of scatter/gather buffers that can
2988 * be passed by block layer = 32 (NR_SG).
2989 * Each BAM descritor needs 64 bits (8 bytes).
2990 * One BAM descriptor is required per buffer transfer.
2991 * So we would require total 256 (32 * 8) bytes of descriptor FIFO.
2992 * But due to HW limitation we need to allocate atleast one extra
2993 * descriptor memory (256 bytes + 8 bytes). But in order to be
2994 * in power of 2, we are allocating 512 bytes of memory.
2995 */
2996 sps_config->desc.size = 512;
2997 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
2998 sps_config->desc.size,
2999 &sps_config->desc.phys_base,
3000 GFP_KERNEL);
3001
Pratibhasagar V00b94332011-10-18 14:57:27 +05303002 if (!sps_config->desc.base) {
3003 rc = -ENOMEM;
3004 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3005 , mmc_hostname(host->mmc));
3006 goto get_config_err;
3007 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003008 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3009
3010 /* Establish connection between peripheral and memory endpoint */
3011 rc = sps_connect(sps_pipe_handle, sps_config);
3012 if (rc) {
3013 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3014 " rc=%d", mmc_hostname(host->mmc),
3015 (u32)sps_pipe_handle, rc);
3016 goto sps_connect_err;
3017 }
3018
3019 sps_event->mode = SPS_TRIGGER_CALLBACK;
3020 sps_event->options = SPS_O_EOT;
3021 sps_event->callback = msmsdcc_sps_complete_cb;
3022 sps_event->xfer_done = NULL;
3023 sps_event->user = (void *)host;
3024
3025 /* Register callback event for EOT (End of transfer) event. */
3026 rc = sps_register_event(sps_pipe_handle, sps_event);
3027 if (rc) {
3028 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3029 " rc=%d", mmc_hostname(host->mmc),
3030 (u32)sps_pipe_handle, rc);
3031 goto reg_event_err;
3032 }
3033 /* Now save the sps pipe handle */
3034 ep->pipe_handle = sps_pipe_handle;
3035 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3036 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3037 __func__, is_producer ? "READ" : "WRITE",
3038 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3039 goto out;
3040
3041reg_event_err:
3042 sps_disconnect(sps_pipe_handle);
3043sps_connect_err:
3044 dma_free_coherent(mmc_dev(host->mmc),
3045 sps_config->desc.size,
3046 sps_config->desc.base,
3047 sps_config->desc.phys_base);
3048get_config_err:
3049 sps_free_endpoint(sps_pipe_handle);
3050out:
3051 return rc;
3052}
3053
3054/**
3055 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3056 *
3057 * This function disconnect endpoint and deallocates
3058 * endpoint context.
3059 *
3060 * This function should only be called once typically
3061 * during driver remove.
3062 *
3063 * @host - Pointer to sdcc host structure
3064 * @ep - Pointer to sps endpoint data structure
3065 *
3066 */
3067static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3068 struct msmsdcc_sps_ep_conn_data *ep)
3069{
3070 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3071 struct sps_connect *sps_config = &ep->config;
3072 struct sps_register_event *sps_event = &ep->event;
3073
3074 sps_event->xfer_done = NULL;
3075 sps_event->callback = NULL;
3076 sps_register_event(sps_pipe_handle, sps_event);
3077 sps_disconnect(sps_pipe_handle);
3078 dma_free_coherent(mmc_dev(host->mmc),
3079 sps_config->desc.size,
3080 sps_config->desc.base,
3081 sps_config->desc.phys_base);
3082 sps_free_endpoint(sps_pipe_handle);
3083}
3084
3085/**
3086 * Reset SDCC peripheral's SPS endpoint
3087 *
3088 * This function disconnects an endpoint.
3089 *
3090 * This function should be called for reseting
3091 * SPS endpoint when data transfer error is
3092 * encountered during data transfer. This
3093 * can be considered as soft reset to endpoint.
3094 *
3095 * This function should only be called if
3096 * msmsdcc_sps_init() is already called.
3097 *
3098 * @host - Pointer to sdcc host structure
3099 * @ep - Pointer to sps endpoint data structure
3100 *
3101 * @return - 0 if successful else negative value.
3102 */
3103static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3104 struct msmsdcc_sps_ep_conn_data *ep)
3105{
3106 int rc = 0;
3107 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3108
3109 rc = sps_disconnect(sps_pipe_handle);
3110 if (rc) {
3111 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3112 " rc=%d", mmc_hostname(host->mmc), __func__,
3113 (u32)sps_pipe_handle, rc);
3114 goto out;
3115 }
3116 out:
3117 return rc;
3118}
3119
3120/**
3121 * Restore SDCC peripheral's SPS endpoint
3122 *
3123 * This function connects an endpoint.
3124 *
3125 * This function should be called for restoring
3126 * SPS endpoint after data transfer error is
3127 * encountered during data transfer. This
3128 * can be considered as soft reset to endpoint.
3129 *
3130 * This function should only be called if
3131 * msmsdcc_sps_reset_ep() is called before.
3132 *
3133 * @host - Pointer to sdcc host structure
3134 * @ep - Pointer to sps endpoint data structure
3135 *
3136 * @return - 0 if successful else negative value.
3137 */
3138static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3139 struct msmsdcc_sps_ep_conn_data *ep)
3140{
3141 int rc = 0;
3142 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3143 struct sps_connect *sps_config = &ep->config;
3144 struct sps_register_event *sps_event = &ep->event;
3145
3146 /* Establish connection between peripheral and memory endpoint */
3147 rc = sps_connect(sps_pipe_handle, sps_config);
3148 if (rc) {
3149 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3150 " rc=%d", mmc_hostname(host->mmc), __func__,
3151 (u32)sps_pipe_handle, rc);
3152 goto out;
3153 }
3154
3155 /* Register callback event for EOT (End of transfer) event. */
3156 rc = sps_register_event(sps_pipe_handle, sps_event);
3157 if (rc) {
3158 pr_err("%s: %s: sps_register_event() failed!!!"
3159 " pipe_handle=0x%x, rc=%d",
3160 mmc_hostname(host->mmc), __func__,
3161 (u32)sps_pipe_handle, rc);
3162 goto reg_event_err;
3163 }
3164 goto out;
3165
3166reg_event_err:
3167 sps_disconnect(sps_pipe_handle);
3168out:
3169 return rc;
3170}
3171
3172/**
3173 * Initialize SPS HW connected with SDCC core
3174 *
3175 * This function register BAM HW resources with
3176 * SPS driver and then initialize 2 SPS endpoints
3177 *
3178 * This function should only be called once typically
3179 * during driver probe.
3180 *
3181 * @host - Pointer to sdcc host structure
3182 *
3183 * @return - 0 if successful else negative value.
3184 *
3185 */
3186static int msmsdcc_sps_init(struct msmsdcc_host *host)
3187{
3188 int rc = 0;
3189 struct sps_bam_props bam = {0};
3190
3191 host->bam_base = ioremap(host->bam_memres->start,
3192 resource_size(host->bam_memres));
3193 if (!host->bam_base) {
3194 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3195 " size=0x%x", mmc_hostname(host->mmc),
3196 host->bam_memres->start,
3197 (host->bam_memres->end -
3198 host->bam_memres->start));
3199 rc = -ENOMEM;
3200 goto out;
3201 }
3202
3203 bam.phys_addr = host->bam_memres->start;
3204 bam.virt_addr = host->bam_base;
3205 /*
3206 * This event thresold value is only significant for BAM-to-BAM
3207 * transfer. It's ignored for BAM-to-System mode transfer.
3208 */
3209 bam.event_threshold = 0x10; /* Pipe event threshold */
3210 /*
3211 * This threshold controls when the BAM publish
3212 * the descriptor size on the sideband interface.
3213 * SPS HW will only be used when
3214 * data transfer size > MCI_FIFOSIZE (64 bytes).
3215 * PIO mode will be used when
3216 * data transfer size < MCI_FIFOSIZE (64 bytes).
3217 * So set this thresold value to 64 bytes.
3218 */
3219 bam.summing_threshold = 64;
3220 /* SPS driver wll handle the SDCC BAM IRQ */
3221 bam.irq = (u32)host->bam_irqres->start;
3222 bam.manage = SPS_BAM_MGR_LOCAL;
3223
3224 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3225 (u32)bam.phys_addr);
3226 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3227 (u32)bam.virt_addr);
3228
3229 /* Register SDCC Peripheral BAM device to SPS driver */
3230 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3231 if (rc) {
3232 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3233 mmc_hostname(host->mmc), rc);
3234 goto reg_bam_err;
3235 }
3236 pr_info("%s: BAM device registered. bam_handle=0x%x",
3237 mmc_hostname(host->mmc), host->sps.bam_handle);
3238
3239 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3240 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3241
3242 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3243 SPS_PROD_PERIPHERAL);
3244 if (rc)
3245 goto sps_reset_err;
3246 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3247 SPS_CONS_PERIPHERAL);
3248 if (rc)
3249 goto cons_conn_err;
3250
3251 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3252 mmc_hostname(host->mmc),
3253 (unsigned long long)host->bam_memres->start,
3254 (unsigned int)host->bam_irqres->start);
3255 goto out;
3256
3257cons_conn_err:
3258 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3259sps_reset_err:
3260 sps_deregister_bam_device(host->sps.bam_handle);
3261reg_bam_err:
3262 iounmap(host->bam_base);
3263out:
3264 return rc;
3265}
3266
3267/**
3268 * De-initialize SPS HW connected with SDCC core
3269 *
3270 * This function deinitialize SPS endpoints and then
3271 * deregisters BAM resources from SPS driver.
3272 *
3273 * This function should only be called once typically
3274 * during driver remove.
3275 *
3276 * @host - Pointer to sdcc host structure
3277 *
3278 */
3279static void msmsdcc_sps_exit(struct msmsdcc_host *host)
3280{
3281 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
3282 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3283 sps_deregister_bam_device(host->sps.bam_handle);
3284 iounmap(host->bam_base);
3285}
3286#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
3287
3288static ssize_t
3289show_polling(struct device *dev, struct device_attribute *attr, char *buf)
3290{
3291 struct mmc_host *mmc = dev_get_drvdata(dev);
3292 struct msmsdcc_host *host = mmc_priv(mmc);
3293 int poll;
3294 unsigned long flags;
3295
3296 spin_lock_irqsave(&host->lock, flags);
3297 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
3298 spin_unlock_irqrestore(&host->lock, flags);
3299
3300 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
3301}
3302
3303static ssize_t
3304set_polling(struct device *dev, struct device_attribute *attr,
3305 const char *buf, size_t count)
3306{
3307 struct mmc_host *mmc = dev_get_drvdata(dev);
3308 struct msmsdcc_host *host = mmc_priv(mmc);
3309 int value;
3310 unsigned long flags;
3311
3312 sscanf(buf, "%d", &value);
3313
3314 spin_lock_irqsave(&host->lock, flags);
3315 if (value) {
3316 mmc->caps |= MMC_CAP_NEEDS_POLL;
3317 mmc_detect_change(host->mmc, 0);
3318 } else {
3319 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3320 }
3321#ifdef CONFIG_HAS_EARLYSUSPEND
3322 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
3323#endif
3324 spin_unlock_irqrestore(&host->lock, flags);
3325 return count;
3326}
3327
3328static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
3329 show_polling, set_polling);
3330static struct attribute *dev_attrs[] = {
3331 &dev_attr_polling.attr,
3332 NULL,
3333};
3334static struct attribute_group dev_attr_grp = {
3335 .attrs = dev_attrs,
3336};
3337
3338#ifdef CONFIG_HAS_EARLYSUSPEND
3339static void msmsdcc_early_suspend(struct early_suspend *h)
3340{
3341 struct msmsdcc_host *host =
3342 container_of(h, struct msmsdcc_host, early_suspend);
3343 unsigned long flags;
3344
3345 spin_lock_irqsave(&host->lock, flags);
3346 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
3347 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3348 spin_unlock_irqrestore(&host->lock, flags);
3349};
3350static void msmsdcc_late_resume(struct early_suspend *h)
3351{
3352 struct msmsdcc_host *host =
3353 container_of(h, struct msmsdcc_host, early_suspend);
3354 unsigned long flags;
3355
3356 if (host->polling_enabled) {
3357 spin_lock_irqsave(&host->lock, flags);
3358 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
3359 mmc_detect_change(host->mmc, 0);
3360 spin_unlock_irqrestore(&host->lock, flags);
3361 }
3362};
3363#endif
3364
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303365void msmsdcc_print_regs(const char *name, void __iomem *base,
3366 unsigned int no_of_regs)
3367{
3368 unsigned int i;
3369
3370 if (!base)
3371 return;
3372 pr_info("===== %s: Register Dumps @base=0x%x =====\n",
3373 name, (u32)base);
3374 for (i = 0; i < no_of_regs; i = i + 4) {
3375 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x.\n", i*4,
3376 (u32)readl_relaxed(base + i*4),
3377 (u32)readl_relaxed(base + ((i+1)*4)),
3378 (u32)readl_relaxed(base + ((i+2)*4)),
3379 (u32)readl_relaxed(base + ((i+3)*4)));
3380 }
3381}
3382
3383static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
3384{
3385 /* Dump current state of SDCC clocks, power and irq */
3386 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
3387 (host->pwr ? "ON" : "OFF"));
3388 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
3389 mmc_hostname(host->mmc),
3390 (host->clks_on ? "ON" : "OFF"),
3391 (u32)clk_get_rate(host->clk));
3392 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
3393 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
3394
3395 /* Now dump SDCC registers. Don't print FIFO registers */
3396 if (host->clks_on)
3397 msmsdcc_print_regs("SDCC-CORE", host->base, 28);
3398
3399 if (host->curr.data) {
3400 if (msmsdcc_check_dma_op_req(host->curr.data))
3401 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
3402 else if (host->is_dma_mode)
3403 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
3404 mmc_hostname(host->mmc), host->dma.busy,
3405 host->dma.channel, host->dma.crci);
3406 else if (host->is_sps_mode)
3407 pr_info("%s: SPS mode: busy=%d\n",
3408 mmc_hostname(host->mmc), host->sps.busy);
3409
3410 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
3411 mmc_hostname(host->mmc), host->curr.xfer_size,
3412 host->curr.data_xfered, host->curr.xfer_remain);
3413 pr_info("%s: got_dataend=%d, prog_enable=%d,"
3414 " wait_for_auto_prog_done=%d,"
3415 " got_auto_prog_done=%d\n",
3416 mmc_hostname(host->mmc), host->curr.got_dataend,
3417 host->prog_enable, host->curr.wait_for_auto_prog_done,
3418 host->curr.got_auto_prog_done);
3419 }
3420
3421}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003422static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
3423{
3424 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3425 struct mmc_request *mrq;
3426 unsigned long flags;
3427
3428 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003429 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003430 pr_info("%s: %s: dummy CMD52 timeout\n",
3431 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003432 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003433 }
3434
3435 mrq = host->curr.mrq;
3436
3437 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303438 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
3439 mrq->cmd->opcode);
3440 msmsdcc_dump_sdcc_state(host);
3441
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003442 if (!mrq->cmd->error)
3443 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303444 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003445 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003446 if (mrq->data && !mrq->data->error)
3447 mrq->data->error = -ETIMEDOUT;
3448 host->curr.data_xfered = 0;
3449 if (host->dma.sg && host->is_dma_mode) {
3450 msm_dmov_stop_cmd(host->dma.channel,
3451 &host->dma.hdr, 0);
3452 } else if (host->sps.sg && host->is_sps_mode) {
3453 /* Stop current SPS transfer */
3454 msmsdcc_sps_exit_curr_xfer(host);
3455 } else {
3456 msmsdcc_reset_and_restore(host);
3457 msmsdcc_stop_data(host);
3458 if (mrq->data && mrq->data->stop)
3459 msmsdcc_start_command(host,
3460 mrq->data->stop, 0);
3461 else
3462 msmsdcc_request_end(host, mrq);
3463 }
3464 } else {
3465 if (host->prog_enable) {
3466 host->prog_scan = 0;
3467 host->prog_enable = 0;
3468 }
3469 msmsdcc_reset_and_restore(host);
3470 msmsdcc_request_end(host, mrq);
3471 }
3472 }
3473 spin_unlock_irqrestore(&host->lock, flags);
3474}
3475
San Mehat9d2bd732009-09-22 16:44:22 -07003476static int
3477msmsdcc_probe(struct platform_device *pdev)
3478{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003479 struct mmc_platform_data *plat = pdev->dev.platform_data;
San Mehat9d2bd732009-09-22 16:44:22 -07003480 struct msmsdcc_host *host;
3481 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003482 unsigned long flags;
3483 struct resource *core_irqres = NULL;
3484 struct resource *bam_irqres = NULL;
3485 struct resource *core_memres = NULL;
3486 struct resource *dml_memres = NULL;
3487 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07003488 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07003489 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05303490 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003491 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07003492
3493 /* must have platform data */
3494 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003495 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003496 ret = -EINVAL;
3497 goto out;
3498 }
3499
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003500 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07003501 return -EINVAL;
3502
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003503 if (plat->is_sdio_al_client)
3504 if (!plat->sdio_lpm_gpio_setup || !plat->sdiowakeup_irq)
3505 return -EINVAL;
3506
San Mehat9d2bd732009-09-22 16:44:22 -07003507 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003508 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003509 return -ENXIO;
3510 }
3511
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003512 for (i = 0; i < pdev->num_resources; i++) {
3513 if (pdev->resource[i].flags & IORESOURCE_MEM) {
3514 if (!strcmp(pdev->resource[i].name,
3515 "sdcc_dml_addr"))
3516 dml_memres = &pdev->resource[i];
3517 else if (!strcmp(pdev->resource[i].name,
3518 "sdcc_bam_addr"))
3519 bam_memres = &pdev->resource[i];
3520 else
3521 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07003522
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003523 }
3524 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
3525 if (!strcmp(pdev->resource[i].name,
3526 "sdcc_bam_irq"))
3527 bam_irqres = &pdev->resource[i];
3528 else
3529 core_irqres = &pdev->resource[i];
3530 }
Krishna Konda25786ec2011-07-25 16:21:36 -07003531 if (pdev->resource[i].flags & IORESOURCE_DMA) {
3532 if (!strncmp(pdev->resource[i].name,
3533 "sdcc_dma_chnl",
3534 sizeof("sdcc_dma_chnl")))
3535 dmares = &pdev->resource[i];
3536 else if (!strncmp(pdev->resource[i].name,
3537 "sdcc_dma_crci",
3538 sizeof("sdcc_dma_crci")))
3539 dma_crci_res = &pdev->resource[i];
3540 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003541 }
3542
3543 if (!core_irqres || !core_memres) {
3544 pr_err("%s: Invalid sdcc core resource\n", __func__);
3545 return -ENXIO;
3546 }
3547
3548 /*
3549 * Both BAM and DML memory resource should be preset.
3550 * BAM IRQ resource should also be present.
3551 */
3552 if ((bam_memres && !dml_memres) ||
3553 (!bam_memres && dml_memres) ||
3554 ((bam_memres && dml_memres) && !bam_irqres)) {
3555 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003556 return -ENXIO;
3557 }
3558
3559 /*
3560 * Setup our host structure
3561 */
San Mehat9d2bd732009-09-22 16:44:22 -07003562 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
3563 if (!mmc) {
3564 ret = -ENOMEM;
3565 goto out;
3566 }
3567
3568 host = mmc_priv(mmc);
3569 host->pdev_id = pdev->id;
3570 host->plat = plat;
3571 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08003572 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05303573
3574 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003575 host->is_sps_mode = 1;
3576 else if (dmares)
3577 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07003578
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003579 host->base = ioremap(core_memres->start,
3580 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07003581 if (!host->base) {
3582 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003583 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003584 }
3585
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003586 host->core_irqres = core_irqres;
3587 host->bam_irqres = bam_irqres;
3588 host->core_memres = core_memres;
3589 host->dml_memres = dml_memres;
3590 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07003591 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07003592 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07003593 spin_lock_init(&host->lock);
3594
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003595#ifdef CONFIG_MMC_EMBEDDED_SDIO
3596 if (plat->embedded_sdio)
3597 mmc_set_embedded_sdio_data(mmc,
3598 &plat->embedded_sdio->cis,
3599 &plat->embedded_sdio->cccr,
3600 plat->embedded_sdio->funcs,
3601 plat->embedded_sdio->num_funcs);
3602#endif
3603
Sahitya Tummala62612cf2010-12-08 15:03:03 +05303604 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
3605 (unsigned long)host);
3606
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003607 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
3608 (unsigned long)host);
3609 if (host->is_dma_mode) {
3610 /* Setup DMA */
3611 ret = msmsdcc_init_dma(host);
3612 if (ret)
3613 goto ioremap_free;
3614 } else {
3615 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003616 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003617 }
3618
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003619 /*
3620 * Setup SDCC clock if derived from Dayatona
3621 * fabric core clock.
3622 */
3623 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07003624 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003625 if (!IS_ERR(host->dfab_pclk)) {
3626 /* Set the clock rate to 64MHz for max. performance */
3627 ret = clk_set_rate(host->dfab_pclk, 64000000);
3628 if (ret)
3629 goto dfab_pclk_put;
3630 ret = clk_enable(host->dfab_pclk);
3631 if (ret)
3632 goto dfab_pclk_put;
3633 } else
3634 goto dma_free;
3635 }
3636
3637 /*
3638 * Setup main peripheral bus clock
3639 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003640 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003641 if (!IS_ERR(host->pclk)) {
3642 ret = clk_enable(host->pclk);
3643 if (ret)
3644 goto pclk_put;
3645
3646 host->pclk_rate = clk_get_rate(host->pclk);
3647 }
3648
3649 /*
3650 * Setup SDC MMC clock
3651 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003652 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07003653 if (IS_ERR(host->clk)) {
3654 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003655 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07003656 }
3657
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003658 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
3659 if (ret) {
3660 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
3661 goto clk_put;
3662 }
3663
3664 ret = clk_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003665 if (ret)
3666 goto clk_put;
3667
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003668 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303669 if (!host->clk_rate)
3670 dev_err(&pdev->dev, "Failed to read MCLK\n");
3671 /*
3672 * Set the register write delay according to min. clock frequency
3673 * supported and update later when the host->clk_rate changes.
3674 */
3675 host->reg_write_delay =
3676 (1 + ((3 * USEC_PER_SEC) /
3677 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003678
3679 host->clks_on = 1;
3680
3681 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07003682 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003683 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07003684 goto clk_disable;
3685 }
3686
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003687
3688 /* Clocks has to be running before accessing SPS/DML HW blocks */
3689 if (host->is_sps_mode) {
3690 /* Initialize SPS */
3691 ret = msmsdcc_sps_init(host);
3692 if (ret)
3693 goto vreg_deinit;
3694 /* Initialize DML */
3695 ret = msmsdcc_dml_init(host);
3696 if (ret)
3697 goto sps_exit;
3698 }
San Mehat9d2bd732009-09-22 16:44:22 -07003699
San Mehat9d2bd732009-09-22 16:44:22 -07003700 /*
3701 * Setup MMC host structure
3702 */
3703 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003704 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
3705 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003706 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003707 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
3708 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07003709
San Mehat9d2bd732009-09-22 16:44:22 -07003710 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05303711
3712 /*
3713 * If we send the CMD23 before multi block write/read command
3714 * then we need not to send CMD12 at the end of the transfer.
3715 * If we don't send the CMD12 then only way to detect the PROG_DONE
3716 * status is to use the AUTO_PROG_DONE status provided by SDCC4
3717 * controller. So let's enable the CMD23 for SDCC4 only.
3718 */
Sahitya Tummala85fa0702011-09-15 09:39:37 +05303719 if (!plat->disable_cmd23 && host->plat->sdcc_v4_sup)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05303720 mmc->caps |= MMC_CAP_CMD23;
3721
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003722 mmc->caps |= plat->uhs_caps;
3723 /*
3724 * XPC controls the maximum current in the default speed mode of SDXC
3725 * card. XPC=0 means 100mA (max.) but speed class is not supported.
3726 * XPC=1 means 150mA (max.) and speed class is supported.
3727 */
3728 if (plat->xpc_cap)
3729 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
3730 MMC_CAP_SET_XPC_180);
3731
3732 if (plat->nonremovable)
3733 mmc->caps |= MMC_CAP_NONREMOVABLE;
3734#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
3735 mmc->caps |= MMC_CAP_SDIO_IRQ;
3736#endif
3737
3738 if (plat->is_sdio_al_client)
3739 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07003740
Martin K. Petersena36274e2010-09-10 01:33:59 -04003741 mmc->max_segs = NR_SG;
San Mehat9d2bd732009-09-22 16:44:22 -07003742 mmc->max_blk_size = 4096; /* MCI_DATA_CTL BLOCKSIZE up to 4096 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003743 mmc->max_blk_count = 65535;
San Mehat9d2bd732009-09-22 16:44:22 -07003744
3745 mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */
3746 mmc->max_seg_size = mmc->max_req_size;
3747
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003748 writel_relaxed(0, host->base + MMCIMASK0);
3749 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -07003750
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003751 /* Delay needed (MMCIMASK0 was just written above) */
3752 msmsdcc_delay(host);
3753 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
3754 mb();
3755 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07003756
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003757 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
3758 DRIVER_NAME " (cmd)", host);
3759 if (ret)
3760 goto dml_exit;
3761
3762 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
3763 DRIVER_NAME " (pio)", host);
3764 if (ret)
3765 goto irq_free;
3766
3767 /*
3768 * Enable SDCC IRQ only when host is powered on. Otherwise, this
3769 * IRQ is un-necessarily being monitored by MPM (Modem power
3770 * management block) during idle-power collapse. The MPM will be
3771 * configured to monitor the DATA1 GPIO line with level-low trigger
3772 * and thus depending on the GPIO status, it prevents TCXO shutdown
3773 * during idle-power collapse.
3774 */
3775 disable_irq(core_irqres->start);
3776 host->sdcc_irq_disabled = 1;
3777
3778 if (plat->sdiowakeup_irq) {
3779 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3780 mmc_hostname(mmc));
3781 ret = request_irq(plat->sdiowakeup_irq,
3782 msmsdcc_platform_sdiowakeup_irq,
3783 IRQF_SHARED | IRQF_TRIGGER_LOW,
3784 DRIVER_NAME "sdiowakeup", host);
3785 if (ret) {
3786 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
3787 plat->sdiowakeup_irq, ret);
3788 goto pio_irq_free;
3789 } else {
3790 spin_lock_irqsave(&host->lock, flags);
3791 if (!host->sdio_irq_disabled) {
3792 disable_irq_nosync(plat->sdiowakeup_irq);
3793 host->sdio_irq_disabled = 1;
3794 }
3795 spin_unlock_irqrestore(&host->lock, flags);
3796 }
3797 }
3798
3799 if (plat->cfg_mpm_sdiowakeup) {
3800 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3801 mmc_hostname(mmc));
3802 }
3803
3804 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
3805 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003806 /*
3807 * Setup card detect change
3808 */
3809
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003810 if (plat->status || plat->status_gpio) {
3811 if (plat->status)
3812 host->oldstat = plat->status(mmc_dev(host->mmc));
3813 else
3814 host->oldstat = msmsdcc_slot_status(host);
3815 host->eject = !host->oldstat;
3816 }
San Mehat9d2bd732009-09-22 16:44:22 -07003817
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003818 if (plat->status_irq) {
3819 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07003820 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003821 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07003822 DRIVER_NAME " (slot)",
3823 host);
3824 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003825 pr_err("Unable to get slot IRQ %d (%d)\n",
3826 plat->status_irq, ret);
3827 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003828 }
3829 } else if (plat->register_status_notify) {
3830 plat->register_status_notify(msmsdcc_status_notify_cb, host);
3831 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003832 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07003833 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003834
3835 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003836
3837 ret = pm_runtime_set_active(&(pdev)->dev);
3838 if (ret < 0)
3839 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3840 __func__, ret);
3841 /*
3842 * There is no notion of suspend/resume for SD/MMC/SDIO
3843 * cards. So host can be suspended/resumed with out
3844 * worrying about its children.
3845 */
3846 pm_suspend_ignore_children(&(pdev)->dev, true);
3847
3848 /*
3849 * MMC/SD/SDIO bus suspend/resume operations are defined
3850 * only for the slots that will be used for non-removable
3851 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
3852 * defined. Otherwise, they simply become card removal and
3853 * insertion events during suspend and resume respectively.
3854 * Hence, enable run-time PM only for slots for which bus
3855 * suspend/resume operations are defined.
3856 */
3857#ifdef CONFIG_MMC_UNSAFE_RESUME
3858 /*
3859 * If this capability is set, MMC core will enable/disable host
3860 * for every claim/release operation on a host. We use this
3861 * notification to increment/decrement runtime pm usage count.
3862 */
3863 mmc->caps |= MMC_CAP_DISABLE;
3864 pm_runtime_enable(&(pdev)->dev);
3865#else
3866 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
3867 mmc->caps |= MMC_CAP_DISABLE;
3868 pm_runtime_enable(&(pdev)->dev);
3869 }
3870#endif
3871 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
3872 (unsigned long)host);
3873
San Mehat9d2bd732009-09-22 16:44:22 -07003874 mmc_add_host(mmc);
3875
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003876#ifdef CONFIG_HAS_EARLYSUSPEND
3877 host->early_suspend.suspend = msmsdcc_early_suspend;
3878 host->early_suspend.resume = msmsdcc_late_resume;
3879 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
3880 register_early_suspend(&host->early_suspend);
3881#endif
San Mehat9d2bd732009-09-22 16:44:22 -07003882
Krishna Konda25786ec2011-07-25 16:21:36 -07003883 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
3884 " dmacrcri %d\n", mmc_hostname(mmc),
3885 (unsigned long long)core_memres->start,
3886 (unsigned int) core_irqres->start,
3887 (unsigned int) plat->status_irq, host->dma.channel,
3888 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003889
3890 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
3891 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
3892 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
3893 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
3894 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
3895 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
3896 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
3897 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
3898 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
3899 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
3900 host->eject);
3901 pr_info("%s: Power save feature enable = %d\n",
3902 mmc_hostname(mmc), msmsdcc_pwrsave);
3903
Krishna Konda25786ec2011-07-25 16:21:36 -07003904 if (host->is_dma_mode && host->dma.channel != -1
3905 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003906 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003907 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003908 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003909 mmc_hostname(mmc), host->dma.cmd_busaddr,
3910 host->dma.cmdptr_busaddr);
3911 } else if (host->is_sps_mode) {
3912 pr_info("%s: SPS-BAM data transfer mode available\n",
3913 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003914 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003915 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003916
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003917#if defined(CONFIG_DEBUG_FS)
3918 msmsdcc_dbg_createhost(host);
3919#endif
3920 if (!plat->status_irq) {
3921 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
3922 if (ret)
3923 goto platform_irq_free;
3924 }
San Mehat9d2bd732009-09-22 16:44:22 -07003925 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003926
3927 platform_irq_free:
3928 del_timer_sync(&host->req_tout_timer);
3929 pm_runtime_disable(&(pdev)->dev);
3930 pm_runtime_set_suspended(&(pdev)->dev);
3931
3932 if (plat->status_irq)
3933 free_irq(plat->status_irq, host);
3934 sdiowakeup_irq_free:
3935 wake_lock_destroy(&host->sdio_suspend_wlock);
3936 if (plat->sdiowakeup_irq)
3937 free_irq(plat->sdiowakeup_irq, host);
3938 pio_irq_free:
3939 if (plat->sdiowakeup_irq)
3940 wake_lock_destroy(&host->sdio_wlock);
3941 free_irq(core_irqres->start, host);
3942 irq_free:
3943 free_irq(core_irqres->start, host);
3944 dml_exit:
3945 if (host->is_sps_mode)
3946 msmsdcc_dml_exit(host);
3947 sps_exit:
3948 if (host->is_sps_mode)
3949 msmsdcc_sps_exit(host);
3950 vreg_deinit:
3951 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07003952 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003953 clk_disable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003954 clk_put:
3955 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003956 pclk_disable:
3957 if (!IS_ERR(host->pclk))
3958 clk_disable(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07003959 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003960 if (!IS_ERR(host->pclk))
3961 clk_put(host->pclk);
3962 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3963 clk_disable(host->dfab_pclk);
3964 dfab_pclk_put:
3965 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3966 clk_put(host->dfab_pclk);
3967 dma_free:
3968 if (host->is_dma_mode) {
3969 if (host->dmares)
3970 dma_free_coherent(NULL,
3971 sizeof(struct msmsdcc_nc_dmadata),
3972 host->dma.nc, host->dma.nc_busaddr);
3973 }
3974 ioremap_free:
3975 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07003976 host_free:
3977 mmc_free_host(mmc);
3978 out:
3979 return ret;
3980}
3981
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003982static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07003983{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003984 struct mmc_host *mmc = mmc_get_drvdata(pdev);
3985 struct mmc_platform_data *plat;
3986 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07003987
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003988 if (!mmc)
3989 return -ENXIO;
3990
3991 if (pm_runtime_suspended(&(pdev)->dev))
3992 pm_runtime_resume(&(pdev)->dev);
3993
3994 host = mmc_priv(mmc);
3995
3996 DBG(host, "Removing SDCC device = %d\n", pdev->id);
3997 plat = host->plat;
3998
3999 if (!plat->status_irq)
4000 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
4001
4002 del_timer_sync(&host->req_tout_timer);
4003 tasklet_kill(&host->dma_tlet);
4004 tasklet_kill(&host->sps.tlet);
4005 mmc_remove_host(mmc);
4006
4007 if (plat->status_irq)
4008 free_irq(plat->status_irq, host);
4009
4010 wake_lock_destroy(&host->sdio_suspend_wlock);
4011 if (plat->sdiowakeup_irq) {
4012 wake_lock_destroy(&host->sdio_wlock);
4013 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
4014 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07004015 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004016
4017 free_irq(host->core_irqres->start, host);
4018 free_irq(host->core_irqres->start, host);
4019
4020 clk_put(host->clk);
4021 if (!IS_ERR(host->pclk))
4022 clk_put(host->pclk);
4023 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4024 clk_put(host->dfab_pclk);
4025
4026 msmsdcc_vreg_init(host, false);
4027
4028 if (host->is_dma_mode) {
4029 if (host->dmares)
4030 dma_free_coherent(NULL,
4031 sizeof(struct msmsdcc_nc_dmadata),
4032 host->dma.nc, host->dma.nc_busaddr);
4033 }
4034
4035 if (host->is_sps_mode) {
4036 msmsdcc_dml_exit(host);
4037 msmsdcc_sps_exit(host);
4038 }
4039
4040 iounmap(host->base);
4041 mmc_free_host(mmc);
4042
4043#ifdef CONFIG_HAS_EARLYSUSPEND
4044 unregister_early_suspend(&host->early_suspend);
4045#endif
4046 pm_runtime_disable(&(pdev)->dev);
4047 pm_runtime_set_suspended(&(pdev)->dev);
4048
4049 return 0;
4050}
4051
4052#ifdef CONFIG_MSM_SDIO_AL
4053int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4054{
4055 struct msmsdcc_host *host = mmc_priv(mmc);
4056 unsigned long flags;
4057
4058 spin_lock_irqsave(&host->lock, flags);
4059 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
4060 enable ? "En" : "Dis");
4061
4062 if (enable) {
4063 if (!host->sdcc_irq_disabled) {
4064 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05304065 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004066 host->sdcc_irq_disabled = 1;
4067 }
4068
4069 if (host->clks_on) {
4070 msmsdcc_setup_clocks(host, false);
4071 host->clks_on = 0;
4072 }
4073
4074 if (!host->sdio_gpio_lpm) {
4075 spin_unlock_irqrestore(&host->lock, flags);
4076 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
4077 spin_lock_irqsave(&host->lock, flags);
4078 host->sdio_gpio_lpm = 1;
4079 }
4080
4081 if (host->sdio_irq_disabled) {
4082 msmsdcc_enable_irq_wake(host);
4083 enable_irq(host->plat->sdiowakeup_irq);
4084 host->sdio_irq_disabled = 0;
4085 }
4086 } else {
4087 if (!host->sdio_irq_disabled) {
4088 disable_irq_nosync(host->plat->sdiowakeup_irq);
4089 host->sdio_irq_disabled = 1;
4090 msmsdcc_disable_irq_wake(host);
4091 }
4092
4093 if (host->sdio_gpio_lpm) {
4094 spin_unlock_irqrestore(&host->lock, flags);
4095 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
4096 spin_lock_irqsave(&host->lock, flags);
4097 host->sdio_gpio_lpm = 0;
4098 }
4099
4100 if (!host->clks_on) {
4101 msmsdcc_setup_clocks(host, true);
4102 host->clks_on = 1;
4103 }
4104
4105 if (host->sdcc_irq_disabled) {
4106 writel_relaxed(host->mci_irqenable,
4107 host->base + MMCIMASK0);
4108 mb();
4109 enable_irq(host->core_irqres->start);
4110 host->sdcc_irq_disabled = 0;
4111 }
4112 wake_lock_timeout(&host->sdio_wlock, 1);
4113 }
4114 spin_unlock_irqrestore(&host->lock, flags);
4115 return 0;
4116}
4117#else
4118int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4119{
4120 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004121}
4122#endif
4123
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004124#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07004125static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004126msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004127{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004128 struct mmc_host *mmc = dev_get_drvdata(dev);
4129 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07004130 int rc = 0;
4131
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004132 if (host->plat->is_sdio_al_client)
4133 return 0;
4134
Sahitya Tummala7661a452011-07-18 13:28:35 +05304135 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004136 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004137 host->sdcc_suspending = 1;
4138 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07004139
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004140 /*
4141 * If the clocks are already turned off by SDIO clients (as
4142 * part of LPM), then clocks should be turned on before
4143 * calling mmc_suspend_host() because mmc_suspend_host might
4144 * send some commands to the card. The clocks will be turned
4145 * off again after mmc_suspend_host. Thus for SD/MMC/SDIO
4146 * cards, clocks will be turned on before mmc_suspend_host
4147 * and turned off after mmc_suspend_host.
4148 */
4149 mmc->ios.clock = host->clk_rate;
4150 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07004151
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004152 /*
4153 * MMC core thinks that host is disabled by now since
4154 * runtime suspend is scheduled after msmsdcc_disable()
4155 * is called. Thus, MMC core will try to enable the host
4156 * while suspending it. This results in a synchronous
4157 * runtime resume request while in runtime suspending
4158 * context and hence inorder to complete this resume
4159 * requet, it will wait for suspend to be complete,
4160 * but runtime suspend also can not proceed further
4161 * until the host is resumed. Thus, it leads to a hang.
4162 * Hence, increase the pm usage count before suspending
4163 * the host so that any resume requests after this will
4164 * simple become pm usage counter increment operations.
4165 */
4166 pm_runtime_get_noresume(dev);
4167 rc = mmc_suspend_host(mmc);
4168 pm_runtime_put_noidle(dev);
4169
4170 if (!rc) {
4171 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
4172 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ)) {
4173 disable_irq(host->core_irqres->start);
4174 host->sdcc_irq_disabled = 1;
4175
4176 /*
4177 * If MMC core level suspend is not supported,
4178 * turn off clocks to allow deep sleep (TCXO
4179 * shutdown).
4180 */
4181 mmc->ios.clock = 0;
4182 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4183 enable_irq(host->core_irqres->start);
4184 host->sdcc_irq_disabled = 0;
4185
4186 if (host->plat->sdiowakeup_irq) {
4187 host->sdio_irq_disabled = 0;
4188 msmsdcc_enable_irq_wake(host);
4189 enable_irq(host->plat->sdiowakeup_irq);
4190 }
4191 }
4192 }
4193 host->sdcc_suspending = 0;
4194 mmc->suspend_task = NULL;
4195 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
4196 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004197 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304198 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004199 return rc;
4200}
4201
4202static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004203msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004204{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004205 struct mmc_host *mmc = dev_get_drvdata(dev);
4206 struct msmsdcc_host *host = mmc_priv(mmc);
4207 unsigned long flags;
4208
4209 if (host->plat->is_sdio_al_client)
4210 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07004211
Sahitya Tummala7661a452011-07-18 13:28:35 +05304212 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004213 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004214 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
4215 if (host->sdcc_irq_disabled) {
4216 enable_irq(host->core_irqres->start);
4217 host->sdcc_irq_disabled = 0;
4218 }
4219 }
4220 mmc->ios.clock = host->clk_rate;
4221 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07004222
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004223 spin_lock_irqsave(&host->lock, flags);
4224 writel_relaxed(host->mci_irqenable, host->base + MMCIMASK0);
4225 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07004226
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004227 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
4228 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) &&
4229 !host->sdio_irq_disabled) {
4230 if (host->plat->sdiowakeup_irq) {
4231 disable_irq_nosync(
4232 host->plat->sdiowakeup_irq);
4233 msmsdcc_disable_irq_wake(host);
4234 host->sdio_irq_disabled = 1;
4235 }
4236 }
San Mehat9d2bd732009-09-22 16:44:22 -07004237
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004238 spin_unlock_irqrestore(&host->lock, flags);
4239
4240 mmc_resume_host(mmc);
4241
4242 /*
4243 * FIXME: Clearing of flags must be handled in clients
4244 * resume handler.
4245 */
4246 spin_lock_irqsave(&host->lock, flags);
4247 mmc->pm_flags = 0;
4248 spin_unlock_irqrestore(&host->lock, flags);
4249
4250 /*
4251 * After resuming the host wait for sometime so that
4252 * the SDIO work will be processed.
4253 */
4254 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO)) {
4255 if ((host->plat->cfg_mpm_sdiowakeup ||
4256 host->plat->sdiowakeup_irq) &&
4257 wake_lock_active(&host->sdio_wlock))
4258 wake_lock_timeout(&host->sdio_wlock, 1);
4259 }
4260
4261 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004262 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304263 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004264 return 0;
4265}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004266
4267static int msmsdcc_runtime_idle(struct device *dev)
4268{
4269 struct mmc_host *mmc = dev_get_drvdata(dev);
4270 struct msmsdcc_host *host = mmc_priv(mmc);
4271
4272 if (host->plat->is_sdio_al_client)
4273 return 0;
4274
4275 /* Idle timeout is not configurable for now */
4276 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
4277
4278 return -EAGAIN;
4279}
4280
4281static int msmsdcc_pm_suspend(struct device *dev)
4282{
4283 struct mmc_host *mmc = dev_get_drvdata(dev);
4284 struct msmsdcc_host *host = mmc_priv(mmc);
4285 int rc = 0;
4286
4287 if (host->plat->is_sdio_al_client)
4288 return 0;
4289
4290
4291 if (host->plat->status_irq)
4292 disable_irq(host->plat->status_irq);
4293
4294 if (!pm_runtime_suspended(dev))
4295 rc = msmsdcc_runtime_suspend(dev);
4296
4297 return rc;
4298}
4299
4300static int msmsdcc_pm_resume(struct device *dev)
4301{
4302 struct mmc_host *mmc = dev_get_drvdata(dev);
4303 struct msmsdcc_host *host = mmc_priv(mmc);
4304 int rc = 0;
4305
4306 if (host->plat->is_sdio_al_client)
4307 return 0;
4308
Sahitya Tummalafb486372011-09-02 19:01:49 +05304309 if (!pm_runtime_suspended(dev))
4310 rc = msmsdcc_runtime_resume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004311 if (host->plat->status_irq) {
4312 msmsdcc_check_status((unsigned long)host);
4313 enable_irq(host->plat->status_irq);
4314 }
4315
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004316 return rc;
4317}
4318
Daniel Walker08ecfde2010-06-23 12:32:20 -07004319#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004320#define msmsdcc_runtime_suspend NULL
4321#define msmsdcc_runtime_resume NULL
4322#define msmsdcc_runtime_idle NULL
4323#define msmsdcc_pm_suspend NULL
4324#define msmsdcc_pm_resume NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07004325#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004326
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004327static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
4328 .runtime_suspend = msmsdcc_runtime_suspend,
4329 .runtime_resume = msmsdcc_runtime_resume,
4330 .runtime_idle = msmsdcc_runtime_idle,
4331 .suspend = msmsdcc_pm_suspend,
4332 .resume = msmsdcc_pm_resume,
4333};
4334
San Mehat9d2bd732009-09-22 16:44:22 -07004335static struct platform_driver msmsdcc_driver = {
4336 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004337 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07004338 .driver = {
4339 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004340 .pm = &msmsdcc_dev_pm_ops,
San Mehat9d2bd732009-09-22 16:44:22 -07004341 },
4342};
4343
4344static int __init msmsdcc_init(void)
4345{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004346#if defined(CONFIG_DEBUG_FS)
4347 int ret = 0;
4348 ret = msmsdcc_dbg_init();
4349 if (ret) {
4350 pr_err("Failed to create debug fs dir \n");
4351 return ret;
4352 }
4353#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004354 return platform_driver_register(&msmsdcc_driver);
4355}
4356
4357static void __exit msmsdcc_exit(void)
4358{
4359 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004360
4361#if defined(CONFIG_DEBUG_FS)
4362 debugfs_remove(debugfs_file);
4363 debugfs_remove(debugfs_dir);
4364#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004365}
4366
4367module_init(msmsdcc_init);
4368module_exit(msmsdcc_exit);
4369
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004370MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07004371MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004372
4373#if defined(CONFIG_DEBUG_FS)
4374
4375static int
4376msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
4377{
4378 file->private_data = inode->i_private;
4379 return 0;
4380}
4381
4382static ssize_t
4383msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
4384 size_t count, loff_t *ppos)
4385{
4386 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
4387 char buf[1024];
4388 int max, i;
4389
4390 i = 0;
4391 max = sizeof(buf) - 1;
4392
4393 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
4394 host->curr.cmd, host->curr.data);
4395 if (host->curr.cmd) {
4396 struct mmc_command *cmd = host->curr.cmd;
4397
4398 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
4399 cmd->opcode, cmd->arg, cmd->flags);
4400 }
4401 if (host->curr.data) {
4402 struct mmc_data *data = host->curr.data;
4403 i += scnprintf(buf + i, max - i,
4404 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
4405 data->timeout_ns, data->timeout_clks,
4406 data->blksz, data->blocks, data->error,
4407 data->flags);
4408 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
4409 host->curr.xfer_size, host->curr.xfer_remain,
4410 host->curr.data_xfered, host->dma.sg);
4411 }
4412
4413 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
4414}
4415
4416static const struct file_operations msmsdcc_dbg_state_ops = {
4417 .read = msmsdcc_dbg_state_read,
4418 .open = msmsdcc_dbg_state_open,
4419};
4420
4421static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
4422{
4423 if (debugfs_dir) {
4424 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
4425 0644, debugfs_dir, host,
4426 &msmsdcc_dbg_state_ops);
4427 }
4428}
4429
4430static int __init msmsdcc_dbg_init(void)
4431{
4432 int err;
4433
4434 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
4435 if (IS_ERR(debugfs_dir)) {
4436 err = PTR_ERR(debugfs_dir);
4437 debugfs_dir = NULL;
4438 return err;
4439 }
4440
4441 return 0;
4442}
4443#endif