blob: a5fa1d9998ac137508e2d50a676f29ba01350b01 [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
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001138 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001139
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001140 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1141 (MCI_IRQ_PIO)) == 0)
1142 return IRQ_NONE;
1143
1144#if IRQ_DEBUG
1145 msmsdcc_print_status(host, "irq1-r", status);
1146#endif
1147
1148 spin_lock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001149
1150 do {
1151 unsigned long flags;
1152 unsigned int remain, len;
1153 char *buffer;
1154
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001155 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1156 | MCI_RXDATAAVLBL)))
1157 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001158
1159 /* Map the current scatter buffer */
1160 local_irq_save(flags);
1161 buffer = kmap_atomic(sg_page(host->pio.sg),
1162 KM_BIO_SRC_IRQ) + host->pio.sg->offset;
1163 buffer += host->pio.sg_off;
1164 remain = host->pio.sg->length - host->pio.sg_off;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001165
San Mehat9d2bd732009-09-22 16:44:22 -07001166 len = 0;
1167 if (status & MCI_RXACTIVE)
1168 len = msmsdcc_pio_read(host, buffer, remain);
1169 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001170 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001171
1172 /* Unmap the buffer */
1173 kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
1174 local_irq_restore(flags);
1175
1176 host->pio.sg_off += len;
1177 host->curr.xfer_remain -= len;
1178 host->curr.data_xfered += len;
1179 remain -= len;
1180
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001181 if (remain) /* Done with this page? */
1182 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001183
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001184 if (status & MCI_RXACTIVE && host->curr.user_pages)
1185 flush_dcache_page(sg_page(host->pio.sg));
San Mehat9d2bd732009-09-22 16:44:22 -07001186
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001187 if (!--host->pio.sg_len) {
1188 memset(&host->pio, 0, sizeof(host->pio));
1189 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001190 }
1191
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001192 /* Advance to next sg */
1193 host->pio.sg++;
1194 host->pio.sg_off = 0;
1195
1196 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001197 } while (1);
1198
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001199 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1200 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1201 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1202 host->base + MMCIMASK0);
1203 if (!host->curr.xfer_remain) {
1204 /* Delay needed (same port was just written) */
1205 msmsdcc_delay(host);
1206 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1207 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1208 }
1209 mb();
1210 } else if (!host->curr.xfer_remain) {
1211 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1212 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1213 mb();
1214 }
San Mehat9d2bd732009-09-22 16:44:22 -07001215
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001216 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001217
1218 return IRQ_HANDLED;
1219}
1220
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001221static void
1222msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1223
1224static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1225 struct mmc_data *data)
1226{
1227 u32 loop_cnt = 0;
1228
1229 /*
1230 * For read commands with data less than fifo size, it is possible to
1231 * get DATAEND first and RXDATA_AVAIL might be set later because of
1232 * synchronization delay through the asynchronous RX FIFO. Thus, for
1233 * such cases, even after DATAEND interrupt is received software
1234 * should poll for RXDATA_AVAIL until the requested data is read out
1235 * of FIFO. This change is needed to get around this abnormal but
1236 * sometimes expected behavior of SDCC3 controller.
1237 *
1238 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1239 * after the data is loaded into RX FIFO. This would amount to less
1240 * than a microsecond and thus looping for 1000 times is good enough
1241 * for that delay.
1242 */
1243 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1244 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1245 spin_unlock(&host->lock);
1246 msmsdcc_pio_irq(1, host);
1247 spin_lock(&host->lock);
1248 }
1249 }
1250 if (loop_cnt == 1000) {
1251 pr_info("%s: Timed out while polling for Rx Data\n",
1252 mmc_hostname(host->mmc));
1253 data->error = -ETIMEDOUT;
1254 msmsdcc_reset_and_restore(host);
1255 }
1256}
1257
San Mehat9d2bd732009-09-22 16:44:22 -07001258static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1259{
1260 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001261
1262 host->curr.cmd = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001263 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1264 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1265 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1266 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -07001267
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001268 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Sahitya Tummala5a0ae912011-07-18 13:34:01 +05301269 pr_debug("%s: Command timeout\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001270 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001271 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
1272 !host->cmd19_tuning_in_progress) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001273 pr_err("%s: Command CRC error\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001274 cmd->error = -EILSEQ;
1275 }
1276
1277 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001278 if (host->curr.data && host->dma.sg &&
1279 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001280 msm_dmov_stop_cmd(host->dma.channel,
1281 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001282 else if (host->curr.data && host->sps.sg &&
1283 host->is_sps_mode){
1284 /* Stop current SPS transfer */
1285 msmsdcc_sps_exit_curr_xfer(host);
1286 }
San Mehat9d2bd732009-09-22 16:44:22 -07001287 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301288 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001289 msmsdcc_stop_data(host);
1290 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301291 } else { /* host->data == NULL */
1292 if (!cmd->error && host->prog_enable) {
1293 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001294 host->prog_scan = 0;
1295 host->prog_enable = 0;
1296 msmsdcc_request_end(host, cmd->mrq);
1297 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301298 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301299 } else {
1300 if (host->prog_enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001301 host->prog_scan = 0;
1302 host->prog_enable = 0;
1303 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001304 if (host->dummy_52_needed)
1305 host->dummy_52_needed = 0;
1306 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001307 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301308 msmsdcc_request_end(host, cmd->mrq);
1309 }
1310 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001311 } else if (cmd->data) {
San Mehat56a8b5b2009-11-21 12:29:46 -08001312 if (!(cmd->data->flags & MMC_DATA_READ))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001313 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001314 }
1315}
1316
San Mehat9d2bd732009-09-22 16:44:22 -07001317static irqreturn_t
1318msmsdcc_irq(int irq, void *dev_id)
1319{
1320 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001321 u32 status;
1322 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001323 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001324
1325 spin_lock(&host->lock);
1326
1327 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001328 struct mmc_command *cmd;
1329 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001330
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001331 if (timer) {
1332 timer = 0;
1333 msmsdcc_delay(host);
1334 }
San Mehat865c8062009-11-13 13:42:06 -08001335
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001336 if (!host->clks_on) {
1337 pr_debug("%s: %s: SDIO async irq received\n",
1338 mmc_hostname(host->mmc), __func__);
1339 host->mmc->ios.clock = host->clk_rate;
1340 spin_unlock(&host->lock);
1341 host->mmc->ops->set_ios(host->mmc, &host->mmc->ios);
1342 spin_lock(&host->lock);
1343 if (host->plat->cfg_mpm_sdiowakeup &&
1344 (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
1345 wake_lock(&host->sdio_wlock);
1346 /* only ansyc interrupt can come when clocks are off */
1347 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
1348 }
1349
1350 status = readl_relaxed(host->base + MMCISTATUS);
1351
1352 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1353 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001354 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001355
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001356#if IRQ_DEBUG
1357 msmsdcc_print_status(host, "irq0-r", status);
1358#endif
1359 status &= readl_relaxed(host->base + MMCIMASK0);
1360 writel_relaxed(status, host->base + MMCICLEAR);
1361 mb();
1362#if IRQ_DEBUG
1363 msmsdcc_print_status(host, "irq0-p", status);
1364#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001365
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001366#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
1367 if (status & MCI_SDIOINTROPE) {
1368 if (host->sdcc_suspending)
1369 wake_lock(&host->sdio_suspend_wlock);
1370 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001371 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001372#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001373 data = host->curr.data;
1374
1375 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001376 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1377 MCI_CMDTIMEOUT)) {
1378 if (status & MCI_CMDTIMEOUT)
1379 pr_debug("%s: dummy CMD52 timeout\n",
1380 mmc_hostname(host->mmc));
1381 if (status & MCI_CMDCRCFAIL)
1382 pr_debug("%s: dummy CMD52 CRC failed\n",
1383 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001384 host->dummy_52_sent = 0;
1385 host->dummy_52_needed = 0;
1386 if (data) {
1387 msmsdcc_stop_data(host);
1388 msmsdcc_request_end(host, data->mrq);
1389 }
1390 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001391 spin_unlock(&host->lock);
1392 return IRQ_HANDLED;
1393 }
1394 break;
1395 }
1396
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001397 /*
1398 * Check for proper command response
1399 */
1400 cmd = host->curr.cmd;
1401 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1402 MCI_CMDTIMEOUT | MCI_PROGDONE |
1403 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1404 msmsdcc_do_cmdirq(host, status);
1405 }
1406
1407 if (data) {
1408 /* Check for data errors */
1409 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1410 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1411 msmsdcc_data_err(host, data, status);
1412 host->curr.data_xfered = 0;
1413 if (host->dma.sg && host->is_dma_mode)
1414 msm_dmov_stop_cmd(host->dma.channel,
1415 &host->dma.hdr, 0);
1416 else if (host->sps.sg && host->is_sps_mode) {
1417 /* Stop current SPS transfer */
1418 msmsdcc_sps_exit_curr_xfer(host);
1419 }
1420 else {
1421 msmsdcc_reset_and_restore(host);
1422 if (host->curr.data)
1423 msmsdcc_stop_data(host);
1424 if (!data->stop)
1425 timer |=
1426 msmsdcc_request_end(host,
1427 data->mrq);
1428 else {
1429 msmsdcc_start_command(host,
1430 data->stop,
1431 0);
1432 timer = 1;
1433 }
1434 }
1435 }
1436
1437 /* Check for data done */
1438 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1439 host->curr.got_dataend = 1;
1440
1441 if (host->curr.got_dataend) {
1442 /*
1443 * If DMA is still in progress, we complete
1444 * via the completion handler
1445 */
1446 if (!host->dma.busy && !host->sps.busy) {
1447 /*
1448 * There appears to be an issue in the
1449 * controller where if you request a
1450 * small block transfer (< fifo size),
1451 * you may get your DATAEND/DATABLKEND
1452 * irq without the PIO data irq.
1453 *
1454 * Check to see if theres still data
1455 * to be read, and simulate a PIO irq.
1456 */
1457 if (data->flags & MMC_DATA_READ)
1458 msmsdcc_wait_for_rxdata(host,
1459 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001460 if (!data->error) {
1461 host->curr.data_xfered =
1462 host->curr.xfer_size;
1463 host->curr.xfer_remain -=
1464 host->curr.xfer_size;
1465 }
1466
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001467 if (!host->dummy_52_needed) {
1468 msmsdcc_stop_data(host);
1469 if (!data->stop) {
1470 msmsdcc_request_end(
1471 host,
1472 data->mrq);
1473 } else {
1474 msmsdcc_start_command(
1475 host,
1476 data->stop, 0);
1477 timer = 1;
1478 }
1479 } else {
1480 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001481 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001482 &dummy52cmd,
1483 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001484 }
1485 }
1486 }
1487 }
1488
San Mehat9d2bd732009-09-22 16:44:22 -07001489 ret = 1;
1490 } while (status);
1491
1492 spin_unlock(&host->lock);
1493
San Mehat9d2bd732009-09-22 16:44:22 -07001494 return IRQ_RETVAL(ret);
1495}
1496
1497static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001498msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1499{
1500 if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
1501 /* Queue/read data, daisy-chain command when data starts */
1502 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
1503 } else {
1504 msmsdcc_start_command(host, mrq->cmd, 0);
1505 }
1506}
1507
1508static void
San Mehat9d2bd732009-09-22 16:44:22 -07001509msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1510{
1511 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001512 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001513
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001514 /*
1515 * Get the SDIO AL client out of LPM.
1516 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001517 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001518 if (host->plat->is_sdio_al_client)
1519 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001520
1521 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001522 WARN(host->curr.mrq, "Request in progress\n");
1523 WARN(!host->pwr, "SDCC power is turned off\n");
1524 WARN(!host->clks_on, "SDCC clocks are turned off\n");
1525 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
San Mehat9d2bd732009-09-22 16:44:22 -07001526
1527 if (host->eject) {
1528 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1529 mrq->cmd->error = 0;
1530 mrq->data->bytes_xfered = mrq->data->blksz *
1531 mrq->data->blocks;
1532 } else
1533 mrq->cmd->error = -ENOMEDIUM;
1534
1535 spin_unlock_irqrestore(&host->lock, flags);
1536 mmc_request_done(mmc, mrq);
1537 return;
1538 }
1539
1540 host->curr.mrq = mrq;
1541
Oluwafemi Adeyemif6c97c82011-08-22 10:53:44 -07001542 if (!host->plat->sdcc_v4_sup) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001543 if (mrq->data && mrq->data->flags == MMC_DATA_WRITE) {
1544 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001545 mrq->cmd->opcode == 54) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001546 host->dummy_52_needed = 1;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001547 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001548 }
San Mehat9d2bd732009-09-22 16:44:22 -07001549 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001550 msmsdcc_request_start(host, mrq);
San Mehat9d2bd732009-09-22 16:44:22 -07001551 spin_unlock_irqrestore(&host->lock, flags);
1552}
1553
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001554static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1555 int min_uV, int max_uV)
1556{
1557 int rc = 0;
1558
1559 if (vreg->set_voltage_sup) {
1560 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1561 if (rc) {
1562 pr_err("%s: regulator_set_voltage(%s) failed."
1563 " min_uV=%d, max_uV=%d, rc=%d\n",
1564 __func__, vreg->name, min_uV, max_uV, rc);
1565 }
1566 }
1567
1568 return rc;
1569}
1570
1571static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1572 int uA_load)
1573{
1574 int rc = 0;
1575
1576 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1577 if (rc < 0)
1578 pr_err("%s: regulator_set_optimum_mode(reg=%s, uA_load=%d)"
1579 " failed. rc=%d\n", __func__, vreg->name,
1580 uA_load, rc);
1581 else
1582 /* regulator_set_optimum_mode() can return non zero value
1583 * even for success case.
1584 */
1585 rc = 0;
1586
1587 return rc;
1588}
1589
1590static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1591 struct device *dev)
1592{
1593 int rc = 0;
1594
1595 /* check if regulator is already initialized? */
1596 if (vreg->reg)
1597 goto out;
1598
1599 /* Get the regulator handle */
1600 vreg->reg = regulator_get(dev, vreg->name);
1601 if (IS_ERR(vreg->reg)) {
1602 rc = PTR_ERR(vreg->reg);
1603 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
1604 __func__, vreg->name, rc);
1605 }
1606out:
1607 return rc;
1608}
1609
1610static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
1611{
1612 if (vreg->reg)
1613 regulator_put(vreg->reg);
1614}
1615
1616/* This init function should be called only once for each SDCC slot */
1617static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
1618{
1619 int rc = 0;
1620 struct msm_mmc_slot_reg_data *curr_slot;
1621 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1622 struct device *dev = mmc_dev(host->mmc);
1623
1624 curr_slot = host->plat->vreg_data;
1625 if (!curr_slot)
1626 goto out;
1627
1628 curr_vdd_reg = curr_slot->vdd_data;
1629 curr_vccq_reg = curr_slot->vccq_data;
1630 curr_vddp_reg = curr_slot->vddp_data;
1631
1632 if (is_init) {
1633 /*
1634 * Get the regulator handle from voltage regulator framework
1635 * and then try to set the voltage level for the regulator
1636 */
1637 if (curr_vdd_reg) {
1638 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
1639 if (rc)
1640 goto out;
1641 }
1642 if (curr_vccq_reg) {
1643 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
1644 if (rc)
1645 goto vdd_reg_deinit;
1646 }
1647 if (curr_vddp_reg) {
1648 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
1649 if (rc)
1650 goto vccq_reg_deinit;
1651 }
1652 goto out;
1653 } else {
1654 /* Deregister all regulators from regulator framework */
1655 goto vddp_reg_deinit;
1656 }
1657vddp_reg_deinit:
1658 if (curr_vddp_reg)
1659 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
1660vccq_reg_deinit:
1661 if (curr_vccq_reg)
1662 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
1663vdd_reg_deinit:
1664 if (curr_vdd_reg)
1665 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
1666out:
1667 return rc;
1668}
1669
1670static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
1671{
1672 int rc = 0;
1673
Subhash Jadavanicc922692011-08-01 23:05:01 +05301674 /* Put regulator in HPM (high power mode) */
1675 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
1676 if (rc < 0)
1677 goto out;
1678
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001679 if (!vreg->is_enabled) {
1680 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301681 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
1682 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001683 if (rc)
1684 goto out;
1685
1686 rc = regulator_enable(vreg->reg);
1687 if (rc) {
1688 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
1689 __func__, vreg->name, rc);
1690 goto out;
1691 }
1692 vreg->is_enabled = true;
1693 }
1694
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001695out:
1696 return rc;
1697}
1698
1699static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
1700{
1701 int rc = 0;
1702
1703 /* Never disable regulator marked as always_on */
1704 if (vreg->is_enabled && !vreg->always_on) {
1705 rc = regulator_disable(vreg->reg);
1706 if (rc) {
1707 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
1708 __func__, vreg->name, rc);
1709 goto out;
1710 }
1711 vreg->is_enabled = false;
1712
1713 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
1714 if (rc < 0)
1715 goto out;
1716
1717 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301718 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001719 if (rc)
1720 goto out;
1721 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
1722 /* Put always_on regulator in LPM (low power mode) */
1723 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
1724 if (rc < 0)
1725 goto out;
1726 }
1727out:
1728 return rc;
1729}
1730
1731static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
1732{
1733 int rc = 0, i;
1734 struct msm_mmc_slot_reg_data *curr_slot;
1735 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1736 struct msm_mmc_reg_data *vreg_table[3];
1737
1738 curr_slot = host->plat->vreg_data;
1739 if (!curr_slot)
1740 goto out;
1741
1742 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
1743 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
1744 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
1745
1746 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
1747 if (vreg_table[i]) {
1748 if (enable)
1749 rc = msmsdcc_vreg_enable(vreg_table[i]);
1750 else
1751 rc = msmsdcc_vreg_disable(vreg_table[i]);
1752 if (rc)
1753 goto out;
1754 }
1755 }
1756out:
1757 return rc;
1758}
1759
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301760static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001761{
1762 int rc = 0;
1763
1764 if (host->plat->vreg_data) {
1765 struct msm_mmc_reg_data *vddp_reg =
1766 host->plat->vreg_data->vddp_data;
1767
1768 if (vddp_reg && vddp_reg->is_enabled)
1769 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
1770 }
1771
1772 return rc;
1773}
1774
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301775static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
1776{
1777 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1778 int rc = 0;
1779
1780 if (curr_slot && curr_slot->vddp_data) {
1781 rc = msmsdcc_set_vddp_level(host,
1782 curr_slot->vddp_data->low_vol_level);
1783
1784 if (rc)
1785 pr_err("%s: %s: failed to change vddp level to %d",
1786 mmc_hostname(host->mmc), __func__,
1787 curr_slot->vddp_data->low_vol_level);
1788 }
1789
1790 return rc;
1791}
1792
1793static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
1794{
1795 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1796 int rc = 0;
1797
1798 if (curr_slot && curr_slot->vddp_data) {
1799 rc = msmsdcc_set_vddp_level(host,
1800 curr_slot->vddp_data->high_vol_level);
1801
1802 if (rc)
1803 pr_err("%s: %s: failed to change vddp level to %d",
1804 mmc_hostname(host->mmc), __func__,
1805 curr_slot->vddp_data->high_vol_level);
1806 }
1807
1808 return rc;
1809}
1810
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001811static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
1812{
1813 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
1814 return 1;
1815 return 0;
1816}
1817
1818static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
1819{
1820 if (enable) {
1821 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1822 clk_enable(host->dfab_pclk);
1823 if (!IS_ERR(host->pclk))
1824 clk_enable(host->pclk);
1825 clk_enable(host->clk);
1826 } else {
1827 clk_disable(host->clk);
1828 if (!IS_ERR(host->pclk))
1829 clk_disable(host->pclk);
1830 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1831 clk_disable(host->dfab_pclk);
1832 }
1833}
1834
1835static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
1836 unsigned int req_clk)
1837{
1838 unsigned int sel_clk = -1;
1839
1840 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
1841 unsigned char cnt;
1842
1843 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
1844 if (host->plat->sup_clk_table[cnt] > req_clk)
1845 break;
1846 else if (host->plat->sup_clk_table[cnt] == req_clk) {
1847 sel_clk = host->plat->sup_clk_table[cnt];
1848 break;
1849 } else
1850 sel_clk = host->plat->sup_clk_table[cnt];
1851 }
1852 } else {
1853 if ((req_clk < host->plat->msmsdcc_fmax) &&
1854 (req_clk > host->plat->msmsdcc_fmid))
1855 sel_clk = host->plat->msmsdcc_fmid;
1856 else
1857 sel_clk = req_clk;
1858 }
1859
1860 return sel_clk;
1861}
1862
1863static inline unsigned int msmsdcc_get_min_sup_clk_rate(
1864 struct msmsdcc_host *host)
1865{
1866 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
1867 return host->plat->sup_clk_table[0];
1868 else
1869 return host->plat->msmsdcc_fmin;
1870}
1871
1872static inline unsigned int msmsdcc_get_max_sup_clk_rate(
1873 struct msmsdcc_host *host)
1874{
1875 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
1876 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
1877 else
1878 return host->plat->msmsdcc_fmax;
1879}
1880
1881static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05301882{
1883 struct msm_mmc_gpio_data *curr;
1884 int i, rc = 0;
1885
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001886 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301887 for (i = 0; i < curr->size; i++) {
1888 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001889 if (curr->gpio[i].is_always_on &&
1890 curr->gpio[i].is_enabled)
1891 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301892 rc = gpio_request(curr->gpio[i].no,
1893 curr->gpio[i].name);
1894 if (rc) {
1895 pr_err("%s: gpio_request(%d, %s) failed %d\n",
1896 mmc_hostname(host->mmc),
1897 curr->gpio[i].no,
1898 curr->gpio[i].name, rc);
1899 goto free_gpios;
1900 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001901 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301902 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001903 if (curr->gpio[i].is_always_on)
1904 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301905 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001906 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301907 }
1908 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001909 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301910
1911free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001912 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05301913 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001914 curr->gpio[i].is_enabled = false;
1915 }
1916out:
1917 return rc;
1918}
1919
1920static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
1921{
1922 struct msm_mmc_pad_data *curr;
1923 int i;
1924
1925 curr = host->plat->pin_data->pad_data;
1926 for (i = 0; i < curr->drv->size; i++) {
1927 if (enable)
1928 msm_tlmm_set_hdrive(curr->drv->on[i].no,
1929 curr->drv->on[i].val);
1930 else
1931 msm_tlmm_set_hdrive(curr->drv->off[i].no,
1932 curr->drv->off[i].val);
1933 }
1934
1935 for (i = 0; i < curr->pull->size; i++) {
1936 if (enable)
1937 msm_tlmm_set_hdrive(curr->pull->on[i].no,
1938 curr->pull->on[i].val);
1939 else
1940 msm_tlmm_set_hdrive(curr->pull->off[i].no,
1941 curr->pull->off[i].val);
1942 }
1943
1944 return 0;
1945}
1946
1947static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
1948{
1949 int rc = 0;
1950
1951 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
1952 return 0;
1953
1954 if (host->plat->pin_data->is_gpio)
1955 rc = msmsdcc_setup_gpio(host, enable);
1956 else
1957 rc = msmsdcc_setup_pad(host, enable);
1958
1959 if (!rc)
1960 host->plat->pin_data->cfg_sts = enable;
1961
1962 return rc;
1963}
1964
1965static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
1966{
1967 unsigned int wakeup_irq;
1968
1969 wakeup_irq = (host->plat->sdiowakeup_irq) ?
1970 host->plat->sdiowakeup_irq :
1971 host->core_irqres->start;
1972
1973 if (!host->irq_wake_enabled) {
1974 enable_irq_wake(wakeup_irq);
1975 host->irq_wake_enabled = true;
1976 }
1977}
1978
1979static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
1980{
1981 unsigned int wakeup_irq;
1982
1983 wakeup_irq = (host->plat->sdiowakeup_irq) ?
1984 host->plat->sdiowakeup_irq :
1985 host->core_irqres->start;
1986
1987 if (host->irq_wake_enabled) {
1988 disable_irq_wake(wakeup_irq);
1989 host->irq_wake_enabled = false;
1990 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05301991}
1992
San Mehat9d2bd732009-09-22 16:44:22 -07001993static void
1994msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
1995{
1996 struct msmsdcc_host *host = mmc_priv(mmc);
1997 u32 clk = 0, pwr = 0;
1998 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08001999 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002000 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002001
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002002 DBG(host, "ios->clock = %u\n", ios->clock);
Sahitya Tummala7a892482011-01-18 11:22:49 +05302003
San Mehat9d2bd732009-09-22 16:44:22 -07002004 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002005 spin_lock_irqsave(&host->lock, flags);
2006 if (!host->clks_on) {
2007 msmsdcc_setup_clocks(host, true);
2008 host->clks_on = 1;
2009 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2010 if (!host->plat->sdiowakeup_irq) {
2011 writel_relaxed(host->mci_irqenable,
2012 host->base + MMCIMASK0);
2013 mb();
2014 if (host->plat->cfg_mpm_sdiowakeup &&
2015 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2016 host->plat->cfg_mpm_sdiowakeup(
2017 mmc_dev(mmc), SDC_DAT1_DISWAKE);
2018 msmsdcc_disable_irq_wake(host);
2019 } else if (!(mmc->pm_flags &
2020 MMC_PM_WAKE_SDIO_IRQ)) {
2021 writel_relaxed(host->mci_irqenable,
2022 host->base + MMCIMASK0);
2023 }
2024 }
San Mehat9d2bd732009-09-22 16:44:22 -07002025 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002026 spin_unlock_irqrestore(&host->lock, flags);
2027
2028 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2029 /*
2030 * For DDR50 mode, controller needs clock rate to be
2031 * double than what is required on the SD card CLK pin.
2032 */
Subhash Jadavanib808efac2011-06-27 15:14:07 -07002033 if (ios->ddr || (ios->timing == MMC_TIMING_UHS_DDR50)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002034 /*
2035 * Make sure that we don't double the clock if
2036 * doubled clock rate is already set
2037 */
2038 if (!host->ddr_doubled_clk_rate ||
2039 (host->ddr_doubled_clk_rate &&
2040 (host->ddr_doubled_clk_rate != ios->clock))) {
2041 host->ddr_doubled_clk_rate =
2042 msmsdcc_get_sup_clk_rate(
2043 host, (ios->clock * 2));
2044 clock = host->ddr_doubled_clk_rate;
2045 }
2046 } else {
2047 host->ddr_doubled_clk_rate = 0;
2048 }
2049
2050 if (clock != host->clk_rate) {
2051 rc = clk_set_rate(host->clk, clock);
2052 if (rc < 0)
2053 pr_debug("%s: failed to set clk rate %u\n",
2054 mmc_hostname(mmc), clock);
2055 host->clk_rate = clock;
2056 }
2057 /*
2058 * give atleast 2 MCLK cycles delay for clocks
2059 * and SDCC core to stabilize
2060 */
2061 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002062 clk |= MCI_CLK_ENABLE;
2063 }
2064
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002065 if (ios->bus_width == MMC_BUS_WIDTH_8)
2066 clk |= MCI_CLK_WIDEBUS_8;
2067 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2068 clk |= MCI_CLK_WIDEBUS_4;
2069 else
2070 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002071
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002072 if (msmsdcc_is_pwrsave(host))
2073 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002074
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002075 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002076
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002077 host->tuning_needed = 0;
2078 /*
2079 * Select the controller timing mode according
2080 * to current bus speed mode
2081 */
2082 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2083 (ios->timing == MMC_TIMING_UHS_SDR50)) {
2084 clk |= (4 << 14);
2085 host->tuning_needed = 1;
Subhash Jadavanib808efac2011-06-27 15:14:07 -07002086 } else if (ios->ddr || ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002087 clk |= (3 << 14);
2088 } else {
2089 clk |= (2 << 14); /* feedback clock */
2090 }
2091
2092 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2093 clk |= (2 << 23);
2094
2095 if (host->io_pad_pwr_switch)
2096 clk |= IO_PAD_PWR_SWITCH;
2097
2098 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
San Mehat9d2bd732009-09-22 16:44:22 -07002099 pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002100 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2101 pwr |= msmsdcc_setup_vreg(host, !!ios->vdd);
San Mehat9d2bd732009-09-22 16:44:22 -07002102
2103 switch (ios->power_mode) {
2104 case MMC_POWER_OFF:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002105 htc_pwrsink_set(PWRSINK_SDCARD, 0);
2106 if (!host->sdcc_irq_disabled) {
2107 if (host->plat->cfg_mpm_sdiowakeup)
2108 host->plat->cfg_mpm_sdiowakeup(
2109 mmc_dev(mmc), SDC_DAT1_DISABLE);
2110 disable_irq(host->core_irqres->start);
2111 host->sdcc_irq_disabled = 1;
2112 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302113 /*
2114 * As VDD pad rail is always on, set low voltage for VDD
2115 * pad rail when slot is unused (when card is not present
2116 * or during system suspend).
2117 */
2118 msmsdcc_set_vddp_low_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002119 msmsdcc_setup_pins(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002120 break;
2121 case MMC_POWER_UP:
2122 pwr |= MCI_PWR_UP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002123 if (host->sdcc_irq_disabled) {
2124 if (host->plat->cfg_mpm_sdiowakeup)
2125 host->plat->cfg_mpm_sdiowakeup(
2126 mmc_dev(mmc), SDC_DAT1_ENABLE);
2127 enable_irq(host->core_irqres->start);
2128 host->sdcc_irq_disabled = 0;
2129 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302130 msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002131 msmsdcc_setup_pins(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07002132 break;
2133 case MMC_POWER_ON:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002134 htc_pwrsink_set(PWRSINK_SDCARD, 100);
San Mehat9d2bd732009-09-22 16:44:22 -07002135 pwr |= MCI_PWR_ON;
2136 break;
2137 }
2138
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002139 spin_lock_irqsave(&host->lock, flags);
2140 if (!host->clks_on) {
2141 /* force the clocks to be on */
2142 msmsdcc_setup_clocks(host, true);
2143 /*
2144 * give atleast 2 MCLK cycles delay for clocks
2145 * and SDCC core to stabilize
2146 */
2147 msmsdcc_delay(host);
2148 }
2149 writel_relaxed(clk, host->base + MMCICLOCK);
2150 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002151
2152 if (host->pwr != pwr) {
2153 host->pwr = pwr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002154 writel_relaxed(pwr, host->base + MMCIPOWER);
2155 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07002156 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002157 if (!host->clks_on) {
2158 /* force the clocks to be off */
2159 msmsdcc_setup_clocks(host, false);
2160 /*
2161 * give atleast 2 MCLK cycles delay for clocks
2162 * and SDCC core to stabilize
2163 */
2164 msmsdcc_delay(host);
2165 }
2166
2167 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
2168 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2169 if (!host->plat->sdiowakeup_irq) {
2170 writel_relaxed(MCI_SDIOINTMASK,
2171 host->base + MMCIMASK0);
2172 mb();
2173 if (host->plat->cfg_mpm_sdiowakeup &&
2174 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2175 host->plat->cfg_mpm_sdiowakeup(
2176 mmc_dev(mmc), SDC_DAT1_ENWAKE);
2177 msmsdcc_enable_irq_wake(host);
2178 } else if (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2179 writel_relaxed(0, host->base + MMCIMASK0);
2180 } else {
2181 writel_relaxed(MCI_SDIOINTMASK,
2182 host->base + MMCIMASK0);
2183 }
2184 msmsdcc_delay(host);
2185 }
2186 msmsdcc_setup_clocks(host, false);
2187 host->clks_on = 0;
2188 }
San Mehat4adbbcc2009-11-08 13:00:37 -08002189 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002190}
2191
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002192int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2193{
2194 struct msmsdcc_host *host = mmc_priv(mmc);
2195 u32 clk;
2196
2197 clk = readl_relaxed(host->base + MMCICLOCK);
2198 pr_debug("Changing to pwr_save=%d", pwrsave);
2199 if (pwrsave && msmsdcc_is_pwrsave(host))
2200 clk |= MCI_CLK_PWRSAVE;
2201 else
2202 clk &= ~MCI_CLK_PWRSAVE;
2203 writel_relaxed(clk, host->base + MMCICLOCK);
2204 mb();
2205
2206 return 0;
2207}
2208
2209static int msmsdcc_get_ro(struct mmc_host *mmc)
2210{
2211 int status = -ENOSYS;
2212 struct msmsdcc_host *host = mmc_priv(mmc);
2213
2214 if (host->plat->wpswitch) {
2215 status = host->plat->wpswitch(mmc_dev(mmc));
2216 } else if (host->plat->wpswitch_gpio) {
2217 status = gpio_request(host->plat->wpswitch_gpio,
2218 "SD_WP_Switch");
2219 if (status) {
2220 pr_err("%s: %s: Failed to request GPIO %d\n",
2221 mmc_hostname(mmc), __func__,
2222 host->plat->wpswitch_gpio);
2223 } else {
2224 status = gpio_direction_input(
2225 host->plat->wpswitch_gpio);
2226 if (!status) {
2227 /*
2228 * Wait for atleast 300ms as debounce
2229 * time for GPIO input to stabilize.
2230 */
2231 msleep(300);
2232 status = gpio_get_value_cansleep(
2233 host->plat->wpswitch_gpio);
2234 status ^= !host->plat->wpswitch_polarity;
2235 }
2236 gpio_free(host->plat->wpswitch_gpio);
2237 }
2238 }
2239
2240 if (status < 0)
2241 status = -ENOSYS;
2242 pr_debug("%s: Card read-only status %d\n", __func__, status);
2243
2244 return status;
2245}
2246
2247#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002248static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2249{
2250 struct msmsdcc_host *host = mmc_priv(mmc);
2251 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002252
2253 if (enable) {
2254 spin_lock_irqsave(&host->lock, flags);
2255 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
2256 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
2257 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2258 spin_unlock_irqrestore(&host->lock, flags);
2259 } else {
2260 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
2261 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
2262 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2263 }
2264 mb();
2265}
2266#endif /* CONFIG_MMC_MSM_SDIO_SUPPORT */
2267
2268#ifdef CONFIG_PM_RUNTIME
2269static int msmsdcc_enable(struct mmc_host *mmc)
2270{
Sahitya Tummala8605fca2011-08-22 15:39:19 +05302271 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002272 struct device *dev = mmc->parent;
2273
Sahitya Tummala8605fca2011-08-22 15:39:19 +05302274 if (pm_runtime_suspended(dev))
2275 rc = pm_runtime_get_sync(dev);
2276 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002277 pm_runtime_get_noresume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002278
Sahitya Tummala8605fca2011-08-22 15:39:19 +05302279 if (rc < 0)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002280 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2281 __func__, rc);
Sahitya Tummala8605fca2011-08-22 15:39:19 +05302282 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002283}
2284
2285static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2286{
2287 int rc;
2288
2289 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO)
2290 return -ENOTSUPP;
2291
2292 rc = pm_runtime_put_sync(mmc->parent);
2293
2294 if (rc < 0)
2295 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2296 __func__, rc);
2297 return rc;
2298}
2299#else
2300#define msmsdcc_enable NULL
2301#define msmsdcc_disable NULL
2302#endif
2303
2304static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2305 struct mmc_ios *ios)
2306{
2307 struct msmsdcc_host *host = mmc_priv(mmc);
2308 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302309 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002310
2311 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2312 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302313 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002314 goto out;
2315 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2316 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302317 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002318 goto out;
2319 }
San Mehat9d2bd732009-09-22 16:44:22 -07002320
2321 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002322 /*
2323 * If we are here means voltage switch from high voltage to
2324 * low voltage is required
2325 */
2326
2327 /*
2328 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2329 * register until they become all zeros.
2330 */
2331 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302332 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002333 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2334 mmc_hostname(mmc), __func__);
2335 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002336 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002337
2338 /* Stop SD CLK output. */
2339 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2340 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2341
San Mehat9d2bd732009-09-22 16:44:22 -07002342 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002343
2344 /*
2345 * Switch VDDPX from high voltage to low voltage
2346 * to change the VDD of the SD IO pads.
2347 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302348 rc = msmsdcc_set_vddp_low_vol(host);
2349 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002350 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002351
2352 spin_lock_irqsave(&host->lock, flags);
2353 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2354 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
2355 host->io_pad_pwr_switch = 1;
2356 spin_unlock_irqrestore(&host->lock, flags);
2357
2358 /* Wait 5 ms for the voltage regulater in the card to become stable. */
2359 usleep_range(5000, 5500);
2360
2361 spin_lock_irqsave(&host->lock, flags);
2362 /* Start SD CLK output. */
2363 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2364 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2365 spin_unlock_irqrestore(&host->lock, flags);
2366
2367 /*
2368 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
2369 * don't become all ones within 1 ms then a Voltage Switch
2370 * sequence has failed and a power cycle to the card is required.
2371 * Otherwise Voltage Switch sequence is completed successfully.
2372 */
2373 usleep_range(1000, 1500);
2374
2375 spin_lock_irqsave(&host->lock, flags);
2376 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
2377 != (0xF << 1)) {
2378 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
2379 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302380 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002381 goto out_unlock;
2382 }
2383
2384out_unlock:
2385 spin_unlock_irqrestore(&host->lock, flags);
2386out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302387 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002388}
2389
2390static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2391 u8 phase);
2392/* Initialize the DLL (Programmable Delay Line ) */
2393static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
2394{
2395 int rc = 0;
2396 u32 wait_timeout;
2397
2398 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
2399 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2400 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2401
2402 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
2403 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2404 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2405
2406 msmsdcc_delay(host);
2407
2408 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
2409 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2410 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2411
2412 /* Initialize the phase to 0 */
2413 rc = msmsdcc_config_cm_sdc4_dll_phase(host, 0);
2414 if (rc)
2415 goto out;
2416
2417 wait_timeout = 1000;
2418 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
2419 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
2420 /* max. wait for 1 sec for LOCK bit to be set */
2421 if (--wait_timeout == 0) {
2422 pr_err("%s: %s: DLL failed to lock at phase: %d",
2423 mmc_hostname(host->mmc), __func__, 0);
2424 rc = -1;
2425 goto out;
2426 }
2427 /* wait for 1ms */
2428 usleep_range(1000, 1500);
2429 }
2430out:
2431 return rc;
2432}
2433
2434/*
2435 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
2436 * calibration sequence. This function should be called before
2437 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
2438 * commands (CMD17/CMD18).
2439 */
2440static void msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
2441{
2442 /* Set CDR_EN bit to 1. */
2443 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) |
2444 MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2445
2446 /* Set CDR_EXT_EN bit to 0. */
2447 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2448 & ~MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2449
2450 /* Set CK_OUT_EN bit to 0. */
2451 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2452 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2453
2454 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2455 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)
2456 ;
2457
2458 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2459 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2460 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2461
2462 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register is 1. */
2463 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN))
2464 ;
2465}
2466
2467static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2468 u8 phase)
2469{
2470 int rc = 0;
2471 u32 mclk_freq = 0;
2472 u32 wait_timeout;
2473
2474 /* Set CDR_EN bit to 0. */
2475 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2476 & ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2477
2478 /* Set CDR_EXT_EN bit to 1. */
2479 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2480 | MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2481
2482 /* Program the MCLK value to MCLK_FREQ bit field */
2483 if (host->clk_rate <= 112000000)
2484 mclk_freq = 0;
2485 else if (host->clk_rate <= 125000000)
2486 mclk_freq = 1;
2487 else if (host->clk_rate <= 137000000)
2488 mclk_freq = 2;
2489 else if (host->clk_rate <= 150000000)
2490 mclk_freq = 3;
2491 else if (host->clk_rate <= 162000000)
2492 mclk_freq = 4;
2493 else if (host->clk_rate <= 175000000)
2494 mclk_freq = 5;
2495 else if (host->clk_rate <= 187000000)
2496 mclk_freq = 6;
2497 else if (host->clk_rate <= 200000000)
2498 mclk_freq = 7;
2499
2500 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2501 & ~(7 << 24)) | (mclk_freq << 24)),
2502 host->base + MCI_DLL_CONFIG);
2503
2504 /* Set CK_OUT_EN bit to 0. */
2505 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2506 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2507
2508 /* Set DLL_EN bit to 1. */
2509 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2510 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
2511
2512 wait_timeout = 1000;
2513 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2514 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN) {
2515 /* max. wait for 1 sec for LOCK bit for be set */
2516 if (--wait_timeout == 0) {
2517 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 0",
2518 mmc_hostname(host->mmc), __func__, phase);
2519 rc = -1;
2520 goto out;
2521 }
2522 /* wait for 1ms */
2523 usleep_range(1000, 1500);
2524 }
2525
2526 /*
2527 * Write the selected DLL clock output phase (0 ... 15)
2528 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
2529 */
2530 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2531 & ~(0xF << 20)) | (phase << 20)),
2532 host->base + MCI_DLL_CONFIG);
2533
2534 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2535 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2536 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2537
2538 wait_timeout = 1000;
2539 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
2540 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)) {
2541 /* max. wait for 1 sec for LOCK bit for be set */
2542 if (--wait_timeout == 0) {
2543 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 1",
2544 mmc_hostname(host->mmc), __func__, phase);
2545 rc = -1;
2546 goto out;
2547 }
2548 /* wait for 1ms */
2549 usleep_range(1000, 1500);
2550 }
2551out:
2552 return rc;
2553}
2554
2555static int msmsdcc_execute_tuning(struct mmc_host *mmc)
2556{
2557 struct msmsdcc_host *host = mmc_priv(mmc);
2558 u8 phase;
2559 u8 *data_buf;
2560 u8 tuned_phases[16], tuned_phase_cnt = 0;
2561 int rc = 0;
2562
2563 /* Tuning is only required for SDR50 & SDR104 modes */
2564 if (!host->tuning_needed) {
2565 rc = 0;
2566 goto out;
2567 }
2568
2569 host->cmd19_tuning_in_progress = 1;
2570 /*
2571 * Make sure that clock is always enabled when DLL
2572 * tuning is in progress. Keeping PWRSAVE ON may
2573 * turn off the clock. So let's disable the PWRSAVE
2574 * here and re-enable it once tuning is completed.
2575 */
2576 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2577 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2578 /* first of all reset the tuning block */
2579 rc = msmsdcc_init_cm_sdc4_dll(host);
2580 if (rc)
2581 goto out;
2582
2583 data_buf = kmalloc(64, GFP_KERNEL);
2584 if (!data_buf) {
2585 rc = -ENOMEM;
2586 goto out;
2587 }
2588
2589 phase = 0;
2590 do {
2591 struct mmc_command cmd = {0};
2592 struct mmc_data data = {0};
2593 struct mmc_request mrq = {
2594 .cmd = &cmd,
2595 .data = &data
2596 };
2597 struct scatterlist sg;
2598
2599 /* set the phase in delay line hw block */
2600 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2601 if (rc)
2602 goto kfree;
2603
2604 cmd.opcode = MMC_SEND_TUNING_BLOCK;
2605 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
2606
2607 data.blksz = 64;
2608 data.blocks = 1;
2609 data.flags = MMC_DATA_READ;
2610 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
2611
2612 data.sg = &sg;
2613 data.sg_len = 1;
2614 sg_init_one(&sg, data_buf, 64);
2615 memset(data_buf, 0, 64);
2616 mmc_wait_for_req(mmc, &mrq);
2617
2618 if (!cmd.error && !data.error &&
2619 !memcmp(data_buf, cmd19_tuning_block, 64)) {
2620 /* tuning is successful with this tuning point */
2621 tuned_phases[tuned_phase_cnt++] = phase;
2622 }
2623 } while (++phase < 16);
2624
2625 kfree(data_buf);
2626
2627 if (tuned_phase_cnt) {
2628 tuned_phase_cnt--;
2629 tuned_phase_cnt = (tuned_phase_cnt * 3) / 4;
2630 phase = tuned_phases[tuned_phase_cnt];
2631 /*
2632 * Finally set the selected phase in delay
2633 * line hw block.
2634 */
2635 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2636 if (rc)
2637 goto out;
2638 } else {
2639 /* tuning failed */
2640 rc = -EAGAIN;
2641 pr_err("%s: %s: no tuning point found",
2642 mmc_hostname(mmc), __func__);
2643 }
2644 goto out;
2645
2646kfree:
2647 kfree(data_buf);
2648out:
2649 /* re-enable PWESAVE */
2650 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2651 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2652 host->cmd19_tuning_in_progress = 0;
2653 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07002654}
2655
2656static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002657 .enable = msmsdcc_enable,
2658 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07002659 .request = msmsdcc_request,
2660 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002661 .get_ro = msmsdcc_get_ro,
2662#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002663 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002664#endif
2665 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
2666 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07002667};
2668
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002669static unsigned int
2670msmsdcc_slot_status(struct msmsdcc_host *host)
2671{
2672 int status;
2673 unsigned int gpio_no = host->plat->status_gpio;
2674
2675 status = gpio_request(gpio_no, "SD_HW_Detect");
2676 if (status) {
2677 pr_err("%s: %s: Failed to request GPIO %d\n",
2678 mmc_hostname(host->mmc), __func__, gpio_no);
2679 } else {
2680 status = gpio_direction_input(gpio_no);
2681 if (!status)
2682 status = !gpio_get_value_cansleep(gpio_no);
2683 gpio_free(gpio_no);
2684 }
2685 return status;
2686}
2687
San Mehat9d2bd732009-09-22 16:44:22 -07002688static void
2689msmsdcc_check_status(unsigned long data)
2690{
2691 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
2692 unsigned int status;
2693
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002694 if (host->plat->status || host->plat->status_gpio) {
2695 if (host->plat->status)
2696 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07002697 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002698 status = msmsdcc_slot_status(host);
2699
2700 host->eject = !status;
2701 if (status ^ host->oldstat) {
2702 pr_info("%s: Slot status change detected (%d -> %d)\n",
2703 mmc_hostname(host->mmc), host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07002704 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002705 }
2706 host->oldstat = status;
2707 } else {
2708 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07002709 }
San Mehat9d2bd732009-09-22 16:44:22 -07002710}
2711
2712static irqreturn_t
2713msmsdcc_platform_status_irq(int irq, void *dev_id)
2714{
2715 struct msmsdcc_host *host = dev_id;
2716
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002717 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07002718 msmsdcc_check_status((unsigned long) host);
2719 return IRQ_HANDLED;
2720}
2721
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002722static irqreturn_t
2723msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
2724{
2725 struct msmsdcc_host *host = dev_id;
2726
2727 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
2728 spin_lock(&host->lock);
2729 if (!host->sdio_irq_disabled) {
2730 disable_irq_nosync(irq);
2731 if (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2732 wake_lock(&host->sdio_wlock);
2733 msmsdcc_disable_irq_wake(host);
2734 }
2735 host->sdio_irq_disabled = 1;
2736 }
2737 if (host->plat->is_sdio_al_client) {
2738 if (!host->clks_on) {
2739 msmsdcc_setup_clocks(host, true);
2740 host->clks_on = 1;
2741 }
2742 if (host->sdcc_irq_disabled) {
2743 writel_relaxed(host->mci_irqenable,
2744 host->base + MMCIMASK0);
2745 mb();
2746 enable_irq(host->core_irqres->start);
2747 host->sdcc_irq_disabled = 0;
2748 }
2749 wake_lock(&host->sdio_wlock);
2750 }
2751 spin_unlock(&host->lock);
2752
2753 return IRQ_HANDLED;
2754}
2755
San Mehat9d2bd732009-09-22 16:44:22 -07002756static void
2757msmsdcc_status_notify_cb(int card_present, void *dev_id)
2758{
2759 struct msmsdcc_host *host = dev_id;
2760
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002761 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07002762 card_present);
2763 msmsdcc_check_status((unsigned long) host);
2764}
2765
San Mehat9d2bd732009-09-22 16:44:22 -07002766static int
2767msmsdcc_init_dma(struct msmsdcc_host *host)
2768{
2769 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
2770 host->dma.host = host;
2771 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07002772 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07002773
2774 if (!host->dmares)
2775 return -ENODEV;
2776
2777 host->dma.nc = dma_alloc_coherent(NULL,
2778 sizeof(struct msmsdcc_nc_dmadata),
2779 &host->dma.nc_busaddr,
2780 GFP_KERNEL);
2781 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07002782 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07002783 return -ENOMEM;
2784 }
2785 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
2786 host->dma.cmd_busaddr = host->dma.nc_busaddr;
2787 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
2788 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
2789 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07002790 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07002791
2792 return 0;
2793}
2794
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002795#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
2796/**
2797 * Allocate and Connect a SDCC peripheral's SPS endpoint
2798 *
2799 * This function allocates endpoint context and
2800 * connect it with memory endpoint by calling
2801 * appropriate SPS driver APIs.
2802 *
2803 * Also registers a SPS callback function with
2804 * SPS driver
2805 *
2806 * This function should only be called once typically
2807 * during driver probe.
2808 *
2809 * @host - Pointer to sdcc host structure
2810 * @ep - Pointer to sps endpoint data structure
2811 * @is_produce - 1 means Producer endpoint
2812 * 0 means Consumer endpoint
2813 *
2814 * @return - 0 if successful else negative value.
2815 *
2816 */
2817static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
2818 struct msmsdcc_sps_ep_conn_data *ep,
2819 bool is_producer)
2820{
2821 int rc = 0;
2822 struct sps_pipe *sps_pipe_handle;
2823 struct sps_connect *sps_config = &ep->config;
2824 struct sps_register_event *sps_event = &ep->event;
2825
2826 /* Allocate endpoint context */
2827 sps_pipe_handle = sps_alloc_endpoint();
2828 if (!sps_pipe_handle) {
2829 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
2830 mmc_hostname(host->mmc), is_producer);
2831 rc = -ENOMEM;
2832 goto out;
2833 }
2834
2835 /* Get default connection configuration for an endpoint */
2836 rc = sps_get_config(sps_pipe_handle, sps_config);
2837 if (rc) {
2838 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
2839 " rc=%d", mmc_hostname(host->mmc),
2840 (u32)sps_pipe_handle, rc);
2841 goto get_config_err;
2842 }
2843
2844 /* Modify the default connection configuration */
2845 if (is_producer) {
2846 /*
2847 * For SDCC producer transfer, source should be
2848 * SDCC peripheral where as destination should
2849 * be system memory.
2850 */
2851 sps_config->source = host->sps.bam_handle;
2852 sps_config->destination = SPS_DEV_HANDLE_MEM;
2853 /* Producer pipe will handle this connection */
2854 sps_config->mode = SPS_MODE_SRC;
2855 sps_config->options =
2856 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
2857 } else {
2858 /*
2859 * For SDCC consumer transfer, source should be
2860 * system memory where as destination should
2861 * SDCC peripheral
2862 */
2863 sps_config->source = SPS_DEV_HANDLE_MEM;
2864 sps_config->destination = host->sps.bam_handle;
2865 sps_config->mode = SPS_MODE_DEST;
2866 sps_config->options =
2867 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
2868 }
2869
2870 /* Producer pipe index */
2871 sps_config->src_pipe_index = host->sps.src_pipe_index;
2872 /* Consumer pipe index */
2873 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
2874 /*
2875 * This event thresold value is only significant for BAM-to-BAM
2876 * transfer. It's ignored for BAM-to-System mode transfer.
2877 */
2878 sps_config->event_thresh = 0x10;
2879 /*
2880 * Max. no of scatter/gather buffers that can
2881 * be passed by block layer = 32 (NR_SG).
2882 * Each BAM descritor needs 64 bits (8 bytes).
2883 * One BAM descriptor is required per buffer transfer.
2884 * So we would require total 256 (32 * 8) bytes of descriptor FIFO.
2885 * But due to HW limitation we need to allocate atleast one extra
2886 * descriptor memory (256 bytes + 8 bytes). But in order to be
2887 * in power of 2, we are allocating 512 bytes of memory.
2888 */
2889 sps_config->desc.size = 512;
2890 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
2891 sps_config->desc.size,
2892 &sps_config->desc.phys_base,
2893 GFP_KERNEL);
2894
2895 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
2896
2897 /* Establish connection between peripheral and memory endpoint */
2898 rc = sps_connect(sps_pipe_handle, sps_config);
2899 if (rc) {
2900 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
2901 " rc=%d", mmc_hostname(host->mmc),
2902 (u32)sps_pipe_handle, rc);
2903 goto sps_connect_err;
2904 }
2905
2906 sps_event->mode = SPS_TRIGGER_CALLBACK;
2907 sps_event->options = SPS_O_EOT;
2908 sps_event->callback = msmsdcc_sps_complete_cb;
2909 sps_event->xfer_done = NULL;
2910 sps_event->user = (void *)host;
2911
2912 /* Register callback event for EOT (End of transfer) event. */
2913 rc = sps_register_event(sps_pipe_handle, sps_event);
2914 if (rc) {
2915 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
2916 " rc=%d", mmc_hostname(host->mmc),
2917 (u32)sps_pipe_handle, rc);
2918 goto reg_event_err;
2919 }
2920 /* Now save the sps pipe handle */
2921 ep->pipe_handle = sps_pipe_handle;
2922 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
2923 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
2924 __func__, is_producer ? "READ" : "WRITE",
2925 (u32)sps_pipe_handle, sps_config->desc.phys_base);
2926 goto out;
2927
2928reg_event_err:
2929 sps_disconnect(sps_pipe_handle);
2930sps_connect_err:
2931 dma_free_coherent(mmc_dev(host->mmc),
2932 sps_config->desc.size,
2933 sps_config->desc.base,
2934 sps_config->desc.phys_base);
2935get_config_err:
2936 sps_free_endpoint(sps_pipe_handle);
2937out:
2938 return rc;
2939}
2940
2941/**
2942 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
2943 *
2944 * This function disconnect endpoint and deallocates
2945 * endpoint context.
2946 *
2947 * This function should only be called once typically
2948 * during driver remove.
2949 *
2950 * @host - Pointer to sdcc host structure
2951 * @ep - Pointer to sps endpoint data structure
2952 *
2953 */
2954static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
2955 struct msmsdcc_sps_ep_conn_data *ep)
2956{
2957 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
2958 struct sps_connect *sps_config = &ep->config;
2959 struct sps_register_event *sps_event = &ep->event;
2960
2961 sps_event->xfer_done = NULL;
2962 sps_event->callback = NULL;
2963 sps_register_event(sps_pipe_handle, sps_event);
2964 sps_disconnect(sps_pipe_handle);
2965 dma_free_coherent(mmc_dev(host->mmc),
2966 sps_config->desc.size,
2967 sps_config->desc.base,
2968 sps_config->desc.phys_base);
2969 sps_free_endpoint(sps_pipe_handle);
2970}
2971
2972/**
2973 * Reset SDCC peripheral's SPS endpoint
2974 *
2975 * This function disconnects an endpoint.
2976 *
2977 * This function should be called for reseting
2978 * SPS endpoint when data transfer error is
2979 * encountered during data transfer. This
2980 * can be considered as soft reset to endpoint.
2981 *
2982 * This function should only be called if
2983 * msmsdcc_sps_init() is already called.
2984 *
2985 * @host - Pointer to sdcc host structure
2986 * @ep - Pointer to sps endpoint data structure
2987 *
2988 * @return - 0 if successful else negative value.
2989 */
2990static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
2991 struct msmsdcc_sps_ep_conn_data *ep)
2992{
2993 int rc = 0;
2994 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
2995
2996 rc = sps_disconnect(sps_pipe_handle);
2997 if (rc) {
2998 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
2999 " rc=%d", mmc_hostname(host->mmc), __func__,
3000 (u32)sps_pipe_handle, rc);
3001 goto out;
3002 }
3003 out:
3004 return rc;
3005}
3006
3007/**
3008 * Restore SDCC peripheral's SPS endpoint
3009 *
3010 * This function connects an endpoint.
3011 *
3012 * This function should be called for restoring
3013 * SPS endpoint after data transfer error is
3014 * encountered during data transfer. This
3015 * can be considered as soft reset to endpoint.
3016 *
3017 * This function should only be called if
3018 * msmsdcc_sps_reset_ep() is called before.
3019 *
3020 * @host - Pointer to sdcc host structure
3021 * @ep - Pointer to sps endpoint data structure
3022 *
3023 * @return - 0 if successful else negative value.
3024 */
3025static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3026 struct msmsdcc_sps_ep_conn_data *ep)
3027{
3028 int rc = 0;
3029 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3030 struct sps_connect *sps_config = &ep->config;
3031 struct sps_register_event *sps_event = &ep->event;
3032
3033 /* Establish connection between peripheral and memory endpoint */
3034 rc = sps_connect(sps_pipe_handle, sps_config);
3035 if (rc) {
3036 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3037 " rc=%d", mmc_hostname(host->mmc), __func__,
3038 (u32)sps_pipe_handle, rc);
3039 goto out;
3040 }
3041
3042 /* Register callback event for EOT (End of transfer) event. */
3043 rc = sps_register_event(sps_pipe_handle, sps_event);
3044 if (rc) {
3045 pr_err("%s: %s: sps_register_event() failed!!!"
3046 " pipe_handle=0x%x, rc=%d",
3047 mmc_hostname(host->mmc), __func__,
3048 (u32)sps_pipe_handle, rc);
3049 goto reg_event_err;
3050 }
3051 goto out;
3052
3053reg_event_err:
3054 sps_disconnect(sps_pipe_handle);
3055out:
3056 return rc;
3057}
3058
3059/**
3060 * Initialize SPS HW connected with SDCC core
3061 *
3062 * This function register BAM HW resources with
3063 * SPS driver and then initialize 2 SPS endpoints
3064 *
3065 * This function should only be called once typically
3066 * during driver probe.
3067 *
3068 * @host - Pointer to sdcc host structure
3069 *
3070 * @return - 0 if successful else negative value.
3071 *
3072 */
3073static int msmsdcc_sps_init(struct msmsdcc_host *host)
3074{
3075 int rc = 0;
3076 struct sps_bam_props bam = {0};
3077
3078 host->bam_base = ioremap(host->bam_memres->start,
3079 resource_size(host->bam_memres));
3080 if (!host->bam_base) {
3081 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3082 " size=0x%x", mmc_hostname(host->mmc),
3083 host->bam_memres->start,
3084 (host->bam_memres->end -
3085 host->bam_memres->start));
3086 rc = -ENOMEM;
3087 goto out;
3088 }
3089
3090 bam.phys_addr = host->bam_memres->start;
3091 bam.virt_addr = host->bam_base;
3092 /*
3093 * This event thresold value is only significant for BAM-to-BAM
3094 * transfer. It's ignored for BAM-to-System mode transfer.
3095 */
3096 bam.event_threshold = 0x10; /* Pipe event threshold */
3097 /*
3098 * This threshold controls when the BAM publish
3099 * the descriptor size on the sideband interface.
3100 * SPS HW will only be used when
3101 * data transfer size > MCI_FIFOSIZE (64 bytes).
3102 * PIO mode will be used when
3103 * data transfer size < MCI_FIFOSIZE (64 bytes).
3104 * So set this thresold value to 64 bytes.
3105 */
3106 bam.summing_threshold = 64;
3107 /* SPS driver wll handle the SDCC BAM IRQ */
3108 bam.irq = (u32)host->bam_irqres->start;
3109 bam.manage = SPS_BAM_MGR_LOCAL;
3110
3111 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3112 (u32)bam.phys_addr);
3113 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3114 (u32)bam.virt_addr);
3115
3116 /* Register SDCC Peripheral BAM device to SPS driver */
3117 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3118 if (rc) {
3119 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3120 mmc_hostname(host->mmc), rc);
3121 goto reg_bam_err;
3122 }
3123 pr_info("%s: BAM device registered. bam_handle=0x%x",
3124 mmc_hostname(host->mmc), host->sps.bam_handle);
3125
3126 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3127 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3128
3129 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3130 SPS_PROD_PERIPHERAL);
3131 if (rc)
3132 goto sps_reset_err;
3133 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3134 SPS_CONS_PERIPHERAL);
3135 if (rc)
3136 goto cons_conn_err;
3137
3138 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3139 mmc_hostname(host->mmc),
3140 (unsigned long long)host->bam_memres->start,
3141 (unsigned int)host->bam_irqres->start);
3142 goto out;
3143
3144cons_conn_err:
3145 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3146sps_reset_err:
3147 sps_deregister_bam_device(host->sps.bam_handle);
3148reg_bam_err:
3149 iounmap(host->bam_base);
3150out:
3151 return rc;
3152}
3153
3154/**
3155 * De-initialize SPS HW connected with SDCC core
3156 *
3157 * This function deinitialize SPS endpoints and then
3158 * deregisters BAM resources from SPS driver.
3159 *
3160 * This function should only be called once typically
3161 * during driver remove.
3162 *
3163 * @host - Pointer to sdcc host structure
3164 *
3165 */
3166static void msmsdcc_sps_exit(struct msmsdcc_host *host)
3167{
3168 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
3169 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3170 sps_deregister_bam_device(host->sps.bam_handle);
3171 iounmap(host->bam_base);
3172}
3173#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
3174
3175static ssize_t
3176show_polling(struct device *dev, struct device_attribute *attr, char *buf)
3177{
3178 struct mmc_host *mmc = dev_get_drvdata(dev);
3179 struct msmsdcc_host *host = mmc_priv(mmc);
3180 int poll;
3181 unsigned long flags;
3182
3183 spin_lock_irqsave(&host->lock, flags);
3184 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
3185 spin_unlock_irqrestore(&host->lock, flags);
3186
3187 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
3188}
3189
3190static ssize_t
3191set_polling(struct device *dev, struct device_attribute *attr,
3192 const char *buf, size_t count)
3193{
3194 struct mmc_host *mmc = dev_get_drvdata(dev);
3195 struct msmsdcc_host *host = mmc_priv(mmc);
3196 int value;
3197 unsigned long flags;
3198
3199 sscanf(buf, "%d", &value);
3200
3201 spin_lock_irqsave(&host->lock, flags);
3202 if (value) {
3203 mmc->caps |= MMC_CAP_NEEDS_POLL;
3204 mmc_detect_change(host->mmc, 0);
3205 } else {
3206 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3207 }
3208#ifdef CONFIG_HAS_EARLYSUSPEND
3209 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
3210#endif
3211 spin_unlock_irqrestore(&host->lock, flags);
3212 return count;
3213}
3214
3215static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
3216 show_polling, set_polling);
3217static struct attribute *dev_attrs[] = {
3218 &dev_attr_polling.attr,
3219 NULL,
3220};
3221static struct attribute_group dev_attr_grp = {
3222 .attrs = dev_attrs,
3223};
3224
3225#ifdef CONFIG_HAS_EARLYSUSPEND
3226static void msmsdcc_early_suspend(struct early_suspend *h)
3227{
3228 struct msmsdcc_host *host =
3229 container_of(h, struct msmsdcc_host, early_suspend);
3230 unsigned long flags;
3231
3232 spin_lock_irqsave(&host->lock, flags);
3233 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
3234 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3235 spin_unlock_irqrestore(&host->lock, flags);
3236};
3237static void msmsdcc_late_resume(struct early_suspend *h)
3238{
3239 struct msmsdcc_host *host =
3240 container_of(h, struct msmsdcc_host, early_suspend);
3241 unsigned long flags;
3242
3243 if (host->polling_enabled) {
3244 spin_lock_irqsave(&host->lock, flags);
3245 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
3246 mmc_detect_change(host->mmc, 0);
3247 spin_unlock_irqrestore(&host->lock, flags);
3248 }
3249};
3250#endif
3251
3252static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
3253{
3254 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3255 struct mmc_request *mrq;
3256 unsigned long flags;
3257
3258 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003259 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003260 pr_info("%s: %s: dummy CMD52 timeout\n",
3261 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003262 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003263 }
3264
3265 mrq = host->curr.mrq;
3266
3267 if (mrq && mrq->cmd) {
3268 pr_info("%s: %s CMD%d\n", mmc_hostname(host->mmc),
3269 __func__, mrq->cmd->opcode);
3270 if (!mrq->cmd->error)
3271 mrq->cmd->error = -ETIMEDOUT;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003272 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003273 host->dummy_52_needed = 0;
3274 if (host->curr.data) {
3275 pr_info("%s: %s Request timeout\n",
3276 mmc_hostname(host->mmc), __func__);
3277 if (mrq->data && !mrq->data->error)
3278 mrq->data->error = -ETIMEDOUT;
3279 host->curr.data_xfered = 0;
3280 if (host->dma.sg && host->is_dma_mode) {
3281 msm_dmov_stop_cmd(host->dma.channel,
3282 &host->dma.hdr, 0);
3283 } else if (host->sps.sg && host->is_sps_mode) {
3284 /* Stop current SPS transfer */
3285 msmsdcc_sps_exit_curr_xfer(host);
3286 } else {
3287 msmsdcc_reset_and_restore(host);
3288 msmsdcc_stop_data(host);
3289 if (mrq->data && mrq->data->stop)
3290 msmsdcc_start_command(host,
3291 mrq->data->stop, 0);
3292 else
3293 msmsdcc_request_end(host, mrq);
3294 }
3295 } else {
3296 if (host->prog_enable) {
3297 host->prog_scan = 0;
3298 host->prog_enable = 0;
3299 }
3300 msmsdcc_reset_and_restore(host);
3301 msmsdcc_request_end(host, mrq);
3302 }
3303 }
3304 spin_unlock_irqrestore(&host->lock, flags);
3305}
3306
San Mehat9d2bd732009-09-22 16:44:22 -07003307static int
3308msmsdcc_probe(struct platform_device *pdev)
3309{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003310 struct mmc_platform_data *plat = pdev->dev.platform_data;
San Mehat9d2bd732009-09-22 16:44:22 -07003311 struct msmsdcc_host *host;
3312 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003313 unsigned long flags;
3314 struct resource *core_irqres = NULL;
3315 struct resource *bam_irqres = NULL;
3316 struct resource *core_memres = NULL;
3317 struct resource *dml_memres = NULL;
3318 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07003319 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07003320 struct resource *dma_crci_res = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07003321 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003322 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07003323
3324 /* must have platform data */
3325 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003326 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003327 ret = -EINVAL;
3328 goto out;
3329 }
3330
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003331 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07003332 return -EINVAL;
3333
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003334 if (plat->is_sdio_al_client)
3335 if (!plat->sdio_lpm_gpio_setup || !plat->sdiowakeup_irq)
3336 return -EINVAL;
3337
San Mehat9d2bd732009-09-22 16:44:22 -07003338 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003339 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003340 return -ENXIO;
3341 }
3342
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003343 for (i = 0; i < pdev->num_resources; i++) {
3344 if (pdev->resource[i].flags & IORESOURCE_MEM) {
3345 if (!strcmp(pdev->resource[i].name,
3346 "sdcc_dml_addr"))
3347 dml_memres = &pdev->resource[i];
3348 else if (!strcmp(pdev->resource[i].name,
3349 "sdcc_bam_addr"))
3350 bam_memres = &pdev->resource[i];
3351 else
3352 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07003353
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003354 }
3355 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
3356 if (!strcmp(pdev->resource[i].name,
3357 "sdcc_bam_irq"))
3358 bam_irqres = &pdev->resource[i];
3359 else
3360 core_irqres = &pdev->resource[i];
3361 }
Krishna Konda25786ec2011-07-25 16:21:36 -07003362 if (pdev->resource[i].flags & IORESOURCE_DMA) {
3363 if (!strncmp(pdev->resource[i].name,
3364 "sdcc_dma_chnl",
3365 sizeof("sdcc_dma_chnl")))
3366 dmares = &pdev->resource[i];
3367 else if (!strncmp(pdev->resource[i].name,
3368 "sdcc_dma_crci",
3369 sizeof("sdcc_dma_crci")))
3370 dma_crci_res = &pdev->resource[i];
3371 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003372 }
3373
3374 if (!core_irqres || !core_memres) {
3375 pr_err("%s: Invalid sdcc core resource\n", __func__);
3376 return -ENXIO;
3377 }
3378
3379 /*
3380 * Both BAM and DML memory resource should be preset.
3381 * BAM IRQ resource should also be present.
3382 */
3383 if ((bam_memres && !dml_memres) ||
3384 (!bam_memres && dml_memres) ||
3385 ((bam_memres && dml_memres) && !bam_irqres)) {
3386 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003387 return -ENXIO;
3388 }
3389
3390 /*
3391 * Setup our host structure
3392 */
San Mehat9d2bd732009-09-22 16:44:22 -07003393 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
3394 if (!mmc) {
3395 ret = -ENOMEM;
3396 goto out;
3397 }
3398
3399 host = mmc_priv(mmc);
3400 host->pdev_id = pdev->id;
3401 host->plat = plat;
3402 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08003403 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05303404
3405 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003406 host->is_sps_mode = 1;
3407 else if (dmares)
3408 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07003409
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003410 host->base = ioremap(core_memres->start,
3411 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07003412 if (!host->base) {
3413 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003414 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003415 }
3416
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003417 host->core_irqres = core_irqres;
3418 host->bam_irqres = bam_irqres;
3419 host->core_memres = core_memres;
3420 host->dml_memres = dml_memres;
3421 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07003422 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07003423 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07003424 spin_lock_init(&host->lock);
3425
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003426#ifdef CONFIG_MMC_EMBEDDED_SDIO
3427 if (plat->embedded_sdio)
3428 mmc_set_embedded_sdio_data(mmc,
3429 &plat->embedded_sdio->cis,
3430 &plat->embedded_sdio->cccr,
3431 plat->embedded_sdio->funcs,
3432 plat->embedded_sdio->num_funcs);
3433#endif
3434
Sahitya Tummala62612cf2010-12-08 15:03:03 +05303435 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
3436 (unsigned long)host);
3437
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003438 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
3439 (unsigned long)host);
3440 if (host->is_dma_mode) {
3441 /* Setup DMA */
3442 ret = msmsdcc_init_dma(host);
3443 if (ret)
3444 goto ioremap_free;
3445 } else {
3446 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003447 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003448 }
3449
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003450 /*
3451 * Setup SDCC clock if derived from Dayatona
3452 * fabric core clock.
3453 */
3454 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07003455 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003456 if (!IS_ERR(host->dfab_pclk)) {
3457 /* Set the clock rate to 64MHz for max. performance */
3458 ret = clk_set_rate(host->dfab_pclk, 64000000);
3459 if (ret)
3460 goto dfab_pclk_put;
3461 ret = clk_enable(host->dfab_pclk);
3462 if (ret)
3463 goto dfab_pclk_put;
3464 } else
3465 goto dma_free;
3466 }
3467
3468 /*
3469 * Setup main peripheral bus clock
3470 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003471 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003472 if (!IS_ERR(host->pclk)) {
3473 ret = clk_enable(host->pclk);
3474 if (ret)
3475 goto pclk_put;
3476
3477 host->pclk_rate = clk_get_rate(host->pclk);
3478 }
3479
3480 /*
3481 * Setup SDC MMC clock
3482 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003483 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07003484 if (IS_ERR(host->clk)) {
3485 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003486 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07003487 }
3488
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003489 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
3490 if (ret) {
3491 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
3492 goto clk_put;
3493 }
3494
3495 ret = clk_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003496 if (ret)
3497 goto clk_put;
3498
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003499 host->clk_rate = clk_get_rate(host->clk);
3500
3501 host->clks_on = 1;
3502
3503 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07003504 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003505 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07003506 goto clk_disable;
3507 }
3508
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003509
3510 /* Clocks has to be running before accessing SPS/DML HW blocks */
3511 if (host->is_sps_mode) {
3512 /* Initialize SPS */
3513 ret = msmsdcc_sps_init(host);
3514 if (ret)
3515 goto vreg_deinit;
3516 /* Initialize DML */
3517 ret = msmsdcc_dml_init(host);
3518 if (ret)
3519 goto sps_exit;
3520 }
San Mehat9d2bd732009-09-22 16:44:22 -07003521
San Mehat9d2bd732009-09-22 16:44:22 -07003522 /*
3523 * Setup MMC host structure
3524 */
3525 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003526 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
3527 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003528 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003529 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
3530 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07003531
San Mehat9d2bd732009-09-22 16:44:22 -07003532 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003533 mmc->caps |= plat->uhs_caps;
3534 /*
3535 * XPC controls the maximum current in the default speed mode of SDXC
3536 * card. XPC=0 means 100mA (max.) but speed class is not supported.
3537 * XPC=1 means 150mA (max.) and speed class is supported.
3538 */
3539 if (plat->xpc_cap)
3540 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
3541 MMC_CAP_SET_XPC_180);
3542
3543 if (plat->nonremovable)
3544 mmc->caps |= MMC_CAP_NONREMOVABLE;
3545#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
3546 mmc->caps |= MMC_CAP_SDIO_IRQ;
3547#endif
3548
3549 if (plat->is_sdio_al_client)
3550 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07003551
Martin K. Petersena36274e2010-09-10 01:33:59 -04003552 mmc->max_segs = NR_SG;
San Mehat9d2bd732009-09-22 16:44:22 -07003553 mmc->max_blk_size = 4096; /* MCI_DATA_CTL BLOCKSIZE up to 4096 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003554 mmc->max_blk_count = 65535;
San Mehat9d2bd732009-09-22 16:44:22 -07003555
3556 mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */
3557 mmc->max_seg_size = mmc->max_req_size;
3558
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003559 writel_relaxed(0, host->base + MMCIMASK0);
3560 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -07003561
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003562 /* Delay needed (MMCIMASK0 was just written above) */
3563 msmsdcc_delay(host);
3564 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
3565 mb();
3566 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07003567
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003568 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
3569 DRIVER_NAME " (cmd)", host);
3570 if (ret)
3571 goto dml_exit;
3572
3573 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
3574 DRIVER_NAME " (pio)", host);
3575 if (ret)
3576 goto irq_free;
3577
3578 /*
3579 * Enable SDCC IRQ only when host is powered on. Otherwise, this
3580 * IRQ is un-necessarily being monitored by MPM (Modem power
3581 * management block) during idle-power collapse. The MPM will be
3582 * configured to monitor the DATA1 GPIO line with level-low trigger
3583 * and thus depending on the GPIO status, it prevents TCXO shutdown
3584 * during idle-power collapse.
3585 */
3586 disable_irq(core_irqres->start);
3587 host->sdcc_irq_disabled = 1;
3588
3589 if (plat->sdiowakeup_irq) {
3590 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3591 mmc_hostname(mmc));
3592 ret = request_irq(plat->sdiowakeup_irq,
3593 msmsdcc_platform_sdiowakeup_irq,
3594 IRQF_SHARED | IRQF_TRIGGER_LOW,
3595 DRIVER_NAME "sdiowakeup", host);
3596 if (ret) {
3597 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
3598 plat->sdiowakeup_irq, ret);
3599 goto pio_irq_free;
3600 } else {
3601 spin_lock_irqsave(&host->lock, flags);
3602 if (!host->sdio_irq_disabled) {
3603 disable_irq_nosync(plat->sdiowakeup_irq);
3604 host->sdio_irq_disabled = 1;
3605 }
3606 spin_unlock_irqrestore(&host->lock, flags);
3607 }
3608 }
3609
3610 if (plat->cfg_mpm_sdiowakeup) {
3611 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3612 mmc_hostname(mmc));
3613 }
3614
3615 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
3616 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003617 /*
3618 * Setup card detect change
3619 */
3620
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003621 if (plat->status || plat->status_gpio) {
3622 if (plat->status)
3623 host->oldstat = plat->status(mmc_dev(host->mmc));
3624 else
3625 host->oldstat = msmsdcc_slot_status(host);
3626 host->eject = !host->oldstat;
3627 }
San Mehat9d2bd732009-09-22 16:44:22 -07003628
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003629 if (plat->status_irq) {
3630 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07003631 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003632 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07003633 DRIVER_NAME " (slot)",
3634 host);
3635 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003636 pr_err("Unable to get slot IRQ %d (%d)\n",
3637 plat->status_irq, ret);
3638 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003639 }
3640 } else if (plat->register_status_notify) {
3641 plat->register_status_notify(msmsdcc_status_notify_cb, host);
3642 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003643 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07003644 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003645
3646 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003647
3648 ret = pm_runtime_set_active(&(pdev)->dev);
3649 if (ret < 0)
3650 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3651 __func__, ret);
3652 /*
3653 * There is no notion of suspend/resume for SD/MMC/SDIO
3654 * cards. So host can be suspended/resumed with out
3655 * worrying about its children.
3656 */
3657 pm_suspend_ignore_children(&(pdev)->dev, true);
3658
3659 /*
3660 * MMC/SD/SDIO bus suspend/resume operations are defined
3661 * only for the slots that will be used for non-removable
3662 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
3663 * defined. Otherwise, they simply become card removal and
3664 * insertion events during suspend and resume respectively.
3665 * Hence, enable run-time PM only for slots for which bus
3666 * suspend/resume operations are defined.
3667 */
3668#ifdef CONFIG_MMC_UNSAFE_RESUME
3669 /*
3670 * If this capability is set, MMC core will enable/disable host
3671 * for every claim/release operation on a host. We use this
3672 * notification to increment/decrement runtime pm usage count.
3673 */
3674 mmc->caps |= MMC_CAP_DISABLE;
3675 pm_runtime_enable(&(pdev)->dev);
3676#else
3677 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
3678 mmc->caps |= MMC_CAP_DISABLE;
3679 pm_runtime_enable(&(pdev)->dev);
3680 }
3681#endif
3682 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
3683 (unsigned long)host);
3684
San Mehat9d2bd732009-09-22 16:44:22 -07003685 mmc_add_host(mmc);
3686
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003687#ifdef CONFIG_HAS_EARLYSUSPEND
3688 host->early_suspend.suspend = msmsdcc_early_suspend;
3689 host->early_suspend.resume = msmsdcc_late_resume;
3690 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
3691 register_early_suspend(&host->early_suspend);
3692#endif
San Mehat9d2bd732009-09-22 16:44:22 -07003693
Krishna Konda25786ec2011-07-25 16:21:36 -07003694 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
3695 " dmacrcri %d\n", mmc_hostname(mmc),
3696 (unsigned long long)core_memres->start,
3697 (unsigned int) core_irqres->start,
3698 (unsigned int) plat->status_irq, host->dma.channel,
3699 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003700
3701 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
3702 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
3703 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
3704 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
3705 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
3706 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
3707 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
3708 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
3709 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
3710 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
3711 host->eject);
3712 pr_info("%s: Power save feature enable = %d\n",
3713 mmc_hostname(mmc), msmsdcc_pwrsave);
3714
Krishna Konda25786ec2011-07-25 16:21:36 -07003715 if (host->is_dma_mode && host->dma.channel != -1
3716 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003717 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003718 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003719 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003720 mmc_hostname(mmc), host->dma.cmd_busaddr,
3721 host->dma.cmdptr_busaddr);
3722 } else if (host->is_sps_mode) {
3723 pr_info("%s: SPS-BAM data transfer mode available\n",
3724 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003725 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003726 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003727
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003728#if defined(CONFIG_DEBUG_FS)
3729 msmsdcc_dbg_createhost(host);
3730#endif
3731 if (!plat->status_irq) {
3732 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
3733 if (ret)
3734 goto platform_irq_free;
3735 }
San Mehat9d2bd732009-09-22 16:44:22 -07003736 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003737
3738 platform_irq_free:
3739 del_timer_sync(&host->req_tout_timer);
3740 pm_runtime_disable(&(pdev)->dev);
3741 pm_runtime_set_suspended(&(pdev)->dev);
3742
3743 if (plat->status_irq)
3744 free_irq(plat->status_irq, host);
3745 sdiowakeup_irq_free:
3746 wake_lock_destroy(&host->sdio_suspend_wlock);
3747 if (plat->sdiowakeup_irq)
3748 free_irq(plat->sdiowakeup_irq, host);
3749 pio_irq_free:
3750 if (plat->sdiowakeup_irq)
3751 wake_lock_destroy(&host->sdio_wlock);
3752 free_irq(core_irqres->start, host);
3753 irq_free:
3754 free_irq(core_irqres->start, host);
3755 dml_exit:
3756 if (host->is_sps_mode)
3757 msmsdcc_dml_exit(host);
3758 sps_exit:
3759 if (host->is_sps_mode)
3760 msmsdcc_sps_exit(host);
3761 vreg_deinit:
3762 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07003763 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003764 clk_disable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003765 clk_put:
3766 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003767 pclk_disable:
3768 if (!IS_ERR(host->pclk))
3769 clk_disable(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07003770 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003771 if (!IS_ERR(host->pclk))
3772 clk_put(host->pclk);
3773 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3774 clk_disable(host->dfab_pclk);
3775 dfab_pclk_put:
3776 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3777 clk_put(host->dfab_pclk);
3778 dma_free:
3779 if (host->is_dma_mode) {
3780 if (host->dmares)
3781 dma_free_coherent(NULL,
3782 sizeof(struct msmsdcc_nc_dmadata),
3783 host->dma.nc, host->dma.nc_busaddr);
3784 }
3785 ioremap_free:
3786 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07003787 host_free:
3788 mmc_free_host(mmc);
3789 out:
3790 return ret;
3791}
3792
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003793static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07003794{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003795 struct mmc_host *mmc = mmc_get_drvdata(pdev);
3796 struct mmc_platform_data *plat;
3797 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07003798
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003799 if (!mmc)
3800 return -ENXIO;
3801
3802 if (pm_runtime_suspended(&(pdev)->dev))
3803 pm_runtime_resume(&(pdev)->dev);
3804
3805 host = mmc_priv(mmc);
3806
3807 DBG(host, "Removing SDCC device = %d\n", pdev->id);
3808 plat = host->plat;
3809
3810 if (!plat->status_irq)
3811 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
3812
3813 del_timer_sync(&host->req_tout_timer);
3814 tasklet_kill(&host->dma_tlet);
3815 tasklet_kill(&host->sps.tlet);
3816 mmc_remove_host(mmc);
3817
3818 if (plat->status_irq)
3819 free_irq(plat->status_irq, host);
3820
3821 wake_lock_destroy(&host->sdio_suspend_wlock);
3822 if (plat->sdiowakeup_irq) {
3823 wake_lock_destroy(&host->sdio_wlock);
3824 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
3825 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07003826 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003827
3828 free_irq(host->core_irqres->start, host);
3829 free_irq(host->core_irqres->start, host);
3830
3831 clk_put(host->clk);
3832 if (!IS_ERR(host->pclk))
3833 clk_put(host->pclk);
3834 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3835 clk_put(host->dfab_pclk);
3836
3837 msmsdcc_vreg_init(host, false);
3838
3839 if (host->is_dma_mode) {
3840 if (host->dmares)
3841 dma_free_coherent(NULL,
3842 sizeof(struct msmsdcc_nc_dmadata),
3843 host->dma.nc, host->dma.nc_busaddr);
3844 }
3845
3846 if (host->is_sps_mode) {
3847 msmsdcc_dml_exit(host);
3848 msmsdcc_sps_exit(host);
3849 }
3850
3851 iounmap(host->base);
3852 mmc_free_host(mmc);
3853
3854#ifdef CONFIG_HAS_EARLYSUSPEND
3855 unregister_early_suspend(&host->early_suspend);
3856#endif
3857 pm_runtime_disable(&(pdev)->dev);
3858 pm_runtime_set_suspended(&(pdev)->dev);
3859
3860 return 0;
3861}
3862
3863#ifdef CONFIG_MSM_SDIO_AL
3864int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
3865{
3866 struct msmsdcc_host *host = mmc_priv(mmc);
3867 unsigned long flags;
3868
3869 spin_lock_irqsave(&host->lock, flags);
3870 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
3871 enable ? "En" : "Dis");
3872
3873 if (enable) {
3874 if (!host->sdcc_irq_disabled) {
3875 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05303876 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003877 host->sdcc_irq_disabled = 1;
3878 }
3879
3880 if (host->clks_on) {
3881 msmsdcc_setup_clocks(host, false);
3882 host->clks_on = 0;
3883 }
3884
3885 if (!host->sdio_gpio_lpm) {
3886 spin_unlock_irqrestore(&host->lock, flags);
3887 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
3888 spin_lock_irqsave(&host->lock, flags);
3889 host->sdio_gpio_lpm = 1;
3890 }
3891
3892 if (host->sdio_irq_disabled) {
3893 msmsdcc_enable_irq_wake(host);
3894 enable_irq(host->plat->sdiowakeup_irq);
3895 host->sdio_irq_disabled = 0;
3896 }
3897 } else {
3898 if (!host->sdio_irq_disabled) {
3899 disable_irq_nosync(host->plat->sdiowakeup_irq);
3900 host->sdio_irq_disabled = 1;
3901 msmsdcc_disable_irq_wake(host);
3902 }
3903
3904 if (host->sdio_gpio_lpm) {
3905 spin_unlock_irqrestore(&host->lock, flags);
3906 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
3907 spin_lock_irqsave(&host->lock, flags);
3908 host->sdio_gpio_lpm = 0;
3909 }
3910
3911 if (!host->clks_on) {
3912 msmsdcc_setup_clocks(host, true);
3913 host->clks_on = 1;
3914 }
3915
3916 if (host->sdcc_irq_disabled) {
3917 writel_relaxed(host->mci_irqenable,
3918 host->base + MMCIMASK0);
3919 mb();
3920 enable_irq(host->core_irqres->start);
3921 host->sdcc_irq_disabled = 0;
3922 }
3923 wake_lock_timeout(&host->sdio_wlock, 1);
3924 }
3925 spin_unlock_irqrestore(&host->lock, flags);
3926 return 0;
3927}
3928#else
3929int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
3930{
3931 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07003932}
3933#endif
3934
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003935#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07003936static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003937msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07003938{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003939 struct mmc_host *mmc = dev_get_drvdata(dev);
3940 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07003941 int rc = 0;
3942
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003943 if (host->plat->is_sdio_al_client)
3944 return 0;
3945
Sahitya Tummala7661a452011-07-18 13:28:35 +05303946 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003947 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003948 host->sdcc_suspending = 1;
3949 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07003950
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003951 /*
3952 * If the clocks are already turned off by SDIO clients (as
3953 * part of LPM), then clocks should be turned on before
3954 * calling mmc_suspend_host() because mmc_suspend_host might
3955 * send some commands to the card. The clocks will be turned
3956 * off again after mmc_suspend_host. Thus for SD/MMC/SDIO
3957 * cards, clocks will be turned on before mmc_suspend_host
3958 * and turned off after mmc_suspend_host.
3959 */
3960 mmc->ios.clock = host->clk_rate;
3961 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07003962
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003963 /*
3964 * MMC core thinks that host is disabled by now since
3965 * runtime suspend is scheduled after msmsdcc_disable()
3966 * is called. Thus, MMC core will try to enable the host
3967 * while suspending it. This results in a synchronous
3968 * runtime resume request while in runtime suspending
3969 * context and hence inorder to complete this resume
3970 * requet, it will wait for suspend to be complete,
3971 * but runtime suspend also can not proceed further
3972 * until the host is resumed. Thus, it leads to a hang.
3973 * Hence, increase the pm usage count before suspending
3974 * the host so that any resume requests after this will
3975 * simple become pm usage counter increment operations.
3976 */
3977 pm_runtime_get_noresume(dev);
3978 rc = mmc_suspend_host(mmc);
3979 pm_runtime_put_noidle(dev);
3980
3981 if (!rc) {
3982 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
3983 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ)) {
3984 disable_irq(host->core_irqres->start);
3985 host->sdcc_irq_disabled = 1;
3986
3987 /*
3988 * If MMC core level suspend is not supported,
3989 * turn off clocks to allow deep sleep (TCXO
3990 * shutdown).
3991 */
3992 mmc->ios.clock = 0;
3993 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
3994 enable_irq(host->core_irqres->start);
3995 host->sdcc_irq_disabled = 0;
3996
3997 if (host->plat->sdiowakeup_irq) {
3998 host->sdio_irq_disabled = 0;
3999 msmsdcc_enable_irq_wake(host);
4000 enable_irq(host->plat->sdiowakeup_irq);
4001 }
4002 }
4003 }
4004 host->sdcc_suspending = 0;
4005 mmc->suspend_task = NULL;
4006 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
4007 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004008 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304009 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004010 return rc;
4011}
4012
4013static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004014msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004015{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004016 struct mmc_host *mmc = dev_get_drvdata(dev);
4017 struct msmsdcc_host *host = mmc_priv(mmc);
4018 unsigned long flags;
4019
4020 if (host->plat->is_sdio_al_client)
4021 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07004022
Sahitya Tummala7661a452011-07-18 13:28:35 +05304023 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004024 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004025 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
4026 if (host->sdcc_irq_disabled) {
4027 enable_irq(host->core_irqres->start);
4028 host->sdcc_irq_disabled = 0;
4029 }
4030 }
4031 mmc->ios.clock = host->clk_rate;
4032 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07004033
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004034 spin_lock_irqsave(&host->lock, flags);
4035 writel_relaxed(host->mci_irqenable, host->base + MMCIMASK0);
4036 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07004037
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004038 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
4039 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) &&
4040 !host->sdio_irq_disabled) {
4041 if (host->plat->sdiowakeup_irq) {
4042 disable_irq_nosync(
4043 host->plat->sdiowakeup_irq);
4044 msmsdcc_disable_irq_wake(host);
4045 host->sdio_irq_disabled = 1;
4046 }
4047 }
San Mehat9d2bd732009-09-22 16:44:22 -07004048
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004049 spin_unlock_irqrestore(&host->lock, flags);
4050
4051 mmc_resume_host(mmc);
4052
4053 /*
4054 * FIXME: Clearing of flags must be handled in clients
4055 * resume handler.
4056 */
4057 spin_lock_irqsave(&host->lock, flags);
4058 mmc->pm_flags = 0;
4059 spin_unlock_irqrestore(&host->lock, flags);
4060
4061 /*
4062 * After resuming the host wait for sometime so that
4063 * the SDIO work will be processed.
4064 */
4065 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO)) {
4066 if ((host->plat->cfg_mpm_sdiowakeup ||
4067 host->plat->sdiowakeup_irq) &&
4068 wake_lock_active(&host->sdio_wlock))
4069 wake_lock_timeout(&host->sdio_wlock, 1);
4070 }
4071
4072 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004073 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304074 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004075 return 0;
4076}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004077
4078static int msmsdcc_runtime_idle(struct device *dev)
4079{
4080 struct mmc_host *mmc = dev_get_drvdata(dev);
4081 struct msmsdcc_host *host = mmc_priv(mmc);
4082
4083 if (host->plat->is_sdio_al_client)
4084 return 0;
4085
4086 /* Idle timeout is not configurable for now */
4087 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
4088
4089 return -EAGAIN;
4090}
4091
4092static int msmsdcc_pm_suspend(struct device *dev)
4093{
4094 struct mmc_host *mmc = dev_get_drvdata(dev);
4095 struct msmsdcc_host *host = mmc_priv(mmc);
4096 int rc = 0;
4097
4098 if (host->plat->is_sdio_al_client)
4099 return 0;
4100
4101
4102 if (host->plat->status_irq)
4103 disable_irq(host->plat->status_irq);
4104
4105 if (!pm_runtime_suspended(dev))
4106 rc = msmsdcc_runtime_suspend(dev);
4107
4108 return rc;
4109}
4110
4111static int msmsdcc_pm_resume(struct device *dev)
4112{
4113 struct mmc_host *mmc = dev_get_drvdata(dev);
4114 struct msmsdcc_host *host = mmc_priv(mmc);
4115 int rc = 0;
4116
4117 if (host->plat->is_sdio_al_client)
4118 return 0;
4119
4120 rc = msmsdcc_runtime_resume(dev);
4121 if (host->plat->status_irq) {
4122 msmsdcc_check_status((unsigned long)host);
4123 enable_irq(host->plat->status_irq);
4124 }
4125
4126 /* Update the run-time PM status */
4127 pm_runtime_disable(dev);
4128 rc = pm_runtime_set_active(dev);
4129 if (rc < 0)
4130 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
4131 __func__, rc);
4132 pm_runtime_enable(dev);
4133
4134 return rc;
4135}
4136
Daniel Walker08ecfde2010-06-23 12:32:20 -07004137#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004138#define msmsdcc_runtime_suspend NULL
4139#define msmsdcc_runtime_resume NULL
4140#define msmsdcc_runtime_idle NULL
4141#define msmsdcc_pm_suspend NULL
4142#define msmsdcc_pm_resume NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07004143#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004144
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004145static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
4146 .runtime_suspend = msmsdcc_runtime_suspend,
4147 .runtime_resume = msmsdcc_runtime_resume,
4148 .runtime_idle = msmsdcc_runtime_idle,
4149 .suspend = msmsdcc_pm_suspend,
4150 .resume = msmsdcc_pm_resume,
4151};
4152
San Mehat9d2bd732009-09-22 16:44:22 -07004153static struct platform_driver msmsdcc_driver = {
4154 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004155 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07004156 .driver = {
4157 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004158 .pm = &msmsdcc_dev_pm_ops,
San Mehat9d2bd732009-09-22 16:44:22 -07004159 },
4160};
4161
4162static int __init msmsdcc_init(void)
4163{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004164#if defined(CONFIG_DEBUG_FS)
4165 int ret = 0;
4166 ret = msmsdcc_dbg_init();
4167 if (ret) {
4168 pr_err("Failed to create debug fs dir \n");
4169 return ret;
4170 }
4171#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004172 return platform_driver_register(&msmsdcc_driver);
4173}
4174
4175static void __exit msmsdcc_exit(void)
4176{
4177 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004178
4179#if defined(CONFIG_DEBUG_FS)
4180 debugfs_remove(debugfs_file);
4181 debugfs_remove(debugfs_dir);
4182#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004183}
4184
4185module_init(msmsdcc_init);
4186module_exit(msmsdcc_exit);
4187
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004188MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07004189MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004190
4191#if defined(CONFIG_DEBUG_FS)
4192
4193static int
4194msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
4195{
4196 file->private_data = inode->i_private;
4197 return 0;
4198}
4199
4200static ssize_t
4201msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
4202 size_t count, loff_t *ppos)
4203{
4204 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
4205 char buf[1024];
4206 int max, i;
4207
4208 i = 0;
4209 max = sizeof(buf) - 1;
4210
4211 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
4212 host->curr.cmd, host->curr.data);
4213 if (host->curr.cmd) {
4214 struct mmc_command *cmd = host->curr.cmd;
4215
4216 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
4217 cmd->opcode, cmd->arg, cmd->flags);
4218 }
4219 if (host->curr.data) {
4220 struct mmc_data *data = host->curr.data;
4221 i += scnprintf(buf + i, max - i,
4222 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
4223 data->timeout_ns, data->timeout_clks,
4224 data->blksz, data->blocks, data->error,
4225 data->flags);
4226 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
4227 host->curr.xfer_size, host->curr.xfer_remain,
4228 host->curr.data_xfered, host->dma.sg);
4229 }
4230
4231 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
4232}
4233
4234static const struct file_operations msmsdcc_dbg_state_ops = {
4235 .read = msmsdcc_dbg_state_read,
4236 .open = msmsdcc_dbg_state_open,
4237};
4238
4239static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
4240{
4241 if (debugfs_dir) {
4242 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
4243 0644, debugfs_dir, host,
4244 &msmsdcc_dbg_state_ops);
4245 }
4246}
4247
4248static int __init msmsdcc_dbg_init(void)
4249{
4250 int err;
4251
4252 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
4253 if (IS_ERR(debugfs_dir)) {
4254 err = PTR_ERR(debugfs_dir);
4255 debugfs_dir = NULL;
4256 return err;
4257 }
4258
4259 return 0;
4260}
4261#endif