blob: d6a343a305ef77963694e5c9d7fa1c2e9d68b46f [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/**
162 * Apply soft reset
163 *
164 * This function applies soft reset to SDCC core and
165 * BAM, DML core.
166 *
167 * This function should be called to recover from error
168 * conditions encountered with CMD/DATA tranfsers with card.
169 *
170 * Soft reset should only be used with SDCC controller v4.
171 *
172 * @host - Pointer to driver's host structure
173 *
174 */
175static void msmsdcc_soft_reset_and_restore(struct msmsdcc_host *host)
176{
177 int rc;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530178
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700179 if (host->is_sps_mode) {
180 /* Reset DML first */
181 msmsdcc_dml_reset(host);
182 /* Now reset all BAM pipes connections */
183 rc = msmsdcc_sps_reset_ep(host, &host->sps.prod);
184 if (rc)
185 pr_err("%s:msmsdcc_sps_reset_ep() error=%d\n",
186 mmc_hostname(host->mmc), rc);
187 rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
188 if (rc)
189 pr_err("%s:msmsdcc_sps_reset_ep() error=%d\n",
190 mmc_hostname(host->mmc), rc);
191 }
192 /*
193 * Reset SDCC controller's DPSM (data path state machine
194 * and CPSM (command path state machine).
195 */
196 mb();
197 writel_relaxed(0, host->base + MMCICOMMAND);
198 writel_relaxed(0, host->base + MMCIDATACTRL);
199 mb();
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700201 pr_debug("%s: Applied soft reset to Controller\n",
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530202 mmc_hostname(host->mmc));
203
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700204 if (host->is_sps_mode) {
205 /* Restore all BAM pipes connections */
206 rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
207 if (rc)
208 pr_err("%s:msmsdcc_sps_restore_ep() error=%d\n",
209 mmc_hostname(host->mmc), rc);
210 rc = msmsdcc_sps_restore_ep(host, &host->sps.cons);
211 if (rc)
212 pr_err("%s:msmsdcc_sps_restore_ep() error=%d\n",
213 mmc_hostname(host->mmc), rc);
214 msmsdcc_dml_init(host);
215 }
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530216}
217
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700218static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
219{
220 if (host->plat->sdcc_v4_sup) {
221 msmsdcc_soft_reset_and_restore(host);
222 } else {
223 /* Give Clock reset (hard reset) to controller */
224 u32 mci_clk = 0;
225 u32 mci_mask0 = 0;
226 int ret;
227
228 /* Save the controller state */
229 mci_clk = readl_relaxed(host->base + MMCICLOCK);
230 mci_mask0 = readl_relaxed(host->base + MMCIMASK0);
231
232 mb();
233 /* Reset the controller */
234 ret = clk_reset(host->clk, CLK_RESET_ASSERT);
235 if (ret)
236 pr_err("%s: Clock assert failed at %u Hz"
237 " with err %d\n", mmc_hostname(host->mmc),
238 host->clk_rate, ret);
239
240 ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
241 if (ret)
242 pr_err("%s: Clock deassert failed at %u Hz"
243 " with err %d\n", mmc_hostname(host->mmc),
244 host->clk_rate, ret);
245
246 pr_debug("%s: Controller has been reinitialized\n",
247 mmc_hostname(host->mmc));
248
249 mb();
250 /* Restore the contoller state */
251 writel_relaxed(host->pwr, host->base + MMCIPOWER);
252 writel_relaxed(mci_clk, host->base + MMCICLOCK);
253 writel_relaxed(mci_mask0, host->base + MMCIMASK0);
254 ret = clk_set_rate(host->clk, host->clk_rate);
255 if (ret)
256 pr_err("%s: Failed to set clk rate %u Hz. err %d\n",
257 mmc_hostname(host->mmc),
258 host->clk_rate, ret);
259 mb();
260 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700261 if (host->dummy_52_needed)
262 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700263}
264
265static int
San Mehat9d2bd732009-09-22 16:44:22 -0700266msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
267{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700268 int retval = 0;
269
San Mehat9d2bd732009-09-22 16:44:22 -0700270 BUG_ON(host->curr.data);
271
272 host->curr.mrq = NULL;
273 host->curr.cmd = NULL;
274
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700275 del_timer(&host->req_tout_timer);
276
San Mehat9d2bd732009-09-22 16:44:22 -0700277 if (mrq->data)
278 mrq->data->bytes_xfered = host->curr.data_xfered;
279 if (mrq->cmd->error == -ETIMEDOUT)
280 mdelay(5);
281
282 /*
283 * Need to drop the host lock here; mmc_request_done may call
284 * back into the driver...
285 */
286 spin_unlock(&host->lock);
287 mmc_request_done(host->mmc, mrq);
288 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700289
290 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700291}
292
Krishna Konda3e5c4d02011-07-11 16:31:45 -0700293static inline void msmsdcc_delay(struct msmsdcc_host *host);
294
San Mehat9d2bd732009-09-22 16:44:22 -0700295static void
296msmsdcc_stop_data(struct msmsdcc_host *host)
297{
San Mehat9d2bd732009-09-22 16:44:22 -0700298 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530299 host->curr.got_dataend = 0;
Krishna Konda3f5d48f2011-07-27 10:47:31 -0700300 writel_relaxed(readl_relaxed(host->base + MMCIDATACTRL) &
301 (~(MCI_DPSM_ENABLE)), host->base + MMCIDATACTRL);
Krishna Konda3e5c4d02011-07-11 16:31:45 -0700302 msmsdcc_delay(host); /* Allow the DPSM to be reset */
San Mehat9d2bd732009-09-22 16:44:22 -0700303}
304
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700305static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700306{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700307 return host->core_memres->start + MMCIFIFO;
308}
309
310static inline unsigned int msmsdcc_get_min_sup_clk_rate(
311 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530312
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700313static inline void msmsdcc_delay(struct msmsdcc_host *host)
314{
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530315 ktime_t start, diff;
316
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700317 mb();
318 udelay(1 + ((3 * USEC_PER_SEC) /
319 (host->clk_rate ? host->clk_rate :
320 msmsdcc_get_min_sup_clk_rate(host))));
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530321
322 if (host->plat->sdcc_v4_sup &&
323 (readl_relaxed(host->base + MCI_STATUS2) &
324 MCI_MCLK_REG_WR_ACTIVE)) {
325 start = ktime_get();
326 while (readl_relaxed(host->base + MCI_STATUS2) &
327 MCI_MCLK_REG_WR_ACTIVE) {
328 diff = ktime_sub(ktime_get(), start);
329 /* poll for max. 1 ms */
330 if (ktime_to_us(diff) > 1000) {
331 pr_warning("%s: previous reg. write is"
332 " still active\n",
333 mmc_hostname(host->mmc));
334 break;
335 }
336 }
337 }
San Mehat9d2bd732009-09-22 16:44:22 -0700338}
339
San Mehat56a8b5b2009-11-21 12:29:46 -0800340static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700341msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
342{
343 writel_relaxed(arg, host->base + MMCIARGUMENT);
344 msmsdcc_delay(host);
345 writel_relaxed(c, host->base + MMCICOMMAND);
346 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800347}
348
349static void
350msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
351{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700352 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800353
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700354 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
355 writel_relaxed((unsigned int)host->curr.xfer_size,
356 host->base + MMCIDATALENGTH);
357 msmsdcc_delay(host); /* Allow data parms to be applied */
358 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
359 msmsdcc_delay(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800360
San Mehat6ac9ea62009-12-02 17:24:58 -0800361 if (host->cmd_cmd) {
362 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700363 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800364 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800365}
366
San Mehat9d2bd732009-09-22 16:44:22 -0700367static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530368msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700369{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530370 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700371 unsigned long flags;
372 struct mmc_request *mrq;
373
374 spin_lock_irqsave(&host->lock, flags);
375 mrq = host->curr.mrq;
376 BUG_ON(!mrq);
377
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530378 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700379 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700380 goto out;
381 }
382
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530383 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700384 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700385 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700386 } else {
387 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530388 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700389 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530390 mmc_hostname(host->mmc), host->dma.result);
391 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700392 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530393 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530394 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700395 host->dma.err.flush[0], host->dma.err.flush[1],
396 host->dma.err.flush[2], host->dma.err.flush[3],
397 host->dma.err.flush[4],
398 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530399 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700400 if (!mrq->data->error)
401 mrq->data->error = -EIO;
402 }
San Mehat9d2bd732009-09-22 16:44:22 -0700403 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents,
404 host->dma.dir);
405
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700406 if (host->curr.user_pages) {
407 struct scatterlist *sg = host->dma.sg;
408 int i;
409
410 for (i = 0; i < host->dma.num_ents; i++, sg++)
411 flush_dcache_page(sg_page(sg));
412 }
413
San Mehat9d2bd732009-09-22 16:44:22 -0700414 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800415 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700416
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530417 if (host->curr.got_dataend || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700418
419 /*
420 * If we've already gotten our DATAEND / DATABLKEND
421 * for this request, then complete it through here.
422 */
San Mehat9d2bd732009-09-22 16:44:22 -0700423
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700424 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700425 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700426 host->curr.xfer_remain -= host->curr.xfer_size;
427 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700428 if (host->dummy_52_needed) {
429 mrq->data->bytes_xfered = host->curr.data_xfered;
430 host->dummy_52_sent = 1;
431 msmsdcc_start_command(host, &dummy52cmd,
432 MCI_CPSM_PROGENA);
433 goto out;
434 }
435 msmsdcc_stop_data(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700436 if (!mrq->data->stop || mrq->cmd->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700437 host->curr.mrq = NULL;
438 host->curr.cmd = NULL;
439 mrq->data->bytes_xfered = host->curr.data_xfered;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700440 del_timer(&host->req_tout_timer);
San Mehat9d2bd732009-09-22 16:44:22 -0700441 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700442
San Mehat9d2bd732009-09-22 16:44:22 -0700443 mmc_request_done(host->mmc, mrq);
444 return;
445 } else
446 msmsdcc_start_command(host, mrq->data->stop, 0);
447 }
448
449out:
450 spin_unlock_irqrestore(&host->lock, flags);
451 return;
452}
453
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700454#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
455/**
456 * Callback notification from SPS driver
457 *
458 * This callback function gets triggered called from
459 * SPS driver when requested SPS data transfer is
460 * completed.
461 *
462 * SPS driver invokes this callback in BAM irq context so
463 * SDCC driver schedule a tasklet for further processing
464 * this callback notification at later point of time in
465 * tasklet context and immediately returns control back
466 * to SPS driver.
467 *
468 * @nofity - Pointer to sps event notify sturcture
469 *
470 */
471static void
472msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
473{
474 struct msmsdcc_host *host =
475 (struct msmsdcc_host *)
476 ((struct sps_event_notify *)notify)->user;
477
478 host->sps.notify = *notify;
479 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
480 mmc_hostname(host->mmc), __func__, notify->event_id,
481 notify->data.transfer.iovec.addr,
482 notify->data.transfer.iovec.size,
483 notify->data.transfer.iovec.flags);
484 /* Schedule a tasklet for completing data transfer */
485 tasklet_schedule(&host->sps.tlet);
486}
487
488/**
489 * Tasklet handler for processing SPS callback event
490 *
491 * This function processing SPS event notification and
492 * checks if the SPS transfer is completed or not and
493 * then accordingly notifies status to MMC core layer.
494 *
495 * This function is called in tasklet context.
496 *
497 * @data - Pointer to sdcc driver data
498 *
499 */
500static void msmsdcc_sps_complete_tlet(unsigned long data)
501{
502 unsigned long flags;
503 int i, rc;
504 u32 data_xfered = 0;
505 struct mmc_request *mrq;
506 struct sps_iovec iovec;
507 struct sps_pipe *sps_pipe_handle;
508 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
509 struct sps_event_notify *notify = &host->sps.notify;
510
511 spin_lock_irqsave(&host->lock, flags);
512 if (host->sps.dir == DMA_FROM_DEVICE)
513 sps_pipe_handle = host->sps.prod.pipe_handle;
514 else
515 sps_pipe_handle = host->sps.cons.pipe_handle;
516 mrq = host->curr.mrq;
517
518 if (!mrq) {
519 spin_unlock_irqrestore(&host->lock, flags);
520 return;
521 }
522
523 pr_debug("%s: %s: sps event_id=%d\n",
524 mmc_hostname(host->mmc), __func__,
525 notify->event_id);
526
527 if (msmsdcc_is_dml_busy(host)) {
528 /* oops !!! this should never happen. */
529 pr_err("%s: %s: Received SPS EOT event"
530 " but DML HW is still busy !!!\n",
531 mmc_hostname(host->mmc), __func__);
532 }
533 /*
534 * Got End of transfer event!!! Check if all of the data
535 * has been transferred?
536 */
537 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
538 rc = sps_get_iovec(sps_pipe_handle, &iovec);
539 if (rc) {
540 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
541 mmc_hostname(host->mmc), __func__, rc, i);
542 break;
543 }
544 data_xfered += iovec.size;
545 }
546
547 if (data_xfered == host->curr.xfer_size) {
548 host->curr.data_xfered = host->curr.xfer_size;
549 host->curr.xfer_remain -= host->curr.xfer_size;
550 pr_debug("%s: Data xfer success. data_xfered=0x%x",
551 mmc_hostname(host->mmc),
552 host->curr.xfer_size);
553 } else {
554 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
555 " xfer_size=%d", mmc_hostname(host->mmc),
556 data_xfered, host->curr.xfer_size);
557 msmsdcc_reset_and_restore(host);
558 if (!mrq->data->error)
559 mrq->data->error = -EIO;
560 }
561
562 /* Unmap sg buffers */
563 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
564 host->sps.dir);
565
566 host->sps.sg = NULL;
567 host->sps.busy = 0;
568
569 if (host->curr.got_dataend || mrq->data->error) {
570 /*
571 * If we've already gotten our DATAEND / DATABLKEND
572 * for this request, then complete it through here.
573 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700574
575 if (!mrq->data->error) {
576 host->curr.data_xfered = host->curr.xfer_size;
577 host->curr.xfer_remain -= host->curr.xfer_size;
578 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700579 if (host->dummy_52_needed) {
580 mrq->data->bytes_xfered = host->curr.data_xfered;
581 host->dummy_52_sent = 1;
582 msmsdcc_start_command(host, &dummy52cmd,
583 MCI_CPSM_PROGENA);
584 return;
585 }
586 msmsdcc_stop_data(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700587 if (!mrq->data->stop || mrq->cmd->error) {
588 host->curr.mrq = NULL;
589 host->curr.cmd = NULL;
590 mrq->data->bytes_xfered = host->curr.data_xfered;
591 del_timer(&host->req_tout_timer);
592 spin_unlock_irqrestore(&host->lock, flags);
593
594 mmc_request_done(host->mmc, mrq);
595 return;
596 } else {
597 msmsdcc_start_command(host, mrq->data->stop, 0);
598 }
599 }
600 spin_unlock_irqrestore(&host->lock, flags);
601}
602
603/**
604 * Exit from current SPS data transfer
605 *
606 * This function exits from current SPS data transfer.
607 *
608 * This function should be called when error condition
609 * is encountered during data transfer.
610 *
611 * @host - Pointer to sdcc host structure
612 *
613 */
614static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
615{
616 struct mmc_request *mrq;
617
618 mrq = host->curr.mrq;
619 BUG_ON(!mrq);
620
621 msmsdcc_reset_and_restore(host);
622 if (!mrq->data->error)
623 mrq->data->error = -EIO;
624
625 /* Unmap sg buffers */
626 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
627 host->sps.dir);
628
629 host->sps.sg = NULL;
630 host->sps.busy = 0;
631 if (host->curr.data)
632 msmsdcc_stop_data(host);
633
634 if (!mrq->data->stop || mrq->cmd->error)
635 msmsdcc_request_end(host, mrq);
636 else
637 msmsdcc_start_command(host, mrq->data->stop, 0);
638
639}
640#else
641static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
642static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
643static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
644#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
645
646static void msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
647
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530648static void
649msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
650 unsigned int result,
651 struct msm_dmov_errdata *err)
652{
653 struct msmsdcc_dma_data *dma_data =
654 container_of(cmd, struct msmsdcc_dma_data, hdr);
655 struct msmsdcc_host *host = dma_data->host;
656
657 dma_data->result = result;
658 if (err)
659 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
660
661 tasklet_schedule(&host->dma_tlet);
662}
663
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700664static int msmsdcc_check_dma_op_req(struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700665{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700666 if (((data->blksz * data->blocks) < MCI_FIFOSIZE) ||
667 ((data->blksz * data->blocks) % MCI_FIFOSIZE))
San Mehat9d2bd732009-09-22 16:44:22 -0700668 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700669 else
670 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700671}
672
673static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
674{
675 struct msmsdcc_nc_dmadata *nc;
676 dmov_box *box;
677 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700678 unsigned int n;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700679 int i;
San Mehat9d2bd732009-09-22 16:44:22 -0700680 struct scatterlist *sg = data->sg;
681
Krishna Konda25786ec2011-07-25 16:21:36 -0700682 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700683 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700684
Krishna Konda25786ec2011-07-25 16:21:36 -0700685 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
686
San Mehat9d2bd732009-09-22 16:44:22 -0700687 host->dma.sg = data->sg;
688 host->dma.num_ents = data->sg_len;
689
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700690 BUG_ON(host->dma.num_ents > NR_SG); /* Prevent memory corruption */
San Mehat56a8b5b2009-11-21 12:29:46 -0800691
San Mehat9d2bd732009-09-22 16:44:22 -0700692 nc = host->dma.nc;
693
San Mehat9d2bd732009-09-22 16:44:22 -0700694 if (data->flags & MMC_DATA_READ)
695 host->dma.dir = DMA_FROM_DEVICE;
696 else
697 host->dma.dir = DMA_TO_DEVICE;
698
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700699 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
San Mehat9d2bd732009-09-22 16:44:22 -0700700 host->curr.user_pages = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700701 box = &nc->cmd[0];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700702 for (i = 0; i < host->dma.num_ents; i++) {
San Mehat9d2bd732009-09-22 16:44:22 -0700703 box->cmd = CMD_MODE_BOX;
704
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700705 /* Initialize sg dma address */
706 sg->dma_address = pfn_to_dma(mmc_dev(host->mmc),
707 page_to_pfn(sg_page(sg)))
708 + sg->offset;
709
710 if (i == (host->dma.num_ents - 1))
San Mehat9d2bd732009-09-22 16:44:22 -0700711 box->cmd |= CMD_LC;
712 rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ?
713 (sg_dma_len(sg) / MCI_FIFOSIZE) + 1 :
714 (sg_dma_len(sg) / MCI_FIFOSIZE) ;
715
716 if (data->flags & MMC_DATA_READ) {
717 box->src_row_addr = msmsdcc_fifo_addr(host);
718 box->dst_row_addr = sg_dma_address(sg);
719
720 box->src_dst_len = (MCI_FIFOSIZE << 16) |
721 (MCI_FIFOSIZE);
722 box->row_offset = MCI_FIFOSIZE;
723
724 box->num_rows = rows * ((1 << 16) + 1);
Krishna Konda25786ec2011-07-25 16:21:36 -0700725 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
San Mehat9d2bd732009-09-22 16:44:22 -0700726 } else {
727 box->src_row_addr = sg_dma_address(sg);
728 box->dst_row_addr = msmsdcc_fifo_addr(host);
729
730 box->src_dst_len = (MCI_FIFOSIZE << 16) |
731 (MCI_FIFOSIZE);
732 box->row_offset = (MCI_FIFOSIZE << 16);
733
734 box->num_rows = rows * ((1 << 16) + 1);
Krishna Konda25786ec2011-07-25 16:21:36 -0700735 box->cmd |= CMD_DST_CRCI(host->dma.crci);
San Mehat9d2bd732009-09-22 16:44:22 -0700736 }
737 box++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700738 sg++;
739 }
740
741 /* location of command block must be 64 bit aligned */
742 BUG_ON(host->dma.cmd_busaddr & 0x07);
743
744 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
745 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
746 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
747 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
Krishna Konda25786ec2011-07-25 16:21:36 -0700748 host->dma.hdr.crci_mask = msm_dmov_build_crci_mask(1, host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700749
750 n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
751 host->dma.num_ents, host->dma.dir);
752 /* dsb inside dma_map_sg will write nc out to mem as well */
753
754 if (n != host->dma.num_ents) {
755 pr_err("%s: Unable to map in all sg elements\n",
756 mmc_hostname(host->mmc));
757 host->dma.sg = NULL;
758 host->dma.num_ents = 0;
759 return -ENOMEM;
San Mehat56a8b5b2009-11-21 12:29:46 -0800760 }
San Mehat9d2bd732009-09-22 16:44:22 -0700761
762 return 0;
763}
764
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700765#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
766/**
767 * Submits data transfer request to SPS driver
768 *
769 * This function make sg (scatter gather) data buffers
770 * DMA ready and then submits them to SPS driver for
771 * transfer.
772 *
773 * @host - Pointer to sdcc host structure
774 * @data - Pointer to mmc_data structure
775 *
776 * @return 0 if success else negative value
777 */
778static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
779 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -0800780{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700781 int rc = 0;
782 u32 flags;
783 int i;
784 u32 addr, len, data_cnt;
785 struct scatterlist *sg = data->sg;
786 struct sps_pipe *sps_pipe_handle;
787
788 BUG_ON(data->sg_len > NR_SG); /* Prevent memory corruption */
789
790 host->sps.sg = data->sg;
791 host->sps.num_ents = data->sg_len;
792 host->sps.xfer_req_cnt = 0;
793 if (data->flags & MMC_DATA_READ) {
794 host->sps.dir = DMA_FROM_DEVICE;
795 sps_pipe_handle = host->sps.prod.pipe_handle;
796 } else {
797 host->sps.dir = DMA_TO_DEVICE;
798 sps_pipe_handle = host->sps.cons.pipe_handle;
799 }
800
801 /* Make sg buffers DMA ready */
802 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
803 host->sps.dir);
804
805 if (rc != data->sg_len) {
806 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
807 mmc_hostname(host->mmc), rc);
808 host->sps.sg = NULL;
809 host->sps.num_ents = 0;
810 rc = -ENOMEM;
811 goto dma_map_err;
812 }
813
814 pr_debug("%s: %s: %s: pipe=0x%x, total_xfer=0x%x, sg_len=%d\n",
815 mmc_hostname(host->mmc), __func__,
816 host->sps.dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
817 (u32)sps_pipe_handle, host->curr.xfer_size, data->sg_len);
818
819 for (i = 0; i < data->sg_len; i++) {
820 /*
821 * Check if this is the last buffer to transfer?
822 * If yes then set the INT and EOT flags.
823 */
824 len = sg_dma_len(sg);
825 addr = sg_dma_address(sg);
826 flags = 0;
827 while (len > 0) {
828 if (len > SPS_MAX_DESC_SIZE) {
829 data_cnt = SPS_MAX_DESC_SIZE;
830 } else {
831 data_cnt = len;
832 if (i == data->sg_len - 1)
833 flags = SPS_IOVEC_FLAG_INT |
834 SPS_IOVEC_FLAG_EOT;
835 }
836 rc = sps_transfer_one(sps_pipe_handle, addr,
837 data_cnt, host, flags);
838 if (rc) {
839 pr_err("%s: sps_transfer_one() error! rc=%d,"
840 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
841 mmc_hostname(host->mmc), rc,
842 (u32)sps_pipe_handle, (u32)sg, i);
843 goto dma_map_err;
844 }
845 addr += data_cnt;
846 len -= data_cnt;
847 host->sps.xfer_req_cnt++;
848 }
849 sg++;
850 }
851 goto out;
852
853dma_map_err:
854 /* unmap sg buffers */
855 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
856 host->sps.dir);
857out:
858 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -0700859}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700860#else
861static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
862 struct mmc_data *data) { return 0; }
863#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -0700864
865static void
San Mehat56a8b5b2009-11-21 12:29:46 -0800866msmsdcc_start_command_deferred(struct msmsdcc_host *host,
867 struct mmc_command *cmd, u32 *c)
868{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700869 DBG(host, "op %02x arg %08x flags %08x\n",
870 cmd->opcode, cmd->arg, cmd->flags);
871
San Mehat56a8b5b2009-11-21 12:29:46 -0800872 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
873
874 if (cmd->flags & MMC_RSP_PRESENT) {
875 if (cmd->flags & MMC_RSP_136)
876 *c |= MCI_CPSM_LONGRSP;
877 *c |= MCI_CPSM_RESPONSE;
878 }
879
880 if (/*interrupt*/0)
881 *c |= MCI_CPSM_INTERRUPT;
882
883 if ((((cmd->opcode == 17) || (cmd->opcode == 18)) ||
884 ((cmd->opcode == 24) || (cmd->opcode == 25))) ||
885 (cmd->opcode == 53))
886 *c |= MCI_CSPM_DATCMD;
887
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700888 /* Check if AUTO CMD19 is required or not? */
889 if (((cmd->opcode == 17) || (cmd->opcode == 18)) &&
890 host->tuning_needed) {
891 msmsdcc_enable_cdr_cm_sdc4_dll(host);
892 *c |= MCI_CSPM_AUTO_CMD19;
893 }
894
Sahitya Tummalad5137bd2010-12-08 15:03:04 +0530895 if (host->prog_scan && (cmd->opcode == 12)) {
896 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700897 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +0530898 }
899
San Mehat56a8b5b2009-11-21 12:29:46 -0800900 if (cmd == cmd->mrq->stop)
901 *c |= MCI_CSPM_MCIABORT;
902
San Mehat56a8b5b2009-11-21 12:29:46 -0800903 if (host->curr.cmd != NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700904 pr_err("%s: Overlapping command requests\n",
905 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -0800906 }
907 host->curr.cmd = cmd;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700908
909 /*
910 * Kick the software command timeout timer here.
911 * Timer expires in 10 secs.
912 */
913 mod_timer(&host->req_tout_timer,
914 (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
San Mehat56a8b5b2009-11-21 12:29:46 -0800915}
916
917static void
918msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
919 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -0700920{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +0530921 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -0700922 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700923 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -0700924 unsigned int pio_irqmask = 0;
925
926 host->curr.data = data;
927 host->curr.xfer_size = data->blksz * data->blocks;
928 host->curr.xfer_remain = host->curr.xfer_size;
929 host->curr.data_xfered = 0;
930 host->curr.got_dataend = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700931
932 memset(&host->pio, 0, sizeof(host->pio));
933
San Mehat9d2bd732009-09-22 16:44:22 -0700934 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
935
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700936 if (!msmsdcc_check_dma_op_req(data)) {
937 if (host->is_dma_mode && !msmsdcc_config_dma(host, data)) {
938 datactrl |= MCI_DPSM_DMAENABLE;
939 } else if (host->is_sps_mode) {
940 if (!msmsdcc_is_dml_busy(host)) {
941 if (!msmsdcc_sps_start_xfer(host, data)) {
942 /* Now kick start DML transfer */
943 mb();
944 msmsdcc_dml_start_xfer(host, data);
945 datactrl |= MCI_DPSM_DMAENABLE;
946 host->sps.busy = 1;
947 }
948 } else {
949 /*
950 * Can't proceed with new transfer as
951 * previous trasnfer is already in progress.
952 * There is no point of going into PIO mode
953 * as well. Is this a time to do kernel panic?
954 */
955 pr_err("%s: %s: DML HW is busy!!!"
956 " Can't perform new SPS transfers"
957 " now\n", mmc_hostname(host->mmc),
958 __func__);
959 }
960 }
961 }
962
963 /* Is data transfer in PIO mode required? */
964 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700965 host->pio.sg = data->sg;
966 host->pio.sg_len = data->sg_len;
967 host->pio.sg_off = 0;
968
969 if (data->flags & MMC_DATA_READ) {
970 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
971 if (host->curr.xfer_remain < MCI_FIFOSIZE)
972 pio_irqmask |= MCI_RXDATAAVLBLMASK;
973 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700974 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
975 MCI_TXFIFOEMPTYMASK;
San Mehat9d2bd732009-09-22 16:44:22 -0700976 }
977
978 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +0530979 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
San Mehat9d2bd732009-09-22 16:44:22 -0700980
San Mehat56a8b5b2009-11-21 12:29:46 -0800981 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700982 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -0800983 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -0700984
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700985 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
986 /* Use ADM (Application Data Mover) HW for Data transfer */
987 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -0800988 host->cmd_timeout = timeout;
989 host->cmd_pio_irqmask = pio_irqmask;
990 host->cmd_datactrl = datactrl;
991 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -0700992
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700993 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
994 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -0700995 host->dma.busy = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700996 if (data->flags & MMC_DATA_WRITE)
997 host->prog_scan = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -0800998
999 if (cmd) {
1000 msmsdcc_start_command_deferred(host, cmd, &c);
1001 host->cmd_c = c;
1002 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001003 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1004 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1005 host->base + MMCIMASK0);
1006 mb();
1007 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001008 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001009 /* SPS-BAM mode or PIO mode */
1010 if (data->flags & MMC_DATA_WRITE)
1011 host->prog_scan = 1;
1012 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001013
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001014 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001015
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001016 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1017 (~(MCI_IRQ_PIO))) | pio_irqmask,
1018 host->base + MMCIMASK0);
1019 msmsdcc_delay(host); /* Allow parms to be applied */
1020 writel_relaxed(datactrl, base + MMCIDATACTRL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001021
1022 if (cmd) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001023 msmsdcc_delay(host); /* Delay between data/command */
San Mehat56a8b5b2009-11-21 12:29:46 -08001024 /* Daisy-chain the command if requested */
1025 msmsdcc_start_command(host, cmd, c);
1026 }
San Mehat9d2bd732009-09-22 16:44:22 -07001027 }
1028}
1029
1030static void
1031msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1032{
San Mehat56a8b5b2009-11-21 12:29:46 -08001033 msmsdcc_start_command_deferred(host, cmd, &c);
1034 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001035}
1036
1037static void
1038msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1039 unsigned int status)
1040{
1041 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001042 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1043 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1044 pr_err("%s: Data CRC error\n",
1045 mmc_hostname(host->mmc));
1046 pr_err("%s: opcode 0x%.8x\n", __func__,
1047 data->mrq->cmd->opcode);
1048 pr_err("%s: blksz %d, blocks %d\n", __func__,
1049 data->blksz, data->blocks);
1050 data->error = -EILSEQ;
1051 }
San Mehat9d2bd732009-09-22 16:44:22 -07001052 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001053 /* CRC is optional for the bus test commands, not all
1054 * cards respond back with CRC. However controller
1055 * waits for the CRC and times out. Hence ignore the
1056 * data timeouts during the Bustest.
1057 */
1058 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1059 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1060 pr_err("%s: Data timeout\n",
1061 mmc_hostname(host->mmc));
1062 data->error = -ETIMEDOUT;
1063 }
San Mehat9d2bd732009-09-22 16:44:22 -07001064 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001065 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001066 data->error = -EIO;
1067 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001068 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001069 data->error = -EIO;
1070 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001071 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001072 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001073 data->error = -EIO;
1074 }
San Mehat9d2bd732009-09-22 16:44:22 -07001075
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001076 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001077 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001078 host->dummy_52_needed = 0;
1079}
San Mehat9d2bd732009-09-22 16:44:22 -07001080
1081static int
1082msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1083{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001084 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001085 uint32_t *ptr = (uint32_t *) buffer;
1086 int count = 0;
1087
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301088 if (remain % 4)
1089 remain = ((remain >> 2) + 1) << 2;
1090
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001091 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1092
1093 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001094 ptr++;
1095 count += sizeof(uint32_t);
1096
1097 remain -= sizeof(uint32_t);
1098 if (remain == 0)
1099 break;
1100 }
1101 return count;
1102}
1103
1104static int
1105msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001106 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001107{
1108 void __iomem *base = host->base;
1109 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001110 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001111
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001112 while (readl_relaxed(base + MMCISTATUS) &
1113 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1114 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001115
San Mehat9d2bd732009-09-22 16:44:22 -07001116 count = min(remain, maxcnt);
1117
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301118 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1119 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001120 ptr += count;
1121 remain -= count;
1122
1123 if (remain == 0)
1124 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001125 }
1126 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001127
1128 return ptr - buffer;
1129}
1130
San Mehat1cd22962010-02-03 12:59:29 -08001131static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001132msmsdcc_pio_irq(int irq, void *dev_id)
1133{
1134 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001135 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001136 uint32_t status;
1137
Murali Palnati36448a42011-09-02 15:06:18 +05301138 spin_lock(&host->lock);
1139
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001140 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001141
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001142 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301143 (MCI_IRQ_PIO)) == 0) {
1144 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001145 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301146 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001147
1148#if IRQ_DEBUG
1149 msmsdcc_print_status(host, "irq1-r", status);
1150#endif
1151
San Mehat9d2bd732009-09-22 16:44:22 -07001152 do {
1153 unsigned long flags;
1154 unsigned int remain, len;
1155 char *buffer;
1156
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001157 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1158 | MCI_RXDATAAVLBL)))
1159 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001160
1161 /* Map the current scatter buffer */
1162 local_irq_save(flags);
1163 buffer = kmap_atomic(sg_page(host->pio.sg),
1164 KM_BIO_SRC_IRQ) + host->pio.sg->offset;
1165 buffer += host->pio.sg_off;
1166 remain = host->pio.sg->length - host->pio.sg_off;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001167
San Mehat9d2bd732009-09-22 16:44:22 -07001168 len = 0;
1169 if (status & MCI_RXACTIVE)
1170 len = msmsdcc_pio_read(host, buffer, remain);
1171 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001172 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001173
1174 /* Unmap the buffer */
1175 kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
1176 local_irq_restore(flags);
1177
1178 host->pio.sg_off += len;
1179 host->curr.xfer_remain -= len;
1180 host->curr.data_xfered += len;
1181 remain -= len;
1182
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001183 if (remain) /* Done with this page? */
1184 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001185
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001186 if (status & MCI_RXACTIVE && host->curr.user_pages)
1187 flush_dcache_page(sg_page(host->pio.sg));
San Mehat9d2bd732009-09-22 16:44:22 -07001188
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001189 if (!--host->pio.sg_len) {
1190 memset(&host->pio, 0, sizeof(host->pio));
1191 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001192 }
1193
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001194 /* Advance to next sg */
1195 host->pio.sg++;
1196 host->pio.sg_off = 0;
1197
1198 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001199 } while (1);
1200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001201 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1202 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1203 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1204 host->base + MMCIMASK0);
1205 if (!host->curr.xfer_remain) {
1206 /* Delay needed (same port was just written) */
1207 msmsdcc_delay(host);
1208 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1209 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1210 }
1211 mb();
1212 } else if (!host->curr.xfer_remain) {
1213 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1214 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1215 mb();
1216 }
San Mehat9d2bd732009-09-22 16:44:22 -07001217
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001218 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001219
1220 return IRQ_HANDLED;
1221}
1222
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001223static void
1224msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1225
1226static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1227 struct mmc_data *data)
1228{
1229 u32 loop_cnt = 0;
1230
1231 /*
1232 * For read commands with data less than fifo size, it is possible to
1233 * get DATAEND first and RXDATA_AVAIL might be set later because of
1234 * synchronization delay through the asynchronous RX FIFO. Thus, for
1235 * such cases, even after DATAEND interrupt is received software
1236 * should poll for RXDATA_AVAIL until the requested data is read out
1237 * of FIFO. This change is needed to get around this abnormal but
1238 * sometimes expected behavior of SDCC3 controller.
1239 *
1240 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1241 * after the data is loaded into RX FIFO. This would amount to less
1242 * than a microsecond and thus looping for 1000 times is good enough
1243 * for that delay.
1244 */
1245 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1246 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1247 spin_unlock(&host->lock);
1248 msmsdcc_pio_irq(1, host);
1249 spin_lock(&host->lock);
1250 }
1251 }
1252 if (loop_cnt == 1000) {
1253 pr_info("%s: Timed out while polling for Rx Data\n",
1254 mmc_hostname(host->mmc));
1255 data->error = -ETIMEDOUT;
1256 msmsdcc_reset_and_restore(host);
1257 }
1258}
1259
San Mehat9d2bd732009-09-22 16:44:22 -07001260static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1261{
1262 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001263
1264 host->curr.cmd = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001265 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1266 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1267 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1268 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -07001269
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001270 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Sahitya Tummala5a0ae912011-07-18 13:34:01 +05301271 pr_debug("%s: Command timeout\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001272 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001273 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
1274 !host->cmd19_tuning_in_progress) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001275 pr_err("%s: Command CRC error\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001276 cmd->error = -EILSEQ;
1277 }
1278
1279 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001280 if (host->curr.data && host->dma.sg &&
1281 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001282 msm_dmov_stop_cmd(host->dma.channel,
1283 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001284 else if (host->curr.data && host->sps.sg &&
1285 host->is_sps_mode){
1286 /* Stop current SPS transfer */
1287 msmsdcc_sps_exit_curr_xfer(host);
1288 }
San Mehat9d2bd732009-09-22 16:44:22 -07001289 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301290 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001291 msmsdcc_stop_data(host);
1292 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301293 } else { /* host->data == NULL */
1294 if (!cmd->error && host->prog_enable) {
1295 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001296 host->prog_scan = 0;
1297 host->prog_enable = 0;
1298 msmsdcc_request_end(host, cmd->mrq);
1299 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301300 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301301 } else {
1302 if (host->prog_enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001303 host->prog_scan = 0;
1304 host->prog_enable = 0;
1305 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001306 if (host->dummy_52_needed)
1307 host->dummy_52_needed = 0;
1308 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001309 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301310 msmsdcc_request_end(host, cmd->mrq);
1311 }
1312 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001313 } else if (cmd->data) {
San Mehat56a8b5b2009-11-21 12:29:46 -08001314 if (!(cmd->data->flags & MMC_DATA_READ))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001315 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001316 }
1317}
1318
San Mehat9d2bd732009-09-22 16:44:22 -07001319static irqreturn_t
1320msmsdcc_irq(int irq, void *dev_id)
1321{
1322 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001323 u32 status;
1324 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001325 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001326
1327 spin_lock(&host->lock);
1328
1329 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001330 struct mmc_command *cmd;
1331 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001332
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001333 if (timer) {
1334 timer = 0;
1335 msmsdcc_delay(host);
1336 }
San Mehat865c8062009-11-13 13:42:06 -08001337
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001338 if (!host->clks_on) {
1339 pr_debug("%s: %s: SDIO async irq received\n",
1340 mmc_hostname(host->mmc), __func__);
1341 host->mmc->ios.clock = host->clk_rate;
1342 spin_unlock(&host->lock);
1343 host->mmc->ops->set_ios(host->mmc, &host->mmc->ios);
1344 spin_lock(&host->lock);
1345 if (host->plat->cfg_mpm_sdiowakeup &&
1346 (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
1347 wake_lock(&host->sdio_wlock);
1348 /* only ansyc interrupt can come when clocks are off */
1349 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
1350 }
1351
1352 status = readl_relaxed(host->base + MMCISTATUS);
1353
1354 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1355 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001356 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001357
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001358#if IRQ_DEBUG
1359 msmsdcc_print_status(host, "irq0-r", status);
1360#endif
1361 status &= readl_relaxed(host->base + MMCIMASK0);
1362 writel_relaxed(status, host->base + MMCICLEAR);
1363 mb();
1364#if IRQ_DEBUG
1365 msmsdcc_print_status(host, "irq0-p", status);
1366#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001367
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001368#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
1369 if (status & MCI_SDIOINTROPE) {
1370 if (host->sdcc_suspending)
1371 wake_lock(&host->sdio_suspend_wlock);
1372 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001373 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001374#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001375 data = host->curr.data;
1376
1377 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001378 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1379 MCI_CMDTIMEOUT)) {
1380 if (status & MCI_CMDTIMEOUT)
1381 pr_debug("%s: dummy CMD52 timeout\n",
1382 mmc_hostname(host->mmc));
1383 if (status & MCI_CMDCRCFAIL)
1384 pr_debug("%s: dummy CMD52 CRC failed\n",
1385 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001386 host->dummy_52_sent = 0;
1387 host->dummy_52_needed = 0;
1388 if (data) {
1389 msmsdcc_stop_data(host);
1390 msmsdcc_request_end(host, data->mrq);
1391 }
1392 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001393 spin_unlock(&host->lock);
1394 return IRQ_HANDLED;
1395 }
1396 break;
1397 }
1398
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001399 /*
1400 * Check for proper command response
1401 */
1402 cmd = host->curr.cmd;
1403 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1404 MCI_CMDTIMEOUT | MCI_PROGDONE |
1405 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1406 msmsdcc_do_cmdirq(host, status);
1407 }
1408
1409 if (data) {
1410 /* Check for data errors */
1411 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1412 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1413 msmsdcc_data_err(host, data, status);
1414 host->curr.data_xfered = 0;
1415 if (host->dma.sg && host->is_dma_mode)
1416 msm_dmov_stop_cmd(host->dma.channel,
1417 &host->dma.hdr, 0);
1418 else if (host->sps.sg && host->is_sps_mode) {
1419 /* Stop current SPS transfer */
1420 msmsdcc_sps_exit_curr_xfer(host);
1421 }
1422 else {
1423 msmsdcc_reset_and_restore(host);
1424 if (host->curr.data)
1425 msmsdcc_stop_data(host);
1426 if (!data->stop)
1427 timer |=
1428 msmsdcc_request_end(host,
1429 data->mrq);
1430 else {
1431 msmsdcc_start_command(host,
1432 data->stop,
1433 0);
1434 timer = 1;
1435 }
1436 }
1437 }
1438
1439 /* Check for data done */
1440 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1441 host->curr.got_dataend = 1;
1442
1443 if (host->curr.got_dataend) {
1444 /*
1445 * If DMA is still in progress, we complete
1446 * via the completion handler
1447 */
1448 if (!host->dma.busy && !host->sps.busy) {
1449 /*
1450 * There appears to be an issue in the
1451 * controller where if you request a
1452 * small block transfer (< fifo size),
1453 * you may get your DATAEND/DATABLKEND
1454 * irq without the PIO data irq.
1455 *
1456 * Check to see if theres still data
1457 * to be read, and simulate a PIO irq.
1458 */
1459 if (data->flags & MMC_DATA_READ)
1460 msmsdcc_wait_for_rxdata(host,
1461 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001462 if (!data->error) {
1463 host->curr.data_xfered =
1464 host->curr.xfer_size;
1465 host->curr.xfer_remain -=
1466 host->curr.xfer_size;
1467 }
1468
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001469 if (!host->dummy_52_needed) {
1470 msmsdcc_stop_data(host);
1471 if (!data->stop) {
1472 msmsdcc_request_end(
1473 host,
1474 data->mrq);
1475 } else {
1476 msmsdcc_start_command(
1477 host,
1478 data->stop, 0);
1479 timer = 1;
1480 }
1481 } else {
1482 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001483 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001484 &dummy52cmd,
1485 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001486 }
1487 }
1488 }
1489 }
1490
San Mehat9d2bd732009-09-22 16:44:22 -07001491 ret = 1;
1492 } while (status);
1493
1494 spin_unlock(&host->lock);
1495
San Mehat9d2bd732009-09-22 16:44:22 -07001496 return IRQ_RETVAL(ret);
1497}
1498
1499static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001500msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1501{
1502 if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
1503 /* Queue/read data, daisy-chain command when data starts */
1504 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
1505 } else {
1506 msmsdcc_start_command(host, mrq->cmd, 0);
1507 }
1508}
1509
1510static void
San Mehat9d2bd732009-09-22 16:44:22 -07001511msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1512{
1513 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001514 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001515
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001516 /*
1517 * Get the SDIO AL client out of LPM.
1518 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001519 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001520 if (host->plat->is_sdio_al_client)
1521 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001522
1523 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001524 WARN(host->curr.mrq, "Request in progress\n");
1525 WARN(!host->pwr, "SDCC power is turned off\n");
1526 WARN(!host->clks_on, "SDCC clocks are turned off\n");
1527 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
San Mehat9d2bd732009-09-22 16:44:22 -07001528
1529 if (host->eject) {
1530 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1531 mrq->cmd->error = 0;
1532 mrq->data->bytes_xfered = mrq->data->blksz *
1533 mrq->data->blocks;
1534 } else
1535 mrq->cmd->error = -ENOMEDIUM;
1536
1537 spin_unlock_irqrestore(&host->lock, flags);
1538 mmc_request_done(mmc, mrq);
1539 return;
1540 }
1541
1542 host->curr.mrq = mrq;
1543
Oluwafemi Adeyemif6c97c82011-08-22 10:53:44 -07001544 if (!host->plat->sdcc_v4_sup) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001545 if (mrq->data && mrq->data->flags == MMC_DATA_WRITE) {
1546 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001547 mrq->cmd->opcode == 54) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001548 host->dummy_52_needed = 1;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001549 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001550 }
San Mehat9d2bd732009-09-22 16:44:22 -07001551 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001552 msmsdcc_request_start(host, mrq);
San Mehat9d2bd732009-09-22 16:44:22 -07001553 spin_unlock_irqrestore(&host->lock, flags);
1554}
1555
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001556static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1557 int min_uV, int max_uV)
1558{
1559 int rc = 0;
1560
1561 if (vreg->set_voltage_sup) {
1562 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1563 if (rc) {
1564 pr_err("%s: regulator_set_voltage(%s) failed."
1565 " min_uV=%d, max_uV=%d, rc=%d\n",
1566 __func__, vreg->name, min_uV, max_uV, rc);
1567 }
1568 }
1569
1570 return rc;
1571}
1572
1573static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1574 int uA_load)
1575{
1576 int rc = 0;
1577
1578 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1579 if (rc < 0)
1580 pr_err("%s: regulator_set_optimum_mode(reg=%s, uA_load=%d)"
1581 " failed. rc=%d\n", __func__, vreg->name,
1582 uA_load, rc);
1583 else
1584 /* regulator_set_optimum_mode() can return non zero value
1585 * even for success case.
1586 */
1587 rc = 0;
1588
1589 return rc;
1590}
1591
1592static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1593 struct device *dev)
1594{
1595 int rc = 0;
1596
1597 /* check if regulator is already initialized? */
1598 if (vreg->reg)
1599 goto out;
1600
1601 /* Get the regulator handle */
1602 vreg->reg = regulator_get(dev, vreg->name);
1603 if (IS_ERR(vreg->reg)) {
1604 rc = PTR_ERR(vreg->reg);
1605 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
1606 __func__, vreg->name, rc);
1607 }
1608out:
1609 return rc;
1610}
1611
1612static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
1613{
1614 if (vreg->reg)
1615 regulator_put(vreg->reg);
1616}
1617
1618/* This init function should be called only once for each SDCC slot */
1619static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
1620{
1621 int rc = 0;
1622 struct msm_mmc_slot_reg_data *curr_slot;
1623 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1624 struct device *dev = mmc_dev(host->mmc);
1625
1626 curr_slot = host->plat->vreg_data;
1627 if (!curr_slot)
1628 goto out;
1629
1630 curr_vdd_reg = curr_slot->vdd_data;
1631 curr_vccq_reg = curr_slot->vccq_data;
1632 curr_vddp_reg = curr_slot->vddp_data;
1633
1634 if (is_init) {
1635 /*
1636 * Get the regulator handle from voltage regulator framework
1637 * and then try to set the voltage level for the regulator
1638 */
1639 if (curr_vdd_reg) {
1640 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
1641 if (rc)
1642 goto out;
1643 }
1644 if (curr_vccq_reg) {
1645 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
1646 if (rc)
1647 goto vdd_reg_deinit;
1648 }
1649 if (curr_vddp_reg) {
1650 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
1651 if (rc)
1652 goto vccq_reg_deinit;
1653 }
1654 goto out;
1655 } else {
1656 /* Deregister all regulators from regulator framework */
1657 goto vddp_reg_deinit;
1658 }
1659vddp_reg_deinit:
1660 if (curr_vddp_reg)
1661 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
1662vccq_reg_deinit:
1663 if (curr_vccq_reg)
1664 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
1665vdd_reg_deinit:
1666 if (curr_vdd_reg)
1667 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
1668out:
1669 return rc;
1670}
1671
1672static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
1673{
1674 int rc = 0;
1675
Subhash Jadavanicc922692011-08-01 23:05:01 +05301676 /* Put regulator in HPM (high power mode) */
1677 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
1678 if (rc < 0)
1679 goto out;
1680
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001681 if (!vreg->is_enabled) {
1682 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301683 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
1684 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001685 if (rc)
1686 goto out;
1687
1688 rc = regulator_enable(vreg->reg);
1689 if (rc) {
1690 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
1691 __func__, vreg->name, rc);
1692 goto out;
1693 }
1694 vreg->is_enabled = true;
1695 }
1696
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001697out:
1698 return rc;
1699}
1700
1701static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
1702{
1703 int rc = 0;
1704
1705 /* Never disable regulator marked as always_on */
1706 if (vreg->is_enabled && !vreg->always_on) {
1707 rc = regulator_disable(vreg->reg);
1708 if (rc) {
1709 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
1710 __func__, vreg->name, rc);
1711 goto out;
1712 }
1713 vreg->is_enabled = false;
1714
1715 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
1716 if (rc < 0)
1717 goto out;
1718
1719 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301720 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001721 if (rc)
1722 goto out;
1723 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
1724 /* Put always_on regulator in LPM (low power mode) */
1725 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
1726 if (rc < 0)
1727 goto out;
1728 }
1729out:
1730 return rc;
1731}
1732
1733static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
1734{
1735 int rc = 0, i;
1736 struct msm_mmc_slot_reg_data *curr_slot;
1737 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1738 struct msm_mmc_reg_data *vreg_table[3];
1739
1740 curr_slot = host->plat->vreg_data;
1741 if (!curr_slot)
1742 goto out;
1743
1744 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
1745 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
1746 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
1747
1748 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
1749 if (vreg_table[i]) {
1750 if (enable)
1751 rc = msmsdcc_vreg_enable(vreg_table[i]);
1752 else
1753 rc = msmsdcc_vreg_disable(vreg_table[i]);
1754 if (rc)
1755 goto out;
1756 }
1757 }
1758out:
1759 return rc;
1760}
1761
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301762static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001763{
1764 int rc = 0;
1765
1766 if (host->plat->vreg_data) {
1767 struct msm_mmc_reg_data *vddp_reg =
1768 host->plat->vreg_data->vddp_data;
1769
1770 if (vddp_reg && vddp_reg->is_enabled)
1771 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
1772 }
1773
1774 return rc;
1775}
1776
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301777static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
1778{
1779 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1780 int rc = 0;
1781
1782 if (curr_slot && curr_slot->vddp_data) {
1783 rc = msmsdcc_set_vddp_level(host,
1784 curr_slot->vddp_data->low_vol_level);
1785
1786 if (rc)
1787 pr_err("%s: %s: failed to change vddp level to %d",
1788 mmc_hostname(host->mmc), __func__,
1789 curr_slot->vddp_data->low_vol_level);
1790 }
1791
1792 return rc;
1793}
1794
1795static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
1796{
1797 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1798 int rc = 0;
1799
1800 if (curr_slot && curr_slot->vddp_data) {
1801 rc = msmsdcc_set_vddp_level(host,
1802 curr_slot->vddp_data->high_vol_level);
1803
1804 if (rc)
1805 pr_err("%s: %s: failed to change vddp level to %d",
1806 mmc_hostname(host->mmc), __func__,
1807 curr_slot->vddp_data->high_vol_level);
1808 }
1809
1810 return rc;
1811}
1812
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001813static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
1814{
1815 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
1816 return 1;
1817 return 0;
1818}
1819
1820static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
1821{
1822 if (enable) {
1823 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1824 clk_enable(host->dfab_pclk);
1825 if (!IS_ERR(host->pclk))
1826 clk_enable(host->pclk);
1827 clk_enable(host->clk);
1828 } else {
1829 clk_disable(host->clk);
1830 if (!IS_ERR(host->pclk))
1831 clk_disable(host->pclk);
1832 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1833 clk_disable(host->dfab_pclk);
1834 }
1835}
1836
1837static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
1838 unsigned int req_clk)
1839{
1840 unsigned int sel_clk = -1;
1841
1842 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
1843 unsigned char cnt;
1844
1845 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
1846 if (host->plat->sup_clk_table[cnt] > req_clk)
1847 break;
1848 else if (host->plat->sup_clk_table[cnt] == req_clk) {
1849 sel_clk = host->plat->sup_clk_table[cnt];
1850 break;
1851 } else
1852 sel_clk = host->plat->sup_clk_table[cnt];
1853 }
1854 } else {
1855 if ((req_clk < host->plat->msmsdcc_fmax) &&
1856 (req_clk > host->plat->msmsdcc_fmid))
1857 sel_clk = host->plat->msmsdcc_fmid;
1858 else
1859 sel_clk = req_clk;
1860 }
1861
1862 return sel_clk;
1863}
1864
1865static inline unsigned int msmsdcc_get_min_sup_clk_rate(
1866 struct msmsdcc_host *host)
1867{
1868 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
1869 return host->plat->sup_clk_table[0];
1870 else
1871 return host->plat->msmsdcc_fmin;
1872}
1873
1874static inline unsigned int msmsdcc_get_max_sup_clk_rate(
1875 struct msmsdcc_host *host)
1876{
1877 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
1878 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
1879 else
1880 return host->plat->msmsdcc_fmax;
1881}
1882
1883static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05301884{
1885 struct msm_mmc_gpio_data *curr;
1886 int i, rc = 0;
1887
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001888 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301889 for (i = 0; i < curr->size; i++) {
1890 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001891 if (curr->gpio[i].is_always_on &&
1892 curr->gpio[i].is_enabled)
1893 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301894 rc = gpio_request(curr->gpio[i].no,
1895 curr->gpio[i].name);
1896 if (rc) {
1897 pr_err("%s: gpio_request(%d, %s) failed %d\n",
1898 mmc_hostname(host->mmc),
1899 curr->gpio[i].no,
1900 curr->gpio[i].name, rc);
1901 goto free_gpios;
1902 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001903 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301904 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001905 if (curr->gpio[i].is_always_on)
1906 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301907 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001908 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301909 }
1910 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001911 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301912
1913free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001914 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05301915 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001916 curr->gpio[i].is_enabled = false;
1917 }
1918out:
1919 return rc;
1920}
1921
1922static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
1923{
1924 struct msm_mmc_pad_data *curr;
1925 int i;
1926
1927 curr = host->plat->pin_data->pad_data;
1928 for (i = 0; i < curr->drv->size; i++) {
1929 if (enable)
1930 msm_tlmm_set_hdrive(curr->drv->on[i].no,
1931 curr->drv->on[i].val);
1932 else
1933 msm_tlmm_set_hdrive(curr->drv->off[i].no,
1934 curr->drv->off[i].val);
1935 }
1936
1937 for (i = 0; i < curr->pull->size; i++) {
1938 if (enable)
1939 msm_tlmm_set_hdrive(curr->pull->on[i].no,
1940 curr->pull->on[i].val);
1941 else
1942 msm_tlmm_set_hdrive(curr->pull->off[i].no,
1943 curr->pull->off[i].val);
1944 }
1945
1946 return 0;
1947}
1948
1949static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
1950{
1951 int rc = 0;
1952
1953 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
1954 return 0;
1955
1956 if (host->plat->pin_data->is_gpio)
1957 rc = msmsdcc_setup_gpio(host, enable);
1958 else
1959 rc = msmsdcc_setup_pad(host, enable);
1960
1961 if (!rc)
1962 host->plat->pin_data->cfg_sts = enable;
1963
1964 return rc;
1965}
1966
1967static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
1968{
1969 unsigned int wakeup_irq;
1970
1971 wakeup_irq = (host->plat->sdiowakeup_irq) ?
1972 host->plat->sdiowakeup_irq :
1973 host->core_irqres->start;
1974
1975 if (!host->irq_wake_enabled) {
1976 enable_irq_wake(wakeup_irq);
1977 host->irq_wake_enabled = true;
1978 }
1979}
1980
1981static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
1982{
1983 unsigned int wakeup_irq;
1984
1985 wakeup_irq = (host->plat->sdiowakeup_irq) ?
1986 host->plat->sdiowakeup_irq :
1987 host->core_irqres->start;
1988
1989 if (host->irq_wake_enabled) {
1990 disable_irq_wake(wakeup_irq);
1991 host->irq_wake_enabled = false;
1992 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05301993}
1994
San Mehat9d2bd732009-09-22 16:44:22 -07001995static void
1996msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
1997{
1998 struct msmsdcc_host *host = mmc_priv(mmc);
1999 u32 clk = 0, pwr = 0;
2000 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002001 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002002 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002003
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002004 DBG(host, "ios->clock = %u\n", ios->clock);
Sahitya Tummala7a892482011-01-18 11:22:49 +05302005
San Mehat9d2bd732009-09-22 16:44:22 -07002006 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002007 spin_lock_irqsave(&host->lock, flags);
2008 if (!host->clks_on) {
2009 msmsdcc_setup_clocks(host, true);
2010 host->clks_on = 1;
2011 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2012 if (!host->plat->sdiowakeup_irq) {
2013 writel_relaxed(host->mci_irqenable,
2014 host->base + MMCIMASK0);
2015 mb();
2016 if (host->plat->cfg_mpm_sdiowakeup &&
2017 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2018 host->plat->cfg_mpm_sdiowakeup(
2019 mmc_dev(mmc), SDC_DAT1_DISWAKE);
2020 msmsdcc_disable_irq_wake(host);
2021 } else if (!(mmc->pm_flags &
2022 MMC_PM_WAKE_SDIO_IRQ)) {
2023 writel_relaxed(host->mci_irqenable,
2024 host->base + MMCIMASK0);
2025 }
2026 }
San Mehat9d2bd732009-09-22 16:44:22 -07002027 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002028 spin_unlock_irqrestore(&host->lock, flags);
2029
2030 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2031 /*
2032 * For DDR50 mode, controller needs clock rate to be
2033 * double than what is required on the SD card CLK pin.
2034 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302035 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002036 /*
2037 * Make sure that we don't double the clock if
2038 * doubled clock rate is already set
2039 */
2040 if (!host->ddr_doubled_clk_rate ||
2041 (host->ddr_doubled_clk_rate &&
2042 (host->ddr_doubled_clk_rate != ios->clock))) {
2043 host->ddr_doubled_clk_rate =
2044 msmsdcc_get_sup_clk_rate(
2045 host, (ios->clock * 2));
2046 clock = host->ddr_doubled_clk_rate;
2047 }
2048 } else {
2049 host->ddr_doubled_clk_rate = 0;
2050 }
2051
2052 if (clock != host->clk_rate) {
2053 rc = clk_set_rate(host->clk, clock);
2054 if (rc < 0)
2055 pr_debug("%s: failed to set clk rate %u\n",
2056 mmc_hostname(mmc), clock);
2057 host->clk_rate = clock;
2058 }
2059 /*
2060 * give atleast 2 MCLK cycles delay for clocks
2061 * and SDCC core to stabilize
2062 */
2063 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002064 clk |= MCI_CLK_ENABLE;
2065 }
2066
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002067 if (ios->bus_width == MMC_BUS_WIDTH_8)
2068 clk |= MCI_CLK_WIDEBUS_8;
2069 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2070 clk |= MCI_CLK_WIDEBUS_4;
2071 else
2072 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002073
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002074 if (msmsdcc_is_pwrsave(host))
2075 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002076
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002077 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002078
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002079 host->tuning_needed = 0;
2080 /*
2081 * Select the controller timing mode according
2082 * to current bus speed mode
2083 */
2084 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2085 (ios->timing == MMC_TIMING_UHS_SDR50)) {
2086 clk |= (4 << 14);
2087 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302088 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002089 clk |= (3 << 14);
2090 } else {
2091 clk |= (2 << 14); /* feedback clock */
2092 }
2093
2094 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2095 clk |= (2 << 23);
2096
2097 if (host->io_pad_pwr_switch)
2098 clk |= IO_PAD_PWR_SWITCH;
2099
2100 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
San Mehat9d2bd732009-09-22 16:44:22 -07002101 pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002102 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2103 pwr |= msmsdcc_setup_vreg(host, !!ios->vdd);
San Mehat9d2bd732009-09-22 16:44:22 -07002104
2105 switch (ios->power_mode) {
2106 case MMC_POWER_OFF:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002107 htc_pwrsink_set(PWRSINK_SDCARD, 0);
2108 if (!host->sdcc_irq_disabled) {
2109 if (host->plat->cfg_mpm_sdiowakeup)
2110 host->plat->cfg_mpm_sdiowakeup(
2111 mmc_dev(mmc), SDC_DAT1_DISABLE);
2112 disable_irq(host->core_irqres->start);
2113 host->sdcc_irq_disabled = 1;
2114 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302115 /*
2116 * As VDD pad rail is always on, set low voltage for VDD
2117 * pad rail when slot is unused (when card is not present
2118 * or during system suspend).
2119 */
2120 msmsdcc_set_vddp_low_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002121 msmsdcc_setup_pins(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002122 break;
2123 case MMC_POWER_UP:
2124 pwr |= MCI_PWR_UP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002125 if (host->sdcc_irq_disabled) {
2126 if (host->plat->cfg_mpm_sdiowakeup)
2127 host->plat->cfg_mpm_sdiowakeup(
2128 mmc_dev(mmc), SDC_DAT1_ENABLE);
2129 enable_irq(host->core_irqres->start);
2130 host->sdcc_irq_disabled = 0;
2131 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302132 msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002133 msmsdcc_setup_pins(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07002134 break;
2135 case MMC_POWER_ON:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002136 htc_pwrsink_set(PWRSINK_SDCARD, 100);
San Mehat9d2bd732009-09-22 16:44:22 -07002137 pwr |= MCI_PWR_ON;
2138 break;
2139 }
2140
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002141 spin_lock_irqsave(&host->lock, flags);
2142 if (!host->clks_on) {
2143 /* force the clocks to be on */
2144 msmsdcc_setup_clocks(host, true);
2145 /*
2146 * give atleast 2 MCLK cycles delay for clocks
2147 * and SDCC core to stabilize
2148 */
2149 msmsdcc_delay(host);
2150 }
2151 writel_relaxed(clk, host->base + MMCICLOCK);
2152 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002153
2154 if (host->pwr != pwr) {
2155 host->pwr = pwr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002156 writel_relaxed(pwr, host->base + MMCIPOWER);
2157 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07002158 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002159 if (!host->clks_on) {
2160 /* force the clocks to be off */
2161 msmsdcc_setup_clocks(host, false);
2162 /*
2163 * give atleast 2 MCLK cycles delay for clocks
2164 * and SDCC core to stabilize
2165 */
2166 msmsdcc_delay(host);
2167 }
2168
2169 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
2170 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2171 if (!host->plat->sdiowakeup_irq) {
2172 writel_relaxed(MCI_SDIOINTMASK,
2173 host->base + MMCIMASK0);
2174 mb();
2175 if (host->plat->cfg_mpm_sdiowakeup &&
2176 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2177 host->plat->cfg_mpm_sdiowakeup(
2178 mmc_dev(mmc), SDC_DAT1_ENWAKE);
2179 msmsdcc_enable_irq_wake(host);
2180 } else if (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2181 writel_relaxed(0, host->base + MMCIMASK0);
2182 } else {
2183 writel_relaxed(MCI_SDIOINTMASK,
2184 host->base + MMCIMASK0);
2185 }
2186 msmsdcc_delay(host);
2187 }
2188 msmsdcc_setup_clocks(host, false);
2189 host->clks_on = 0;
2190 }
San Mehat4adbbcc2009-11-08 13:00:37 -08002191 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002192}
2193
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002194int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2195{
2196 struct msmsdcc_host *host = mmc_priv(mmc);
2197 u32 clk;
2198
2199 clk = readl_relaxed(host->base + MMCICLOCK);
2200 pr_debug("Changing to pwr_save=%d", pwrsave);
2201 if (pwrsave && msmsdcc_is_pwrsave(host))
2202 clk |= MCI_CLK_PWRSAVE;
2203 else
2204 clk &= ~MCI_CLK_PWRSAVE;
2205 writel_relaxed(clk, host->base + MMCICLOCK);
2206 mb();
2207
2208 return 0;
2209}
2210
2211static int msmsdcc_get_ro(struct mmc_host *mmc)
2212{
2213 int status = -ENOSYS;
2214 struct msmsdcc_host *host = mmc_priv(mmc);
2215
2216 if (host->plat->wpswitch) {
2217 status = host->plat->wpswitch(mmc_dev(mmc));
2218 } else if (host->plat->wpswitch_gpio) {
2219 status = gpio_request(host->plat->wpswitch_gpio,
2220 "SD_WP_Switch");
2221 if (status) {
2222 pr_err("%s: %s: Failed to request GPIO %d\n",
2223 mmc_hostname(mmc), __func__,
2224 host->plat->wpswitch_gpio);
2225 } else {
2226 status = gpio_direction_input(
2227 host->plat->wpswitch_gpio);
2228 if (!status) {
2229 /*
2230 * Wait for atleast 300ms as debounce
2231 * time for GPIO input to stabilize.
2232 */
2233 msleep(300);
2234 status = gpio_get_value_cansleep(
2235 host->plat->wpswitch_gpio);
2236 status ^= !host->plat->wpswitch_polarity;
2237 }
2238 gpio_free(host->plat->wpswitch_gpio);
2239 }
2240 }
2241
2242 if (status < 0)
2243 status = -ENOSYS;
2244 pr_debug("%s: Card read-only status %d\n", __func__, status);
2245
2246 return status;
2247}
2248
2249#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002250static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2251{
2252 struct msmsdcc_host *host = mmc_priv(mmc);
2253 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002254
2255 if (enable) {
2256 spin_lock_irqsave(&host->lock, flags);
2257 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
2258 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
2259 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2260 spin_unlock_irqrestore(&host->lock, flags);
2261 } else {
2262 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
2263 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
2264 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2265 }
2266 mb();
2267}
2268#endif /* CONFIG_MMC_MSM_SDIO_SUPPORT */
2269
2270#ifdef CONFIG_PM_RUNTIME
2271static int msmsdcc_enable(struct mmc_host *mmc)
2272{
Sahitya Tummala8605fca2011-08-22 15:39:19 +05302273 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002274 struct device *dev = mmc->parent;
2275
Sahitya Tummala8605fca2011-08-22 15:39:19 +05302276 if (pm_runtime_suspended(dev))
2277 rc = pm_runtime_get_sync(dev);
2278 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002279 pm_runtime_get_noresume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002280
Sahitya Tummala8605fca2011-08-22 15:39:19 +05302281 if (rc < 0)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002282 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2283 __func__, rc);
Sahitya Tummala8605fca2011-08-22 15:39:19 +05302284 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002285}
2286
2287static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2288{
2289 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302290 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002291
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302292 if (host->plat->disable_runtime_pm)
2293 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002294 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO)
2295 return -ENOTSUPP;
2296
2297 rc = pm_runtime_put_sync(mmc->parent);
2298
2299 if (rc < 0)
2300 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2301 __func__, rc);
2302 return rc;
2303}
2304#else
2305#define msmsdcc_enable NULL
2306#define msmsdcc_disable NULL
2307#endif
2308
2309static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2310 struct mmc_ios *ios)
2311{
2312 struct msmsdcc_host *host = mmc_priv(mmc);
2313 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302314 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002315
2316 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2317 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302318 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002319 goto out;
2320 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2321 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302322 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002323 goto out;
2324 }
San Mehat9d2bd732009-09-22 16:44:22 -07002325
2326 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002327 /*
2328 * If we are here means voltage switch from high voltage to
2329 * low voltage is required
2330 */
2331
2332 /*
2333 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2334 * register until they become all zeros.
2335 */
2336 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302337 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002338 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2339 mmc_hostname(mmc), __func__);
2340 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002341 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002342
2343 /* Stop SD CLK output. */
2344 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2345 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2346
San Mehat9d2bd732009-09-22 16:44:22 -07002347 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002348
2349 /*
2350 * Switch VDDPX from high voltage to low voltage
2351 * to change the VDD of the SD IO pads.
2352 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302353 rc = msmsdcc_set_vddp_low_vol(host);
2354 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002355 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002356
2357 spin_lock_irqsave(&host->lock, flags);
2358 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2359 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
2360 host->io_pad_pwr_switch = 1;
2361 spin_unlock_irqrestore(&host->lock, flags);
2362
2363 /* Wait 5 ms for the voltage regulater in the card to become stable. */
2364 usleep_range(5000, 5500);
2365
2366 spin_lock_irqsave(&host->lock, flags);
2367 /* Start SD CLK output. */
2368 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2369 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2370 spin_unlock_irqrestore(&host->lock, flags);
2371
2372 /*
2373 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
2374 * don't become all ones within 1 ms then a Voltage Switch
2375 * sequence has failed and a power cycle to the card is required.
2376 * Otherwise Voltage Switch sequence is completed successfully.
2377 */
2378 usleep_range(1000, 1500);
2379
2380 spin_lock_irqsave(&host->lock, flags);
2381 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
2382 != (0xF << 1)) {
2383 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
2384 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302385 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002386 goto out_unlock;
2387 }
2388
2389out_unlock:
2390 spin_unlock_irqrestore(&host->lock, flags);
2391out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302392 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002393}
2394
2395static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2396 u8 phase);
2397/* Initialize the DLL (Programmable Delay Line ) */
2398static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
2399{
2400 int rc = 0;
2401 u32 wait_timeout;
2402
2403 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
2404 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2405 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2406
2407 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
2408 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2409 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2410
2411 msmsdcc_delay(host);
2412
2413 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
2414 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2415 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2416
2417 /* Initialize the phase to 0 */
2418 rc = msmsdcc_config_cm_sdc4_dll_phase(host, 0);
2419 if (rc)
2420 goto out;
2421
2422 wait_timeout = 1000;
2423 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
2424 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
2425 /* max. wait for 1 sec for LOCK bit to be set */
2426 if (--wait_timeout == 0) {
2427 pr_err("%s: %s: DLL failed to lock at phase: %d",
2428 mmc_hostname(host->mmc), __func__, 0);
2429 rc = -1;
2430 goto out;
2431 }
2432 /* wait for 1ms */
2433 usleep_range(1000, 1500);
2434 }
2435out:
2436 return rc;
2437}
2438
2439/*
2440 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
2441 * calibration sequence. This function should be called before
2442 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
2443 * commands (CMD17/CMD18).
2444 */
2445static void msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
2446{
2447 /* Set CDR_EN bit to 1. */
2448 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) |
2449 MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2450
2451 /* Set CDR_EXT_EN bit to 0. */
2452 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2453 & ~MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2454
2455 /* Set CK_OUT_EN bit to 0. */
2456 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2457 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2458
2459 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2460 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)
2461 ;
2462
2463 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2464 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2465 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2466
2467 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register is 1. */
2468 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN))
2469 ;
2470}
2471
2472static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2473 u8 phase)
2474{
2475 int rc = 0;
2476 u32 mclk_freq = 0;
2477 u32 wait_timeout;
2478
2479 /* Set CDR_EN bit to 0. */
2480 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2481 & ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2482
2483 /* Set CDR_EXT_EN bit to 1. */
2484 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2485 | MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2486
2487 /* Program the MCLK value to MCLK_FREQ bit field */
2488 if (host->clk_rate <= 112000000)
2489 mclk_freq = 0;
2490 else if (host->clk_rate <= 125000000)
2491 mclk_freq = 1;
2492 else if (host->clk_rate <= 137000000)
2493 mclk_freq = 2;
2494 else if (host->clk_rate <= 150000000)
2495 mclk_freq = 3;
2496 else if (host->clk_rate <= 162000000)
2497 mclk_freq = 4;
2498 else if (host->clk_rate <= 175000000)
2499 mclk_freq = 5;
2500 else if (host->clk_rate <= 187000000)
2501 mclk_freq = 6;
2502 else if (host->clk_rate <= 200000000)
2503 mclk_freq = 7;
2504
2505 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2506 & ~(7 << 24)) | (mclk_freq << 24)),
2507 host->base + MCI_DLL_CONFIG);
2508
2509 /* Set CK_OUT_EN bit to 0. */
2510 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2511 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2512
2513 /* Set DLL_EN bit to 1. */
2514 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2515 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
2516
2517 wait_timeout = 1000;
2518 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2519 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN) {
2520 /* max. wait for 1 sec for LOCK bit for be set */
2521 if (--wait_timeout == 0) {
2522 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 0",
2523 mmc_hostname(host->mmc), __func__, phase);
2524 rc = -1;
2525 goto out;
2526 }
2527 /* wait for 1ms */
2528 usleep_range(1000, 1500);
2529 }
2530
2531 /*
2532 * Write the selected DLL clock output phase (0 ... 15)
2533 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
2534 */
2535 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2536 & ~(0xF << 20)) | (phase << 20)),
2537 host->base + MCI_DLL_CONFIG);
2538
2539 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2540 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2541 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2542
2543 wait_timeout = 1000;
2544 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
2545 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)) {
2546 /* max. wait for 1 sec for LOCK bit for be set */
2547 if (--wait_timeout == 0) {
2548 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 1",
2549 mmc_hostname(host->mmc), __func__, phase);
2550 rc = -1;
2551 goto out;
2552 }
2553 /* wait for 1ms */
2554 usleep_range(1000, 1500);
2555 }
2556out:
2557 return rc;
2558}
2559
2560static int msmsdcc_execute_tuning(struct mmc_host *mmc)
2561{
2562 struct msmsdcc_host *host = mmc_priv(mmc);
2563 u8 phase;
2564 u8 *data_buf;
2565 u8 tuned_phases[16], tuned_phase_cnt = 0;
2566 int rc = 0;
2567
2568 /* Tuning is only required for SDR50 & SDR104 modes */
2569 if (!host->tuning_needed) {
2570 rc = 0;
2571 goto out;
2572 }
2573
2574 host->cmd19_tuning_in_progress = 1;
2575 /*
2576 * Make sure that clock is always enabled when DLL
2577 * tuning is in progress. Keeping PWRSAVE ON may
2578 * turn off the clock. So let's disable the PWRSAVE
2579 * here and re-enable it once tuning is completed.
2580 */
2581 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2582 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2583 /* first of all reset the tuning block */
2584 rc = msmsdcc_init_cm_sdc4_dll(host);
2585 if (rc)
2586 goto out;
2587
2588 data_buf = kmalloc(64, GFP_KERNEL);
2589 if (!data_buf) {
2590 rc = -ENOMEM;
2591 goto out;
2592 }
2593
2594 phase = 0;
2595 do {
2596 struct mmc_command cmd = {0};
2597 struct mmc_data data = {0};
2598 struct mmc_request mrq = {
2599 .cmd = &cmd,
2600 .data = &data
2601 };
2602 struct scatterlist sg;
2603
2604 /* set the phase in delay line hw block */
2605 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2606 if (rc)
2607 goto kfree;
2608
2609 cmd.opcode = MMC_SEND_TUNING_BLOCK;
2610 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
2611
2612 data.blksz = 64;
2613 data.blocks = 1;
2614 data.flags = MMC_DATA_READ;
2615 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
2616
2617 data.sg = &sg;
2618 data.sg_len = 1;
2619 sg_init_one(&sg, data_buf, 64);
2620 memset(data_buf, 0, 64);
2621 mmc_wait_for_req(mmc, &mrq);
2622
2623 if (!cmd.error && !data.error &&
2624 !memcmp(data_buf, cmd19_tuning_block, 64)) {
2625 /* tuning is successful with this tuning point */
2626 tuned_phases[tuned_phase_cnt++] = phase;
2627 }
2628 } while (++phase < 16);
2629
2630 kfree(data_buf);
2631
2632 if (tuned_phase_cnt) {
2633 tuned_phase_cnt--;
2634 tuned_phase_cnt = (tuned_phase_cnt * 3) / 4;
2635 phase = tuned_phases[tuned_phase_cnt];
2636 /*
2637 * Finally set the selected phase in delay
2638 * line hw block.
2639 */
2640 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2641 if (rc)
2642 goto out;
2643 } else {
2644 /* tuning failed */
2645 rc = -EAGAIN;
2646 pr_err("%s: %s: no tuning point found",
2647 mmc_hostname(mmc), __func__);
2648 }
2649 goto out;
2650
2651kfree:
2652 kfree(data_buf);
2653out:
2654 /* re-enable PWESAVE */
2655 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2656 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2657 host->cmd19_tuning_in_progress = 0;
2658 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07002659}
2660
2661static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002662 .enable = msmsdcc_enable,
2663 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07002664 .request = msmsdcc_request,
2665 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002666 .get_ro = msmsdcc_get_ro,
2667#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002668 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002669#endif
2670 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
2671 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07002672};
2673
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002674static unsigned int
2675msmsdcc_slot_status(struct msmsdcc_host *host)
2676{
2677 int status;
2678 unsigned int gpio_no = host->plat->status_gpio;
2679
2680 status = gpio_request(gpio_no, "SD_HW_Detect");
2681 if (status) {
2682 pr_err("%s: %s: Failed to request GPIO %d\n",
2683 mmc_hostname(host->mmc), __func__, gpio_no);
2684 } else {
2685 status = gpio_direction_input(gpio_no);
2686 if (!status)
2687 status = !gpio_get_value_cansleep(gpio_no);
2688 gpio_free(gpio_no);
2689 }
2690 return status;
2691}
2692
San Mehat9d2bd732009-09-22 16:44:22 -07002693static void
2694msmsdcc_check_status(unsigned long data)
2695{
2696 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
2697 unsigned int status;
2698
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002699 if (host->plat->status || host->plat->status_gpio) {
2700 if (host->plat->status)
2701 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07002702 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002703 status = msmsdcc_slot_status(host);
2704
2705 host->eject = !status;
2706 if (status ^ host->oldstat) {
2707 pr_info("%s: Slot status change detected (%d -> %d)\n",
2708 mmc_hostname(host->mmc), host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07002709 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002710 }
2711 host->oldstat = status;
2712 } else {
2713 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07002714 }
San Mehat9d2bd732009-09-22 16:44:22 -07002715}
2716
2717static irqreturn_t
2718msmsdcc_platform_status_irq(int irq, void *dev_id)
2719{
2720 struct msmsdcc_host *host = dev_id;
2721
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002722 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07002723 msmsdcc_check_status((unsigned long) host);
2724 return IRQ_HANDLED;
2725}
2726
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002727static irqreturn_t
2728msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
2729{
2730 struct msmsdcc_host *host = dev_id;
2731
2732 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
2733 spin_lock(&host->lock);
2734 if (!host->sdio_irq_disabled) {
2735 disable_irq_nosync(irq);
2736 if (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2737 wake_lock(&host->sdio_wlock);
2738 msmsdcc_disable_irq_wake(host);
2739 }
2740 host->sdio_irq_disabled = 1;
2741 }
2742 if (host->plat->is_sdio_al_client) {
2743 if (!host->clks_on) {
2744 msmsdcc_setup_clocks(host, true);
2745 host->clks_on = 1;
2746 }
2747 if (host->sdcc_irq_disabled) {
2748 writel_relaxed(host->mci_irqenable,
2749 host->base + MMCIMASK0);
2750 mb();
2751 enable_irq(host->core_irqres->start);
2752 host->sdcc_irq_disabled = 0;
2753 }
2754 wake_lock(&host->sdio_wlock);
2755 }
2756 spin_unlock(&host->lock);
2757
2758 return IRQ_HANDLED;
2759}
2760
San Mehat9d2bd732009-09-22 16:44:22 -07002761static void
2762msmsdcc_status_notify_cb(int card_present, void *dev_id)
2763{
2764 struct msmsdcc_host *host = dev_id;
2765
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002766 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07002767 card_present);
2768 msmsdcc_check_status((unsigned long) host);
2769}
2770
San Mehat9d2bd732009-09-22 16:44:22 -07002771static int
2772msmsdcc_init_dma(struct msmsdcc_host *host)
2773{
2774 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
2775 host->dma.host = host;
2776 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07002777 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07002778
2779 if (!host->dmares)
2780 return -ENODEV;
2781
2782 host->dma.nc = dma_alloc_coherent(NULL,
2783 sizeof(struct msmsdcc_nc_dmadata),
2784 &host->dma.nc_busaddr,
2785 GFP_KERNEL);
2786 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07002787 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07002788 return -ENOMEM;
2789 }
2790 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
2791 host->dma.cmd_busaddr = host->dma.nc_busaddr;
2792 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
2793 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
2794 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07002795 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07002796
2797 return 0;
2798}
2799
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002800#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
2801/**
2802 * Allocate and Connect a SDCC peripheral's SPS endpoint
2803 *
2804 * This function allocates endpoint context and
2805 * connect it with memory endpoint by calling
2806 * appropriate SPS driver APIs.
2807 *
2808 * Also registers a SPS callback function with
2809 * SPS driver
2810 *
2811 * This function should only be called once typically
2812 * during driver probe.
2813 *
2814 * @host - Pointer to sdcc host structure
2815 * @ep - Pointer to sps endpoint data structure
2816 * @is_produce - 1 means Producer endpoint
2817 * 0 means Consumer endpoint
2818 *
2819 * @return - 0 if successful else negative value.
2820 *
2821 */
2822static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
2823 struct msmsdcc_sps_ep_conn_data *ep,
2824 bool is_producer)
2825{
2826 int rc = 0;
2827 struct sps_pipe *sps_pipe_handle;
2828 struct sps_connect *sps_config = &ep->config;
2829 struct sps_register_event *sps_event = &ep->event;
2830
2831 /* Allocate endpoint context */
2832 sps_pipe_handle = sps_alloc_endpoint();
2833 if (!sps_pipe_handle) {
2834 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
2835 mmc_hostname(host->mmc), is_producer);
2836 rc = -ENOMEM;
2837 goto out;
2838 }
2839
2840 /* Get default connection configuration for an endpoint */
2841 rc = sps_get_config(sps_pipe_handle, sps_config);
2842 if (rc) {
2843 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
2844 " rc=%d", mmc_hostname(host->mmc),
2845 (u32)sps_pipe_handle, rc);
2846 goto get_config_err;
2847 }
2848
2849 /* Modify the default connection configuration */
2850 if (is_producer) {
2851 /*
2852 * For SDCC producer transfer, source should be
2853 * SDCC peripheral where as destination should
2854 * be system memory.
2855 */
2856 sps_config->source = host->sps.bam_handle;
2857 sps_config->destination = SPS_DEV_HANDLE_MEM;
2858 /* Producer pipe will handle this connection */
2859 sps_config->mode = SPS_MODE_SRC;
2860 sps_config->options =
2861 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
2862 } else {
2863 /*
2864 * For SDCC consumer transfer, source should be
2865 * system memory where as destination should
2866 * SDCC peripheral
2867 */
2868 sps_config->source = SPS_DEV_HANDLE_MEM;
2869 sps_config->destination = host->sps.bam_handle;
2870 sps_config->mode = SPS_MODE_DEST;
2871 sps_config->options =
2872 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
2873 }
2874
2875 /* Producer pipe index */
2876 sps_config->src_pipe_index = host->sps.src_pipe_index;
2877 /* Consumer pipe index */
2878 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
2879 /*
2880 * This event thresold value is only significant for BAM-to-BAM
2881 * transfer. It's ignored for BAM-to-System mode transfer.
2882 */
2883 sps_config->event_thresh = 0x10;
2884 /*
2885 * Max. no of scatter/gather buffers that can
2886 * be passed by block layer = 32 (NR_SG).
2887 * Each BAM descritor needs 64 bits (8 bytes).
2888 * One BAM descriptor is required per buffer transfer.
2889 * So we would require total 256 (32 * 8) bytes of descriptor FIFO.
2890 * But due to HW limitation we need to allocate atleast one extra
2891 * descriptor memory (256 bytes + 8 bytes). But in order to be
2892 * in power of 2, we are allocating 512 bytes of memory.
2893 */
2894 sps_config->desc.size = 512;
2895 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
2896 sps_config->desc.size,
2897 &sps_config->desc.phys_base,
2898 GFP_KERNEL);
2899
2900 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
2901
2902 /* Establish connection between peripheral and memory endpoint */
2903 rc = sps_connect(sps_pipe_handle, sps_config);
2904 if (rc) {
2905 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
2906 " rc=%d", mmc_hostname(host->mmc),
2907 (u32)sps_pipe_handle, rc);
2908 goto sps_connect_err;
2909 }
2910
2911 sps_event->mode = SPS_TRIGGER_CALLBACK;
2912 sps_event->options = SPS_O_EOT;
2913 sps_event->callback = msmsdcc_sps_complete_cb;
2914 sps_event->xfer_done = NULL;
2915 sps_event->user = (void *)host;
2916
2917 /* Register callback event for EOT (End of transfer) event. */
2918 rc = sps_register_event(sps_pipe_handle, sps_event);
2919 if (rc) {
2920 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
2921 " rc=%d", mmc_hostname(host->mmc),
2922 (u32)sps_pipe_handle, rc);
2923 goto reg_event_err;
2924 }
2925 /* Now save the sps pipe handle */
2926 ep->pipe_handle = sps_pipe_handle;
2927 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
2928 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
2929 __func__, is_producer ? "READ" : "WRITE",
2930 (u32)sps_pipe_handle, sps_config->desc.phys_base);
2931 goto out;
2932
2933reg_event_err:
2934 sps_disconnect(sps_pipe_handle);
2935sps_connect_err:
2936 dma_free_coherent(mmc_dev(host->mmc),
2937 sps_config->desc.size,
2938 sps_config->desc.base,
2939 sps_config->desc.phys_base);
2940get_config_err:
2941 sps_free_endpoint(sps_pipe_handle);
2942out:
2943 return rc;
2944}
2945
2946/**
2947 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
2948 *
2949 * This function disconnect endpoint and deallocates
2950 * endpoint context.
2951 *
2952 * This function should only be called once typically
2953 * during driver remove.
2954 *
2955 * @host - Pointer to sdcc host structure
2956 * @ep - Pointer to sps endpoint data structure
2957 *
2958 */
2959static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
2960 struct msmsdcc_sps_ep_conn_data *ep)
2961{
2962 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
2963 struct sps_connect *sps_config = &ep->config;
2964 struct sps_register_event *sps_event = &ep->event;
2965
2966 sps_event->xfer_done = NULL;
2967 sps_event->callback = NULL;
2968 sps_register_event(sps_pipe_handle, sps_event);
2969 sps_disconnect(sps_pipe_handle);
2970 dma_free_coherent(mmc_dev(host->mmc),
2971 sps_config->desc.size,
2972 sps_config->desc.base,
2973 sps_config->desc.phys_base);
2974 sps_free_endpoint(sps_pipe_handle);
2975}
2976
2977/**
2978 * Reset SDCC peripheral's SPS endpoint
2979 *
2980 * This function disconnects an endpoint.
2981 *
2982 * This function should be called for reseting
2983 * SPS endpoint when data transfer error is
2984 * encountered during data transfer. This
2985 * can be considered as soft reset to endpoint.
2986 *
2987 * This function should only be called if
2988 * msmsdcc_sps_init() is already called.
2989 *
2990 * @host - Pointer to sdcc host structure
2991 * @ep - Pointer to sps endpoint data structure
2992 *
2993 * @return - 0 if successful else negative value.
2994 */
2995static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
2996 struct msmsdcc_sps_ep_conn_data *ep)
2997{
2998 int rc = 0;
2999 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3000
3001 rc = sps_disconnect(sps_pipe_handle);
3002 if (rc) {
3003 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3004 " rc=%d", mmc_hostname(host->mmc), __func__,
3005 (u32)sps_pipe_handle, rc);
3006 goto out;
3007 }
3008 out:
3009 return rc;
3010}
3011
3012/**
3013 * Restore SDCC peripheral's SPS endpoint
3014 *
3015 * This function connects an endpoint.
3016 *
3017 * This function should be called for restoring
3018 * SPS endpoint after data transfer error is
3019 * encountered during data transfer. This
3020 * can be considered as soft reset to endpoint.
3021 *
3022 * This function should only be called if
3023 * msmsdcc_sps_reset_ep() is called before.
3024 *
3025 * @host - Pointer to sdcc host structure
3026 * @ep - Pointer to sps endpoint data structure
3027 *
3028 * @return - 0 if successful else negative value.
3029 */
3030static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3031 struct msmsdcc_sps_ep_conn_data *ep)
3032{
3033 int rc = 0;
3034 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3035 struct sps_connect *sps_config = &ep->config;
3036 struct sps_register_event *sps_event = &ep->event;
3037
3038 /* Establish connection between peripheral and memory endpoint */
3039 rc = sps_connect(sps_pipe_handle, sps_config);
3040 if (rc) {
3041 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3042 " rc=%d", mmc_hostname(host->mmc), __func__,
3043 (u32)sps_pipe_handle, rc);
3044 goto out;
3045 }
3046
3047 /* Register callback event for EOT (End of transfer) event. */
3048 rc = sps_register_event(sps_pipe_handle, sps_event);
3049 if (rc) {
3050 pr_err("%s: %s: sps_register_event() failed!!!"
3051 " pipe_handle=0x%x, rc=%d",
3052 mmc_hostname(host->mmc), __func__,
3053 (u32)sps_pipe_handle, rc);
3054 goto reg_event_err;
3055 }
3056 goto out;
3057
3058reg_event_err:
3059 sps_disconnect(sps_pipe_handle);
3060out:
3061 return rc;
3062}
3063
3064/**
3065 * Initialize SPS HW connected with SDCC core
3066 *
3067 * This function register BAM HW resources with
3068 * SPS driver and then initialize 2 SPS endpoints
3069 *
3070 * This function should only be called once typically
3071 * during driver probe.
3072 *
3073 * @host - Pointer to sdcc host structure
3074 *
3075 * @return - 0 if successful else negative value.
3076 *
3077 */
3078static int msmsdcc_sps_init(struct msmsdcc_host *host)
3079{
3080 int rc = 0;
3081 struct sps_bam_props bam = {0};
3082
3083 host->bam_base = ioremap(host->bam_memres->start,
3084 resource_size(host->bam_memres));
3085 if (!host->bam_base) {
3086 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3087 " size=0x%x", mmc_hostname(host->mmc),
3088 host->bam_memres->start,
3089 (host->bam_memres->end -
3090 host->bam_memres->start));
3091 rc = -ENOMEM;
3092 goto out;
3093 }
3094
3095 bam.phys_addr = host->bam_memres->start;
3096 bam.virt_addr = host->bam_base;
3097 /*
3098 * This event thresold value is only significant for BAM-to-BAM
3099 * transfer. It's ignored for BAM-to-System mode transfer.
3100 */
3101 bam.event_threshold = 0x10; /* Pipe event threshold */
3102 /*
3103 * This threshold controls when the BAM publish
3104 * the descriptor size on the sideband interface.
3105 * SPS HW will only be used when
3106 * data transfer size > MCI_FIFOSIZE (64 bytes).
3107 * PIO mode will be used when
3108 * data transfer size < MCI_FIFOSIZE (64 bytes).
3109 * So set this thresold value to 64 bytes.
3110 */
3111 bam.summing_threshold = 64;
3112 /* SPS driver wll handle the SDCC BAM IRQ */
3113 bam.irq = (u32)host->bam_irqres->start;
3114 bam.manage = SPS_BAM_MGR_LOCAL;
3115
3116 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3117 (u32)bam.phys_addr);
3118 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3119 (u32)bam.virt_addr);
3120
3121 /* Register SDCC Peripheral BAM device to SPS driver */
3122 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3123 if (rc) {
3124 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3125 mmc_hostname(host->mmc), rc);
3126 goto reg_bam_err;
3127 }
3128 pr_info("%s: BAM device registered. bam_handle=0x%x",
3129 mmc_hostname(host->mmc), host->sps.bam_handle);
3130
3131 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3132 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3133
3134 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3135 SPS_PROD_PERIPHERAL);
3136 if (rc)
3137 goto sps_reset_err;
3138 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3139 SPS_CONS_PERIPHERAL);
3140 if (rc)
3141 goto cons_conn_err;
3142
3143 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3144 mmc_hostname(host->mmc),
3145 (unsigned long long)host->bam_memres->start,
3146 (unsigned int)host->bam_irqres->start);
3147 goto out;
3148
3149cons_conn_err:
3150 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3151sps_reset_err:
3152 sps_deregister_bam_device(host->sps.bam_handle);
3153reg_bam_err:
3154 iounmap(host->bam_base);
3155out:
3156 return rc;
3157}
3158
3159/**
3160 * De-initialize SPS HW connected with SDCC core
3161 *
3162 * This function deinitialize SPS endpoints and then
3163 * deregisters BAM resources from SPS driver.
3164 *
3165 * This function should only be called once typically
3166 * during driver remove.
3167 *
3168 * @host - Pointer to sdcc host structure
3169 *
3170 */
3171static void msmsdcc_sps_exit(struct msmsdcc_host *host)
3172{
3173 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
3174 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3175 sps_deregister_bam_device(host->sps.bam_handle);
3176 iounmap(host->bam_base);
3177}
3178#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
3179
3180static ssize_t
3181show_polling(struct device *dev, struct device_attribute *attr, char *buf)
3182{
3183 struct mmc_host *mmc = dev_get_drvdata(dev);
3184 struct msmsdcc_host *host = mmc_priv(mmc);
3185 int poll;
3186 unsigned long flags;
3187
3188 spin_lock_irqsave(&host->lock, flags);
3189 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
3190 spin_unlock_irqrestore(&host->lock, flags);
3191
3192 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
3193}
3194
3195static ssize_t
3196set_polling(struct device *dev, struct device_attribute *attr,
3197 const char *buf, size_t count)
3198{
3199 struct mmc_host *mmc = dev_get_drvdata(dev);
3200 struct msmsdcc_host *host = mmc_priv(mmc);
3201 int value;
3202 unsigned long flags;
3203
3204 sscanf(buf, "%d", &value);
3205
3206 spin_lock_irqsave(&host->lock, flags);
3207 if (value) {
3208 mmc->caps |= MMC_CAP_NEEDS_POLL;
3209 mmc_detect_change(host->mmc, 0);
3210 } else {
3211 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3212 }
3213#ifdef CONFIG_HAS_EARLYSUSPEND
3214 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
3215#endif
3216 spin_unlock_irqrestore(&host->lock, flags);
3217 return count;
3218}
3219
3220static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
3221 show_polling, set_polling);
3222static struct attribute *dev_attrs[] = {
3223 &dev_attr_polling.attr,
3224 NULL,
3225};
3226static struct attribute_group dev_attr_grp = {
3227 .attrs = dev_attrs,
3228};
3229
3230#ifdef CONFIG_HAS_EARLYSUSPEND
3231static void msmsdcc_early_suspend(struct early_suspend *h)
3232{
3233 struct msmsdcc_host *host =
3234 container_of(h, struct msmsdcc_host, early_suspend);
3235 unsigned long flags;
3236
3237 spin_lock_irqsave(&host->lock, flags);
3238 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
3239 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3240 spin_unlock_irqrestore(&host->lock, flags);
3241};
3242static void msmsdcc_late_resume(struct early_suspend *h)
3243{
3244 struct msmsdcc_host *host =
3245 container_of(h, struct msmsdcc_host, early_suspend);
3246 unsigned long flags;
3247
3248 if (host->polling_enabled) {
3249 spin_lock_irqsave(&host->lock, flags);
3250 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
3251 mmc_detect_change(host->mmc, 0);
3252 spin_unlock_irqrestore(&host->lock, flags);
3253 }
3254};
3255#endif
3256
3257static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
3258{
3259 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3260 struct mmc_request *mrq;
3261 unsigned long flags;
3262
3263 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003264 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003265 pr_info("%s: %s: dummy CMD52 timeout\n",
3266 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003267 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003268 }
3269
3270 mrq = host->curr.mrq;
3271
3272 if (mrq && mrq->cmd) {
3273 pr_info("%s: %s CMD%d\n", mmc_hostname(host->mmc),
3274 __func__, mrq->cmd->opcode);
3275 if (!mrq->cmd->error)
3276 mrq->cmd->error = -ETIMEDOUT;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003277 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003278 host->dummy_52_needed = 0;
3279 if (host->curr.data) {
3280 pr_info("%s: %s Request timeout\n",
3281 mmc_hostname(host->mmc), __func__);
3282 if (mrq->data && !mrq->data->error)
3283 mrq->data->error = -ETIMEDOUT;
3284 host->curr.data_xfered = 0;
3285 if (host->dma.sg && host->is_dma_mode) {
3286 msm_dmov_stop_cmd(host->dma.channel,
3287 &host->dma.hdr, 0);
3288 } else if (host->sps.sg && host->is_sps_mode) {
3289 /* Stop current SPS transfer */
3290 msmsdcc_sps_exit_curr_xfer(host);
3291 } else {
3292 msmsdcc_reset_and_restore(host);
3293 msmsdcc_stop_data(host);
3294 if (mrq->data && mrq->data->stop)
3295 msmsdcc_start_command(host,
3296 mrq->data->stop, 0);
3297 else
3298 msmsdcc_request_end(host, mrq);
3299 }
3300 } else {
3301 if (host->prog_enable) {
3302 host->prog_scan = 0;
3303 host->prog_enable = 0;
3304 }
3305 msmsdcc_reset_and_restore(host);
3306 msmsdcc_request_end(host, mrq);
3307 }
3308 }
3309 spin_unlock_irqrestore(&host->lock, flags);
3310}
3311
San Mehat9d2bd732009-09-22 16:44:22 -07003312static int
3313msmsdcc_probe(struct platform_device *pdev)
3314{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003315 struct mmc_platform_data *plat = pdev->dev.platform_data;
San Mehat9d2bd732009-09-22 16:44:22 -07003316 struct msmsdcc_host *host;
3317 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003318 unsigned long flags;
3319 struct resource *core_irqres = NULL;
3320 struct resource *bam_irqres = NULL;
3321 struct resource *core_memres = NULL;
3322 struct resource *dml_memres = NULL;
3323 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07003324 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07003325 struct resource *dma_crci_res = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07003326 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003327 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07003328
3329 /* must have platform data */
3330 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003331 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003332 ret = -EINVAL;
3333 goto out;
3334 }
3335
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003336 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07003337 return -EINVAL;
3338
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003339 if (plat->is_sdio_al_client)
3340 if (!plat->sdio_lpm_gpio_setup || !plat->sdiowakeup_irq)
3341 return -EINVAL;
3342
San Mehat9d2bd732009-09-22 16:44:22 -07003343 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003344 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003345 return -ENXIO;
3346 }
3347
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003348 for (i = 0; i < pdev->num_resources; i++) {
3349 if (pdev->resource[i].flags & IORESOURCE_MEM) {
3350 if (!strcmp(pdev->resource[i].name,
3351 "sdcc_dml_addr"))
3352 dml_memres = &pdev->resource[i];
3353 else if (!strcmp(pdev->resource[i].name,
3354 "sdcc_bam_addr"))
3355 bam_memres = &pdev->resource[i];
3356 else
3357 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07003358
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003359 }
3360 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
3361 if (!strcmp(pdev->resource[i].name,
3362 "sdcc_bam_irq"))
3363 bam_irqres = &pdev->resource[i];
3364 else
3365 core_irqres = &pdev->resource[i];
3366 }
Krishna Konda25786ec2011-07-25 16:21:36 -07003367 if (pdev->resource[i].flags & IORESOURCE_DMA) {
3368 if (!strncmp(pdev->resource[i].name,
3369 "sdcc_dma_chnl",
3370 sizeof("sdcc_dma_chnl")))
3371 dmares = &pdev->resource[i];
3372 else if (!strncmp(pdev->resource[i].name,
3373 "sdcc_dma_crci",
3374 sizeof("sdcc_dma_crci")))
3375 dma_crci_res = &pdev->resource[i];
3376 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003377 }
3378
3379 if (!core_irqres || !core_memres) {
3380 pr_err("%s: Invalid sdcc core resource\n", __func__);
3381 return -ENXIO;
3382 }
3383
3384 /*
3385 * Both BAM and DML memory resource should be preset.
3386 * BAM IRQ resource should also be present.
3387 */
3388 if ((bam_memres && !dml_memres) ||
3389 (!bam_memres && dml_memres) ||
3390 ((bam_memres && dml_memres) && !bam_irqres)) {
3391 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003392 return -ENXIO;
3393 }
3394
3395 /*
3396 * Setup our host structure
3397 */
San Mehat9d2bd732009-09-22 16:44:22 -07003398 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
3399 if (!mmc) {
3400 ret = -ENOMEM;
3401 goto out;
3402 }
3403
3404 host = mmc_priv(mmc);
3405 host->pdev_id = pdev->id;
3406 host->plat = plat;
3407 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08003408 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05303409
3410 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003411 host->is_sps_mode = 1;
3412 else if (dmares)
3413 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07003414
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003415 host->base = ioremap(core_memres->start,
3416 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07003417 if (!host->base) {
3418 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003419 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003420 }
3421
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003422 host->core_irqres = core_irqres;
3423 host->bam_irqres = bam_irqres;
3424 host->core_memres = core_memres;
3425 host->dml_memres = dml_memres;
3426 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07003427 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07003428 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07003429 spin_lock_init(&host->lock);
3430
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003431#ifdef CONFIG_MMC_EMBEDDED_SDIO
3432 if (plat->embedded_sdio)
3433 mmc_set_embedded_sdio_data(mmc,
3434 &plat->embedded_sdio->cis,
3435 &plat->embedded_sdio->cccr,
3436 plat->embedded_sdio->funcs,
3437 plat->embedded_sdio->num_funcs);
3438#endif
3439
Sahitya Tummala62612cf2010-12-08 15:03:03 +05303440 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
3441 (unsigned long)host);
3442
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003443 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
3444 (unsigned long)host);
3445 if (host->is_dma_mode) {
3446 /* Setup DMA */
3447 ret = msmsdcc_init_dma(host);
3448 if (ret)
3449 goto ioremap_free;
3450 } else {
3451 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003452 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003453 }
3454
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003455 /*
3456 * Setup SDCC clock if derived from Dayatona
3457 * fabric core clock.
3458 */
3459 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07003460 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003461 if (!IS_ERR(host->dfab_pclk)) {
3462 /* Set the clock rate to 64MHz for max. performance */
3463 ret = clk_set_rate(host->dfab_pclk, 64000000);
3464 if (ret)
3465 goto dfab_pclk_put;
3466 ret = clk_enable(host->dfab_pclk);
3467 if (ret)
3468 goto dfab_pclk_put;
3469 } else
3470 goto dma_free;
3471 }
3472
3473 /*
3474 * Setup main peripheral bus clock
3475 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003476 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003477 if (!IS_ERR(host->pclk)) {
3478 ret = clk_enable(host->pclk);
3479 if (ret)
3480 goto pclk_put;
3481
3482 host->pclk_rate = clk_get_rate(host->pclk);
3483 }
3484
3485 /*
3486 * Setup SDC MMC clock
3487 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003488 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07003489 if (IS_ERR(host->clk)) {
3490 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003491 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07003492 }
3493
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003494 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
3495 if (ret) {
3496 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
3497 goto clk_put;
3498 }
3499
3500 ret = clk_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003501 if (ret)
3502 goto clk_put;
3503
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003504 host->clk_rate = clk_get_rate(host->clk);
3505
3506 host->clks_on = 1;
3507
3508 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07003509 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003510 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07003511 goto clk_disable;
3512 }
3513
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003514
3515 /* Clocks has to be running before accessing SPS/DML HW blocks */
3516 if (host->is_sps_mode) {
3517 /* Initialize SPS */
3518 ret = msmsdcc_sps_init(host);
3519 if (ret)
3520 goto vreg_deinit;
3521 /* Initialize DML */
3522 ret = msmsdcc_dml_init(host);
3523 if (ret)
3524 goto sps_exit;
3525 }
San Mehat9d2bd732009-09-22 16:44:22 -07003526
San Mehat9d2bd732009-09-22 16:44:22 -07003527 /*
3528 * Setup MMC host structure
3529 */
3530 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003531 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
3532 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003533 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003534 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
3535 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07003536
San Mehat9d2bd732009-09-22 16:44:22 -07003537 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003538 mmc->caps |= plat->uhs_caps;
3539 /*
3540 * XPC controls the maximum current in the default speed mode of SDXC
3541 * card. XPC=0 means 100mA (max.) but speed class is not supported.
3542 * XPC=1 means 150mA (max.) and speed class is supported.
3543 */
3544 if (plat->xpc_cap)
3545 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
3546 MMC_CAP_SET_XPC_180);
3547
3548 if (plat->nonremovable)
3549 mmc->caps |= MMC_CAP_NONREMOVABLE;
3550#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
3551 mmc->caps |= MMC_CAP_SDIO_IRQ;
3552#endif
3553
3554 if (plat->is_sdio_al_client)
3555 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07003556
Martin K. Petersena36274e2010-09-10 01:33:59 -04003557 mmc->max_segs = NR_SG;
San Mehat9d2bd732009-09-22 16:44:22 -07003558 mmc->max_blk_size = 4096; /* MCI_DATA_CTL BLOCKSIZE up to 4096 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003559 mmc->max_blk_count = 65535;
San Mehat9d2bd732009-09-22 16:44:22 -07003560
3561 mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */
3562 mmc->max_seg_size = mmc->max_req_size;
3563
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003564 writel_relaxed(0, host->base + MMCIMASK0);
3565 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -07003566
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003567 /* Delay needed (MMCIMASK0 was just written above) */
3568 msmsdcc_delay(host);
3569 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
3570 mb();
3571 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07003572
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003573 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
3574 DRIVER_NAME " (cmd)", host);
3575 if (ret)
3576 goto dml_exit;
3577
3578 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
3579 DRIVER_NAME " (pio)", host);
3580 if (ret)
3581 goto irq_free;
3582
3583 /*
3584 * Enable SDCC IRQ only when host is powered on. Otherwise, this
3585 * IRQ is un-necessarily being monitored by MPM (Modem power
3586 * management block) during idle-power collapse. The MPM will be
3587 * configured to monitor the DATA1 GPIO line with level-low trigger
3588 * and thus depending on the GPIO status, it prevents TCXO shutdown
3589 * during idle-power collapse.
3590 */
3591 disable_irq(core_irqres->start);
3592 host->sdcc_irq_disabled = 1;
3593
3594 if (plat->sdiowakeup_irq) {
3595 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3596 mmc_hostname(mmc));
3597 ret = request_irq(plat->sdiowakeup_irq,
3598 msmsdcc_platform_sdiowakeup_irq,
3599 IRQF_SHARED | IRQF_TRIGGER_LOW,
3600 DRIVER_NAME "sdiowakeup", host);
3601 if (ret) {
3602 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
3603 plat->sdiowakeup_irq, ret);
3604 goto pio_irq_free;
3605 } else {
3606 spin_lock_irqsave(&host->lock, flags);
3607 if (!host->sdio_irq_disabled) {
3608 disable_irq_nosync(plat->sdiowakeup_irq);
3609 host->sdio_irq_disabled = 1;
3610 }
3611 spin_unlock_irqrestore(&host->lock, flags);
3612 }
3613 }
3614
3615 if (plat->cfg_mpm_sdiowakeup) {
3616 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3617 mmc_hostname(mmc));
3618 }
3619
3620 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
3621 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003622 /*
3623 * Setup card detect change
3624 */
3625
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003626 if (plat->status || plat->status_gpio) {
3627 if (plat->status)
3628 host->oldstat = plat->status(mmc_dev(host->mmc));
3629 else
3630 host->oldstat = msmsdcc_slot_status(host);
3631 host->eject = !host->oldstat;
3632 }
San Mehat9d2bd732009-09-22 16:44:22 -07003633
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003634 if (plat->status_irq) {
3635 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07003636 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003637 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07003638 DRIVER_NAME " (slot)",
3639 host);
3640 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003641 pr_err("Unable to get slot IRQ %d (%d)\n",
3642 plat->status_irq, ret);
3643 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003644 }
3645 } else if (plat->register_status_notify) {
3646 plat->register_status_notify(msmsdcc_status_notify_cb, host);
3647 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003648 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07003649 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003650
3651 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003652
3653 ret = pm_runtime_set_active(&(pdev)->dev);
3654 if (ret < 0)
3655 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3656 __func__, ret);
3657 /*
3658 * There is no notion of suspend/resume for SD/MMC/SDIO
3659 * cards. So host can be suspended/resumed with out
3660 * worrying about its children.
3661 */
3662 pm_suspend_ignore_children(&(pdev)->dev, true);
3663
3664 /*
3665 * MMC/SD/SDIO bus suspend/resume operations are defined
3666 * only for the slots that will be used for non-removable
3667 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
3668 * defined. Otherwise, they simply become card removal and
3669 * insertion events during suspend and resume respectively.
3670 * Hence, enable run-time PM only for slots for which bus
3671 * suspend/resume operations are defined.
3672 */
3673#ifdef CONFIG_MMC_UNSAFE_RESUME
3674 /*
3675 * If this capability is set, MMC core will enable/disable host
3676 * for every claim/release operation on a host. We use this
3677 * notification to increment/decrement runtime pm usage count.
3678 */
3679 mmc->caps |= MMC_CAP_DISABLE;
3680 pm_runtime_enable(&(pdev)->dev);
3681#else
3682 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
3683 mmc->caps |= MMC_CAP_DISABLE;
3684 pm_runtime_enable(&(pdev)->dev);
3685 }
3686#endif
3687 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
3688 (unsigned long)host);
3689
San Mehat9d2bd732009-09-22 16:44:22 -07003690 mmc_add_host(mmc);
3691
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003692#ifdef CONFIG_HAS_EARLYSUSPEND
3693 host->early_suspend.suspend = msmsdcc_early_suspend;
3694 host->early_suspend.resume = msmsdcc_late_resume;
3695 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
3696 register_early_suspend(&host->early_suspend);
3697#endif
San Mehat9d2bd732009-09-22 16:44:22 -07003698
Krishna Konda25786ec2011-07-25 16:21:36 -07003699 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
3700 " dmacrcri %d\n", mmc_hostname(mmc),
3701 (unsigned long long)core_memres->start,
3702 (unsigned int) core_irqres->start,
3703 (unsigned int) plat->status_irq, host->dma.channel,
3704 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003705
3706 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
3707 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
3708 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
3709 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
3710 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
3711 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
3712 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
3713 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
3714 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
3715 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
3716 host->eject);
3717 pr_info("%s: Power save feature enable = %d\n",
3718 mmc_hostname(mmc), msmsdcc_pwrsave);
3719
Krishna Konda25786ec2011-07-25 16:21:36 -07003720 if (host->is_dma_mode && host->dma.channel != -1
3721 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003722 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003723 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003724 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003725 mmc_hostname(mmc), host->dma.cmd_busaddr,
3726 host->dma.cmdptr_busaddr);
3727 } else if (host->is_sps_mode) {
3728 pr_info("%s: SPS-BAM data transfer mode available\n",
3729 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003730 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003731 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003732
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003733#if defined(CONFIG_DEBUG_FS)
3734 msmsdcc_dbg_createhost(host);
3735#endif
3736 if (!plat->status_irq) {
3737 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
3738 if (ret)
3739 goto platform_irq_free;
3740 }
San Mehat9d2bd732009-09-22 16:44:22 -07003741 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003742
3743 platform_irq_free:
3744 del_timer_sync(&host->req_tout_timer);
3745 pm_runtime_disable(&(pdev)->dev);
3746 pm_runtime_set_suspended(&(pdev)->dev);
3747
3748 if (plat->status_irq)
3749 free_irq(plat->status_irq, host);
3750 sdiowakeup_irq_free:
3751 wake_lock_destroy(&host->sdio_suspend_wlock);
3752 if (plat->sdiowakeup_irq)
3753 free_irq(plat->sdiowakeup_irq, host);
3754 pio_irq_free:
3755 if (plat->sdiowakeup_irq)
3756 wake_lock_destroy(&host->sdio_wlock);
3757 free_irq(core_irqres->start, host);
3758 irq_free:
3759 free_irq(core_irqres->start, host);
3760 dml_exit:
3761 if (host->is_sps_mode)
3762 msmsdcc_dml_exit(host);
3763 sps_exit:
3764 if (host->is_sps_mode)
3765 msmsdcc_sps_exit(host);
3766 vreg_deinit:
3767 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07003768 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003769 clk_disable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003770 clk_put:
3771 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003772 pclk_disable:
3773 if (!IS_ERR(host->pclk))
3774 clk_disable(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07003775 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003776 if (!IS_ERR(host->pclk))
3777 clk_put(host->pclk);
3778 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3779 clk_disable(host->dfab_pclk);
3780 dfab_pclk_put:
3781 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3782 clk_put(host->dfab_pclk);
3783 dma_free:
3784 if (host->is_dma_mode) {
3785 if (host->dmares)
3786 dma_free_coherent(NULL,
3787 sizeof(struct msmsdcc_nc_dmadata),
3788 host->dma.nc, host->dma.nc_busaddr);
3789 }
3790 ioremap_free:
3791 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07003792 host_free:
3793 mmc_free_host(mmc);
3794 out:
3795 return ret;
3796}
3797
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003798static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07003799{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003800 struct mmc_host *mmc = mmc_get_drvdata(pdev);
3801 struct mmc_platform_data *plat;
3802 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07003803
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003804 if (!mmc)
3805 return -ENXIO;
3806
3807 if (pm_runtime_suspended(&(pdev)->dev))
3808 pm_runtime_resume(&(pdev)->dev);
3809
3810 host = mmc_priv(mmc);
3811
3812 DBG(host, "Removing SDCC device = %d\n", pdev->id);
3813 plat = host->plat;
3814
3815 if (!plat->status_irq)
3816 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
3817
3818 del_timer_sync(&host->req_tout_timer);
3819 tasklet_kill(&host->dma_tlet);
3820 tasklet_kill(&host->sps.tlet);
3821 mmc_remove_host(mmc);
3822
3823 if (plat->status_irq)
3824 free_irq(plat->status_irq, host);
3825
3826 wake_lock_destroy(&host->sdio_suspend_wlock);
3827 if (plat->sdiowakeup_irq) {
3828 wake_lock_destroy(&host->sdio_wlock);
3829 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
3830 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07003831 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003832
3833 free_irq(host->core_irqres->start, host);
3834 free_irq(host->core_irqres->start, host);
3835
3836 clk_put(host->clk);
3837 if (!IS_ERR(host->pclk))
3838 clk_put(host->pclk);
3839 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3840 clk_put(host->dfab_pclk);
3841
3842 msmsdcc_vreg_init(host, false);
3843
3844 if (host->is_dma_mode) {
3845 if (host->dmares)
3846 dma_free_coherent(NULL,
3847 sizeof(struct msmsdcc_nc_dmadata),
3848 host->dma.nc, host->dma.nc_busaddr);
3849 }
3850
3851 if (host->is_sps_mode) {
3852 msmsdcc_dml_exit(host);
3853 msmsdcc_sps_exit(host);
3854 }
3855
3856 iounmap(host->base);
3857 mmc_free_host(mmc);
3858
3859#ifdef CONFIG_HAS_EARLYSUSPEND
3860 unregister_early_suspend(&host->early_suspend);
3861#endif
3862 pm_runtime_disable(&(pdev)->dev);
3863 pm_runtime_set_suspended(&(pdev)->dev);
3864
3865 return 0;
3866}
3867
3868#ifdef CONFIG_MSM_SDIO_AL
3869int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
3870{
3871 struct msmsdcc_host *host = mmc_priv(mmc);
3872 unsigned long flags;
3873
3874 spin_lock_irqsave(&host->lock, flags);
3875 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
3876 enable ? "En" : "Dis");
3877
3878 if (enable) {
3879 if (!host->sdcc_irq_disabled) {
3880 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05303881 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003882 host->sdcc_irq_disabled = 1;
3883 }
3884
3885 if (host->clks_on) {
3886 msmsdcc_setup_clocks(host, false);
3887 host->clks_on = 0;
3888 }
3889
3890 if (!host->sdio_gpio_lpm) {
3891 spin_unlock_irqrestore(&host->lock, flags);
3892 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
3893 spin_lock_irqsave(&host->lock, flags);
3894 host->sdio_gpio_lpm = 1;
3895 }
3896
3897 if (host->sdio_irq_disabled) {
3898 msmsdcc_enable_irq_wake(host);
3899 enable_irq(host->plat->sdiowakeup_irq);
3900 host->sdio_irq_disabled = 0;
3901 }
3902 } else {
3903 if (!host->sdio_irq_disabled) {
3904 disable_irq_nosync(host->plat->sdiowakeup_irq);
3905 host->sdio_irq_disabled = 1;
3906 msmsdcc_disable_irq_wake(host);
3907 }
3908
3909 if (host->sdio_gpio_lpm) {
3910 spin_unlock_irqrestore(&host->lock, flags);
3911 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
3912 spin_lock_irqsave(&host->lock, flags);
3913 host->sdio_gpio_lpm = 0;
3914 }
3915
3916 if (!host->clks_on) {
3917 msmsdcc_setup_clocks(host, true);
3918 host->clks_on = 1;
3919 }
3920
3921 if (host->sdcc_irq_disabled) {
3922 writel_relaxed(host->mci_irqenable,
3923 host->base + MMCIMASK0);
3924 mb();
3925 enable_irq(host->core_irqres->start);
3926 host->sdcc_irq_disabled = 0;
3927 }
3928 wake_lock_timeout(&host->sdio_wlock, 1);
3929 }
3930 spin_unlock_irqrestore(&host->lock, flags);
3931 return 0;
3932}
3933#else
3934int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
3935{
3936 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07003937}
3938#endif
3939
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003940#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07003941static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003942msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07003943{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003944 struct mmc_host *mmc = dev_get_drvdata(dev);
3945 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07003946 int rc = 0;
3947
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003948 if (host->plat->is_sdio_al_client)
3949 return 0;
3950
Sahitya Tummala7661a452011-07-18 13:28:35 +05303951 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003952 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003953 host->sdcc_suspending = 1;
3954 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07003955
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003956 /*
3957 * If the clocks are already turned off by SDIO clients (as
3958 * part of LPM), then clocks should be turned on before
3959 * calling mmc_suspend_host() because mmc_suspend_host might
3960 * send some commands to the card. The clocks will be turned
3961 * off again after mmc_suspend_host. Thus for SD/MMC/SDIO
3962 * cards, clocks will be turned on before mmc_suspend_host
3963 * and turned off after mmc_suspend_host.
3964 */
3965 mmc->ios.clock = host->clk_rate;
3966 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07003967
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003968 /*
3969 * MMC core thinks that host is disabled by now since
3970 * runtime suspend is scheduled after msmsdcc_disable()
3971 * is called. Thus, MMC core will try to enable the host
3972 * while suspending it. This results in a synchronous
3973 * runtime resume request while in runtime suspending
3974 * context and hence inorder to complete this resume
3975 * requet, it will wait for suspend to be complete,
3976 * but runtime suspend also can not proceed further
3977 * until the host is resumed. Thus, it leads to a hang.
3978 * Hence, increase the pm usage count before suspending
3979 * the host so that any resume requests after this will
3980 * simple become pm usage counter increment operations.
3981 */
3982 pm_runtime_get_noresume(dev);
3983 rc = mmc_suspend_host(mmc);
3984 pm_runtime_put_noidle(dev);
3985
3986 if (!rc) {
3987 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
3988 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ)) {
3989 disable_irq(host->core_irqres->start);
3990 host->sdcc_irq_disabled = 1;
3991
3992 /*
3993 * If MMC core level suspend is not supported,
3994 * turn off clocks to allow deep sleep (TCXO
3995 * shutdown).
3996 */
3997 mmc->ios.clock = 0;
3998 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
3999 enable_irq(host->core_irqres->start);
4000 host->sdcc_irq_disabled = 0;
4001
4002 if (host->plat->sdiowakeup_irq) {
4003 host->sdio_irq_disabled = 0;
4004 msmsdcc_enable_irq_wake(host);
4005 enable_irq(host->plat->sdiowakeup_irq);
4006 }
4007 }
4008 }
4009 host->sdcc_suspending = 0;
4010 mmc->suspend_task = NULL;
4011 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
4012 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004013 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304014 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004015 return rc;
4016}
4017
4018static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004019msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004020{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004021 struct mmc_host *mmc = dev_get_drvdata(dev);
4022 struct msmsdcc_host *host = mmc_priv(mmc);
4023 unsigned long flags;
4024
4025 if (host->plat->is_sdio_al_client)
4026 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07004027
Sahitya Tummala7661a452011-07-18 13:28:35 +05304028 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004029 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004030 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
4031 if (host->sdcc_irq_disabled) {
4032 enable_irq(host->core_irqres->start);
4033 host->sdcc_irq_disabled = 0;
4034 }
4035 }
4036 mmc->ios.clock = host->clk_rate;
4037 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07004038
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004039 spin_lock_irqsave(&host->lock, flags);
4040 writel_relaxed(host->mci_irqenable, host->base + MMCIMASK0);
4041 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07004042
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004043 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
4044 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) &&
4045 !host->sdio_irq_disabled) {
4046 if (host->plat->sdiowakeup_irq) {
4047 disable_irq_nosync(
4048 host->plat->sdiowakeup_irq);
4049 msmsdcc_disable_irq_wake(host);
4050 host->sdio_irq_disabled = 1;
4051 }
4052 }
San Mehat9d2bd732009-09-22 16:44:22 -07004053
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004054 spin_unlock_irqrestore(&host->lock, flags);
4055
4056 mmc_resume_host(mmc);
4057
4058 /*
4059 * FIXME: Clearing of flags must be handled in clients
4060 * resume handler.
4061 */
4062 spin_lock_irqsave(&host->lock, flags);
4063 mmc->pm_flags = 0;
4064 spin_unlock_irqrestore(&host->lock, flags);
4065
4066 /*
4067 * After resuming the host wait for sometime so that
4068 * the SDIO work will be processed.
4069 */
4070 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO)) {
4071 if ((host->plat->cfg_mpm_sdiowakeup ||
4072 host->plat->sdiowakeup_irq) &&
4073 wake_lock_active(&host->sdio_wlock))
4074 wake_lock_timeout(&host->sdio_wlock, 1);
4075 }
4076
4077 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004078 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304079 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004080 return 0;
4081}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004082
4083static int msmsdcc_runtime_idle(struct device *dev)
4084{
4085 struct mmc_host *mmc = dev_get_drvdata(dev);
4086 struct msmsdcc_host *host = mmc_priv(mmc);
4087
4088 if (host->plat->is_sdio_al_client)
4089 return 0;
4090
4091 /* Idle timeout is not configurable for now */
4092 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
4093
4094 return -EAGAIN;
4095}
4096
4097static int msmsdcc_pm_suspend(struct device *dev)
4098{
4099 struct mmc_host *mmc = dev_get_drvdata(dev);
4100 struct msmsdcc_host *host = mmc_priv(mmc);
4101 int rc = 0;
4102
4103 if (host->plat->is_sdio_al_client)
4104 return 0;
4105
4106
4107 if (host->plat->status_irq)
4108 disable_irq(host->plat->status_irq);
4109
4110 if (!pm_runtime_suspended(dev))
4111 rc = msmsdcc_runtime_suspend(dev);
4112
4113 return rc;
4114}
4115
4116static int msmsdcc_pm_resume(struct device *dev)
4117{
4118 struct mmc_host *mmc = dev_get_drvdata(dev);
4119 struct msmsdcc_host *host = mmc_priv(mmc);
4120 int rc = 0;
4121
4122 if (host->plat->is_sdio_al_client)
4123 return 0;
4124
Sahitya Tummalafb486372011-09-02 19:01:49 +05304125 if (!pm_runtime_suspended(dev))
4126 rc = msmsdcc_runtime_resume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004127 if (host->plat->status_irq) {
4128 msmsdcc_check_status((unsigned long)host);
4129 enable_irq(host->plat->status_irq);
4130 }
4131
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004132 return rc;
4133}
4134
Daniel Walker08ecfde2010-06-23 12:32:20 -07004135#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004136#define msmsdcc_runtime_suspend NULL
4137#define msmsdcc_runtime_resume NULL
4138#define msmsdcc_runtime_idle NULL
4139#define msmsdcc_pm_suspend NULL
4140#define msmsdcc_pm_resume NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07004141#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004142
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004143static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
4144 .runtime_suspend = msmsdcc_runtime_suspend,
4145 .runtime_resume = msmsdcc_runtime_resume,
4146 .runtime_idle = msmsdcc_runtime_idle,
4147 .suspend = msmsdcc_pm_suspend,
4148 .resume = msmsdcc_pm_resume,
4149};
4150
San Mehat9d2bd732009-09-22 16:44:22 -07004151static struct platform_driver msmsdcc_driver = {
4152 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004153 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07004154 .driver = {
4155 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004156 .pm = &msmsdcc_dev_pm_ops,
San Mehat9d2bd732009-09-22 16:44:22 -07004157 },
4158};
4159
4160static int __init msmsdcc_init(void)
4161{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004162#if defined(CONFIG_DEBUG_FS)
4163 int ret = 0;
4164 ret = msmsdcc_dbg_init();
4165 if (ret) {
4166 pr_err("Failed to create debug fs dir \n");
4167 return ret;
4168 }
4169#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004170 return platform_driver_register(&msmsdcc_driver);
4171}
4172
4173static void __exit msmsdcc_exit(void)
4174{
4175 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004176
4177#if defined(CONFIG_DEBUG_FS)
4178 debugfs_remove(debugfs_file);
4179 debugfs_remove(debugfs_dir);
4180#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004181}
4182
4183module_init(msmsdcc_init);
4184module_exit(msmsdcc_exit);
4185
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004186MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07004187MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004188
4189#if defined(CONFIG_DEBUG_FS)
4190
4191static int
4192msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
4193{
4194 file->private_data = inode->i_private;
4195 return 0;
4196}
4197
4198static ssize_t
4199msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
4200 size_t count, loff_t *ppos)
4201{
4202 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
4203 char buf[1024];
4204 int max, i;
4205
4206 i = 0;
4207 max = sizeof(buf) - 1;
4208
4209 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
4210 host->curr.cmd, host->curr.data);
4211 if (host->curr.cmd) {
4212 struct mmc_command *cmd = host->curr.cmd;
4213
4214 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
4215 cmd->opcode, cmd->arg, cmd->flags);
4216 }
4217 if (host->curr.data) {
4218 struct mmc_data *data = host->curr.data;
4219 i += scnprintf(buf + i, max - i,
4220 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
4221 data->timeout_ns, data->timeout_clks,
4222 data->blksz, data->blocks, data->error,
4223 data->flags);
4224 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
4225 host->curr.xfer_size, host->curr.xfer_remain,
4226 host->curr.data_xfered, host->dma.sg);
4227 }
4228
4229 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
4230}
4231
4232static const struct file_operations msmsdcc_dbg_state_ops = {
4233 .read = msmsdcc_dbg_state_read,
4234 .open = msmsdcc_dbg_state_open,
4235};
4236
4237static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
4238{
4239 if (debugfs_dir) {
4240 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
4241 0644, debugfs_dir, host,
4242 &msmsdcc_dbg_state_ops);
4243 }
4244}
4245
4246static int __init msmsdcc_dbg_init(void)
4247{
4248 int err;
4249
4250 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
4251 if (IS_ERR(debugfs_dir)) {
4252 err = PTR_ERR(debugfs_dir);
4253 debugfs_dir = NULL;
4254 return err;
4255 }
4256
4257 return 0;
4258}
4259#endif