blob: b5a08d2b58e0cd6d18a8f1041139b6866c0cdc09 [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);
San Mehat9d2bd732009-09-22 16:44:22 -07001016
San Mehat56a8b5b2009-11-21 12:29:46 -08001017 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001018 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001019 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -07001020
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001021 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
1022 /* Use ADM (Application Data Mover) HW for Data transfer */
1023 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001024 host->cmd_timeout = timeout;
1025 host->cmd_pio_irqmask = pio_irqmask;
1026 host->cmd_datactrl = datactrl;
1027 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001028
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001029 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1030 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001031 host->dma.busy = 1;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301032 if ((data->flags & MMC_DATA_WRITE) && !host->curr.mrq->sbc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001033 host->prog_scan = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001034
1035 if (cmd) {
1036 msmsdcc_start_command_deferred(host, cmd, &c);
1037 host->cmd_c = c;
1038 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001039 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1040 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1041 host->base + MMCIMASK0);
1042 mb();
1043 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001044 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001045 /* SPS-BAM mode or PIO mode */
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301046 if ((data->flags & MMC_DATA_WRITE) && !host->curr.mrq->sbc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001047 host->prog_scan = 1;
1048 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001049
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001050 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001051
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001052 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1053 (~(MCI_IRQ_PIO))) | pio_irqmask,
1054 host->base + MMCIMASK0);
1055 msmsdcc_delay(host); /* Allow parms to be applied */
1056 writel_relaxed(datactrl, base + MMCIDATACTRL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001057
1058 if (cmd) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001059 msmsdcc_delay(host); /* Delay between data/command */
San Mehat56a8b5b2009-11-21 12:29:46 -08001060 /* Daisy-chain the command if requested */
1061 msmsdcc_start_command(host, cmd, c);
1062 }
San Mehat9d2bd732009-09-22 16:44:22 -07001063 }
1064}
1065
1066static void
1067msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1068{
San Mehat56a8b5b2009-11-21 12:29:46 -08001069 msmsdcc_start_command_deferred(host, cmd, &c);
1070 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001071}
1072
1073static void
1074msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1075 unsigned int status)
1076{
1077 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001078 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1079 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1080 pr_err("%s: Data CRC error\n",
1081 mmc_hostname(host->mmc));
1082 pr_err("%s: opcode 0x%.8x\n", __func__,
1083 data->mrq->cmd->opcode);
1084 pr_err("%s: blksz %d, blocks %d\n", __func__,
1085 data->blksz, data->blocks);
1086 data->error = -EILSEQ;
1087 }
San Mehat9d2bd732009-09-22 16:44:22 -07001088 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001089 /* CRC is optional for the bus test commands, not all
1090 * cards respond back with CRC. However controller
1091 * waits for the CRC and times out. Hence ignore the
1092 * data timeouts during the Bustest.
1093 */
1094 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1095 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1096 pr_err("%s: Data timeout\n",
1097 mmc_hostname(host->mmc));
1098 data->error = -ETIMEDOUT;
1099 }
San Mehat9d2bd732009-09-22 16:44:22 -07001100 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001101 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001102 data->error = -EIO;
1103 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001104 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001105 data->error = -EIO;
1106 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001107 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001108 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001109 data->error = -EIO;
1110 }
San Mehat9d2bd732009-09-22 16:44:22 -07001111
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001112 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001113 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001114 host->dummy_52_needed = 0;
1115}
San Mehat9d2bd732009-09-22 16:44:22 -07001116
1117static int
1118msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1119{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001120 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001121 uint32_t *ptr = (uint32_t *) buffer;
1122 int count = 0;
1123
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301124 if (remain % 4)
1125 remain = ((remain >> 2) + 1) << 2;
1126
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001127 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1128
1129 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001130 ptr++;
1131 count += sizeof(uint32_t);
1132
1133 remain -= sizeof(uint32_t);
1134 if (remain == 0)
1135 break;
1136 }
1137 return count;
1138}
1139
1140static int
1141msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001142 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001143{
1144 void __iomem *base = host->base;
1145 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001146 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001147
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001148 while (readl_relaxed(base + MMCISTATUS) &
1149 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1150 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001151
San Mehat9d2bd732009-09-22 16:44:22 -07001152 count = min(remain, maxcnt);
1153
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301154 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1155 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001156 ptr += count;
1157 remain -= count;
1158
1159 if (remain == 0)
1160 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001161 }
1162 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001163
1164 return ptr - buffer;
1165}
1166
San Mehat1cd22962010-02-03 12:59:29 -08001167static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001168msmsdcc_pio_irq(int irq, void *dev_id)
1169{
1170 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001171 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001172 uint32_t status;
1173
Murali Palnati36448a42011-09-02 15:06:18 +05301174 spin_lock(&host->lock);
1175
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001176 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001177
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001178 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301179 (MCI_IRQ_PIO)) == 0) {
1180 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001181 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301182 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001183
1184#if IRQ_DEBUG
1185 msmsdcc_print_status(host, "irq1-r", status);
1186#endif
1187
San Mehat9d2bd732009-09-22 16:44:22 -07001188 do {
1189 unsigned long flags;
1190 unsigned int remain, len;
1191 char *buffer;
1192
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001193 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1194 | MCI_RXDATAAVLBL)))
1195 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001196
1197 /* Map the current scatter buffer */
1198 local_irq_save(flags);
1199 buffer = kmap_atomic(sg_page(host->pio.sg),
1200 KM_BIO_SRC_IRQ) + host->pio.sg->offset;
1201 buffer += host->pio.sg_off;
1202 remain = host->pio.sg->length - host->pio.sg_off;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001203
San Mehat9d2bd732009-09-22 16:44:22 -07001204 len = 0;
1205 if (status & MCI_RXACTIVE)
1206 len = msmsdcc_pio_read(host, buffer, remain);
1207 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001208 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001209
1210 /* Unmap the buffer */
1211 kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
1212 local_irq_restore(flags);
1213
1214 host->pio.sg_off += len;
1215 host->curr.xfer_remain -= len;
1216 host->curr.data_xfered += len;
1217 remain -= len;
1218
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001219 if (remain) /* Done with this page? */
1220 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001221
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001222 if (status & MCI_RXACTIVE && host->curr.user_pages)
1223 flush_dcache_page(sg_page(host->pio.sg));
San Mehat9d2bd732009-09-22 16:44:22 -07001224
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001225 if (!--host->pio.sg_len) {
1226 memset(&host->pio, 0, sizeof(host->pio));
1227 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001228 }
1229
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001230 /* Advance to next sg */
1231 host->pio.sg++;
1232 host->pio.sg_off = 0;
1233
1234 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001235 } while (1);
1236
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001237 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1238 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1239 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1240 host->base + MMCIMASK0);
1241 if (!host->curr.xfer_remain) {
1242 /* Delay needed (same port was just written) */
1243 msmsdcc_delay(host);
1244 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1245 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1246 }
1247 mb();
1248 } else if (!host->curr.xfer_remain) {
1249 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1250 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1251 mb();
1252 }
San Mehat9d2bd732009-09-22 16:44:22 -07001253
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001254 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001255
1256 return IRQ_HANDLED;
1257}
1258
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001259static void
1260msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1261
1262static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1263 struct mmc_data *data)
1264{
1265 u32 loop_cnt = 0;
1266
1267 /*
1268 * For read commands with data less than fifo size, it is possible to
1269 * get DATAEND first and RXDATA_AVAIL might be set later because of
1270 * synchronization delay through the asynchronous RX FIFO. Thus, for
1271 * such cases, even after DATAEND interrupt is received software
1272 * should poll for RXDATA_AVAIL until the requested data is read out
1273 * of FIFO. This change is needed to get around this abnormal but
1274 * sometimes expected behavior of SDCC3 controller.
1275 *
1276 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1277 * after the data is loaded into RX FIFO. This would amount to less
1278 * than a microsecond and thus looping for 1000 times is good enough
1279 * for that delay.
1280 */
1281 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1282 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1283 spin_unlock(&host->lock);
1284 msmsdcc_pio_irq(1, host);
1285 spin_lock(&host->lock);
1286 }
1287 }
1288 if (loop_cnt == 1000) {
1289 pr_info("%s: Timed out while polling for Rx Data\n",
1290 mmc_hostname(host->mmc));
1291 data->error = -ETIMEDOUT;
1292 msmsdcc_reset_and_restore(host);
1293 }
1294}
1295
San Mehat9d2bd732009-09-22 16:44:22 -07001296static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1297{
1298 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001299
1300 host->curr.cmd = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001301 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1302 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1303 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1304 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -07001305
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001306 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Sahitya Tummala5a0ae912011-07-18 13:34:01 +05301307 pr_debug("%s: Command timeout\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001308 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001309 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
1310 !host->cmd19_tuning_in_progress) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001311 pr_err("%s: Command CRC error\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001312 cmd->error = -EILSEQ;
1313 }
1314
1315 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001316 if (host->curr.data && host->dma.sg &&
1317 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001318 msm_dmov_stop_cmd(host->dma.channel,
1319 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001320 else if (host->curr.data && host->sps.sg &&
1321 host->is_sps_mode){
1322 /* Stop current SPS transfer */
1323 msmsdcc_sps_exit_curr_xfer(host);
1324 }
San Mehat9d2bd732009-09-22 16:44:22 -07001325 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301326 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001327 msmsdcc_stop_data(host);
1328 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301329 } else { /* host->data == NULL */
1330 if (!cmd->error && host->prog_enable) {
1331 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001332 host->prog_scan = 0;
1333 host->prog_enable = 0;
1334 msmsdcc_request_end(host, cmd->mrq);
1335 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301336 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301337 } else {
1338 if (host->prog_enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001339 host->prog_scan = 0;
1340 host->prog_enable = 0;
1341 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001342 if (host->dummy_52_needed)
1343 host->dummy_52_needed = 0;
1344 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001345 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301346 msmsdcc_request_end(host, cmd->mrq);
1347 }
1348 }
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301349 } else if ((cmd == host->curr.mrq->sbc) && cmd->data) {
1350 if (cmd->data->flags & MMC_DATA_READ)
1351 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1352 else
1353 msmsdcc_request_start(host, host->curr.mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001354 } else if (cmd->data) {
San Mehat56a8b5b2009-11-21 12:29:46 -08001355 if (!(cmd->data->flags & MMC_DATA_READ))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001356 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001357 }
1358}
1359
San Mehat9d2bd732009-09-22 16:44:22 -07001360static irqreturn_t
1361msmsdcc_irq(int irq, void *dev_id)
1362{
1363 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001364 u32 status;
1365 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001366 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001367
1368 spin_lock(&host->lock);
1369
1370 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001371 struct mmc_command *cmd;
1372 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001373
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001374 if (timer) {
1375 timer = 0;
1376 msmsdcc_delay(host);
1377 }
San Mehat865c8062009-11-13 13:42:06 -08001378
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001379 if (!host->clks_on) {
1380 pr_debug("%s: %s: SDIO async irq received\n",
1381 mmc_hostname(host->mmc), __func__);
1382 host->mmc->ios.clock = host->clk_rate;
1383 spin_unlock(&host->lock);
1384 host->mmc->ops->set_ios(host->mmc, &host->mmc->ios);
1385 spin_lock(&host->lock);
1386 if (host->plat->cfg_mpm_sdiowakeup &&
1387 (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
1388 wake_lock(&host->sdio_wlock);
1389 /* only ansyc interrupt can come when clocks are off */
1390 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301391 if (host->clk_rate <=
1392 msmsdcc_get_min_sup_clk_rate(host))
1393 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001394 }
1395
1396 status = readl_relaxed(host->base + MMCISTATUS);
1397
1398 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1399 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001400 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001401
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001402#if IRQ_DEBUG
1403 msmsdcc_print_status(host, "irq0-r", status);
1404#endif
1405 status &= readl_relaxed(host->base + MMCIMASK0);
1406 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301407 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301408 if (host->clk_rate <=
1409 msmsdcc_get_min_sup_clk_rate(host))
1410 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001411#if IRQ_DEBUG
1412 msmsdcc_print_status(host, "irq0-p", status);
1413#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001414
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001415#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
1416 if (status & MCI_SDIOINTROPE) {
1417 if (host->sdcc_suspending)
1418 wake_lock(&host->sdio_suspend_wlock);
1419 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001420 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001421#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001422 data = host->curr.data;
1423
1424 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001425 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1426 MCI_CMDTIMEOUT)) {
1427 if (status & MCI_CMDTIMEOUT)
1428 pr_debug("%s: dummy CMD52 timeout\n",
1429 mmc_hostname(host->mmc));
1430 if (status & MCI_CMDCRCFAIL)
1431 pr_debug("%s: dummy CMD52 CRC failed\n",
1432 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001433 host->dummy_52_sent = 0;
1434 host->dummy_52_needed = 0;
1435 if (data) {
1436 msmsdcc_stop_data(host);
1437 msmsdcc_request_end(host, data->mrq);
1438 }
1439 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001440 spin_unlock(&host->lock);
1441 return IRQ_HANDLED;
1442 }
1443 break;
1444 }
1445
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001446 /*
1447 * Check for proper command response
1448 */
1449 cmd = host->curr.cmd;
1450 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1451 MCI_CMDTIMEOUT | MCI_PROGDONE |
1452 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1453 msmsdcc_do_cmdirq(host, status);
1454 }
1455
1456 if (data) {
1457 /* Check for data errors */
1458 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1459 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1460 msmsdcc_data_err(host, data, status);
1461 host->curr.data_xfered = 0;
1462 if (host->dma.sg && host->is_dma_mode)
1463 msm_dmov_stop_cmd(host->dma.channel,
1464 &host->dma.hdr, 0);
1465 else if (host->sps.sg && host->is_sps_mode) {
1466 /* Stop current SPS transfer */
1467 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301468 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001469 msmsdcc_reset_and_restore(host);
1470 if (host->curr.data)
1471 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301472 if (!data->stop || (host->curr.mrq->sbc
1473 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001474 timer |=
1475 msmsdcc_request_end(host,
1476 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301477 else if ((host->curr.mrq->sbc
1478 && data->error) ||
1479 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001480 msmsdcc_start_command(host,
1481 data->stop,
1482 0);
1483 timer = 1;
1484 }
1485 }
1486 }
1487
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301488 /* Check for prog done */
1489 if (host->curr.wait_for_auto_prog_done &&
1490 (status & MCI_PROGDONE))
1491 host->curr.got_auto_prog_done = 1;
1492
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001493 /* Check for data done */
1494 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1495 host->curr.got_dataend = 1;
1496
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301497 if (host->curr.got_dataend &&
1498 (!host->curr.wait_for_auto_prog_done ||
1499 (host->curr.wait_for_auto_prog_done &&
1500 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001501 /*
1502 * If DMA is still in progress, we complete
1503 * via the completion handler
1504 */
1505 if (!host->dma.busy && !host->sps.busy) {
1506 /*
1507 * There appears to be an issue in the
1508 * controller where if you request a
1509 * small block transfer (< fifo size),
1510 * you may get your DATAEND/DATABLKEND
1511 * irq without the PIO data irq.
1512 *
1513 * Check to see if theres still data
1514 * to be read, and simulate a PIO irq.
1515 */
1516 if (data->flags & MMC_DATA_READ)
1517 msmsdcc_wait_for_rxdata(host,
1518 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001519 if (!data->error) {
1520 host->curr.data_xfered =
1521 host->curr.xfer_size;
1522 host->curr.xfer_remain -=
1523 host->curr.xfer_size;
1524 }
1525
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001526 if (!host->dummy_52_needed) {
1527 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301528 if (!data->stop ||
1529 (host->curr.mrq->sbc
1530 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001531 msmsdcc_request_end(
1532 host,
1533 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301534 else if ((host->curr.mrq->sbc
1535 && data->error) ||
1536 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001537 msmsdcc_start_command(
1538 host,
1539 data->stop, 0);
1540 timer = 1;
1541 }
1542 } else {
1543 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001544 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001545 &dummy52cmd,
1546 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001547 }
1548 }
1549 }
1550 }
1551
San Mehat9d2bd732009-09-22 16:44:22 -07001552 ret = 1;
1553 } while (status);
1554
1555 spin_unlock(&host->lock);
1556
San Mehat9d2bd732009-09-22 16:44:22 -07001557 return IRQ_RETVAL(ret);
1558}
1559
1560static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001561msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1562{
1563 if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
1564 /* Queue/read data, daisy-chain command when data starts */
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301565 if (mrq->sbc)
1566 msmsdcc_start_data(host, mrq->data, mrq->sbc, 0);
1567 else
1568 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001569 } else {
1570 msmsdcc_start_command(host, mrq->cmd, 0);
1571 }
1572}
1573
1574static void
San Mehat9d2bd732009-09-22 16:44:22 -07001575msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1576{
1577 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001578 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001579
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001580 /*
1581 * Get the SDIO AL client out of LPM.
1582 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001583 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001584 if (host->plat->is_sdio_al_client)
1585 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001586
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301587 /* check if sps pipe reset is pending? */
1588 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1589 msmsdcc_sps_pipes_reset_and_restore(host);
1590 host->sps.pipe_reset_pending = false;
1591 }
1592
San Mehat9d2bd732009-09-22 16:44:22 -07001593 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001594 WARN(host->curr.mrq, "Request in progress\n");
1595 WARN(!host->pwr, "SDCC power is turned off\n");
1596 WARN(!host->clks_on, "SDCC clocks are turned off\n");
1597 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
San Mehat9d2bd732009-09-22 16:44:22 -07001598
1599 if (host->eject) {
1600 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1601 mrq->cmd->error = 0;
1602 mrq->data->bytes_xfered = mrq->data->blksz *
1603 mrq->data->blocks;
1604 } else
1605 mrq->cmd->error = -ENOMEDIUM;
1606
1607 spin_unlock_irqrestore(&host->lock, flags);
1608 mmc_request_done(mmc, mrq);
1609 return;
1610 }
1611
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301612 /*
1613 * Kick the software command timeout timer here.
1614 * Timer expires in 10 secs.
1615 */
1616 mod_timer(&host->req_tout_timer,
1617 (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
San Mehat9d2bd732009-09-22 16:44:22 -07001618
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301619 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301620 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301621 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
1622 mrq->cmd->opcode == 54) {
1623 if (!host->plat->sdcc_v4_sup)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001624 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301625 else
1626 /*
1627 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
1628 * write operations using CMD53 and CMD54.
1629 * Setting this bit with CMD53 would
1630 * automatically triggers PROG_DONE interrupt
1631 * without the need of sending dummy CMD52.
1632 */
1633 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001634 }
San Mehat9d2bd732009-09-22 16:44:22 -07001635 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301636
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301637 if (mrq->sbc) {
1638 mrq->sbc->mrq = mrq;
1639 mrq->sbc->data = mrq->data;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301640 if (mrq->data->flags & MMC_DATA_WRITE) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301641 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301642 msmsdcc_start_command(host, mrq->sbc, 0);
1643 } else {
1644 msmsdcc_request_start(host, mrq);
1645 }
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301646 } else {
1647 msmsdcc_request_start(host, mrq);
1648 }
1649
San Mehat9d2bd732009-09-22 16:44:22 -07001650 spin_unlock_irqrestore(&host->lock, flags);
1651}
1652
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001653static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1654 int min_uV, int max_uV)
1655{
1656 int rc = 0;
1657
1658 if (vreg->set_voltage_sup) {
1659 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1660 if (rc) {
1661 pr_err("%s: regulator_set_voltage(%s) failed."
1662 " min_uV=%d, max_uV=%d, rc=%d\n",
1663 __func__, vreg->name, min_uV, max_uV, rc);
1664 }
1665 }
1666
1667 return rc;
1668}
1669
1670static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1671 int uA_load)
1672{
1673 int rc = 0;
1674
1675 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1676 if (rc < 0)
1677 pr_err("%s: regulator_set_optimum_mode(reg=%s, uA_load=%d)"
1678 " failed. rc=%d\n", __func__, vreg->name,
1679 uA_load, rc);
1680 else
1681 /* regulator_set_optimum_mode() can return non zero value
1682 * even for success case.
1683 */
1684 rc = 0;
1685
1686 return rc;
1687}
1688
1689static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1690 struct device *dev)
1691{
1692 int rc = 0;
1693
1694 /* check if regulator is already initialized? */
1695 if (vreg->reg)
1696 goto out;
1697
1698 /* Get the regulator handle */
1699 vreg->reg = regulator_get(dev, vreg->name);
1700 if (IS_ERR(vreg->reg)) {
1701 rc = PTR_ERR(vreg->reg);
1702 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
1703 __func__, vreg->name, rc);
1704 }
1705out:
1706 return rc;
1707}
1708
1709static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
1710{
1711 if (vreg->reg)
1712 regulator_put(vreg->reg);
1713}
1714
1715/* This init function should be called only once for each SDCC slot */
1716static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
1717{
1718 int rc = 0;
1719 struct msm_mmc_slot_reg_data *curr_slot;
1720 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1721 struct device *dev = mmc_dev(host->mmc);
1722
1723 curr_slot = host->plat->vreg_data;
1724 if (!curr_slot)
1725 goto out;
1726
1727 curr_vdd_reg = curr_slot->vdd_data;
1728 curr_vccq_reg = curr_slot->vccq_data;
1729 curr_vddp_reg = curr_slot->vddp_data;
1730
1731 if (is_init) {
1732 /*
1733 * Get the regulator handle from voltage regulator framework
1734 * and then try to set the voltage level for the regulator
1735 */
1736 if (curr_vdd_reg) {
1737 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
1738 if (rc)
1739 goto out;
1740 }
1741 if (curr_vccq_reg) {
1742 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
1743 if (rc)
1744 goto vdd_reg_deinit;
1745 }
1746 if (curr_vddp_reg) {
1747 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
1748 if (rc)
1749 goto vccq_reg_deinit;
1750 }
1751 goto out;
1752 } else {
1753 /* Deregister all regulators from regulator framework */
1754 goto vddp_reg_deinit;
1755 }
1756vddp_reg_deinit:
1757 if (curr_vddp_reg)
1758 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
1759vccq_reg_deinit:
1760 if (curr_vccq_reg)
1761 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
1762vdd_reg_deinit:
1763 if (curr_vdd_reg)
1764 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
1765out:
1766 return rc;
1767}
1768
1769static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
1770{
1771 int rc = 0;
1772
Subhash Jadavanicc922692011-08-01 23:05:01 +05301773 /* Put regulator in HPM (high power mode) */
1774 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
1775 if (rc < 0)
1776 goto out;
1777
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001778 if (!vreg->is_enabled) {
1779 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301780 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
1781 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001782 if (rc)
1783 goto out;
1784
1785 rc = regulator_enable(vreg->reg);
1786 if (rc) {
1787 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
1788 __func__, vreg->name, rc);
1789 goto out;
1790 }
1791 vreg->is_enabled = true;
1792 }
1793
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001794out:
1795 return rc;
1796}
1797
1798static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
1799{
1800 int rc = 0;
1801
1802 /* Never disable regulator marked as always_on */
1803 if (vreg->is_enabled && !vreg->always_on) {
1804 rc = regulator_disable(vreg->reg);
1805 if (rc) {
1806 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
1807 __func__, vreg->name, rc);
1808 goto out;
1809 }
1810 vreg->is_enabled = false;
1811
1812 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
1813 if (rc < 0)
1814 goto out;
1815
1816 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301817 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001818 if (rc)
1819 goto out;
1820 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
1821 /* Put always_on regulator in LPM (low power mode) */
1822 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
1823 if (rc < 0)
1824 goto out;
1825 }
1826out:
1827 return rc;
1828}
1829
1830static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
1831{
1832 int rc = 0, i;
1833 struct msm_mmc_slot_reg_data *curr_slot;
1834 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1835 struct msm_mmc_reg_data *vreg_table[3];
1836
1837 curr_slot = host->plat->vreg_data;
1838 if (!curr_slot)
1839 goto out;
1840
1841 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
1842 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
1843 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
1844
1845 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
1846 if (vreg_table[i]) {
1847 if (enable)
1848 rc = msmsdcc_vreg_enable(vreg_table[i]);
1849 else
1850 rc = msmsdcc_vreg_disable(vreg_table[i]);
1851 if (rc)
1852 goto out;
1853 }
1854 }
1855out:
1856 return rc;
1857}
1858
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301859static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001860{
1861 int rc = 0;
1862
1863 if (host->plat->vreg_data) {
1864 struct msm_mmc_reg_data *vddp_reg =
1865 host->plat->vreg_data->vddp_data;
1866
1867 if (vddp_reg && vddp_reg->is_enabled)
1868 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
1869 }
1870
1871 return rc;
1872}
1873
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301874static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
1875{
1876 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1877 int rc = 0;
1878
1879 if (curr_slot && curr_slot->vddp_data) {
1880 rc = msmsdcc_set_vddp_level(host,
1881 curr_slot->vddp_data->low_vol_level);
1882
1883 if (rc)
1884 pr_err("%s: %s: failed to change vddp level to %d",
1885 mmc_hostname(host->mmc), __func__,
1886 curr_slot->vddp_data->low_vol_level);
1887 }
1888
1889 return rc;
1890}
1891
1892static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
1893{
1894 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1895 int rc = 0;
1896
1897 if (curr_slot && curr_slot->vddp_data) {
1898 rc = msmsdcc_set_vddp_level(host,
1899 curr_slot->vddp_data->high_vol_level);
1900
1901 if (rc)
1902 pr_err("%s: %s: failed to change vddp level to %d",
1903 mmc_hostname(host->mmc), __func__,
1904 curr_slot->vddp_data->high_vol_level);
1905 }
1906
1907 return rc;
1908}
1909
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001910static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
1911{
1912 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
1913 return 1;
1914 return 0;
1915}
1916
1917static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
1918{
1919 if (enable) {
1920 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1921 clk_enable(host->dfab_pclk);
1922 if (!IS_ERR(host->pclk))
1923 clk_enable(host->pclk);
1924 clk_enable(host->clk);
1925 } else {
1926 clk_disable(host->clk);
1927 if (!IS_ERR(host->pclk))
1928 clk_disable(host->pclk);
1929 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1930 clk_disable(host->dfab_pclk);
1931 }
1932}
1933
1934static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
1935 unsigned int req_clk)
1936{
1937 unsigned int sel_clk = -1;
1938
1939 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
1940 unsigned char cnt;
1941
1942 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
1943 if (host->plat->sup_clk_table[cnt] > req_clk)
1944 break;
1945 else if (host->plat->sup_clk_table[cnt] == req_clk) {
1946 sel_clk = host->plat->sup_clk_table[cnt];
1947 break;
1948 } else
1949 sel_clk = host->plat->sup_clk_table[cnt];
1950 }
1951 } else {
1952 if ((req_clk < host->plat->msmsdcc_fmax) &&
1953 (req_clk > host->plat->msmsdcc_fmid))
1954 sel_clk = host->plat->msmsdcc_fmid;
1955 else
1956 sel_clk = req_clk;
1957 }
1958
1959 return sel_clk;
1960}
1961
1962static inline unsigned int msmsdcc_get_min_sup_clk_rate(
1963 struct msmsdcc_host *host)
1964{
1965 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
1966 return host->plat->sup_clk_table[0];
1967 else
1968 return host->plat->msmsdcc_fmin;
1969}
1970
1971static inline unsigned int msmsdcc_get_max_sup_clk_rate(
1972 struct msmsdcc_host *host)
1973{
1974 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
1975 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
1976 else
1977 return host->plat->msmsdcc_fmax;
1978}
1979
1980static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05301981{
1982 struct msm_mmc_gpio_data *curr;
1983 int i, rc = 0;
1984
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001985 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301986 for (i = 0; i < curr->size; i++) {
1987 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001988 if (curr->gpio[i].is_always_on &&
1989 curr->gpio[i].is_enabled)
1990 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301991 rc = gpio_request(curr->gpio[i].no,
1992 curr->gpio[i].name);
1993 if (rc) {
1994 pr_err("%s: gpio_request(%d, %s) failed %d\n",
1995 mmc_hostname(host->mmc),
1996 curr->gpio[i].no,
1997 curr->gpio[i].name, rc);
1998 goto free_gpios;
1999 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002000 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302001 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002002 if (curr->gpio[i].is_always_on)
2003 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302004 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002005 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302006 }
2007 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002008 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302009
2010free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002011 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302012 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002013 curr->gpio[i].is_enabled = false;
2014 }
2015out:
2016 return rc;
2017}
2018
2019static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2020{
2021 struct msm_mmc_pad_data *curr;
2022 int i;
2023
2024 curr = host->plat->pin_data->pad_data;
2025 for (i = 0; i < curr->drv->size; i++) {
2026 if (enable)
2027 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2028 curr->drv->on[i].val);
2029 else
2030 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2031 curr->drv->off[i].val);
2032 }
2033
2034 for (i = 0; i < curr->pull->size; i++) {
2035 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002036 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002037 curr->pull->on[i].val);
2038 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002039 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002040 curr->pull->off[i].val);
2041 }
2042
2043 return 0;
2044}
2045
2046static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2047{
2048 int rc = 0;
2049
2050 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2051 return 0;
2052
2053 if (host->plat->pin_data->is_gpio)
2054 rc = msmsdcc_setup_gpio(host, enable);
2055 else
2056 rc = msmsdcc_setup_pad(host, enable);
2057
2058 if (!rc)
2059 host->plat->pin_data->cfg_sts = enable;
2060
2061 return rc;
2062}
2063
2064static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2065{
2066 unsigned int wakeup_irq;
2067
2068 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2069 host->plat->sdiowakeup_irq :
2070 host->core_irqres->start;
2071
2072 if (!host->irq_wake_enabled) {
2073 enable_irq_wake(wakeup_irq);
2074 host->irq_wake_enabled = true;
2075 }
2076}
2077
2078static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2079{
2080 unsigned int wakeup_irq;
2081
2082 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2083 host->plat->sdiowakeup_irq :
2084 host->core_irqres->start;
2085
2086 if (host->irq_wake_enabled) {
2087 disable_irq_wake(wakeup_irq);
2088 host->irq_wake_enabled = false;
2089 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302090}
2091
San Mehat9d2bd732009-09-22 16:44:22 -07002092static void
2093msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2094{
2095 struct msmsdcc_host *host = mmc_priv(mmc);
2096 u32 clk = 0, pwr = 0;
2097 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002098 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002099 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002100
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002101 DBG(host, "ios->clock = %u\n", ios->clock);
Sahitya Tummala7a892482011-01-18 11:22:49 +05302102
San Mehat9d2bd732009-09-22 16:44:22 -07002103 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002104 spin_lock_irqsave(&host->lock, flags);
2105 if (!host->clks_on) {
2106 msmsdcc_setup_clocks(host, true);
2107 host->clks_on = 1;
2108 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2109 if (!host->plat->sdiowakeup_irq) {
2110 writel_relaxed(host->mci_irqenable,
2111 host->base + MMCIMASK0);
2112 mb();
2113 if (host->plat->cfg_mpm_sdiowakeup &&
2114 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2115 host->plat->cfg_mpm_sdiowakeup(
2116 mmc_dev(mmc), SDC_DAT1_DISWAKE);
2117 msmsdcc_disable_irq_wake(host);
2118 } else if (!(mmc->pm_flags &
2119 MMC_PM_WAKE_SDIO_IRQ)) {
2120 writel_relaxed(host->mci_irqenable,
2121 host->base + MMCIMASK0);
2122 }
2123 }
San Mehat9d2bd732009-09-22 16:44:22 -07002124 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002125 spin_unlock_irqrestore(&host->lock, flags);
2126
2127 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2128 /*
2129 * For DDR50 mode, controller needs clock rate to be
2130 * double than what is required on the SD card CLK pin.
2131 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302132 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002133 /*
2134 * Make sure that we don't double the clock if
2135 * doubled clock rate is already set
2136 */
2137 if (!host->ddr_doubled_clk_rate ||
2138 (host->ddr_doubled_clk_rate &&
2139 (host->ddr_doubled_clk_rate != ios->clock))) {
2140 host->ddr_doubled_clk_rate =
2141 msmsdcc_get_sup_clk_rate(
2142 host, (ios->clock * 2));
2143 clock = host->ddr_doubled_clk_rate;
2144 }
2145 } else {
2146 host->ddr_doubled_clk_rate = 0;
2147 }
2148
2149 if (clock != host->clk_rate) {
2150 rc = clk_set_rate(host->clk, clock);
2151 if (rc < 0)
2152 pr_debug("%s: failed to set clk rate %u\n",
2153 mmc_hostname(mmc), clock);
2154 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302155 host->reg_write_delay =
2156 (1 + ((3 * USEC_PER_SEC) /
2157 (host->clk_rate ? host->clk_rate :
2158 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002159 }
2160 /*
2161 * give atleast 2 MCLK cycles delay for clocks
2162 * and SDCC core to stabilize
2163 */
2164 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002165 clk |= MCI_CLK_ENABLE;
2166 }
2167
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002168 if (ios->bus_width == MMC_BUS_WIDTH_8)
2169 clk |= MCI_CLK_WIDEBUS_8;
2170 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2171 clk |= MCI_CLK_WIDEBUS_4;
2172 else
2173 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002174
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002175 if (msmsdcc_is_pwrsave(host))
2176 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002177
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002178 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002179
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002180 host->tuning_needed = 0;
2181 /*
2182 * Select the controller timing mode according
2183 * to current bus speed mode
2184 */
2185 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2186 (ios->timing == MMC_TIMING_UHS_SDR50)) {
2187 clk |= (4 << 14);
2188 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302189 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002190 clk |= (3 << 14);
2191 } else {
2192 clk |= (2 << 14); /* feedback clock */
2193 }
2194
2195 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2196 clk |= (2 << 23);
2197
2198 if (host->io_pad_pwr_switch)
2199 clk |= IO_PAD_PWR_SWITCH;
2200
2201 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
San Mehat9d2bd732009-09-22 16:44:22 -07002202 pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002203 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2204 pwr |= msmsdcc_setup_vreg(host, !!ios->vdd);
San Mehat9d2bd732009-09-22 16:44:22 -07002205
2206 switch (ios->power_mode) {
2207 case MMC_POWER_OFF:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002208 htc_pwrsink_set(PWRSINK_SDCARD, 0);
2209 if (!host->sdcc_irq_disabled) {
2210 if (host->plat->cfg_mpm_sdiowakeup)
2211 host->plat->cfg_mpm_sdiowakeup(
2212 mmc_dev(mmc), SDC_DAT1_DISABLE);
2213 disable_irq(host->core_irqres->start);
2214 host->sdcc_irq_disabled = 1;
2215 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302216 /*
2217 * As VDD pad rail is always on, set low voltage for VDD
2218 * pad rail when slot is unused (when card is not present
2219 * or during system suspend).
2220 */
2221 msmsdcc_set_vddp_low_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002222 msmsdcc_setup_pins(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002223 break;
2224 case MMC_POWER_UP:
2225 pwr |= MCI_PWR_UP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002226 if (host->sdcc_irq_disabled) {
2227 if (host->plat->cfg_mpm_sdiowakeup)
2228 host->plat->cfg_mpm_sdiowakeup(
2229 mmc_dev(mmc), SDC_DAT1_ENABLE);
2230 enable_irq(host->core_irqres->start);
2231 host->sdcc_irq_disabled = 0;
2232 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302233 msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002234 msmsdcc_setup_pins(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07002235 break;
2236 case MMC_POWER_ON:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002237 htc_pwrsink_set(PWRSINK_SDCARD, 100);
San Mehat9d2bd732009-09-22 16:44:22 -07002238 pwr |= MCI_PWR_ON;
2239 break;
2240 }
2241
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002242 spin_lock_irqsave(&host->lock, flags);
2243 if (!host->clks_on) {
2244 /* force the clocks to be on */
2245 msmsdcc_setup_clocks(host, true);
2246 /*
2247 * give atleast 2 MCLK cycles delay for clocks
2248 * and SDCC core to stabilize
2249 */
2250 msmsdcc_delay(host);
2251 }
2252 writel_relaxed(clk, host->base + MMCICLOCK);
2253 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002254
2255 if (host->pwr != pwr) {
2256 host->pwr = pwr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002257 writel_relaxed(pwr, host->base + MMCIPOWER);
2258 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07002259 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002260 if (!host->clks_on) {
2261 /* force the clocks to be off */
2262 msmsdcc_setup_clocks(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002263 }
2264
2265 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
2266 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2267 if (!host->plat->sdiowakeup_irq) {
2268 writel_relaxed(MCI_SDIOINTMASK,
2269 host->base + MMCIMASK0);
2270 mb();
2271 if (host->plat->cfg_mpm_sdiowakeup &&
2272 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2273 host->plat->cfg_mpm_sdiowakeup(
2274 mmc_dev(mmc), SDC_DAT1_ENWAKE);
2275 msmsdcc_enable_irq_wake(host);
2276 } else if (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2277 writel_relaxed(0, host->base + MMCIMASK0);
2278 } else {
2279 writel_relaxed(MCI_SDIOINTMASK,
2280 host->base + MMCIMASK0);
2281 }
2282 msmsdcc_delay(host);
2283 }
2284 msmsdcc_setup_clocks(host, false);
2285 host->clks_on = 0;
2286 }
San Mehat4adbbcc2009-11-08 13:00:37 -08002287 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002288}
2289
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002290int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2291{
2292 struct msmsdcc_host *host = mmc_priv(mmc);
2293 u32 clk;
2294
2295 clk = readl_relaxed(host->base + MMCICLOCK);
2296 pr_debug("Changing to pwr_save=%d", pwrsave);
2297 if (pwrsave && msmsdcc_is_pwrsave(host))
2298 clk |= MCI_CLK_PWRSAVE;
2299 else
2300 clk &= ~MCI_CLK_PWRSAVE;
2301 writel_relaxed(clk, host->base + MMCICLOCK);
2302 mb();
2303
2304 return 0;
2305}
2306
2307static int msmsdcc_get_ro(struct mmc_host *mmc)
2308{
2309 int status = -ENOSYS;
2310 struct msmsdcc_host *host = mmc_priv(mmc);
2311
2312 if (host->plat->wpswitch) {
2313 status = host->plat->wpswitch(mmc_dev(mmc));
2314 } else if (host->plat->wpswitch_gpio) {
2315 status = gpio_request(host->plat->wpswitch_gpio,
2316 "SD_WP_Switch");
2317 if (status) {
2318 pr_err("%s: %s: Failed to request GPIO %d\n",
2319 mmc_hostname(mmc), __func__,
2320 host->plat->wpswitch_gpio);
2321 } else {
2322 status = gpio_direction_input(
2323 host->plat->wpswitch_gpio);
2324 if (!status) {
2325 /*
2326 * Wait for atleast 300ms as debounce
2327 * time for GPIO input to stabilize.
2328 */
2329 msleep(300);
2330 status = gpio_get_value_cansleep(
2331 host->plat->wpswitch_gpio);
2332 status ^= !host->plat->wpswitch_polarity;
2333 }
2334 gpio_free(host->plat->wpswitch_gpio);
2335 }
2336 }
2337
2338 if (status < 0)
2339 status = -ENOSYS;
2340 pr_debug("%s: Card read-only status %d\n", __func__, status);
2341
2342 return status;
2343}
2344
2345#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002346static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2347{
2348 struct msmsdcc_host *host = mmc_priv(mmc);
2349 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002350
2351 if (enable) {
2352 spin_lock_irqsave(&host->lock, flags);
2353 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
2354 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
2355 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2356 spin_unlock_irqrestore(&host->lock, flags);
2357 } else {
2358 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
2359 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
2360 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2361 }
2362 mb();
2363}
2364#endif /* CONFIG_MMC_MSM_SDIO_SUPPORT */
2365
2366#ifdef CONFIG_PM_RUNTIME
2367static int msmsdcc_enable(struct mmc_host *mmc)
2368{
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302369 int rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002370 struct device *dev = mmc->parent;
2371
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302372 if (dev->power.runtime_status == RPM_SUSPENDING) {
2373 if (mmc->suspend_task == current) {
2374 pm_runtime_get_noresume(dev);
2375 goto out;
2376 }
2377 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002378
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302379 rc = pm_runtime_get_sync(dev);
2380
2381 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002382 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2383 __func__, rc);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302384 return rc;
2385 }
2386out:
2387 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002388}
2389
2390static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2391{
2392 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302393 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002394
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302395 if (host->plat->disable_runtime_pm)
2396 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002397 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO)
2398 return -ENOTSUPP;
2399
2400 rc = pm_runtime_put_sync(mmc->parent);
2401
2402 if (rc < 0)
2403 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2404 __func__, rc);
2405 return rc;
2406}
2407#else
2408#define msmsdcc_enable NULL
2409#define msmsdcc_disable NULL
2410#endif
2411
2412static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2413 struct mmc_ios *ios)
2414{
2415 struct msmsdcc_host *host = mmc_priv(mmc);
2416 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302417 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002418
2419 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2420 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302421 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002422 goto out;
2423 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2424 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302425 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002426 goto out;
2427 }
San Mehat9d2bd732009-09-22 16:44:22 -07002428
2429 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002430 /*
2431 * If we are here means voltage switch from high voltage to
2432 * low voltage is required
2433 */
2434
2435 /*
2436 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2437 * register until they become all zeros.
2438 */
2439 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302440 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002441 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2442 mmc_hostname(mmc), __func__);
2443 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002444 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002445
2446 /* Stop SD CLK output. */
2447 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2448 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2449
San Mehat9d2bd732009-09-22 16:44:22 -07002450 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002451
2452 /*
2453 * Switch VDDPX from high voltage to low voltage
2454 * to change the VDD of the SD IO pads.
2455 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302456 rc = msmsdcc_set_vddp_low_vol(host);
2457 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002458 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002459
2460 spin_lock_irqsave(&host->lock, flags);
2461 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2462 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
2463 host->io_pad_pwr_switch = 1;
2464 spin_unlock_irqrestore(&host->lock, flags);
2465
2466 /* Wait 5 ms for the voltage regulater in the card to become stable. */
2467 usleep_range(5000, 5500);
2468
2469 spin_lock_irqsave(&host->lock, flags);
2470 /* Start SD CLK output. */
2471 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2472 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2473 spin_unlock_irqrestore(&host->lock, flags);
2474
2475 /*
2476 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
2477 * don't become all ones within 1 ms then a Voltage Switch
2478 * sequence has failed and a power cycle to the card is required.
2479 * Otherwise Voltage Switch sequence is completed successfully.
2480 */
2481 usleep_range(1000, 1500);
2482
2483 spin_lock_irqsave(&host->lock, flags);
2484 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
2485 != (0xF << 1)) {
2486 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
2487 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302488 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002489 goto out_unlock;
2490 }
2491
2492out_unlock:
2493 spin_unlock_irqrestore(&host->lock, flags);
2494out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302495 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002496}
2497
2498static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2499 u8 phase);
2500/* Initialize the DLL (Programmable Delay Line ) */
2501static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
2502{
2503 int rc = 0;
2504 u32 wait_timeout;
2505
2506 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
2507 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2508 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2509
2510 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
2511 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2512 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2513
2514 msmsdcc_delay(host);
2515
2516 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
2517 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2518 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2519
2520 /* Initialize the phase to 0 */
2521 rc = msmsdcc_config_cm_sdc4_dll_phase(host, 0);
2522 if (rc)
2523 goto out;
2524
2525 wait_timeout = 1000;
2526 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
2527 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
2528 /* max. wait for 1 sec for LOCK bit to be set */
2529 if (--wait_timeout == 0) {
2530 pr_err("%s: %s: DLL failed to lock at phase: %d",
2531 mmc_hostname(host->mmc), __func__, 0);
2532 rc = -1;
2533 goto out;
2534 }
2535 /* wait for 1ms */
2536 usleep_range(1000, 1500);
2537 }
2538out:
2539 return rc;
2540}
2541
2542/*
2543 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
2544 * calibration sequence. This function should be called before
2545 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
2546 * commands (CMD17/CMD18).
2547 */
2548static void msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
2549{
2550 /* Set CDR_EN bit to 1. */
2551 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) |
2552 MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2553
2554 /* Set CDR_EXT_EN bit to 0. */
2555 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2556 & ~MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2557
2558 /* Set CK_OUT_EN bit to 0. */
2559 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2560 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2561
2562 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2563 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)
2564 ;
2565
2566 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2567 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2568 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2569
2570 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register is 1. */
2571 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN))
2572 ;
2573}
2574
2575static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2576 u8 phase)
2577{
2578 int rc = 0;
2579 u32 mclk_freq = 0;
2580 u32 wait_timeout;
2581
2582 /* Set CDR_EN bit to 0. */
2583 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2584 & ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2585
2586 /* Set CDR_EXT_EN bit to 1. */
2587 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2588 | MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2589
2590 /* Program the MCLK value to MCLK_FREQ bit field */
2591 if (host->clk_rate <= 112000000)
2592 mclk_freq = 0;
2593 else if (host->clk_rate <= 125000000)
2594 mclk_freq = 1;
2595 else if (host->clk_rate <= 137000000)
2596 mclk_freq = 2;
2597 else if (host->clk_rate <= 150000000)
2598 mclk_freq = 3;
2599 else if (host->clk_rate <= 162000000)
2600 mclk_freq = 4;
2601 else if (host->clk_rate <= 175000000)
2602 mclk_freq = 5;
2603 else if (host->clk_rate <= 187000000)
2604 mclk_freq = 6;
2605 else if (host->clk_rate <= 200000000)
2606 mclk_freq = 7;
2607
2608 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2609 & ~(7 << 24)) | (mclk_freq << 24)),
2610 host->base + MCI_DLL_CONFIG);
2611
2612 /* Set CK_OUT_EN bit to 0. */
2613 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2614 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2615
2616 /* Set DLL_EN bit to 1. */
2617 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2618 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
2619
2620 wait_timeout = 1000;
2621 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2622 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN) {
2623 /* max. wait for 1 sec for LOCK bit for be set */
2624 if (--wait_timeout == 0) {
2625 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 0",
2626 mmc_hostname(host->mmc), __func__, phase);
2627 rc = -1;
2628 goto out;
2629 }
2630 /* wait for 1ms */
2631 usleep_range(1000, 1500);
2632 }
2633
2634 /*
2635 * Write the selected DLL clock output phase (0 ... 15)
2636 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
2637 */
2638 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2639 & ~(0xF << 20)) | (phase << 20)),
2640 host->base + MCI_DLL_CONFIG);
2641
2642 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2643 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2644 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2645
2646 wait_timeout = 1000;
2647 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
2648 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)) {
2649 /* max. wait for 1 sec for LOCK bit for be set */
2650 if (--wait_timeout == 0) {
2651 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 1",
2652 mmc_hostname(host->mmc), __func__, phase);
2653 rc = -1;
2654 goto out;
2655 }
2656 /* wait for 1ms */
2657 usleep_range(1000, 1500);
2658 }
2659out:
2660 return rc;
2661}
2662
2663static int msmsdcc_execute_tuning(struct mmc_host *mmc)
2664{
2665 struct msmsdcc_host *host = mmc_priv(mmc);
2666 u8 phase;
2667 u8 *data_buf;
2668 u8 tuned_phases[16], tuned_phase_cnt = 0;
2669 int rc = 0;
2670
2671 /* Tuning is only required for SDR50 & SDR104 modes */
2672 if (!host->tuning_needed) {
2673 rc = 0;
2674 goto out;
2675 }
2676
2677 host->cmd19_tuning_in_progress = 1;
2678 /*
2679 * Make sure that clock is always enabled when DLL
2680 * tuning is in progress. Keeping PWRSAVE ON may
2681 * turn off the clock. So let's disable the PWRSAVE
2682 * here and re-enable it once tuning is completed.
2683 */
2684 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2685 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2686 /* first of all reset the tuning block */
2687 rc = msmsdcc_init_cm_sdc4_dll(host);
2688 if (rc)
2689 goto out;
2690
2691 data_buf = kmalloc(64, GFP_KERNEL);
2692 if (!data_buf) {
2693 rc = -ENOMEM;
2694 goto out;
2695 }
2696
2697 phase = 0;
2698 do {
2699 struct mmc_command cmd = {0};
2700 struct mmc_data data = {0};
2701 struct mmc_request mrq = {
2702 .cmd = &cmd,
2703 .data = &data
2704 };
2705 struct scatterlist sg;
2706
2707 /* set the phase in delay line hw block */
2708 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2709 if (rc)
2710 goto kfree;
2711
2712 cmd.opcode = MMC_SEND_TUNING_BLOCK;
2713 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
2714
2715 data.blksz = 64;
2716 data.blocks = 1;
2717 data.flags = MMC_DATA_READ;
2718 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
2719
2720 data.sg = &sg;
2721 data.sg_len = 1;
2722 sg_init_one(&sg, data_buf, 64);
2723 memset(data_buf, 0, 64);
2724 mmc_wait_for_req(mmc, &mrq);
2725
2726 if (!cmd.error && !data.error &&
2727 !memcmp(data_buf, cmd19_tuning_block, 64)) {
2728 /* tuning is successful with this tuning point */
2729 tuned_phases[tuned_phase_cnt++] = phase;
2730 }
2731 } while (++phase < 16);
2732
2733 kfree(data_buf);
2734
2735 if (tuned_phase_cnt) {
2736 tuned_phase_cnt--;
2737 tuned_phase_cnt = (tuned_phase_cnt * 3) / 4;
2738 phase = tuned_phases[tuned_phase_cnt];
2739 /*
2740 * Finally set the selected phase in delay
2741 * line hw block.
2742 */
2743 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2744 if (rc)
2745 goto out;
2746 } else {
2747 /* tuning failed */
2748 rc = -EAGAIN;
2749 pr_err("%s: %s: no tuning point found",
2750 mmc_hostname(mmc), __func__);
2751 }
2752 goto out;
2753
2754kfree:
2755 kfree(data_buf);
2756out:
2757 /* re-enable PWESAVE */
2758 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2759 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2760 host->cmd19_tuning_in_progress = 0;
2761 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07002762}
2763
2764static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002765 .enable = msmsdcc_enable,
2766 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07002767 .request = msmsdcc_request,
2768 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002769 .get_ro = msmsdcc_get_ro,
2770#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002771 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002772#endif
2773 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
2774 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07002775};
2776
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002777static unsigned int
2778msmsdcc_slot_status(struct msmsdcc_host *host)
2779{
2780 int status;
2781 unsigned int gpio_no = host->plat->status_gpio;
2782
2783 status = gpio_request(gpio_no, "SD_HW_Detect");
2784 if (status) {
2785 pr_err("%s: %s: Failed to request GPIO %d\n",
2786 mmc_hostname(host->mmc), __func__, gpio_no);
2787 } else {
2788 status = gpio_direction_input(gpio_no);
2789 if (!status)
2790 status = !gpio_get_value_cansleep(gpio_no);
2791 gpio_free(gpio_no);
2792 }
2793 return status;
2794}
2795
San Mehat9d2bd732009-09-22 16:44:22 -07002796static void
2797msmsdcc_check_status(unsigned long data)
2798{
2799 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
2800 unsigned int status;
2801
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002802 if (host->plat->status || host->plat->status_gpio) {
2803 if (host->plat->status)
2804 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07002805 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002806 status = msmsdcc_slot_status(host);
2807
2808 host->eject = !status;
2809 if (status ^ host->oldstat) {
2810 pr_info("%s: Slot status change detected (%d -> %d)\n",
2811 mmc_hostname(host->mmc), host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07002812 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002813 }
2814 host->oldstat = status;
2815 } else {
2816 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07002817 }
San Mehat9d2bd732009-09-22 16:44:22 -07002818}
2819
2820static irqreturn_t
2821msmsdcc_platform_status_irq(int irq, void *dev_id)
2822{
2823 struct msmsdcc_host *host = dev_id;
2824
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002825 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07002826 msmsdcc_check_status((unsigned long) host);
2827 return IRQ_HANDLED;
2828}
2829
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002830static irqreturn_t
2831msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
2832{
2833 struct msmsdcc_host *host = dev_id;
2834
2835 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
2836 spin_lock(&host->lock);
2837 if (!host->sdio_irq_disabled) {
2838 disable_irq_nosync(irq);
2839 if (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2840 wake_lock(&host->sdio_wlock);
2841 msmsdcc_disable_irq_wake(host);
2842 }
2843 host->sdio_irq_disabled = 1;
2844 }
2845 if (host->plat->is_sdio_al_client) {
2846 if (!host->clks_on) {
2847 msmsdcc_setup_clocks(host, true);
2848 host->clks_on = 1;
2849 }
2850 if (host->sdcc_irq_disabled) {
2851 writel_relaxed(host->mci_irqenable,
2852 host->base + MMCIMASK0);
2853 mb();
2854 enable_irq(host->core_irqres->start);
2855 host->sdcc_irq_disabled = 0;
2856 }
2857 wake_lock(&host->sdio_wlock);
2858 }
2859 spin_unlock(&host->lock);
2860
2861 return IRQ_HANDLED;
2862}
2863
San Mehat9d2bd732009-09-22 16:44:22 -07002864static void
2865msmsdcc_status_notify_cb(int card_present, void *dev_id)
2866{
2867 struct msmsdcc_host *host = dev_id;
2868
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002869 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07002870 card_present);
2871 msmsdcc_check_status((unsigned long) host);
2872}
2873
San Mehat9d2bd732009-09-22 16:44:22 -07002874static int
2875msmsdcc_init_dma(struct msmsdcc_host *host)
2876{
2877 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
2878 host->dma.host = host;
2879 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07002880 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07002881
2882 if (!host->dmares)
2883 return -ENODEV;
2884
2885 host->dma.nc = dma_alloc_coherent(NULL,
2886 sizeof(struct msmsdcc_nc_dmadata),
2887 &host->dma.nc_busaddr,
2888 GFP_KERNEL);
2889 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07002890 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07002891 return -ENOMEM;
2892 }
2893 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
2894 host->dma.cmd_busaddr = host->dma.nc_busaddr;
2895 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
2896 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
2897 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07002898 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07002899
2900 return 0;
2901}
2902
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002903#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
2904/**
2905 * Allocate and Connect a SDCC peripheral's SPS endpoint
2906 *
2907 * This function allocates endpoint context and
2908 * connect it with memory endpoint by calling
2909 * appropriate SPS driver APIs.
2910 *
2911 * Also registers a SPS callback function with
2912 * SPS driver
2913 *
2914 * This function should only be called once typically
2915 * during driver probe.
2916 *
2917 * @host - Pointer to sdcc host structure
2918 * @ep - Pointer to sps endpoint data structure
2919 * @is_produce - 1 means Producer endpoint
2920 * 0 means Consumer endpoint
2921 *
2922 * @return - 0 if successful else negative value.
2923 *
2924 */
2925static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
2926 struct msmsdcc_sps_ep_conn_data *ep,
2927 bool is_producer)
2928{
2929 int rc = 0;
2930 struct sps_pipe *sps_pipe_handle;
2931 struct sps_connect *sps_config = &ep->config;
2932 struct sps_register_event *sps_event = &ep->event;
2933
2934 /* Allocate endpoint context */
2935 sps_pipe_handle = sps_alloc_endpoint();
2936 if (!sps_pipe_handle) {
2937 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
2938 mmc_hostname(host->mmc), is_producer);
2939 rc = -ENOMEM;
2940 goto out;
2941 }
2942
2943 /* Get default connection configuration for an endpoint */
2944 rc = sps_get_config(sps_pipe_handle, sps_config);
2945 if (rc) {
2946 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
2947 " rc=%d", mmc_hostname(host->mmc),
2948 (u32)sps_pipe_handle, rc);
2949 goto get_config_err;
2950 }
2951
2952 /* Modify the default connection configuration */
2953 if (is_producer) {
2954 /*
2955 * For SDCC producer transfer, source should be
2956 * SDCC peripheral where as destination should
2957 * be system memory.
2958 */
2959 sps_config->source = host->sps.bam_handle;
2960 sps_config->destination = SPS_DEV_HANDLE_MEM;
2961 /* Producer pipe will handle this connection */
2962 sps_config->mode = SPS_MODE_SRC;
2963 sps_config->options =
2964 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
2965 } else {
2966 /*
2967 * For SDCC consumer transfer, source should be
2968 * system memory where as destination should
2969 * SDCC peripheral
2970 */
2971 sps_config->source = SPS_DEV_HANDLE_MEM;
2972 sps_config->destination = host->sps.bam_handle;
2973 sps_config->mode = SPS_MODE_DEST;
2974 sps_config->options =
2975 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
2976 }
2977
2978 /* Producer pipe index */
2979 sps_config->src_pipe_index = host->sps.src_pipe_index;
2980 /* Consumer pipe index */
2981 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
2982 /*
2983 * This event thresold value is only significant for BAM-to-BAM
2984 * transfer. It's ignored for BAM-to-System mode transfer.
2985 */
2986 sps_config->event_thresh = 0x10;
2987 /*
2988 * Max. no of scatter/gather buffers that can
2989 * be passed by block layer = 32 (NR_SG).
2990 * Each BAM descritor needs 64 bits (8 bytes).
2991 * One BAM descriptor is required per buffer transfer.
2992 * So we would require total 256 (32 * 8) bytes of descriptor FIFO.
2993 * But due to HW limitation we need to allocate atleast one extra
2994 * descriptor memory (256 bytes + 8 bytes). But in order to be
2995 * in power of 2, we are allocating 512 bytes of memory.
2996 */
2997 sps_config->desc.size = 512;
2998 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
2999 sps_config->desc.size,
3000 &sps_config->desc.phys_base,
3001 GFP_KERNEL);
3002
3003 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3004
3005 /* Establish connection between peripheral and memory endpoint */
3006 rc = sps_connect(sps_pipe_handle, sps_config);
3007 if (rc) {
3008 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3009 " rc=%d", mmc_hostname(host->mmc),
3010 (u32)sps_pipe_handle, rc);
3011 goto sps_connect_err;
3012 }
3013
3014 sps_event->mode = SPS_TRIGGER_CALLBACK;
3015 sps_event->options = SPS_O_EOT;
3016 sps_event->callback = msmsdcc_sps_complete_cb;
3017 sps_event->xfer_done = NULL;
3018 sps_event->user = (void *)host;
3019
3020 /* Register callback event for EOT (End of transfer) event. */
3021 rc = sps_register_event(sps_pipe_handle, sps_event);
3022 if (rc) {
3023 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3024 " rc=%d", mmc_hostname(host->mmc),
3025 (u32)sps_pipe_handle, rc);
3026 goto reg_event_err;
3027 }
3028 /* Now save the sps pipe handle */
3029 ep->pipe_handle = sps_pipe_handle;
3030 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3031 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3032 __func__, is_producer ? "READ" : "WRITE",
3033 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3034 goto out;
3035
3036reg_event_err:
3037 sps_disconnect(sps_pipe_handle);
3038sps_connect_err:
3039 dma_free_coherent(mmc_dev(host->mmc),
3040 sps_config->desc.size,
3041 sps_config->desc.base,
3042 sps_config->desc.phys_base);
3043get_config_err:
3044 sps_free_endpoint(sps_pipe_handle);
3045out:
3046 return rc;
3047}
3048
3049/**
3050 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3051 *
3052 * This function disconnect endpoint and deallocates
3053 * endpoint context.
3054 *
3055 * This function should only be called once typically
3056 * during driver remove.
3057 *
3058 * @host - Pointer to sdcc host structure
3059 * @ep - Pointer to sps endpoint data structure
3060 *
3061 */
3062static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3063 struct msmsdcc_sps_ep_conn_data *ep)
3064{
3065 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3066 struct sps_connect *sps_config = &ep->config;
3067 struct sps_register_event *sps_event = &ep->event;
3068
3069 sps_event->xfer_done = NULL;
3070 sps_event->callback = NULL;
3071 sps_register_event(sps_pipe_handle, sps_event);
3072 sps_disconnect(sps_pipe_handle);
3073 dma_free_coherent(mmc_dev(host->mmc),
3074 sps_config->desc.size,
3075 sps_config->desc.base,
3076 sps_config->desc.phys_base);
3077 sps_free_endpoint(sps_pipe_handle);
3078}
3079
3080/**
3081 * Reset SDCC peripheral's SPS endpoint
3082 *
3083 * This function disconnects an endpoint.
3084 *
3085 * This function should be called for reseting
3086 * SPS endpoint when data transfer error is
3087 * encountered during data transfer. This
3088 * can be considered as soft reset to endpoint.
3089 *
3090 * This function should only be called if
3091 * msmsdcc_sps_init() is already called.
3092 *
3093 * @host - Pointer to sdcc host structure
3094 * @ep - Pointer to sps endpoint data structure
3095 *
3096 * @return - 0 if successful else negative value.
3097 */
3098static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3099 struct msmsdcc_sps_ep_conn_data *ep)
3100{
3101 int rc = 0;
3102 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3103
3104 rc = sps_disconnect(sps_pipe_handle);
3105 if (rc) {
3106 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3107 " rc=%d", mmc_hostname(host->mmc), __func__,
3108 (u32)sps_pipe_handle, rc);
3109 goto out;
3110 }
3111 out:
3112 return rc;
3113}
3114
3115/**
3116 * Restore SDCC peripheral's SPS endpoint
3117 *
3118 * This function connects an endpoint.
3119 *
3120 * This function should be called for restoring
3121 * SPS endpoint after data transfer error is
3122 * encountered during data transfer. This
3123 * can be considered as soft reset to endpoint.
3124 *
3125 * This function should only be called if
3126 * msmsdcc_sps_reset_ep() is called before.
3127 *
3128 * @host - Pointer to sdcc host structure
3129 * @ep - Pointer to sps endpoint data structure
3130 *
3131 * @return - 0 if successful else negative value.
3132 */
3133static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3134 struct msmsdcc_sps_ep_conn_data *ep)
3135{
3136 int rc = 0;
3137 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3138 struct sps_connect *sps_config = &ep->config;
3139 struct sps_register_event *sps_event = &ep->event;
3140
3141 /* Establish connection between peripheral and memory endpoint */
3142 rc = sps_connect(sps_pipe_handle, sps_config);
3143 if (rc) {
3144 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3145 " rc=%d", mmc_hostname(host->mmc), __func__,
3146 (u32)sps_pipe_handle, rc);
3147 goto out;
3148 }
3149
3150 /* Register callback event for EOT (End of transfer) event. */
3151 rc = sps_register_event(sps_pipe_handle, sps_event);
3152 if (rc) {
3153 pr_err("%s: %s: sps_register_event() failed!!!"
3154 " pipe_handle=0x%x, rc=%d",
3155 mmc_hostname(host->mmc), __func__,
3156 (u32)sps_pipe_handle, rc);
3157 goto reg_event_err;
3158 }
3159 goto out;
3160
3161reg_event_err:
3162 sps_disconnect(sps_pipe_handle);
3163out:
3164 return rc;
3165}
3166
3167/**
3168 * Initialize SPS HW connected with SDCC core
3169 *
3170 * This function register BAM HW resources with
3171 * SPS driver and then initialize 2 SPS endpoints
3172 *
3173 * This function should only be called once typically
3174 * during driver probe.
3175 *
3176 * @host - Pointer to sdcc host structure
3177 *
3178 * @return - 0 if successful else negative value.
3179 *
3180 */
3181static int msmsdcc_sps_init(struct msmsdcc_host *host)
3182{
3183 int rc = 0;
3184 struct sps_bam_props bam = {0};
3185
3186 host->bam_base = ioremap(host->bam_memres->start,
3187 resource_size(host->bam_memres));
3188 if (!host->bam_base) {
3189 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3190 " size=0x%x", mmc_hostname(host->mmc),
3191 host->bam_memres->start,
3192 (host->bam_memres->end -
3193 host->bam_memres->start));
3194 rc = -ENOMEM;
3195 goto out;
3196 }
3197
3198 bam.phys_addr = host->bam_memres->start;
3199 bam.virt_addr = host->bam_base;
3200 /*
3201 * This event thresold value is only significant for BAM-to-BAM
3202 * transfer. It's ignored for BAM-to-System mode transfer.
3203 */
3204 bam.event_threshold = 0x10; /* Pipe event threshold */
3205 /*
3206 * This threshold controls when the BAM publish
3207 * the descriptor size on the sideband interface.
3208 * SPS HW will only be used when
3209 * data transfer size > MCI_FIFOSIZE (64 bytes).
3210 * PIO mode will be used when
3211 * data transfer size < MCI_FIFOSIZE (64 bytes).
3212 * So set this thresold value to 64 bytes.
3213 */
3214 bam.summing_threshold = 64;
3215 /* SPS driver wll handle the SDCC BAM IRQ */
3216 bam.irq = (u32)host->bam_irqres->start;
3217 bam.manage = SPS_BAM_MGR_LOCAL;
3218
3219 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3220 (u32)bam.phys_addr);
3221 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3222 (u32)bam.virt_addr);
3223
3224 /* Register SDCC Peripheral BAM device to SPS driver */
3225 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3226 if (rc) {
3227 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3228 mmc_hostname(host->mmc), rc);
3229 goto reg_bam_err;
3230 }
3231 pr_info("%s: BAM device registered. bam_handle=0x%x",
3232 mmc_hostname(host->mmc), host->sps.bam_handle);
3233
3234 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3235 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3236
3237 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3238 SPS_PROD_PERIPHERAL);
3239 if (rc)
3240 goto sps_reset_err;
3241 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3242 SPS_CONS_PERIPHERAL);
3243 if (rc)
3244 goto cons_conn_err;
3245
3246 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3247 mmc_hostname(host->mmc),
3248 (unsigned long long)host->bam_memres->start,
3249 (unsigned int)host->bam_irqres->start);
3250 goto out;
3251
3252cons_conn_err:
3253 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3254sps_reset_err:
3255 sps_deregister_bam_device(host->sps.bam_handle);
3256reg_bam_err:
3257 iounmap(host->bam_base);
3258out:
3259 return rc;
3260}
3261
3262/**
3263 * De-initialize SPS HW connected with SDCC core
3264 *
3265 * This function deinitialize SPS endpoints and then
3266 * deregisters BAM resources from SPS driver.
3267 *
3268 * This function should only be called once typically
3269 * during driver remove.
3270 *
3271 * @host - Pointer to sdcc host structure
3272 *
3273 */
3274static void msmsdcc_sps_exit(struct msmsdcc_host *host)
3275{
3276 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
3277 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3278 sps_deregister_bam_device(host->sps.bam_handle);
3279 iounmap(host->bam_base);
3280}
3281#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
3282
3283static ssize_t
3284show_polling(struct device *dev, struct device_attribute *attr, char *buf)
3285{
3286 struct mmc_host *mmc = dev_get_drvdata(dev);
3287 struct msmsdcc_host *host = mmc_priv(mmc);
3288 int poll;
3289 unsigned long flags;
3290
3291 spin_lock_irqsave(&host->lock, flags);
3292 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
3293 spin_unlock_irqrestore(&host->lock, flags);
3294
3295 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
3296}
3297
3298static ssize_t
3299set_polling(struct device *dev, struct device_attribute *attr,
3300 const char *buf, size_t count)
3301{
3302 struct mmc_host *mmc = dev_get_drvdata(dev);
3303 struct msmsdcc_host *host = mmc_priv(mmc);
3304 int value;
3305 unsigned long flags;
3306
3307 sscanf(buf, "%d", &value);
3308
3309 spin_lock_irqsave(&host->lock, flags);
3310 if (value) {
3311 mmc->caps |= MMC_CAP_NEEDS_POLL;
3312 mmc_detect_change(host->mmc, 0);
3313 } else {
3314 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3315 }
3316#ifdef CONFIG_HAS_EARLYSUSPEND
3317 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
3318#endif
3319 spin_unlock_irqrestore(&host->lock, flags);
3320 return count;
3321}
3322
3323static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
3324 show_polling, set_polling);
3325static struct attribute *dev_attrs[] = {
3326 &dev_attr_polling.attr,
3327 NULL,
3328};
3329static struct attribute_group dev_attr_grp = {
3330 .attrs = dev_attrs,
3331};
3332
3333#ifdef CONFIG_HAS_EARLYSUSPEND
3334static void msmsdcc_early_suspend(struct early_suspend *h)
3335{
3336 struct msmsdcc_host *host =
3337 container_of(h, struct msmsdcc_host, early_suspend);
3338 unsigned long flags;
3339
3340 spin_lock_irqsave(&host->lock, flags);
3341 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
3342 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3343 spin_unlock_irqrestore(&host->lock, flags);
3344};
3345static void msmsdcc_late_resume(struct early_suspend *h)
3346{
3347 struct msmsdcc_host *host =
3348 container_of(h, struct msmsdcc_host, early_suspend);
3349 unsigned long flags;
3350
3351 if (host->polling_enabled) {
3352 spin_lock_irqsave(&host->lock, flags);
3353 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
3354 mmc_detect_change(host->mmc, 0);
3355 spin_unlock_irqrestore(&host->lock, flags);
3356 }
3357};
3358#endif
3359
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303360void msmsdcc_print_regs(const char *name, void __iomem *base,
3361 unsigned int no_of_regs)
3362{
3363 unsigned int i;
3364
3365 if (!base)
3366 return;
3367 pr_info("===== %s: Register Dumps @base=0x%x =====\n",
3368 name, (u32)base);
3369 for (i = 0; i < no_of_regs; i = i + 4) {
3370 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x.\n", i*4,
3371 (u32)readl_relaxed(base + i*4),
3372 (u32)readl_relaxed(base + ((i+1)*4)),
3373 (u32)readl_relaxed(base + ((i+2)*4)),
3374 (u32)readl_relaxed(base + ((i+3)*4)));
3375 }
3376}
3377
3378static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
3379{
3380 /* Dump current state of SDCC clocks, power and irq */
3381 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
3382 (host->pwr ? "ON" : "OFF"));
3383 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
3384 mmc_hostname(host->mmc),
3385 (host->clks_on ? "ON" : "OFF"),
3386 (u32)clk_get_rate(host->clk));
3387 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
3388 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
3389
3390 /* Now dump SDCC registers. Don't print FIFO registers */
3391 if (host->clks_on)
3392 msmsdcc_print_regs("SDCC-CORE", host->base, 28);
3393
3394 if (host->curr.data) {
3395 if (msmsdcc_check_dma_op_req(host->curr.data))
3396 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
3397 else if (host->is_dma_mode)
3398 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
3399 mmc_hostname(host->mmc), host->dma.busy,
3400 host->dma.channel, host->dma.crci);
3401 else if (host->is_sps_mode)
3402 pr_info("%s: SPS mode: busy=%d\n",
3403 mmc_hostname(host->mmc), host->sps.busy);
3404
3405 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
3406 mmc_hostname(host->mmc), host->curr.xfer_size,
3407 host->curr.data_xfered, host->curr.xfer_remain);
3408 pr_info("%s: got_dataend=%d, prog_enable=%d,"
3409 " wait_for_auto_prog_done=%d,"
3410 " got_auto_prog_done=%d\n",
3411 mmc_hostname(host->mmc), host->curr.got_dataend,
3412 host->prog_enable, host->curr.wait_for_auto_prog_done,
3413 host->curr.got_auto_prog_done);
3414 }
3415
3416}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003417static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
3418{
3419 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3420 struct mmc_request *mrq;
3421 unsigned long flags;
3422
3423 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003424 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003425 pr_info("%s: %s: dummy CMD52 timeout\n",
3426 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003427 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003428 }
3429
3430 mrq = host->curr.mrq;
3431
3432 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303433 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
3434 mrq->cmd->opcode);
3435 msmsdcc_dump_sdcc_state(host);
3436
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003437 if (!mrq->cmd->error)
3438 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303439 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003440 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003441 if (mrq->data && !mrq->data->error)
3442 mrq->data->error = -ETIMEDOUT;
3443 host->curr.data_xfered = 0;
3444 if (host->dma.sg && host->is_dma_mode) {
3445 msm_dmov_stop_cmd(host->dma.channel,
3446 &host->dma.hdr, 0);
3447 } else if (host->sps.sg && host->is_sps_mode) {
3448 /* Stop current SPS transfer */
3449 msmsdcc_sps_exit_curr_xfer(host);
3450 } else {
3451 msmsdcc_reset_and_restore(host);
3452 msmsdcc_stop_data(host);
3453 if (mrq->data && mrq->data->stop)
3454 msmsdcc_start_command(host,
3455 mrq->data->stop, 0);
3456 else
3457 msmsdcc_request_end(host, mrq);
3458 }
3459 } else {
3460 if (host->prog_enable) {
3461 host->prog_scan = 0;
3462 host->prog_enable = 0;
3463 }
3464 msmsdcc_reset_and_restore(host);
3465 msmsdcc_request_end(host, mrq);
3466 }
3467 }
3468 spin_unlock_irqrestore(&host->lock, flags);
3469}
3470
San Mehat9d2bd732009-09-22 16:44:22 -07003471static int
3472msmsdcc_probe(struct platform_device *pdev)
3473{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003474 struct mmc_platform_data *plat = pdev->dev.platform_data;
San Mehat9d2bd732009-09-22 16:44:22 -07003475 struct msmsdcc_host *host;
3476 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003477 unsigned long flags;
3478 struct resource *core_irqres = NULL;
3479 struct resource *bam_irqres = NULL;
3480 struct resource *core_memres = NULL;
3481 struct resource *dml_memres = NULL;
3482 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07003483 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07003484 struct resource *dma_crci_res = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07003485 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003486 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07003487
3488 /* must have platform data */
3489 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003490 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003491 ret = -EINVAL;
3492 goto out;
3493 }
3494
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003495 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07003496 return -EINVAL;
3497
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003498 if (plat->is_sdio_al_client)
3499 if (!plat->sdio_lpm_gpio_setup || !plat->sdiowakeup_irq)
3500 return -EINVAL;
3501
San Mehat9d2bd732009-09-22 16:44:22 -07003502 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003503 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003504 return -ENXIO;
3505 }
3506
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003507 for (i = 0; i < pdev->num_resources; i++) {
3508 if (pdev->resource[i].flags & IORESOURCE_MEM) {
3509 if (!strcmp(pdev->resource[i].name,
3510 "sdcc_dml_addr"))
3511 dml_memres = &pdev->resource[i];
3512 else if (!strcmp(pdev->resource[i].name,
3513 "sdcc_bam_addr"))
3514 bam_memres = &pdev->resource[i];
3515 else
3516 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07003517
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003518 }
3519 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
3520 if (!strcmp(pdev->resource[i].name,
3521 "sdcc_bam_irq"))
3522 bam_irqres = &pdev->resource[i];
3523 else
3524 core_irqres = &pdev->resource[i];
3525 }
Krishna Konda25786ec2011-07-25 16:21:36 -07003526 if (pdev->resource[i].flags & IORESOURCE_DMA) {
3527 if (!strncmp(pdev->resource[i].name,
3528 "sdcc_dma_chnl",
3529 sizeof("sdcc_dma_chnl")))
3530 dmares = &pdev->resource[i];
3531 else if (!strncmp(pdev->resource[i].name,
3532 "sdcc_dma_crci",
3533 sizeof("sdcc_dma_crci")))
3534 dma_crci_res = &pdev->resource[i];
3535 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003536 }
3537
3538 if (!core_irqres || !core_memres) {
3539 pr_err("%s: Invalid sdcc core resource\n", __func__);
3540 return -ENXIO;
3541 }
3542
3543 /*
3544 * Both BAM and DML memory resource should be preset.
3545 * BAM IRQ resource should also be present.
3546 */
3547 if ((bam_memres && !dml_memres) ||
3548 (!bam_memres && dml_memres) ||
3549 ((bam_memres && dml_memres) && !bam_irqres)) {
3550 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003551 return -ENXIO;
3552 }
3553
3554 /*
3555 * Setup our host structure
3556 */
San Mehat9d2bd732009-09-22 16:44:22 -07003557 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
3558 if (!mmc) {
3559 ret = -ENOMEM;
3560 goto out;
3561 }
3562
3563 host = mmc_priv(mmc);
3564 host->pdev_id = pdev->id;
3565 host->plat = plat;
3566 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08003567 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05303568
3569 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003570 host->is_sps_mode = 1;
3571 else if (dmares)
3572 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07003573
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003574 host->base = ioremap(core_memres->start,
3575 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07003576 if (!host->base) {
3577 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003578 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003579 }
3580
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003581 host->core_irqres = core_irqres;
3582 host->bam_irqres = bam_irqres;
3583 host->core_memres = core_memres;
3584 host->dml_memres = dml_memres;
3585 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07003586 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07003587 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07003588 spin_lock_init(&host->lock);
3589
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003590#ifdef CONFIG_MMC_EMBEDDED_SDIO
3591 if (plat->embedded_sdio)
3592 mmc_set_embedded_sdio_data(mmc,
3593 &plat->embedded_sdio->cis,
3594 &plat->embedded_sdio->cccr,
3595 plat->embedded_sdio->funcs,
3596 plat->embedded_sdio->num_funcs);
3597#endif
3598
Sahitya Tummala62612cf2010-12-08 15:03:03 +05303599 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
3600 (unsigned long)host);
3601
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003602 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
3603 (unsigned long)host);
3604 if (host->is_dma_mode) {
3605 /* Setup DMA */
3606 ret = msmsdcc_init_dma(host);
3607 if (ret)
3608 goto ioremap_free;
3609 } else {
3610 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003611 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003612 }
3613
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003614 /*
3615 * Setup SDCC clock if derived from Dayatona
3616 * fabric core clock.
3617 */
3618 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07003619 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003620 if (!IS_ERR(host->dfab_pclk)) {
3621 /* Set the clock rate to 64MHz for max. performance */
3622 ret = clk_set_rate(host->dfab_pclk, 64000000);
3623 if (ret)
3624 goto dfab_pclk_put;
3625 ret = clk_enable(host->dfab_pclk);
3626 if (ret)
3627 goto dfab_pclk_put;
3628 } else
3629 goto dma_free;
3630 }
3631
3632 /*
3633 * Setup main peripheral bus clock
3634 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003635 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003636 if (!IS_ERR(host->pclk)) {
3637 ret = clk_enable(host->pclk);
3638 if (ret)
3639 goto pclk_put;
3640
3641 host->pclk_rate = clk_get_rate(host->pclk);
3642 }
3643
3644 /*
3645 * Setup SDC MMC clock
3646 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003647 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07003648 if (IS_ERR(host->clk)) {
3649 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003650 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07003651 }
3652
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003653 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
3654 if (ret) {
3655 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
3656 goto clk_put;
3657 }
3658
3659 ret = clk_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003660 if (ret)
3661 goto clk_put;
3662
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003663 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303664 if (!host->clk_rate)
3665 dev_err(&pdev->dev, "Failed to read MCLK\n");
3666 /*
3667 * Set the register write delay according to min. clock frequency
3668 * supported and update later when the host->clk_rate changes.
3669 */
3670 host->reg_write_delay =
3671 (1 + ((3 * USEC_PER_SEC) /
3672 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003673
3674 host->clks_on = 1;
3675
3676 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07003677 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003678 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07003679 goto clk_disable;
3680 }
3681
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003682
3683 /* Clocks has to be running before accessing SPS/DML HW blocks */
3684 if (host->is_sps_mode) {
3685 /* Initialize SPS */
3686 ret = msmsdcc_sps_init(host);
3687 if (ret)
3688 goto vreg_deinit;
3689 /* Initialize DML */
3690 ret = msmsdcc_dml_init(host);
3691 if (ret)
3692 goto sps_exit;
3693 }
San Mehat9d2bd732009-09-22 16:44:22 -07003694
San Mehat9d2bd732009-09-22 16:44:22 -07003695 /*
3696 * Setup MMC host structure
3697 */
3698 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003699 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
3700 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003701 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003702 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
3703 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07003704
San Mehat9d2bd732009-09-22 16:44:22 -07003705 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05303706
3707 /*
3708 * If we send the CMD23 before multi block write/read command
3709 * then we need not to send CMD12 at the end of the transfer.
3710 * If we don't send the CMD12 then only way to detect the PROG_DONE
3711 * status is to use the AUTO_PROG_DONE status provided by SDCC4
3712 * controller. So let's enable the CMD23 for SDCC4 only.
3713 */
Sahitya Tummala85fa0702011-09-15 09:39:37 +05303714 if (!plat->disable_cmd23 && host->plat->sdcc_v4_sup)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05303715 mmc->caps |= MMC_CAP_CMD23;
3716
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003717 mmc->caps |= plat->uhs_caps;
3718 /*
3719 * XPC controls the maximum current in the default speed mode of SDXC
3720 * card. XPC=0 means 100mA (max.) but speed class is not supported.
3721 * XPC=1 means 150mA (max.) and speed class is supported.
3722 */
3723 if (plat->xpc_cap)
3724 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
3725 MMC_CAP_SET_XPC_180);
3726
3727 if (plat->nonremovable)
3728 mmc->caps |= MMC_CAP_NONREMOVABLE;
3729#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
3730 mmc->caps |= MMC_CAP_SDIO_IRQ;
3731#endif
3732
3733 if (plat->is_sdio_al_client)
3734 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07003735
Martin K. Petersena36274e2010-09-10 01:33:59 -04003736 mmc->max_segs = NR_SG;
San Mehat9d2bd732009-09-22 16:44:22 -07003737 mmc->max_blk_size = 4096; /* MCI_DATA_CTL BLOCKSIZE up to 4096 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003738 mmc->max_blk_count = 65535;
San Mehat9d2bd732009-09-22 16:44:22 -07003739
3740 mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */
3741 mmc->max_seg_size = mmc->max_req_size;
3742
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003743 writel_relaxed(0, host->base + MMCIMASK0);
3744 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -07003745
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003746 /* Delay needed (MMCIMASK0 was just written above) */
3747 msmsdcc_delay(host);
3748 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
3749 mb();
3750 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07003751
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003752 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
3753 DRIVER_NAME " (cmd)", host);
3754 if (ret)
3755 goto dml_exit;
3756
3757 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
3758 DRIVER_NAME " (pio)", host);
3759 if (ret)
3760 goto irq_free;
3761
3762 /*
3763 * Enable SDCC IRQ only when host is powered on. Otherwise, this
3764 * IRQ is un-necessarily being monitored by MPM (Modem power
3765 * management block) during idle-power collapse. The MPM will be
3766 * configured to monitor the DATA1 GPIO line with level-low trigger
3767 * and thus depending on the GPIO status, it prevents TCXO shutdown
3768 * during idle-power collapse.
3769 */
3770 disable_irq(core_irqres->start);
3771 host->sdcc_irq_disabled = 1;
3772
3773 if (plat->sdiowakeup_irq) {
3774 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3775 mmc_hostname(mmc));
3776 ret = request_irq(plat->sdiowakeup_irq,
3777 msmsdcc_platform_sdiowakeup_irq,
3778 IRQF_SHARED | IRQF_TRIGGER_LOW,
3779 DRIVER_NAME "sdiowakeup", host);
3780 if (ret) {
3781 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
3782 plat->sdiowakeup_irq, ret);
3783 goto pio_irq_free;
3784 } else {
3785 spin_lock_irqsave(&host->lock, flags);
3786 if (!host->sdio_irq_disabled) {
3787 disable_irq_nosync(plat->sdiowakeup_irq);
3788 host->sdio_irq_disabled = 1;
3789 }
3790 spin_unlock_irqrestore(&host->lock, flags);
3791 }
3792 }
3793
3794 if (plat->cfg_mpm_sdiowakeup) {
3795 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3796 mmc_hostname(mmc));
3797 }
3798
3799 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
3800 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003801 /*
3802 * Setup card detect change
3803 */
3804
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003805 if (plat->status || plat->status_gpio) {
3806 if (plat->status)
3807 host->oldstat = plat->status(mmc_dev(host->mmc));
3808 else
3809 host->oldstat = msmsdcc_slot_status(host);
3810 host->eject = !host->oldstat;
3811 }
San Mehat9d2bd732009-09-22 16:44:22 -07003812
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003813 if (plat->status_irq) {
3814 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07003815 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003816 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07003817 DRIVER_NAME " (slot)",
3818 host);
3819 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003820 pr_err("Unable to get slot IRQ %d (%d)\n",
3821 plat->status_irq, ret);
3822 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003823 }
3824 } else if (plat->register_status_notify) {
3825 plat->register_status_notify(msmsdcc_status_notify_cb, host);
3826 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003827 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07003828 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003829
3830 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003831
3832 ret = pm_runtime_set_active(&(pdev)->dev);
3833 if (ret < 0)
3834 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3835 __func__, ret);
3836 /*
3837 * There is no notion of suspend/resume for SD/MMC/SDIO
3838 * cards. So host can be suspended/resumed with out
3839 * worrying about its children.
3840 */
3841 pm_suspend_ignore_children(&(pdev)->dev, true);
3842
3843 /*
3844 * MMC/SD/SDIO bus suspend/resume operations are defined
3845 * only for the slots that will be used for non-removable
3846 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
3847 * defined. Otherwise, they simply become card removal and
3848 * insertion events during suspend and resume respectively.
3849 * Hence, enable run-time PM only for slots for which bus
3850 * suspend/resume operations are defined.
3851 */
3852#ifdef CONFIG_MMC_UNSAFE_RESUME
3853 /*
3854 * If this capability is set, MMC core will enable/disable host
3855 * for every claim/release operation on a host. We use this
3856 * notification to increment/decrement runtime pm usage count.
3857 */
3858 mmc->caps |= MMC_CAP_DISABLE;
3859 pm_runtime_enable(&(pdev)->dev);
3860#else
3861 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
3862 mmc->caps |= MMC_CAP_DISABLE;
3863 pm_runtime_enable(&(pdev)->dev);
3864 }
3865#endif
3866 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
3867 (unsigned long)host);
3868
San Mehat9d2bd732009-09-22 16:44:22 -07003869 mmc_add_host(mmc);
3870
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003871#ifdef CONFIG_HAS_EARLYSUSPEND
3872 host->early_suspend.suspend = msmsdcc_early_suspend;
3873 host->early_suspend.resume = msmsdcc_late_resume;
3874 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
3875 register_early_suspend(&host->early_suspend);
3876#endif
San Mehat9d2bd732009-09-22 16:44:22 -07003877
Krishna Konda25786ec2011-07-25 16:21:36 -07003878 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
3879 " dmacrcri %d\n", mmc_hostname(mmc),
3880 (unsigned long long)core_memres->start,
3881 (unsigned int) core_irqres->start,
3882 (unsigned int) plat->status_irq, host->dma.channel,
3883 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003884
3885 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
3886 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
3887 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
3888 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
3889 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
3890 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
3891 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
3892 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
3893 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
3894 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
3895 host->eject);
3896 pr_info("%s: Power save feature enable = %d\n",
3897 mmc_hostname(mmc), msmsdcc_pwrsave);
3898
Krishna Konda25786ec2011-07-25 16:21:36 -07003899 if (host->is_dma_mode && host->dma.channel != -1
3900 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003901 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003902 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003903 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003904 mmc_hostname(mmc), host->dma.cmd_busaddr,
3905 host->dma.cmdptr_busaddr);
3906 } else if (host->is_sps_mode) {
3907 pr_info("%s: SPS-BAM data transfer mode available\n",
3908 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003909 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003910 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003911
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003912#if defined(CONFIG_DEBUG_FS)
3913 msmsdcc_dbg_createhost(host);
3914#endif
3915 if (!plat->status_irq) {
3916 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
3917 if (ret)
3918 goto platform_irq_free;
3919 }
San Mehat9d2bd732009-09-22 16:44:22 -07003920 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003921
3922 platform_irq_free:
3923 del_timer_sync(&host->req_tout_timer);
3924 pm_runtime_disable(&(pdev)->dev);
3925 pm_runtime_set_suspended(&(pdev)->dev);
3926
3927 if (plat->status_irq)
3928 free_irq(plat->status_irq, host);
3929 sdiowakeup_irq_free:
3930 wake_lock_destroy(&host->sdio_suspend_wlock);
3931 if (plat->sdiowakeup_irq)
3932 free_irq(plat->sdiowakeup_irq, host);
3933 pio_irq_free:
3934 if (plat->sdiowakeup_irq)
3935 wake_lock_destroy(&host->sdio_wlock);
3936 free_irq(core_irqres->start, host);
3937 irq_free:
3938 free_irq(core_irqres->start, host);
3939 dml_exit:
3940 if (host->is_sps_mode)
3941 msmsdcc_dml_exit(host);
3942 sps_exit:
3943 if (host->is_sps_mode)
3944 msmsdcc_sps_exit(host);
3945 vreg_deinit:
3946 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07003947 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003948 clk_disable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003949 clk_put:
3950 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003951 pclk_disable:
3952 if (!IS_ERR(host->pclk))
3953 clk_disable(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07003954 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003955 if (!IS_ERR(host->pclk))
3956 clk_put(host->pclk);
3957 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3958 clk_disable(host->dfab_pclk);
3959 dfab_pclk_put:
3960 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3961 clk_put(host->dfab_pclk);
3962 dma_free:
3963 if (host->is_dma_mode) {
3964 if (host->dmares)
3965 dma_free_coherent(NULL,
3966 sizeof(struct msmsdcc_nc_dmadata),
3967 host->dma.nc, host->dma.nc_busaddr);
3968 }
3969 ioremap_free:
3970 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07003971 host_free:
3972 mmc_free_host(mmc);
3973 out:
3974 return ret;
3975}
3976
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003977static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07003978{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003979 struct mmc_host *mmc = mmc_get_drvdata(pdev);
3980 struct mmc_platform_data *plat;
3981 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07003982
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003983 if (!mmc)
3984 return -ENXIO;
3985
3986 if (pm_runtime_suspended(&(pdev)->dev))
3987 pm_runtime_resume(&(pdev)->dev);
3988
3989 host = mmc_priv(mmc);
3990
3991 DBG(host, "Removing SDCC device = %d\n", pdev->id);
3992 plat = host->plat;
3993
3994 if (!plat->status_irq)
3995 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
3996
3997 del_timer_sync(&host->req_tout_timer);
3998 tasklet_kill(&host->dma_tlet);
3999 tasklet_kill(&host->sps.tlet);
4000 mmc_remove_host(mmc);
4001
4002 if (plat->status_irq)
4003 free_irq(plat->status_irq, host);
4004
4005 wake_lock_destroy(&host->sdio_suspend_wlock);
4006 if (plat->sdiowakeup_irq) {
4007 wake_lock_destroy(&host->sdio_wlock);
4008 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
4009 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07004010 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004011
4012 free_irq(host->core_irqres->start, host);
4013 free_irq(host->core_irqres->start, host);
4014
4015 clk_put(host->clk);
4016 if (!IS_ERR(host->pclk))
4017 clk_put(host->pclk);
4018 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4019 clk_put(host->dfab_pclk);
4020
4021 msmsdcc_vreg_init(host, false);
4022
4023 if (host->is_dma_mode) {
4024 if (host->dmares)
4025 dma_free_coherent(NULL,
4026 sizeof(struct msmsdcc_nc_dmadata),
4027 host->dma.nc, host->dma.nc_busaddr);
4028 }
4029
4030 if (host->is_sps_mode) {
4031 msmsdcc_dml_exit(host);
4032 msmsdcc_sps_exit(host);
4033 }
4034
4035 iounmap(host->base);
4036 mmc_free_host(mmc);
4037
4038#ifdef CONFIG_HAS_EARLYSUSPEND
4039 unregister_early_suspend(&host->early_suspend);
4040#endif
4041 pm_runtime_disable(&(pdev)->dev);
4042 pm_runtime_set_suspended(&(pdev)->dev);
4043
4044 return 0;
4045}
4046
4047#ifdef CONFIG_MSM_SDIO_AL
4048int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4049{
4050 struct msmsdcc_host *host = mmc_priv(mmc);
4051 unsigned long flags;
4052
4053 spin_lock_irqsave(&host->lock, flags);
4054 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
4055 enable ? "En" : "Dis");
4056
4057 if (enable) {
4058 if (!host->sdcc_irq_disabled) {
4059 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05304060 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004061 host->sdcc_irq_disabled = 1;
4062 }
4063
4064 if (host->clks_on) {
4065 msmsdcc_setup_clocks(host, false);
4066 host->clks_on = 0;
4067 }
4068
4069 if (!host->sdio_gpio_lpm) {
4070 spin_unlock_irqrestore(&host->lock, flags);
4071 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
4072 spin_lock_irqsave(&host->lock, flags);
4073 host->sdio_gpio_lpm = 1;
4074 }
4075
4076 if (host->sdio_irq_disabled) {
4077 msmsdcc_enable_irq_wake(host);
4078 enable_irq(host->plat->sdiowakeup_irq);
4079 host->sdio_irq_disabled = 0;
4080 }
4081 } else {
4082 if (!host->sdio_irq_disabled) {
4083 disable_irq_nosync(host->plat->sdiowakeup_irq);
4084 host->sdio_irq_disabled = 1;
4085 msmsdcc_disable_irq_wake(host);
4086 }
4087
4088 if (host->sdio_gpio_lpm) {
4089 spin_unlock_irqrestore(&host->lock, flags);
4090 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
4091 spin_lock_irqsave(&host->lock, flags);
4092 host->sdio_gpio_lpm = 0;
4093 }
4094
4095 if (!host->clks_on) {
4096 msmsdcc_setup_clocks(host, true);
4097 host->clks_on = 1;
4098 }
4099
4100 if (host->sdcc_irq_disabled) {
4101 writel_relaxed(host->mci_irqenable,
4102 host->base + MMCIMASK0);
4103 mb();
4104 enable_irq(host->core_irqres->start);
4105 host->sdcc_irq_disabled = 0;
4106 }
4107 wake_lock_timeout(&host->sdio_wlock, 1);
4108 }
4109 spin_unlock_irqrestore(&host->lock, flags);
4110 return 0;
4111}
4112#else
4113int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4114{
4115 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004116}
4117#endif
4118
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004119#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07004120static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004121msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004122{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004123 struct mmc_host *mmc = dev_get_drvdata(dev);
4124 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07004125 int rc = 0;
4126
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004127 if (host->plat->is_sdio_al_client)
4128 return 0;
4129
Sahitya Tummala7661a452011-07-18 13:28:35 +05304130 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004131 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004132 host->sdcc_suspending = 1;
4133 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07004134
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004135 /*
4136 * If the clocks are already turned off by SDIO clients (as
4137 * part of LPM), then clocks should be turned on before
4138 * calling mmc_suspend_host() because mmc_suspend_host might
4139 * send some commands to the card. The clocks will be turned
4140 * off again after mmc_suspend_host. Thus for SD/MMC/SDIO
4141 * cards, clocks will be turned on before mmc_suspend_host
4142 * and turned off after mmc_suspend_host.
4143 */
4144 mmc->ios.clock = host->clk_rate;
4145 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07004146
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004147 /*
4148 * MMC core thinks that host is disabled by now since
4149 * runtime suspend is scheduled after msmsdcc_disable()
4150 * is called. Thus, MMC core will try to enable the host
4151 * while suspending it. This results in a synchronous
4152 * runtime resume request while in runtime suspending
4153 * context and hence inorder to complete this resume
4154 * requet, it will wait for suspend to be complete,
4155 * but runtime suspend also can not proceed further
4156 * until the host is resumed. Thus, it leads to a hang.
4157 * Hence, increase the pm usage count before suspending
4158 * the host so that any resume requests after this will
4159 * simple become pm usage counter increment operations.
4160 */
4161 pm_runtime_get_noresume(dev);
4162 rc = mmc_suspend_host(mmc);
4163 pm_runtime_put_noidle(dev);
4164
4165 if (!rc) {
4166 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
4167 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ)) {
4168 disable_irq(host->core_irqres->start);
4169 host->sdcc_irq_disabled = 1;
4170
4171 /*
4172 * If MMC core level suspend is not supported,
4173 * turn off clocks to allow deep sleep (TCXO
4174 * shutdown).
4175 */
4176 mmc->ios.clock = 0;
4177 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4178 enable_irq(host->core_irqres->start);
4179 host->sdcc_irq_disabled = 0;
4180
4181 if (host->plat->sdiowakeup_irq) {
4182 host->sdio_irq_disabled = 0;
4183 msmsdcc_enable_irq_wake(host);
4184 enable_irq(host->plat->sdiowakeup_irq);
4185 }
4186 }
4187 }
4188 host->sdcc_suspending = 0;
4189 mmc->suspend_task = NULL;
4190 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
4191 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004192 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304193 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004194 return rc;
4195}
4196
4197static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004198msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004199{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004200 struct mmc_host *mmc = dev_get_drvdata(dev);
4201 struct msmsdcc_host *host = mmc_priv(mmc);
4202 unsigned long flags;
4203
4204 if (host->plat->is_sdio_al_client)
4205 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07004206
Sahitya Tummala7661a452011-07-18 13:28:35 +05304207 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004208 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004209 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
4210 if (host->sdcc_irq_disabled) {
4211 enable_irq(host->core_irqres->start);
4212 host->sdcc_irq_disabled = 0;
4213 }
4214 }
4215 mmc->ios.clock = host->clk_rate;
4216 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07004217
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004218 spin_lock_irqsave(&host->lock, flags);
4219 writel_relaxed(host->mci_irqenable, host->base + MMCIMASK0);
4220 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07004221
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004222 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
4223 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) &&
4224 !host->sdio_irq_disabled) {
4225 if (host->plat->sdiowakeup_irq) {
4226 disable_irq_nosync(
4227 host->plat->sdiowakeup_irq);
4228 msmsdcc_disable_irq_wake(host);
4229 host->sdio_irq_disabled = 1;
4230 }
4231 }
San Mehat9d2bd732009-09-22 16:44:22 -07004232
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004233 spin_unlock_irqrestore(&host->lock, flags);
4234
4235 mmc_resume_host(mmc);
4236
4237 /*
4238 * FIXME: Clearing of flags must be handled in clients
4239 * resume handler.
4240 */
4241 spin_lock_irqsave(&host->lock, flags);
4242 mmc->pm_flags = 0;
4243 spin_unlock_irqrestore(&host->lock, flags);
4244
4245 /*
4246 * After resuming the host wait for sometime so that
4247 * the SDIO work will be processed.
4248 */
4249 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO)) {
4250 if ((host->plat->cfg_mpm_sdiowakeup ||
4251 host->plat->sdiowakeup_irq) &&
4252 wake_lock_active(&host->sdio_wlock))
4253 wake_lock_timeout(&host->sdio_wlock, 1);
4254 }
4255
4256 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004257 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304258 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004259 return 0;
4260}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004261
4262static int msmsdcc_runtime_idle(struct device *dev)
4263{
4264 struct mmc_host *mmc = dev_get_drvdata(dev);
4265 struct msmsdcc_host *host = mmc_priv(mmc);
4266
4267 if (host->plat->is_sdio_al_client)
4268 return 0;
4269
4270 /* Idle timeout is not configurable for now */
4271 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
4272
4273 return -EAGAIN;
4274}
4275
4276static int msmsdcc_pm_suspend(struct device *dev)
4277{
4278 struct mmc_host *mmc = dev_get_drvdata(dev);
4279 struct msmsdcc_host *host = mmc_priv(mmc);
4280 int rc = 0;
4281
4282 if (host->plat->is_sdio_al_client)
4283 return 0;
4284
4285
4286 if (host->plat->status_irq)
4287 disable_irq(host->plat->status_irq);
4288
4289 if (!pm_runtime_suspended(dev))
4290 rc = msmsdcc_runtime_suspend(dev);
4291
4292 return rc;
4293}
4294
4295static int msmsdcc_pm_resume(struct device *dev)
4296{
4297 struct mmc_host *mmc = dev_get_drvdata(dev);
4298 struct msmsdcc_host *host = mmc_priv(mmc);
4299 int rc = 0;
4300
4301 if (host->plat->is_sdio_al_client)
4302 return 0;
4303
Sahitya Tummalafb486372011-09-02 19:01:49 +05304304 if (!pm_runtime_suspended(dev))
4305 rc = msmsdcc_runtime_resume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004306 if (host->plat->status_irq) {
4307 msmsdcc_check_status((unsigned long)host);
4308 enable_irq(host->plat->status_irq);
4309 }
4310
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004311 return rc;
4312}
4313
Daniel Walker08ecfde2010-06-23 12:32:20 -07004314#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004315#define msmsdcc_runtime_suspend NULL
4316#define msmsdcc_runtime_resume NULL
4317#define msmsdcc_runtime_idle NULL
4318#define msmsdcc_pm_suspend NULL
4319#define msmsdcc_pm_resume NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07004320#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004321
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004322static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
4323 .runtime_suspend = msmsdcc_runtime_suspend,
4324 .runtime_resume = msmsdcc_runtime_resume,
4325 .runtime_idle = msmsdcc_runtime_idle,
4326 .suspend = msmsdcc_pm_suspend,
4327 .resume = msmsdcc_pm_resume,
4328};
4329
San Mehat9d2bd732009-09-22 16:44:22 -07004330static struct platform_driver msmsdcc_driver = {
4331 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004332 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07004333 .driver = {
4334 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004335 .pm = &msmsdcc_dev_pm_ops,
San Mehat9d2bd732009-09-22 16:44:22 -07004336 },
4337};
4338
4339static int __init msmsdcc_init(void)
4340{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004341#if defined(CONFIG_DEBUG_FS)
4342 int ret = 0;
4343 ret = msmsdcc_dbg_init();
4344 if (ret) {
4345 pr_err("Failed to create debug fs dir \n");
4346 return ret;
4347 }
4348#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004349 return platform_driver_register(&msmsdcc_driver);
4350}
4351
4352static void __exit msmsdcc_exit(void)
4353{
4354 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004355
4356#if defined(CONFIG_DEBUG_FS)
4357 debugfs_remove(debugfs_file);
4358 debugfs_remove(debugfs_dir);
4359#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004360}
4361
4362module_init(msmsdcc_init);
4363module_exit(msmsdcc_exit);
4364
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004365MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07004366MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004367
4368#if defined(CONFIG_DEBUG_FS)
4369
4370static int
4371msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
4372{
4373 file->private_data = inode->i_private;
4374 return 0;
4375}
4376
4377static ssize_t
4378msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
4379 size_t count, loff_t *ppos)
4380{
4381 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
4382 char buf[1024];
4383 int max, i;
4384
4385 i = 0;
4386 max = sizeof(buf) - 1;
4387
4388 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
4389 host->curr.cmd, host->curr.data);
4390 if (host->curr.cmd) {
4391 struct mmc_command *cmd = host->curr.cmd;
4392
4393 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
4394 cmd->opcode, cmd->arg, cmd->flags);
4395 }
4396 if (host->curr.data) {
4397 struct mmc_data *data = host->curr.data;
4398 i += scnprintf(buf + i, max - i,
4399 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
4400 data->timeout_ns, data->timeout_clks,
4401 data->blksz, data->blocks, data->error,
4402 data->flags);
4403 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
4404 host->curr.xfer_size, host->curr.xfer_remain,
4405 host->curr.data_xfered, host->dma.sg);
4406 }
4407
4408 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
4409}
4410
4411static const struct file_operations msmsdcc_dbg_state_ops = {
4412 .read = msmsdcc_dbg_state_read,
4413 .open = msmsdcc_dbg_state_open,
4414};
4415
4416static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
4417{
4418 if (debugfs_dir) {
4419 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
4420 0644, debugfs_dir, host,
4421 &msmsdcc_dbg_state_ops);
4422 }
4423}
4424
4425static int __init msmsdcc_dbg_init(void)
4426{
4427 int err;
4428
4429 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
4430 if (IS_ERR(debugfs_dir)) {
4431 err = PTR_ERR(debugfs_dir);
4432 debugfs_dir = NULL;
4433 return err;
4434 }
4435
4436 return 0;
4437}
4438#endif