blob: 274b5b16827d291eee4f595f7619abfd182fe695 [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);
312static inline void msmsdcc_delay(struct msmsdcc_host *host)
313{
314 mb();
315 udelay(1 + ((3 * USEC_PER_SEC) /
316 (host->clk_rate ? host->clk_rate :
317 msmsdcc_get_min_sup_clk_rate(host))));
San Mehat9d2bd732009-09-22 16:44:22 -0700318}
319
San Mehat56a8b5b2009-11-21 12:29:46 -0800320static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700321msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
322{
323 writel_relaxed(arg, host->base + MMCIARGUMENT);
324 msmsdcc_delay(host);
325 writel_relaxed(c, host->base + MMCICOMMAND);
326 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800327}
328
329static void
330msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
331{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700332 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800333
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700334 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
335 writel_relaxed((unsigned int)host->curr.xfer_size,
336 host->base + MMCIDATALENGTH);
337 msmsdcc_delay(host); /* Allow data parms to be applied */
338 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
339 msmsdcc_delay(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800340
San Mehat6ac9ea62009-12-02 17:24:58 -0800341 if (host->cmd_cmd) {
342 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700343 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800344 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800345}
346
San Mehat9d2bd732009-09-22 16:44:22 -0700347static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530348msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700349{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530350 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700351 unsigned long flags;
352 struct mmc_request *mrq;
353
354 spin_lock_irqsave(&host->lock, flags);
355 mrq = host->curr.mrq;
356 BUG_ON(!mrq);
357
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530358 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700359 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700360 goto out;
361 }
362
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530363 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700364 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700365 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700366 } else {
367 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530368 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700369 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530370 mmc_hostname(host->mmc), host->dma.result);
371 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700372 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530373 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530374 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700375 host->dma.err.flush[0], host->dma.err.flush[1],
376 host->dma.err.flush[2], host->dma.err.flush[3],
377 host->dma.err.flush[4],
378 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530379 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700380 if (!mrq->data->error)
381 mrq->data->error = -EIO;
382 }
San Mehat9d2bd732009-09-22 16:44:22 -0700383 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents,
384 host->dma.dir);
385
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700386 if (host->curr.user_pages) {
387 struct scatterlist *sg = host->dma.sg;
388 int i;
389
390 for (i = 0; i < host->dma.num_ents; i++, sg++)
391 flush_dcache_page(sg_page(sg));
392 }
393
San Mehat9d2bd732009-09-22 16:44:22 -0700394 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800395 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700396
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530397 if (host->curr.got_dataend || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700398
399 /*
400 * If we've already gotten our DATAEND / DATABLKEND
401 * for this request, then complete it through here.
402 */
San Mehat9d2bd732009-09-22 16:44:22 -0700403
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700404 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700405 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700406 host->curr.xfer_remain -= host->curr.xfer_size;
407 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700408 if (host->dummy_52_needed) {
409 mrq->data->bytes_xfered = host->curr.data_xfered;
410 host->dummy_52_sent = 1;
411 msmsdcc_start_command(host, &dummy52cmd,
412 MCI_CPSM_PROGENA);
413 goto out;
414 }
415 msmsdcc_stop_data(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700416 if (!mrq->data->stop || mrq->cmd->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700417 host->curr.mrq = NULL;
418 host->curr.cmd = NULL;
419 mrq->data->bytes_xfered = host->curr.data_xfered;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700420 del_timer(&host->req_tout_timer);
San Mehat9d2bd732009-09-22 16:44:22 -0700421 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700422
San Mehat9d2bd732009-09-22 16:44:22 -0700423 mmc_request_done(host->mmc, mrq);
424 return;
425 } else
426 msmsdcc_start_command(host, mrq->data->stop, 0);
427 }
428
429out:
430 spin_unlock_irqrestore(&host->lock, flags);
431 return;
432}
433
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700434#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
435/**
436 * Callback notification from SPS driver
437 *
438 * This callback function gets triggered called from
439 * SPS driver when requested SPS data transfer is
440 * completed.
441 *
442 * SPS driver invokes this callback in BAM irq context so
443 * SDCC driver schedule a tasklet for further processing
444 * this callback notification at later point of time in
445 * tasklet context and immediately returns control back
446 * to SPS driver.
447 *
448 * @nofity - Pointer to sps event notify sturcture
449 *
450 */
451static void
452msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
453{
454 struct msmsdcc_host *host =
455 (struct msmsdcc_host *)
456 ((struct sps_event_notify *)notify)->user;
457
458 host->sps.notify = *notify;
459 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
460 mmc_hostname(host->mmc), __func__, notify->event_id,
461 notify->data.transfer.iovec.addr,
462 notify->data.transfer.iovec.size,
463 notify->data.transfer.iovec.flags);
464 /* Schedule a tasklet for completing data transfer */
465 tasklet_schedule(&host->sps.tlet);
466}
467
468/**
469 * Tasklet handler for processing SPS callback event
470 *
471 * This function processing SPS event notification and
472 * checks if the SPS transfer is completed or not and
473 * then accordingly notifies status to MMC core layer.
474 *
475 * This function is called in tasklet context.
476 *
477 * @data - Pointer to sdcc driver data
478 *
479 */
480static void msmsdcc_sps_complete_tlet(unsigned long data)
481{
482 unsigned long flags;
483 int i, rc;
484 u32 data_xfered = 0;
485 struct mmc_request *mrq;
486 struct sps_iovec iovec;
487 struct sps_pipe *sps_pipe_handle;
488 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
489 struct sps_event_notify *notify = &host->sps.notify;
490
491 spin_lock_irqsave(&host->lock, flags);
492 if (host->sps.dir == DMA_FROM_DEVICE)
493 sps_pipe_handle = host->sps.prod.pipe_handle;
494 else
495 sps_pipe_handle = host->sps.cons.pipe_handle;
496 mrq = host->curr.mrq;
497
498 if (!mrq) {
499 spin_unlock_irqrestore(&host->lock, flags);
500 return;
501 }
502
503 pr_debug("%s: %s: sps event_id=%d\n",
504 mmc_hostname(host->mmc), __func__,
505 notify->event_id);
506
507 if (msmsdcc_is_dml_busy(host)) {
508 /* oops !!! this should never happen. */
509 pr_err("%s: %s: Received SPS EOT event"
510 " but DML HW is still busy !!!\n",
511 mmc_hostname(host->mmc), __func__);
512 }
513 /*
514 * Got End of transfer event!!! Check if all of the data
515 * has been transferred?
516 */
517 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
518 rc = sps_get_iovec(sps_pipe_handle, &iovec);
519 if (rc) {
520 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
521 mmc_hostname(host->mmc), __func__, rc, i);
522 break;
523 }
524 data_xfered += iovec.size;
525 }
526
527 if (data_xfered == host->curr.xfer_size) {
528 host->curr.data_xfered = host->curr.xfer_size;
529 host->curr.xfer_remain -= host->curr.xfer_size;
530 pr_debug("%s: Data xfer success. data_xfered=0x%x",
531 mmc_hostname(host->mmc),
532 host->curr.xfer_size);
533 } else {
534 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
535 " xfer_size=%d", mmc_hostname(host->mmc),
536 data_xfered, host->curr.xfer_size);
537 msmsdcc_reset_and_restore(host);
538 if (!mrq->data->error)
539 mrq->data->error = -EIO;
540 }
541
542 /* Unmap sg buffers */
543 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
544 host->sps.dir);
545
546 host->sps.sg = NULL;
547 host->sps.busy = 0;
548
549 if (host->curr.got_dataend || mrq->data->error) {
550 /*
551 * If we've already gotten our DATAEND / DATABLKEND
552 * for this request, then complete it through here.
553 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700554
555 if (!mrq->data->error) {
556 host->curr.data_xfered = host->curr.xfer_size;
557 host->curr.xfer_remain -= host->curr.xfer_size;
558 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700559 if (host->dummy_52_needed) {
560 mrq->data->bytes_xfered = host->curr.data_xfered;
561 host->dummy_52_sent = 1;
562 msmsdcc_start_command(host, &dummy52cmd,
563 MCI_CPSM_PROGENA);
564 return;
565 }
566 msmsdcc_stop_data(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700567 if (!mrq->data->stop || mrq->cmd->error) {
568 host->curr.mrq = NULL;
569 host->curr.cmd = NULL;
570 mrq->data->bytes_xfered = host->curr.data_xfered;
571 del_timer(&host->req_tout_timer);
572 spin_unlock_irqrestore(&host->lock, flags);
573
574 mmc_request_done(host->mmc, mrq);
575 return;
576 } else {
577 msmsdcc_start_command(host, mrq->data->stop, 0);
578 }
579 }
580 spin_unlock_irqrestore(&host->lock, flags);
581}
582
583/**
584 * Exit from current SPS data transfer
585 *
586 * This function exits from current SPS data transfer.
587 *
588 * This function should be called when error condition
589 * is encountered during data transfer.
590 *
591 * @host - Pointer to sdcc host structure
592 *
593 */
594static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
595{
596 struct mmc_request *mrq;
597
598 mrq = host->curr.mrq;
599 BUG_ON(!mrq);
600
601 msmsdcc_reset_and_restore(host);
602 if (!mrq->data->error)
603 mrq->data->error = -EIO;
604
605 /* Unmap sg buffers */
606 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
607 host->sps.dir);
608
609 host->sps.sg = NULL;
610 host->sps.busy = 0;
611 if (host->curr.data)
612 msmsdcc_stop_data(host);
613
614 if (!mrq->data->stop || mrq->cmd->error)
615 msmsdcc_request_end(host, mrq);
616 else
617 msmsdcc_start_command(host, mrq->data->stop, 0);
618
619}
620#else
621static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
622static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
623static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
624#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
625
626static void msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
627
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530628static void
629msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
630 unsigned int result,
631 struct msm_dmov_errdata *err)
632{
633 struct msmsdcc_dma_data *dma_data =
634 container_of(cmd, struct msmsdcc_dma_data, hdr);
635 struct msmsdcc_host *host = dma_data->host;
636
637 dma_data->result = result;
638 if (err)
639 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
640
641 tasklet_schedule(&host->dma_tlet);
642}
643
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700644static int msmsdcc_check_dma_op_req(struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700645{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700646 if (((data->blksz * data->blocks) < MCI_FIFOSIZE) ||
647 ((data->blksz * data->blocks) % MCI_FIFOSIZE))
San Mehat9d2bd732009-09-22 16:44:22 -0700648 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700649 else
650 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700651}
652
653static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
654{
655 struct msmsdcc_nc_dmadata *nc;
656 dmov_box *box;
657 uint32_t rows;
658 uint32_t crci;
659 unsigned int n;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700660 int i;
San Mehat9d2bd732009-09-22 16:44:22 -0700661 struct scatterlist *sg = data->sg;
662
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700663 if (host->dma.channel == -1)
664 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700665
666 host->dma.sg = data->sg;
667 host->dma.num_ents = data->sg_len;
668
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700669 BUG_ON(host->dma.num_ents > NR_SG); /* Prevent memory corruption */
San Mehat56a8b5b2009-11-21 12:29:46 -0800670
San Mehat9d2bd732009-09-22 16:44:22 -0700671 nc = host->dma.nc;
672
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700673 if (host->pdev_id == 1)
674 crci = DMOV_SDC1_CRCI;
675 else if (host->pdev_id == 2)
676 crci = DMOV_SDC2_CRCI;
677 else if (host->pdev_id == 3)
678 crci = DMOV_SDC3_CRCI;
679 else if (host->pdev_id == 4)
680 crci = DMOV_SDC4_CRCI;
681#ifdef DMOV_SDC5_CRCI
682 else if (host->pdev_id == 5)
683 crci = DMOV_SDC5_CRCI;
684#endif
685 else {
San Mehat9d2bd732009-09-22 16:44:22 -0700686 host->dma.sg = NULL;
687 host->dma.num_ents = 0;
688 return -ENOENT;
689 }
690
691 if (data->flags & MMC_DATA_READ)
692 host->dma.dir = DMA_FROM_DEVICE;
693 else
694 host->dma.dir = DMA_TO_DEVICE;
695
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700696 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
San Mehat9d2bd732009-09-22 16:44:22 -0700697 host->curr.user_pages = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700698 box = &nc->cmd[0];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700699 for (i = 0; i < host->dma.num_ents; i++) {
San Mehat9d2bd732009-09-22 16:44:22 -0700700 box->cmd = CMD_MODE_BOX;
701
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700702 /* Initialize sg dma address */
703 sg->dma_address = pfn_to_dma(mmc_dev(host->mmc),
704 page_to_pfn(sg_page(sg)))
705 + sg->offset;
706
707 if (i == (host->dma.num_ents - 1))
San Mehat9d2bd732009-09-22 16:44:22 -0700708 box->cmd |= CMD_LC;
709 rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ?
710 (sg_dma_len(sg) / MCI_FIFOSIZE) + 1 :
711 (sg_dma_len(sg) / MCI_FIFOSIZE) ;
712
713 if (data->flags & MMC_DATA_READ) {
714 box->src_row_addr = msmsdcc_fifo_addr(host);
715 box->dst_row_addr = sg_dma_address(sg);
716
717 box->src_dst_len = (MCI_FIFOSIZE << 16) |
718 (MCI_FIFOSIZE);
719 box->row_offset = MCI_FIFOSIZE;
720
721 box->num_rows = rows * ((1 << 16) + 1);
722 box->cmd |= CMD_SRC_CRCI(crci);
723 } else {
724 box->src_row_addr = sg_dma_address(sg);
725 box->dst_row_addr = msmsdcc_fifo_addr(host);
726
727 box->src_dst_len = (MCI_FIFOSIZE << 16) |
728 (MCI_FIFOSIZE);
729 box->row_offset = (MCI_FIFOSIZE << 16);
730
731 box->num_rows = rows * ((1 << 16) + 1);
732 box->cmd |= CMD_DST_CRCI(crci);
733 }
734 box++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700735 sg++;
736 }
737
738 /* location of command block must be 64 bit aligned */
739 BUG_ON(host->dma.cmd_busaddr & 0x07);
740
741 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
742 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
743 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
744 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
745 host->dma.hdr.crci_mask = msm_dmov_build_crci_mask(1, crci);
746
747 n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
748 host->dma.num_ents, host->dma.dir);
749 /* dsb inside dma_map_sg will write nc out to mem as well */
750
751 if (n != host->dma.num_ents) {
752 pr_err("%s: Unable to map in all sg elements\n",
753 mmc_hostname(host->mmc));
754 host->dma.sg = NULL;
755 host->dma.num_ents = 0;
756 return -ENOMEM;
San Mehat56a8b5b2009-11-21 12:29:46 -0800757 }
San Mehat9d2bd732009-09-22 16:44:22 -0700758
759 return 0;
760}
761
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700762#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
763/**
764 * Submits data transfer request to SPS driver
765 *
766 * This function make sg (scatter gather) data buffers
767 * DMA ready and then submits them to SPS driver for
768 * transfer.
769 *
770 * @host - Pointer to sdcc host structure
771 * @data - Pointer to mmc_data structure
772 *
773 * @return 0 if success else negative value
774 */
775static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
776 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -0800777{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700778 int rc = 0;
779 u32 flags;
780 int i;
781 u32 addr, len, data_cnt;
782 struct scatterlist *sg = data->sg;
783 struct sps_pipe *sps_pipe_handle;
784
785 BUG_ON(data->sg_len > NR_SG); /* Prevent memory corruption */
786
787 host->sps.sg = data->sg;
788 host->sps.num_ents = data->sg_len;
789 host->sps.xfer_req_cnt = 0;
790 if (data->flags & MMC_DATA_READ) {
791 host->sps.dir = DMA_FROM_DEVICE;
792 sps_pipe_handle = host->sps.prod.pipe_handle;
793 } else {
794 host->sps.dir = DMA_TO_DEVICE;
795 sps_pipe_handle = host->sps.cons.pipe_handle;
796 }
797
798 /* Make sg buffers DMA ready */
799 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
800 host->sps.dir);
801
802 if (rc != data->sg_len) {
803 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
804 mmc_hostname(host->mmc), rc);
805 host->sps.sg = NULL;
806 host->sps.num_ents = 0;
807 rc = -ENOMEM;
808 goto dma_map_err;
809 }
810
811 pr_debug("%s: %s: %s: pipe=0x%x, total_xfer=0x%x, sg_len=%d\n",
812 mmc_hostname(host->mmc), __func__,
813 host->sps.dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
814 (u32)sps_pipe_handle, host->curr.xfer_size, data->sg_len);
815
816 for (i = 0; i < data->sg_len; i++) {
817 /*
818 * Check if this is the last buffer to transfer?
819 * If yes then set the INT and EOT flags.
820 */
821 len = sg_dma_len(sg);
822 addr = sg_dma_address(sg);
823 flags = 0;
824 while (len > 0) {
825 if (len > SPS_MAX_DESC_SIZE) {
826 data_cnt = SPS_MAX_DESC_SIZE;
827 } else {
828 data_cnt = len;
829 if (i == data->sg_len - 1)
830 flags = SPS_IOVEC_FLAG_INT |
831 SPS_IOVEC_FLAG_EOT;
832 }
833 rc = sps_transfer_one(sps_pipe_handle, addr,
834 data_cnt, host, flags);
835 if (rc) {
836 pr_err("%s: sps_transfer_one() error! rc=%d,"
837 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
838 mmc_hostname(host->mmc), rc,
839 (u32)sps_pipe_handle, (u32)sg, i);
840 goto dma_map_err;
841 }
842 addr += data_cnt;
843 len -= data_cnt;
844 host->sps.xfer_req_cnt++;
845 }
846 sg++;
847 }
848 goto out;
849
850dma_map_err:
851 /* unmap sg buffers */
852 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
853 host->sps.dir);
854out:
855 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -0700856}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700857#else
858static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
859 struct mmc_data *data) { return 0; }
860#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -0700861
862static void
San Mehat56a8b5b2009-11-21 12:29:46 -0800863msmsdcc_start_command_deferred(struct msmsdcc_host *host,
864 struct mmc_command *cmd, u32 *c)
865{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700866 DBG(host, "op %02x arg %08x flags %08x\n",
867 cmd->opcode, cmd->arg, cmd->flags);
868
San Mehat56a8b5b2009-11-21 12:29:46 -0800869 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
870
871 if (cmd->flags & MMC_RSP_PRESENT) {
872 if (cmd->flags & MMC_RSP_136)
873 *c |= MCI_CPSM_LONGRSP;
874 *c |= MCI_CPSM_RESPONSE;
875 }
876
877 if (/*interrupt*/0)
878 *c |= MCI_CPSM_INTERRUPT;
879
880 if ((((cmd->opcode == 17) || (cmd->opcode == 18)) ||
881 ((cmd->opcode == 24) || (cmd->opcode == 25))) ||
882 (cmd->opcode == 53))
883 *c |= MCI_CSPM_DATCMD;
884
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700885 /* Check if AUTO CMD19 is required or not? */
886 if (((cmd->opcode == 17) || (cmd->opcode == 18)) &&
887 host->tuning_needed) {
888 msmsdcc_enable_cdr_cm_sdc4_dll(host);
889 *c |= MCI_CSPM_AUTO_CMD19;
890 }
891
Sahitya Tummalad5137bd2010-12-08 15:03:04 +0530892 if (host->prog_scan && (cmd->opcode == 12)) {
893 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700894 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +0530895 }
896
San Mehat56a8b5b2009-11-21 12:29:46 -0800897 if (cmd == cmd->mrq->stop)
898 *c |= MCI_CSPM_MCIABORT;
899
San Mehat56a8b5b2009-11-21 12:29:46 -0800900 if (host->curr.cmd != NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700901 pr_err("%s: Overlapping command requests\n",
902 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -0800903 }
904 host->curr.cmd = cmd;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700905
906 /*
907 * Kick the software command timeout timer here.
908 * Timer expires in 10 secs.
909 */
910 mod_timer(&host->req_tout_timer,
911 (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
San Mehat56a8b5b2009-11-21 12:29:46 -0800912}
913
914static void
915msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
916 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -0700917{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +0530918 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -0700919 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700920 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -0700921 unsigned int pio_irqmask = 0;
922
923 host->curr.data = data;
924 host->curr.xfer_size = data->blksz * data->blocks;
925 host->curr.xfer_remain = host->curr.xfer_size;
926 host->curr.data_xfered = 0;
927 host->curr.got_dataend = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700928
929 memset(&host->pio, 0, sizeof(host->pio));
930
San Mehat9d2bd732009-09-22 16:44:22 -0700931 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
932
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700933 if (!msmsdcc_check_dma_op_req(data)) {
934 if (host->is_dma_mode && !msmsdcc_config_dma(host, data)) {
935 datactrl |= MCI_DPSM_DMAENABLE;
936 } else if (host->is_sps_mode) {
937 if (!msmsdcc_is_dml_busy(host)) {
938 if (!msmsdcc_sps_start_xfer(host, data)) {
939 /* Now kick start DML transfer */
940 mb();
941 msmsdcc_dml_start_xfer(host, data);
942 datactrl |= MCI_DPSM_DMAENABLE;
943 host->sps.busy = 1;
944 }
945 } else {
946 /*
947 * Can't proceed with new transfer as
948 * previous trasnfer is already in progress.
949 * There is no point of going into PIO mode
950 * as well. Is this a time to do kernel panic?
951 */
952 pr_err("%s: %s: DML HW is busy!!!"
953 " Can't perform new SPS transfers"
954 " now\n", mmc_hostname(host->mmc),
955 __func__);
956 }
957 }
958 }
959
960 /* Is data transfer in PIO mode required? */
961 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700962 host->pio.sg = data->sg;
963 host->pio.sg_len = data->sg_len;
964 host->pio.sg_off = 0;
965
966 if (data->flags & MMC_DATA_READ) {
967 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
968 if (host->curr.xfer_remain < MCI_FIFOSIZE)
969 pio_irqmask |= MCI_RXDATAAVLBLMASK;
970 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700971 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
972 MCI_TXFIFOEMPTYMASK;
San Mehat9d2bd732009-09-22 16:44:22 -0700973 }
974
975 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +0530976 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
San Mehat9d2bd732009-09-22 16:44:22 -0700977
San Mehat56a8b5b2009-11-21 12:29:46 -0800978 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700979 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -0800980 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -0700981
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700982 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
983 /* Use ADM (Application Data Mover) HW for Data transfer */
984 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -0800985 host->cmd_timeout = timeout;
986 host->cmd_pio_irqmask = pio_irqmask;
987 host->cmd_datactrl = datactrl;
988 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -0700989
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700990 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
991 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -0700992 host->dma.busy = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700993 if (data->flags & MMC_DATA_WRITE)
994 host->prog_scan = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -0800995
996 if (cmd) {
997 msmsdcc_start_command_deferred(host, cmd, &c);
998 host->cmd_c = c;
999 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001000 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1001 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1002 host->base + MMCIMASK0);
1003 mb();
1004 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001005 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001006 /* SPS-BAM mode or PIO mode */
1007 if (data->flags & MMC_DATA_WRITE)
1008 host->prog_scan = 1;
1009 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001010
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001011 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001012
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001013 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1014 (~(MCI_IRQ_PIO))) | pio_irqmask,
1015 host->base + MMCIMASK0);
1016 msmsdcc_delay(host); /* Allow parms to be applied */
1017 writel_relaxed(datactrl, base + MMCIDATACTRL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001018
1019 if (cmd) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001020 msmsdcc_delay(host); /* Delay between data/command */
San Mehat56a8b5b2009-11-21 12:29:46 -08001021 /* Daisy-chain the command if requested */
1022 msmsdcc_start_command(host, cmd, c);
1023 }
San Mehat9d2bd732009-09-22 16:44:22 -07001024 }
1025}
1026
1027static void
1028msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1029{
San Mehat56a8b5b2009-11-21 12:29:46 -08001030 msmsdcc_start_command_deferred(host, cmd, &c);
1031 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001032}
1033
1034static void
1035msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1036 unsigned int status)
1037{
1038 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001039 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1040 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1041 pr_err("%s: Data CRC error\n",
1042 mmc_hostname(host->mmc));
1043 pr_err("%s: opcode 0x%.8x\n", __func__,
1044 data->mrq->cmd->opcode);
1045 pr_err("%s: blksz %d, blocks %d\n", __func__,
1046 data->blksz, data->blocks);
1047 data->error = -EILSEQ;
1048 }
San Mehat9d2bd732009-09-22 16:44:22 -07001049 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001050 /* CRC is optional for the bus test commands, not all
1051 * cards respond back with CRC. However controller
1052 * waits for the CRC and times out. Hence ignore the
1053 * data timeouts during the Bustest.
1054 */
1055 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1056 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1057 pr_err("%s: Data timeout\n",
1058 mmc_hostname(host->mmc));
1059 data->error = -ETIMEDOUT;
1060 }
San Mehat9d2bd732009-09-22 16:44:22 -07001061 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001062 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001063 data->error = -EIO;
1064 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001065 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001066 data->error = -EIO;
1067 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001068 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001069 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001070 data->error = -EIO;
1071 }
San Mehat9d2bd732009-09-22 16:44:22 -07001072
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001073 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001074 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001075 host->dummy_52_needed = 0;
1076}
San Mehat9d2bd732009-09-22 16:44:22 -07001077
1078static int
1079msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1080{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001081 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001082 uint32_t *ptr = (uint32_t *) buffer;
1083 int count = 0;
1084
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301085 if (remain % 4)
1086 remain = ((remain >> 2) + 1) << 2;
1087
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001088 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1089
1090 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001091 ptr++;
1092 count += sizeof(uint32_t);
1093
1094 remain -= sizeof(uint32_t);
1095 if (remain == 0)
1096 break;
1097 }
1098 return count;
1099}
1100
1101static int
1102msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001103 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001104{
1105 void __iomem *base = host->base;
1106 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001107 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001108
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001109 while (readl_relaxed(base + MMCISTATUS) &
1110 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1111 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001112
San Mehat9d2bd732009-09-22 16:44:22 -07001113 count = min(remain, maxcnt);
1114
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301115 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1116 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001117 ptr += count;
1118 remain -= count;
1119
1120 if (remain == 0)
1121 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001122 }
1123 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001124
1125 return ptr - buffer;
1126}
1127
San Mehat1cd22962010-02-03 12:59:29 -08001128static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001129msmsdcc_pio_irq(int irq, void *dev_id)
1130{
1131 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001132 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001133 uint32_t status;
1134
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001135 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001136
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001137 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1138 (MCI_IRQ_PIO)) == 0)
1139 return IRQ_NONE;
1140
1141#if IRQ_DEBUG
1142 msmsdcc_print_status(host, "irq1-r", status);
1143#endif
1144
1145 spin_lock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001146
1147 do {
1148 unsigned long flags;
1149 unsigned int remain, len;
1150 char *buffer;
1151
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001152 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1153 | MCI_RXDATAAVLBL)))
1154 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001155
1156 /* Map the current scatter buffer */
1157 local_irq_save(flags);
1158 buffer = kmap_atomic(sg_page(host->pio.sg),
1159 KM_BIO_SRC_IRQ) + host->pio.sg->offset;
1160 buffer += host->pio.sg_off;
1161 remain = host->pio.sg->length - host->pio.sg_off;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001162
San Mehat9d2bd732009-09-22 16:44:22 -07001163 len = 0;
1164 if (status & MCI_RXACTIVE)
1165 len = msmsdcc_pio_read(host, buffer, remain);
1166 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001167 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001168
1169 /* Unmap the buffer */
1170 kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
1171 local_irq_restore(flags);
1172
1173 host->pio.sg_off += len;
1174 host->curr.xfer_remain -= len;
1175 host->curr.data_xfered += len;
1176 remain -= len;
1177
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001178 if (remain) /* Done with this page? */
1179 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001180
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001181 if (status & MCI_RXACTIVE && host->curr.user_pages)
1182 flush_dcache_page(sg_page(host->pio.sg));
San Mehat9d2bd732009-09-22 16:44:22 -07001183
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001184 if (!--host->pio.sg_len) {
1185 memset(&host->pio, 0, sizeof(host->pio));
1186 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001187 }
1188
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001189 /* Advance to next sg */
1190 host->pio.sg++;
1191 host->pio.sg_off = 0;
1192
1193 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001194 } while (1);
1195
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001196 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1197 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1198 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1199 host->base + MMCIMASK0);
1200 if (!host->curr.xfer_remain) {
1201 /* Delay needed (same port was just written) */
1202 msmsdcc_delay(host);
1203 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1204 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1205 }
1206 mb();
1207 } else if (!host->curr.xfer_remain) {
1208 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1209 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1210 mb();
1211 }
San Mehat9d2bd732009-09-22 16:44:22 -07001212
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001213 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001214
1215 return IRQ_HANDLED;
1216}
1217
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001218static void
1219msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1220
1221static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1222 struct mmc_data *data)
1223{
1224 u32 loop_cnt = 0;
1225
1226 /*
1227 * For read commands with data less than fifo size, it is possible to
1228 * get DATAEND first and RXDATA_AVAIL might be set later because of
1229 * synchronization delay through the asynchronous RX FIFO. Thus, for
1230 * such cases, even after DATAEND interrupt is received software
1231 * should poll for RXDATA_AVAIL until the requested data is read out
1232 * of FIFO. This change is needed to get around this abnormal but
1233 * sometimes expected behavior of SDCC3 controller.
1234 *
1235 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1236 * after the data is loaded into RX FIFO. This would amount to less
1237 * than a microsecond and thus looping for 1000 times is good enough
1238 * for that delay.
1239 */
1240 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1241 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1242 spin_unlock(&host->lock);
1243 msmsdcc_pio_irq(1, host);
1244 spin_lock(&host->lock);
1245 }
1246 }
1247 if (loop_cnt == 1000) {
1248 pr_info("%s: Timed out while polling for Rx Data\n",
1249 mmc_hostname(host->mmc));
1250 data->error = -ETIMEDOUT;
1251 msmsdcc_reset_and_restore(host);
1252 }
1253}
1254
San Mehat9d2bd732009-09-22 16:44:22 -07001255static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1256{
1257 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001258
1259 host->curr.cmd = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001260 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1261 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1262 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1263 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -07001264
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001265 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Sahitya Tummala5a0ae912011-07-18 13:34:01 +05301266 pr_debug("%s: Command timeout\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001267 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001268 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
1269 !host->cmd19_tuning_in_progress) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001270 pr_err("%s: Command CRC error\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001271 cmd->error = -EILSEQ;
1272 }
1273
1274 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001275 if (host->curr.data && host->dma.sg &&
1276 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001277 msm_dmov_stop_cmd(host->dma.channel,
1278 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001279 else if (host->curr.data && host->sps.sg &&
1280 host->is_sps_mode){
1281 /* Stop current SPS transfer */
1282 msmsdcc_sps_exit_curr_xfer(host);
1283 }
San Mehat9d2bd732009-09-22 16:44:22 -07001284 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301285 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001286 msmsdcc_stop_data(host);
1287 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301288 } else { /* host->data == NULL */
1289 if (!cmd->error && host->prog_enable) {
1290 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001291 host->prog_scan = 0;
1292 host->prog_enable = 0;
1293 msmsdcc_request_end(host, cmd->mrq);
1294 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301295 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301296 } else {
1297 if (host->prog_enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001298 host->prog_scan = 0;
1299 host->prog_enable = 0;
1300 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001301 if (host->dummy_52_needed)
1302 host->dummy_52_needed = 0;
1303 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001304 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301305 msmsdcc_request_end(host, cmd->mrq);
1306 }
1307 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001308 } else if (cmd->data) {
San Mehat56a8b5b2009-11-21 12:29:46 -08001309 if (!(cmd->data->flags & MMC_DATA_READ))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001310 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001311 }
1312}
1313
San Mehat9d2bd732009-09-22 16:44:22 -07001314static irqreturn_t
1315msmsdcc_irq(int irq, void *dev_id)
1316{
1317 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001318 u32 status;
1319 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001320 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001321
1322 spin_lock(&host->lock);
1323
1324 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001325 struct mmc_command *cmd;
1326 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001327
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001328 if (timer) {
1329 timer = 0;
1330 msmsdcc_delay(host);
1331 }
San Mehat865c8062009-11-13 13:42:06 -08001332
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001333 if (!host->clks_on) {
1334 pr_debug("%s: %s: SDIO async irq received\n",
1335 mmc_hostname(host->mmc), __func__);
1336 host->mmc->ios.clock = host->clk_rate;
1337 spin_unlock(&host->lock);
1338 host->mmc->ops->set_ios(host->mmc, &host->mmc->ios);
1339 spin_lock(&host->lock);
1340 if (host->plat->cfg_mpm_sdiowakeup &&
1341 (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
1342 wake_lock(&host->sdio_wlock);
1343 /* only ansyc interrupt can come when clocks are off */
1344 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
1345 }
1346
1347 status = readl_relaxed(host->base + MMCISTATUS);
1348
1349 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1350 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001351 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001352
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001353#if IRQ_DEBUG
1354 msmsdcc_print_status(host, "irq0-r", status);
1355#endif
1356 status &= readl_relaxed(host->base + MMCIMASK0);
1357 writel_relaxed(status, host->base + MMCICLEAR);
1358 mb();
1359#if IRQ_DEBUG
1360 msmsdcc_print_status(host, "irq0-p", status);
1361#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001362
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001363#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
1364 if (status & MCI_SDIOINTROPE) {
1365 if (host->sdcc_suspending)
1366 wake_lock(&host->sdio_suspend_wlock);
1367 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001368 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001369#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001370 data = host->curr.data;
1371
1372 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001373 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1374 MCI_CMDTIMEOUT)) {
1375 if (status & MCI_CMDTIMEOUT)
1376 pr_debug("%s: dummy CMD52 timeout\n",
1377 mmc_hostname(host->mmc));
1378 if (status & MCI_CMDCRCFAIL)
1379 pr_debug("%s: dummy CMD52 CRC failed\n",
1380 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001381 host->dummy_52_sent = 0;
1382 host->dummy_52_needed = 0;
1383 if (data) {
1384 msmsdcc_stop_data(host);
1385 msmsdcc_request_end(host, data->mrq);
1386 }
1387 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001388 spin_unlock(&host->lock);
1389 return IRQ_HANDLED;
1390 }
1391 break;
1392 }
1393
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001394 /*
1395 * Check for proper command response
1396 */
1397 cmd = host->curr.cmd;
1398 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1399 MCI_CMDTIMEOUT | MCI_PROGDONE |
1400 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1401 msmsdcc_do_cmdirq(host, status);
1402 }
1403
1404 if (data) {
1405 /* Check for data errors */
1406 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1407 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1408 msmsdcc_data_err(host, data, status);
1409 host->curr.data_xfered = 0;
1410 if (host->dma.sg && host->is_dma_mode)
1411 msm_dmov_stop_cmd(host->dma.channel,
1412 &host->dma.hdr, 0);
1413 else if (host->sps.sg && host->is_sps_mode) {
1414 /* Stop current SPS transfer */
1415 msmsdcc_sps_exit_curr_xfer(host);
1416 }
1417 else {
1418 msmsdcc_reset_and_restore(host);
1419 if (host->curr.data)
1420 msmsdcc_stop_data(host);
1421 if (!data->stop)
1422 timer |=
1423 msmsdcc_request_end(host,
1424 data->mrq);
1425 else {
1426 msmsdcc_start_command(host,
1427 data->stop,
1428 0);
1429 timer = 1;
1430 }
1431 }
1432 }
1433
1434 /* Check for data done */
1435 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1436 host->curr.got_dataend = 1;
1437
1438 if (host->curr.got_dataend) {
1439 /*
1440 * If DMA is still in progress, we complete
1441 * via the completion handler
1442 */
1443 if (!host->dma.busy && !host->sps.busy) {
1444 /*
1445 * There appears to be an issue in the
1446 * controller where if you request a
1447 * small block transfer (< fifo size),
1448 * you may get your DATAEND/DATABLKEND
1449 * irq without the PIO data irq.
1450 *
1451 * Check to see if theres still data
1452 * to be read, and simulate a PIO irq.
1453 */
1454 if (data->flags & MMC_DATA_READ)
1455 msmsdcc_wait_for_rxdata(host,
1456 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001457 if (!data->error) {
1458 host->curr.data_xfered =
1459 host->curr.xfer_size;
1460 host->curr.xfer_remain -=
1461 host->curr.xfer_size;
1462 }
1463
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001464 if (!host->dummy_52_needed) {
1465 msmsdcc_stop_data(host);
1466 if (!data->stop) {
1467 msmsdcc_request_end(
1468 host,
1469 data->mrq);
1470 } else {
1471 msmsdcc_start_command(
1472 host,
1473 data->stop, 0);
1474 timer = 1;
1475 }
1476 } else {
1477 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001478 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001479 &dummy52cmd,
1480 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001481 }
1482 }
1483 }
1484 }
1485
San Mehat9d2bd732009-09-22 16:44:22 -07001486 ret = 1;
1487 } while (status);
1488
1489 spin_unlock(&host->lock);
1490
San Mehat9d2bd732009-09-22 16:44:22 -07001491 return IRQ_RETVAL(ret);
1492}
1493
1494static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001495msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1496{
1497 if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
1498 /* Queue/read data, daisy-chain command when data starts */
1499 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
1500 } else {
1501 msmsdcc_start_command(host, mrq->cmd, 0);
1502 }
1503}
1504
1505static void
San Mehat9d2bd732009-09-22 16:44:22 -07001506msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1507{
1508 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001509 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001510
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001511 /*
1512 * Get the SDIO AL client out of LPM.
1513 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001514 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001515 if (host->plat->is_sdio_al_client)
1516 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001517
1518 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001519 WARN(host->curr.mrq, "Request in progress\n");
1520 WARN(!host->pwr, "SDCC power is turned off\n");
1521 WARN(!host->clks_on, "SDCC clocks are turned off\n");
1522 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
San Mehat9d2bd732009-09-22 16:44:22 -07001523
1524 if (host->eject) {
1525 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1526 mrq->cmd->error = 0;
1527 mrq->data->bytes_xfered = mrq->data->blksz *
1528 mrq->data->blocks;
1529 } else
1530 mrq->cmd->error = -ENOMEDIUM;
1531
1532 spin_unlock_irqrestore(&host->lock, flags);
1533 mmc_request_done(mmc, mrq);
1534 return;
1535 }
1536
1537 host->curr.mrq = mrq;
1538
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001539 if (host->plat->dummy52_required) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001540 if (mrq->data && mrq->data->flags == MMC_DATA_WRITE) {
1541 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001542 mrq->cmd->opcode == 54) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001543 host->dummy_52_needed = 1;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001544 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001545 }
San Mehat9d2bd732009-09-22 16:44:22 -07001546 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001547 msmsdcc_request_start(host, mrq);
San Mehat9d2bd732009-09-22 16:44:22 -07001548 spin_unlock_irqrestore(&host->lock, flags);
1549}
1550
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001551static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1552 int min_uV, int max_uV)
1553{
1554 int rc = 0;
1555
1556 if (vreg->set_voltage_sup) {
1557 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1558 if (rc) {
1559 pr_err("%s: regulator_set_voltage(%s) failed."
1560 " min_uV=%d, max_uV=%d, rc=%d\n",
1561 __func__, vreg->name, min_uV, max_uV, rc);
1562 }
1563 }
1564
1565 return rc;
1566}
1567
1568static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1569 int uA_load)
1570{
1571 int rc = 0;
1572
1573 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1574 if (rc < 0)
1575 pr_err("%s: regulator_set_optimum_mode(reg=%s, uA_load=%d)"
1576 " failed. rc=%d\n", __func__, vreg->name,
1577 uA_load, rc);
1578 else
1579 /* regulator_set_optimum_mode() can return non zero value
1580 * even for success case.
1581 */
1582 rc = 0;
1583
1584 return rc;
1585}
1586
1587static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1588 struct device *dev)
1589{
1590 int rc = 0;
1591
1592 /* check if regulator is already initialized? */
1593 if (vreg->reg)
1594 goto out;
1595
1596 /* Get the regulator handle */
1597 vreg->reg = regulator_get(dev, vreg->name);
1598 if (IS_ERR(vreg->reg)) {
1599 rc = PTR_ERR(vreg->reg);
1600 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
1601 __func__, vreg->name, rc);
1602 }
1603out:
1604 return rc;
1605}
1606
1607static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
1608{
1609 if (vreg->reg)
1610 regulator_put(vreg->reg);
1611}
1612
1613/* This init function should be called only once for each SDCC slot */
1614static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
1615{
1616 int rc = 0;
1617 struct msm_mmc_slot_reg_data *curr_slot;
1618 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1619 struct device *dev = mmc_dev(host->mmc);
1620
1621 curr_slot = host->plat->vreg_data;
1622 if (!curr_slot)
1623 goto out;
1624
1625 curr_vdd_reg = curr_slot->vdd_data;
1626 curr_vccq_reg = curr_slot->vccq_data;
1627 curr_vddp_reg = curr_slot->vddp_data;
1628
1629 if (is_init) {
1630 /*
1631 * Get the regulator handle from voltage regulator framework
1632 * and then try to set the voltage level for the regulator
1633 */
1634 if (curr_vdd_reg) {
1635 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
1636 if (rc)
1637 goto out;
1638 }
1639 if (curr_vccq_reg) {
1640 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
1641 if (rc)
1642 goto vdd_reg_deinit;
1643 }
1644 if (curr_vddp_reg) {
1645 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
1646 if (rc)
1647 goto vccq_reg_deinit;
1648 }
1649 goto out;
1650 } else {
1651 /* Deregister all regulators from regulator framework */
1652 goto vddp_reg_deinit;
1653 }
1654vddp_reg_deinit:
1655 if (curr_vddp_reg)
1656 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
1657vccq_reg_deinit:
1658 if (curr_vccq_reg)
1659 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
1660vdd_reg_deinit:
1661 if (curr_vdd_reg)
1662 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
1663out:
1664 return rc;
1665}
1666
1667static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
1668{
1669 int rc = 0;
1670
Subhash Jadavanicc922692011-08-01 23:05:01 +05301671 /* Put regulator in HPM (high power mode) */
1672 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
1673 if (rc < 0)
1674 goto out;
1675
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001676 if (!vreg->is_enabled) {
1677 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301678 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
1679 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001680 if (rc)
1681 goto out;
1682
1683 rc = regulator_enable(vreg->reg);
1684 if (rc) {
1685 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
1686 __func__, vreg->name, rc);
1687 goto out;
1688 }
1689 vreg->is_enabled = true;
1690 }
1691
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001692out:
1693 return rc;
1694}
1695
1696static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
1697{
1698 int rc = 0;
1699
1700 /* Never disable regulator marked as always_on */
1701 if (vreg->is_enabled && !vreg->always_on) {
1702 rc = regulator_disable(vreg->reg);
1703 if (rc) {
1704 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
1705 __func__, vreg->name, rc);
1706 goto out;
1707 }
1708 vreg->is_enabled = false;
1709
1710 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
1711 if (rc < 0)
1712 goto out;
1713
1714 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301715 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001716 if (rc)
1717 goto out;
1718 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
1719 /* Put always_on regulator in LPM (low power mode) */
1720 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
1721 if (rc < 0)
1722 goto out;
1723 }
1724out:
1725 return rc;
1726}
1727
1728static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
1729{
1730 int rc = 0, i;
1731 struct msm_mmc_slot_reg_data *curr_slot;
1732 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1733 struct msm_mmc_reg_data *vreg_table[3];
1734
1735 curr_slot = host->plat->vreg_data;
1736 if (!curr_slot)
1737 goto out;
1738
1739 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
1740 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
1741 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
1742
1743 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
1744 if (vreg_table[i]) {
1745 if (enable)
1746 rc = msmsdcc_vreg_enable(vreg_table[i]);
1747 else
1748 rc = msmsdcc_vreg_disable(vreg_table[i]);
1749 if (rc)
1750 goto out;
1751 }
1752 }
1753out:
1754 return rc;
1755}
1756
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301757static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001758{
1759 int rc = 0;
1760
1761 if (host->plat->vreg_data) {
1762 struct msm_mmc_reg_data *vddp_reg =
1763 host->plat->vreg_data->vddp_data;
1764
1765 if (vddp_reg && vddp_reg->is_enabled)
1766 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
1767 }
1768
1769 return rc;
1770}
1771
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301772static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
1773{
1774 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1775 int rc = 0;
1776
1777 if (curr_slot && curr_slot->vddp_data) {
1778 rc = msmsdcc_set_vddp_level(host,
1779 curr_slot->vddp_data->low_vol_level);
1780
1781 if (rc)
1782 pr_err("%s: %s: failed to change vddp level to %d",
1783 mmc_hostname(host->mmc), __func__,
1784 curr_slot->vddp_data->low_vol_level);
1785 }
1786
1787 return rc;
1788}
1789
1790static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
1791{
1792 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1793 int rc = 0;
1794
1795 if (curr_slot && curr_slot->vddp_data) {
1796 rc = msmsdcc_set_vddp_level(host,
1797 curr_slot->vddp_data->high_vol_level);
1798
1799 if (rc)
1800 pr_err("%s: %s: failed to change vddp level to %d",
1801 mmc_hostname(host->mmc), __func__,
1802 curr_slot->vddp_data->high_vol_level);
1803 }
1804
1805 return rc;
1806}
1807
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001808static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
1809{
1810 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
1811 return 1;
1812 return 0;
1813}
1814
1815static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
1816{
1817 if (enable) {
1818 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1819 clk_enable(host->dfab_pclk);
1820 if (!IS_ERR(host->pclk))
1821 clk_enable(host->pclk);
1822 clk_enable(host->clk);
1823 } else {
1824 clk_disable(host->clk);
1825 if (!IS_ERR(host->pclk))
1826 clk_disable(host->pclk);
1827 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1828 clk_disable(host->dfab_pclk);
1829 }
1830}
1831
1832static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
1833 unsigned int req_clk)
1834{
1835 unsigned int sel_clk = -1;
1836
1837 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
1838 unsigned char cnt;
1839
1840 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
1841 if (host->plat->sup_clk_table[cnt] > req_clk)
1842 break;
1843 else if (host->plat->sup_clk_table[cnt] == req_clk) {
1844 sel_clk = host->plat->sup_clk_table[cnt];
1845 break;
1846 } else
1847 sel_clk = host->plat->sup_clk_table[cnt];
1848 }
1849 } else {
1850 if ((req_clk < host->plat->msmsdcc_fmax) &&
1851 (req_clk > host->plat->msmsdcc_fmid))
1852 sel_clk = host->plat->msmsdcc_fmid;
1853 else
1854 sel_clk = req_clk;
1855 }
1856
1857 return sel_clk;
1858}
1859
1860static inline unsigned int msmsdcc_get_min_sup_clk_rate(
1861 struct msmsdcc_host *host)
1862{
1863 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
1864 return host->plat->sup_clk_table[0];
1865 else
1866 return host->plat->msmsdcc_fmin;
1867}
1868
1869static inline unsigned int msmsdcc_get_max_sup_clk_rate(
1870 struct msmsdcc_host *host)
1871{
1872 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
1873 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
1874 else
1875 return host->plat->msmsdcc_fmax;
1876}
1877
1878static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05301879{
1880 struct msm_mmc_gpio_data *curr;
1881 int i, rc = 0;
1882
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001883 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301884 for (i = 0; i < curr->size; i++) {
1885 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001886 if (curr->gpio[i].is_always_on &&
1887 curr->gpio[i].is_enabled)
1888 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301889 rc = gpio_request(curr->gpio[i].no,
1890 curr->gpio[i].name);
1891 if (rc) {
1892 pr_err("%s: gpio_request(%d, %s) failed %d\n",
1893 mmc_hostname(host->mmc),
1894 curr->gpio[i].no,
1895 curr->gpio[i].name, rc);
1896 goto free_gpios;
1897 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001898 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301899 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001900 if (curr->gpio[i].is_always_on)
1901 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301902 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001903 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301904 }
1905 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001906 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301907
1908free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001909 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05301910 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001911 curr->gpio[i].is_enabled = false;
1912 }
1913out:
1914 return rc;
1915}
1916
1917static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
1918{
1919 struct msm_mmc_pad_data *curr;
1920 int i;
1921
1922 curr = host->plat->pin_data->pad_data;
1923 for (i = 0; i < curr->drv->size; i++) {
1924 if (enable)
1925 msm_tlmm_set_hdrive(curr->drv->on[i].no,
1926 curr->drv->on[i].val);
1927 else
1928 msm_tlmm_set_hdrive(curr->drv->off[i].no,
1929 curr->drv->off[i].val);
1930 }
1931
1932 for (i = 0; i < curr->pull->size; i++) {
1933 if (enable)
1934 msm_tlmm_set_hdrive(curr->pull->on[i].no,
1935 curr->pull->on[i].val);
1936 else
1937 msm_tlmm_set_hdrive(curr->pull->off[i].no,
1938 curr->pull->off[i].val);
1939 }
1940
1941 return 0;
1942}
1943
1944static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
1945{
1946 int rc = 0;
1947
1948 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
1949 return 0;
1950
1951 if (host->plat->pin_data->is_gpio)
1952 rc = msmsdcc_setup_gpio(host, enable);
1953 else
1954 rc = msmsdcc_setup_pad(host, enable);
1955
1956 if (!rc)
1957 host->plat->pin_data->cfg_sts = enable;
1958
1959 return rc;
1960}
1961
1962static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
1963{
1964 unsigned int wakeup_irq;
1965
1966 wakeup_irq = (host->plat->sdiowakeup_irq) ?
1967 host->plat->sdiowakeup_irq :
1968 host->core_irqres->start;
1969
1970 if (!host->irq_wake_enabled) {
1971 enable_irq_wake(wakeup_irq);
1972 host->irq_wake_enabled = true;
1973 }
1974}
1975
1976static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
1977{
1978 unsigned int wakeup_irq;
1979
1980 wakeup_irq = (host->plat->sdiowakeup_irq) ?
1981 host->plat->sdiowakeup_irq :
1982 host->core_irqres->start;
1983
1984 if (host->irq_wake_enabled) {
1985 disable_irq_wake(wakeup_irq);
1986 host->irq_wake_enabled = false;
1987 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05301988}
1989
San Mehat9d2bd732009-09-22 16:44:22 -07001990static void
1991msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
1992{
1993 struct msmsdcc_host *host = mmc_priv(mmc);
1994 u32 clk = 0, pwr = 0;
1995 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08001996 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001997 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07001998
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001999 DBG(host, "ios->clock = %u\n", ios->clock);
Sahitya Tummala7a892482011-01-18 11:22:49 +05302000
San Mehat9d2bd732009-09-22 16:44:22 -07002001 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002002 spin_lock_irqsave(&host->lock, flags);
2003 if (!host->clks_on) {
2004 msmsdcc_setup_clocks(host, true);
2005 host->clks_on = 1;
2006 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2007 if (!host->plat->sdiowakeup_irq) {
2008 writel_relaxed(host->mci_irqenable,
2009 host->base + MMCIMASK0);
2010 mb();
2011 if (host->plat->cfg_mpm_sdiowakeup &&
2012 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2013 host->plat->cfg_mpm_sdiowakeup(
2014 mmc_dev(mmc), SDC_DAT1_DISWAKE);
2015 msmsdcc_disable_irq_wake(host);
2016 } else if (!(mmc->pm_flags &
2017 MMC_PM_WAKE_SDIO_IRQ)) {
2018 writel_relaxed(host->mci_irqenable,
2019 host->base + MMCIMASK0);
2020 }
2021 }
San Mehat9d2bd732009-09-22 16:44:22 -07002022 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002023 spin_unlock_irqrestore(&host->lock, flags);
2024
2025 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2026 /*
2027 * For DDR50 mode, controller needs clock rate to be
2028 * double than what is required on the SD card CLK pin.
2029 */
Subhash Jadavanib808efac2011-06-27 15:14:07 -07002030 if (ios->ddr || (ios->timing == MMC_TIMING_UHS_DDR50)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002031 /*
2032 * Make sure that we don't double the clock if
2033 * doubled clock rate is already set
2034 */
2035 if (!host->ddr_doubled_clk_rate ||
2036 (host->ddr_doubled_clk_rate &&
2037 (host->ddr_doubled_clk_rate != ios->clock))) {
2038 host->ddr_doubled_clk_rate =
2039 msmsdcc_get_sup_clk_rate(
2040 host, (ios->clock * 2));
2041 clock = host->ddr_doubled_clk_rate;
2042 }
2043 } else {
2044 host->ddr_doubled_clk_rate = 0;
2045 }
2046
2047 if (clock != host->clk_rate) {
2048 rc = clk_set_rate(host->clk, clock);
2049 if (rc < 0)
2050 pr_debug("%s: failed to set clk rate %u\n",
2051 mmc_hostname(mmc), clock);
2052 host->clk_rate = clock;
2053 }
2054 /*
2055 * give atleast 2 MCLK cycles delay for clocks
2056 * and SDCC core to stabilize
2057 */
2058 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002059 clk |= MCI_CLK_ENABLE;
2060 }
2061
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002062 if (ios->bus_width == MMC_BUS_WIDTH_8)
2063 clk |= MCI_CLK_WIDEBUS_8;
2064 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2065 clk |= MCI_CLK_WIDEBUS_4;
2066 else
2067 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002068
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002069 if (msmsdcc_is_pwrsave(host))
2070 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002071
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002072 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002073
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002074 host->tuning_needed = 0;
2075 /*
2076 * Select the controller timing mode according
2077 * to current bus speed mode
2078 */
2079 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2080 (ios->timing == MMC_TIMING_UHS_SDR50)) {
2081 clk |= (4 << 14);
2082 host->tuning_needed = 1;
Subhash Jadavanib808efac2011-06-27 15:14:07 -07002083 } else if (ios->ddr || ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002084 clk |= (3 << 14);
2085 } else {
2086 clk |= (2 << 14); /* feedback clock */
2087 }
2088
2089 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2090 clk |= (2 << 23);
2091
2092 if (host->io_pad_pwr_switch)
2093 clk |= IO_PAD_PWR_SWITCH;
2094
2095 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
San Mehat9d2bd732009-09-22 16:44:22 -07002096 pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002097 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2098 pwr |= msmsdcc_setup_vreg(host, !!ios->vdd);
San Mehat9d2bd732009-09-22 16:44:22 -07002099
2100 switch (ios->power_mode) {
2101 case MMC_POWER_OFF:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002102 htc_pwrsink_set(PWRSINK_SDCARD, 0);
2103 if (!host->sdcc_irq_disabled) {
2104 if (host->plat->cfg_mpm_sdiowakeup)
2105 host->plat->cfg_mpm_sdiowakeup(
2106 mmc_dev(mmc), SDC_DAT1_DISABLE);
2107 disable_irq(host->core_irqres->start);
2108 host->sdcc_irq_disabled = 1;
2109 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302110 /*
2111 * As VDD pad rail is always on, set low voltage for VDD
2112 * pad rail when slot is unused (when card is not present
2113 * or during system suspend).
2114 */
2115 msmsdcc_set_vddp_low_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002116 msmsdcc_setup_pins(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002117 break;
2118 case MMC_POWER_UP:
2119 pwr |= MCI_PWR_UP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002120 if (host->sdcc_irq_disabled) {
2121 if (host->plat->cfg_mpm_sdiowakeup)
2122 host->plat->cfg_mpm_sdiowakeup(
2123 mmc_dev(mmc), SDC_DAT1_ENABLE);
2124 enable_irq(host->core_irqres->start);
2125 host->sdcc_irq_disabled = 0;
2126 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302127 msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002128 msmsdcc_setup_pins(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07002129 break;
2130 case MMC_POWER_ON:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002131 htc_pwrsink_set(PWRSINK_SDCARD, 100);
San Mehat9d2bd732009-09-22 16:44:22 -07002132 pwr |= MCI_PWR_ON;
2133 break;
2134 }
2135
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002136 spin_lock_irqsave(&host->lock, flags);
2137 if (!host->clks_on) {
2138 /* force the clocks to be on */
2139 msmsdcc_setup_clocks(host, true);
2140 /*
2141 * give atleast 2 MCLK cycles delay for clocks
2142 * and SDCC core to stabilize
2143 */
2144 msmsdcc_delay(host);
2145 }
2146 writel_relaxed(clk, host->base + MMCICLOCK);
2147 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002148
2149 if (host->pwr != pwr) {
2150 host->pwr = pwr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002151 writel_relaxed(pwr, host->base + MMCIPOWER);
2152 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07002153 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002154 if (!host->clks_on) {
2155 /* force the clocks to be off */
2156 msmsdcc_setup_clocks(host, false);
2157 /*
2158 * give atleast 2 MCLK cycles delay for clocks
2159 * and SDCC core to stabilize
2160 */
2161 msmsdcc_delay(host);
2162 }
2163
2164 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
2165 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2166 if (!host->plat->sdiowakeup_irq) {
2167 writel_relaxed(MCI_SDIOINTMASK,
2168 host->base + MMCIMASK0);
2169 mb();
2170 if (host->plat->cfg_mpm_sdiowakeup &&
2171 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2172 host->plat->cfg_mpm_sdiowakeup(
2173 mmc_dev(mmc), SDC_DAT1_ENWAKE);
2174 msmsdcc_enable_irq_wake(host);
2175 } else if (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2176 writel_relaxed(0, host->base + MMCIMASK0);
2177 } else {
2178 writel_relaxed(MCI_SDIOINTMASK,
2179 host->base + MMCIMASK0);
2180 }
2181 msmsdcc_delay(host);
2182 }
2183 msmsdcc_setup_clocks(host, false);
2184 host->clks_on = 0;
2185 }
San Mehat4adbbcc2009-11-08 13:00:37 -08002186 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002187}
2188
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002189int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2190{
2191 struct msmsdcc_host *host = mmc_priv(mmc);
2192 u32 clk;
2193
2194 clk = readl_relaxed(host->base + MMCICLOCK);
2195 pr_debug("Changing to pwr_save=%d", pwrsave);
2196 if (pwrsave && msmsdcc_is_pwrsave(host))
2197 clk |= MCI_CLK_PWRSAVE;
2198 else
2199 clk &= ~MCI_CLK_PWRSAVE;
2200 writel_relaxed(clk, host->base + MMCICLOCK);
2201 mb();
2202
2203 return 0;
2204}
2205
2206static int msmsdcc_get_ro(struct mmc_host *mmc)
2207{
2208 int status = -ENOSYS;
2209 struct msmsdcc_host *host = mmc_priv(mmc);
2210
2211 if (host->plat->wpswitch) {
2212 status = host->plat->wpswitch(mmc_dev(mmc));
2213 } else if (host->plat->wpswitch_gpio) {
2214 status = gpio_request(host->plat->wpswitch_gpio,
2215 "SD_WP_Switch");
2216 if (status) {
2217 pr_err("%s: %s: Failed to request GPIO %d\n",
2218 mmc_hostname(mmc), __func__,
2219 host->plat->wpswitch_gpio);
2220 } else {
2221 status = gpio_direction_input(
2222 host->plat->wpswitch_gpio);
2223 if (!status) {
2224 /*
2225 * Wait for atleast 300ms as debounce
2226 * time for GPIO input to stabilize.
2227 */
2228 msleep(300);
2229 status = gpio_get_value_cansleep(
2230 host->plat->wpswitch_gpio);
2231 status ^= !host->plat->wpswitch_polarity;
2232 }
2233 gpio_free(host->plat->wpswitch_gpio);
2234 }
2235 }
2236
2237 if (status < 0)
2238 status = -ENOSYS;
2239 pr_debug("%s: Card read-only status %d\n", __func__, status);
2240
2241 return status;
2242}
2243
2244#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002245static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2246{
2247 struct msmsdcc_host *host = mmc_priv(mmc);
2248 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002249
2250 if (enable) {
2251 spin_lock_irqsave(&host->lock, flags);
2252 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
2253 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
2254 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2255 spin_unlock_irqrestore(&host->lock, flags);
2256 } else {
2257 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
2258 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
2259 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2260 }
2261 mb();
2262}
2263#endif /* CONFIG_MMC_MSM_SDIO_SUPPORT */
2264
2265#ifdef CONFIG_PM_RUNTIME
2266static int msmsdcc_enable(struct mmc_host *mmc)
2267{
2268 int rc;
2269 struct device *dev = mmc->parent;
2270
2271 if (atomic_read(&dev->power.usage_count) > 0) {
2272 pm_runtime_get_noresume(dev);
2273 goto out;
2274 }
2275
2276 rc = pm_runtime_get_sync(dev);
2277
2278 if (rc < 0) {
2279 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2280 __func__, rc);
2281 return rc;
2282 }
2283out:
2284 return 0;
2285}
2286
2287static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2288{
2289 int rc;
2290
2291 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO)
2292 return -ENOTSUPP;
2293
2294 rc = pm_runtime_put_sync(mmc->parent);
2295
2296 if (rc < 0)
2297 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2298 __func__, rc);
2299 return rc;
2300}
2301#else
2302#define msmsdcc_enable NULL
2303#define msmsdcc_disable NULL
2304#endif
2305
2306static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2307 struct mmc_ios *ios)
2308{
2309 struct msmsdcc_host *host = mmc_priv(mmc);
2310 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302311 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002312
2313 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2314 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302315 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002316 goto out;
2317 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2318 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302319 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002320 goto out;
2321 }
San Mehat9d2bd732009-09-22 16:44:22 -07002322
2323 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002324 /*
2325 * If we are here means voltage switch from high voltage to
2326 * low voltage is required
2327 */
2328
2329 /*
2330 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2331 * register until they become all zeros.
2332 */
2333 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302334 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002335 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2336 mmc_hostname(mmc), __func__);
2337 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002338 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002339
2340 /* Stop SD CLK output. */
2341 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2342 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2343
San Mehat9d2bd732009-09-22 16:44:22 -07002344 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002345
2346 /*
2347 * Switch VDDPX from high voltage to low voltage
2348 * to change the VDD of the SD IO pads.
2349 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302350 rc = msmsdcc_set_vddp_low_vol(host);
2351 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002352 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002353
2354 spin_lock_irqsave(&host->lock, flags);
2355 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2356 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
2357 host->io_pad_pwr_switch = 1;
2358 spin_unlock_irqrestore(&host->lock, flags);
2359
2360 /* Wait 5 ms for the voltage regulater in the card to become stable. */
2361 usleep_range(5000, 5500);
2362
2363 spin_lock_irqsave(&host->lock, flags);
2364 /* Start SD CLK output. */
2365 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2366 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2367 spin_unlock_irqrestore(&host->lock, flags);
2368
2369 /*
2370 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
2371 * don't become all ones within 1 ms then a Voltage Switch
2372 * sequence has failed and a power cycle to the card is required.
2373 * Otherwise Voltage Switch sequence is completed successfully.
2374 */
2375 usleep_range(1000, 1500);
2376
2377 spin_lock_irqsave(&host->lock, flags);
2378 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
2379 != (0xF << 1)) {
2380 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
2381 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302382 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002383 goto out_unlock;
2384 }
2385
2386out_unlock:
2387 spin_unlock_irqrestore(&host->lock, flags);
2388out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302389 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002390}
2391
2392static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2393 u8 phase);
2394/* Initialize the DLL (Programmable Delay Line ) */
2395static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
2396{
2397 int rc = 0;
2398 u32 wait_timeout;
2399
2400 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
2401 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2402 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2403
2404 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
2405 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2406 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2407
2408 msmsdcc_delay(host);
2409
2410 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
2411 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2412 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2413
2414 /* Initialize the phase to 0 */
2415 rc = msmsdcc_config_cm_sdc4_dll_phase(host, 0);
2416 if (rc)
2417 goto out;
2418
2419 wait_timeout = 1000;
2420 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
2421 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
2422 /* max. wait for 1 sec for LOCK bit to be set */
2423 if (--wait_timeout == 0) {
2424 pr_err("%s: %s: DLL failed to lock at phase: %d",
2425 mmc_hostname(host->mmc), __func__, 0);
2426 rc = -1;
2427 goto out;
2428 }
2429 /* wait for 1ms */
2430 usleep_range(1000, 1500);
2431 }
2432out:
2433 return rc;
2434}
2435
2436/*
2437 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
2438 * calibration sequence. This function should be called before
2439 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
2440 * commands (CMD17/CMD18).
2441 */
2442static void msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
2443{
2444 /* Set CDR_EN bit to 1. */
2445 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) |
2446 MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2447
2448 /* Set CDR_EXT_EN bit to 0. */
2449 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2450 & ~MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2451
2452 /* Set CK_OUT_EN bit to 0. */
2453 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2454 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2455
2456 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2457 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)
2458 ;
2459
2460 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2461 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2462 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2463
2464 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register is 1. */
2465 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN))
2466 ;
2467}
2468
2469static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2470 u8 phase)
2471{
2472 int rc = 0;
2473 u32 mclk_freq = 0;
2474 u32 wait_timeout;
2475
2476 /* Set CDR_EN bit to 0. */
2477 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2478 & ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2479
2480 /* Set CDR_EXT_EN bit to 1. */
2481 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2482 | MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2483
2484 /* Program the MCLK value to MCLK_FREQ bit field */
2485 if (host->clk_rate <= 112000000)
2486 mclk_freq = 0;
2487 else if (host->clk_rate <= 125000000)
2488 mclk_freq = 1;
2489 else if (host->clk_rate <= 137000000)
2490 mclk_freq = 2;
2491 else if (host->clk_rate <= 150000000)
2492 mclk_freq = 3;
2493 else if (host->clk_rate <= 162000000)
2494 mclk_freq = 4;
2495 else if (host->clk_rate <= 175000000)
2496 mclk_freq = 5;
2497 else if (host->clk_rate <= 187000000)
2498 mclk_freq = 6;
2499 else if (host->clk_rate <= 200000000)
2500 mclk_freq = 7;
2501
2502 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2503 & ~(7 << 24)) | (mclk_freq << 24)),
2504 host->base + MCI_DLL_CONFIG);
2505
2506 /* Set CK_OUT_EN bit to 0. */
2507 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2508 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2509
2510 /* Set DLL_EN bit to 1. */
2511 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2512 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
2513
2514 wait_timeout = 1000;
2515 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2516 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN) {
2517 /* max. wait for 1 sec for LOCK bit for be set */
2518 if (--wait_timeout == 0) {
2519 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 0",
2520 mmc_hostname(host->mmc), __func__, phase);
2521 rc = -1;
2522 goto out;
2523 }
2524 /* wait for 1ms */
2525 usleep_range(1000, 1500);
2526 }
2527
2528 /*
2529 * Write the selected DLL clock output phase (0 ... 15)
2530 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
2531 */
2532 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2533 & ~(0xF << 20)) | (phase << 20)),
2534 host->base + MCI_DLL_CONFIG);
2535
2536 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2537 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2538 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2539
2540 wait_timeout = 1000;
2541 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
2542 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)) {
2543 /* max. wait for 1 sec for LOCK bit for be set */
2544 if (--wait_timeout == 0) {
2545 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 1",
2546 mmc_hostname(host->mmc), __func__, phase);
2547 rc = -1;
2548 goto out;
2549 }
2550 /* wait for 1ms */
2551 usleep_range(1000, 1500);
2552 }
2553out:
2554 return rc;
2555}
2556
2557static int msmsdcc_execute_tuning(struct mmc_host *mmc)
2558{
2559 struct msmsdcc_host *host = mmc_priv(mmc);
2560 u8 phase;
2561 u8 *data_buf;
2562 u8 tuned_phases[16], tuned_phase_cnt = 0;
2563 int rc = 0;
2564
2565 /* Tuning is only required for SDR50 & SDR104 modes */
2566 if (!host->tuning_needed) {
2567 rc = 0;
2568 goto out;
2569 }
2570
2571 host->cmd19_tuning_in_progress = 1;
2572 /*
2573 * Make sure that clock is always enabled when DLL
2574 * tuning is in progress. Keeping PWRSAVE ON may
2575 * turn off the clock. So let's disable the PWRSAVE
2576 * here and re-enable it once tuning is completed.
2577 */
2578 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2579 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2580 /* first of all reset the tuning block */
2581 rc = msmsdcc_init_cm_sdc4_dll(host);
2582 if (rc)
2583 goto out;
2584
2585 data_buf = kmalloc(64, GFP_KERNEL);
2586 if (!data_buf) {
2587 rc = -ENOMEM;
2588 goto out;
2589 }
2590
2591 phase = 0;
2592 do {
2593 struct mmc_command cmd = {0};
2594 struct mmc_data data = {0};
2595 struct mmc_request mrq = {
2596 .cmd = &cmd,
2597 .data = &data
2598 };
2599 struct scatterlist sg;
2600
2601 /* set the phase in delay line hw block */
2602 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2603 if (rc)
2604 goto kfree;
2605
2606 cmd.opcode = MMC_SEND_TUNING_BLOCK;
2607 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
2608
2609 data.blksz = 64;
2610 data.blocks = 1;
2611 data.flags = MMC_DATA_READ;
2612 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
2613
2614 data.sg = &sg;
2615 data.sg_len = 1;
2616 sg_init_one(&sg, data_buf, 64);
2617 memset(data_buf, 0, 64);
2618 mmc_wait_for_req(mmc, &mrq);
2619
2620 if (!cmd.error && !data.error &&
2621 !memcmp(data_buf, cmd19_tuning_block, 64)) {
2622 /* tuning is successful with this tuning point */
2623 tuned_phases[tuned_phase_cnt++] = phase;
2624 }
2625 } while (++phase < 16);
2626
2627 kfree(data_buf);
2628
2629 if (tuned_phase_cnt) {
2630 tuned_phase_cnt--;
2631 tuned_phase_cnt = (tuned_phase_cnt * 3) / 4;
2632 phase = tuned_phases[tuned_phase_cnt];
2633 /*
2634 * Finally set the selected phase in delay
2635 * line hw block.
2636 */
2637 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2638 if (rc)
2639 goto out;
2640 } else {
2641 /* tuning failed */
2642 rc = -EAGAIN;
2643 pr_err("%s: %s: no tuning point found",
2644 mmc_hostname(mmc), __func__);
2645 }
2646 goto out;
2647
2648kfree:
2649 kfree(data_buf);
2650out:
2651 /* re-enable PWESAVE */
2652 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2653 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2654 host->cmd19_tuning_in_progress = 0;
2655 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07002656}
2657
2658static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002659 .enable = msmsdcc_enable,
2660 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07002661 .request = msmsdcc_request,
2662 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002663 .get_ro = msmsdcc_get_ro,
2664#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002665 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002666#endif
2667 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
2668 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07002669};
2670
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002671static unsigned int
2672msmsdcc_slot_status(struct msmsdcc_host *host)
2673{
2674 int status;
2675 unsigned int gpio_no = host->plat->status_gpio;
2676
2677 status = gpio_request(gpio_no, "SD_HW_Detect");
2678 if (status) {
2679 pr_err("%s: %s: Failed to request GPIO %d\n",
2680 mmc_hostname(host->mmc), __func__, gpio_no);
2681 } else {
2682 status = gpio_direction_input(gpio_no);
2683 if (!status)
2684 status = !gpio_get_value_cansleep(gpio_no);
2685 gpio_free(gpio_no);
2686 }
2687 return status;
2688}
2689
San Mehat9d2bd732009-09-22 16:44:22 -07002690static void
2691msmsdcc_check_status(unsigned long data)
2692{
2693 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
2694 unsigned int status;
2695
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002696 if (host->plat->status || host->plat->status_gpio) {
2697 if (host->plat->status)
2698 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07002699 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002700 status = msmsdcc_slot_status(host);
2701
2702 host->eject = !status;
2703 if (status ^ host->oldstat) {
2704 pr_info("%s: Slot status change detected (%d -> %d)\n",
2705 mmc_hostname(host->mmc), host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07002706 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002707 }
2708 host->oldstat = status;
2709 } else {
2710 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07002711 }
San Mehat9d2bd732009-09-22 16:44:22 -07002712}
2713
2714static irqreturn_t
2715msmsdcc_platform_status_irq(int irq, void *dev_id)
2716{
2717 struct msmsdcc_host *host = dev_id;
2718
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002719 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07002720 msmsdcc_check_status((unsigned long) host);
2721 return IRQ_HANDLED;
2722}
2723
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002724static irqreturn_t
2725msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
2726{
2727 struct msmsdcc_host *host = dev_id;
2728
2729 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
2730 spin_lock(&host->lock);
2731 if (!host->sdio_irq_disabled) {
2732 disable_irq_nosync(irq);
2733 if (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2734 wake_lock(&host->sdio_wlock);
2735 msmsdcc_disable_irq_wake(host);
2736 }
2737 host->sdio_irq_disabled = 1;
2738 }
2739 if (host->plat->is_sdio_al_client) {
2740 if (!host->clks_on) {
2741 msmsdcc_setup_clocks(host, true);
2742 host->clks_on = 1;
2743 }
2744 if (host->sdcc_irq_disabled) {
2745 writel_relaxed(host->mci_irqenable,
2746 host->base + MMCIMASK0);
2747 mb();
2748 enable_irq(host->core_irqres->start);
2749 host->sdcc_irq_disabled = 0;
2750 }
2751 wake_lock(&host->sdio_wlock);
2752 }
2753 spin_unlock(&host->lock);
2754
2755 return IRQ_HANDLED;
2756}
2757
San Mehat9d2bd732009-09-22 16:44:22 -07002758static void
2759msmsdcc_status_notify_cb(int card_present, void *dev_id)
2760{
2761 struct msmsdcc_host *host = dev_id;
2762
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002763 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07002764 card_present);
2765 msmsdcc_check_status((unsigned long) host);
2766}
2767
San Mehat9d2bd732009-09-22 16:44:22 -07002768static int
2769msmsdcc_init_dma(struct msmsdcc_host *host)
2770{
2771 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
2772 host->dma.host = host;
2773 host->dma.channel = -1;
2774
2775 if (!host->dmares)
2776 return -ENODEV;
2777
2778 host->dma.nc = dma_alloc_coherent(NULL,
2779 sizeof(struct msmsdcc_nc_dmadata),
2780 &host->dma.nc_busaddr,
2781 GFP_KERNEL);
2782 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07002783 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07002784 return -ENOMEM;
2785 }
2786 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
2787 host->dma.cmd_busaddr = host->dma.nc_busaddr;
2788 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
2789 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
2790 host->dma.channel = host->dmares->start;
2791
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;
3320 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003321 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07003322
3323 /* must have platform data */
3324 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003325 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003326 ret = -EINVAL;
3327 goto out;
3328 }
3329
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003330 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07003331 return -EINVAL;
3332
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003333 if (plat->is_sdio_al_client)
3334 if (!plat->sdio_lpm_gpio_setup || !plat->sdiowakeup_irq)
3335 return -EINVAL;
3336
San Mehat9d2bd732009-09-22 16:44:22 -07003337 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003338 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003339 return -ENXIO;
3340 }
3341
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003342 for (i = 0; i < pdev->num_resources; i++) {
3343 if (pdev->resource[i].flags & IORESOURCE_MEM) {
3344 if (!strcmp(pdev->resource[i].name,
3345 "sdcc_dml_addr"))
3346 dml_memres = &pdev->resource[i];
3347 else if (!strcmp(pdev->resource[i].name,
3348 "sdcc_bam_addr"))
3349 bam_memres = &pdev->resource[i];
3350 else
3351 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07003352
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003353 }
3354 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
3355 if (!strcmp(pdev->resource[i].name,
3356 "sdcc_bam_irq"))
3357 bam_irqres = &pdev->resource[i];
3358 else
3359 core_irqres = &pdev->resource[i];
3360 }
3361 if (pdev->resource[i].flags & IORESOURCE_DMA)
3362 dmares = &pdev->resource[i];
3363 }
3364
3365 if (!core_irqres || !core_memres) {
3366 pr_err("%s: Invalid sdcc core resource\n", __func__);
3367 return -ENXIO;
3368 }
3369
3370 /*
3371 * Both BAM and DML memory resource should be preset.
3372 * BAM IRQ resource should also be present.
3373 */
3374 if ((bam_memres && !dml_memres) ||
3375 (!bam_memres && dml_memres) ||
3376 ((bam_memres && dml_memres) && !bam_irqres)) {
3377 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003378 return -ENXIO;
3379 }
3380
3381 /*
3382 * Setup our host structure
3383 */
San Mehat9d2bd732009-09-22 16:44:22 -07003384 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
3385 if (!mmc) {
3386 ret = -ENOMEM;
3387 goto out;
3388 }
3389
3390 host = mmc_priv(mmc);
3391 host->pdev_id = pdev->id;
3392 host->plat = plat;
3393 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08003394 host->curr.cmd = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003395 if (bam_memres && dml_memres && bam_irqres)
3396 host->is_sps_mode = 1;
3397 else if (dmares)
3398 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07003399
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003400 host->base = ioremap(core_memres->start,
3401 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07003402 if (!host->base) {
3403 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003404 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003405 }
3406
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003407 host->core_irqres = core_irqres;
3408 host->bam_irqres = bam_irqres;
3409 host->core_memres = core_memres;
3410 host->dml_memres = dml_memres;
3411 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07003412 host->dmares = dmares;
3413 spin_lock_init(&host->lock);
3414
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003415#ifdef CONFIG_MMC_EMBEDDED_SDIO
3416 if (plat->embedded_sdio)
3417 mmc_set_embedded_sdio_data(mmc,
3418 &plat->embedded_sdio->cis,
3419 &plat->embedded_sdio->cccr,
3420 plat->embedded_sdio->funcs,
3421 plat->embedded_sdio->num_funcs);
3422#endif
3423
Sahitya Tummala62612cf2010-12-08 15:03:03 +05303424 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
3425 (unsigned long)host);
3426
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003427 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
3428 (unsigned long)host);
3429 if (host->is_dma_mode) {
3430 /* Setup DMA */
3431 ret = msmsdcc_init_dma(host);
3432 if (ret)
3433 goto ioremap_free;
3434 } else {
3435 host->dma.channel = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003436 }
3437
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003438 /*
3439 * Setup SDCC clock if derived from Dayatona
3440 * fabric core clock.
3441 */
3442 if (plat->pclk_src_dfab) {
3443 host->dfab_pclk = clk_get(&pdev->dev, "dfab_sdc_clk");
3444 if (!IS_ERR(host->dfab_pclk)) {
3445 /* Set the clock rate to 64MHz for max. performance */
3446 ret = clk_set_rate(host->dfab_pclk, 64000000);
3447 if (ret)
3448 goto dfab_pclk_put;
3449 ret = clk_enable(host->dfab_pclk);
3450 if (ret)
3451 goto dfab_pclk_put;
3452 } else
3453 goto dma_free;
3454 }
3455
3456 /*
3457 * Setup main peripheral bus clock
3458 */
3459 host->pclk = clk_get(&pdev->dev, "sdc_pclk");
3460 if (!IS_ERR(host->pclk)) {
3461 ret = clk_enable(host->pclk);
3462 if (ret)
3463 goto pclk_put;
3464
3465 host->pclk_rate = clk_get_rate(host->pclk);
3466 }
3467
3468 /*
3469 * Setup SDC MMC clock
3470 */
San Mehat9d2bd732009-09-22 16:44:22 -07003471 host->clk = clk_get(&pdev->dev, "sdc_clk");
3472 if (IS_ERR(host->clk)) {
3473 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003474 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07003475 }
3476
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003477 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
3478 if (ret) {
3479 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
3480 goto clk_put;
3481 }
3482
3483 ret = clk_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003484 if (ret)
3485 goto clk_put;
3486
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003487 host->clk_rate = clk_get_rate(host->clk);
3488
3489 host->clks_on = 1;
3490
3491 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07003492 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003493 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07003494 goto clk_disable;
3495 }
3496
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003497
3498 /* Clocks has to be running before accessing SPS/DML HW blocks */
3499 if (host->is_sps_mode) {
3500 /* Initialize SPS */
3501 ret = msmsdcc_sps_init(host);
3502 if (ret)
3503 goto vreg_deinit;
3504 /* Initialize DML */
3505 ret = msmsdcc_dml_init(host);
3506 if (ret)
3507 goto sps_exit;
3508 }
San Mehat9d2bd732009-09-22 16:44:22 -07003509
San Mehat9d2bd732009-09-22 16:44:22 -07003510 /*
3511 * Setup MMC host structure
3512 */
3513 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003514 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
3515 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003516 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003517 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
3518 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07003519
San Mehat9d2bd732009-09-22 16:44:22 -07003520 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003521 mmc->caps |= plat->uhs_caps;
3522 /*
3523 * XPC controls the maximum current in the default speed mode of SDXC
3524 * card. XPC=0 means 100mA (max.) but speed class is not supported.
3525 * XPC=1 means 150mA (max.) and speed class is supported.
3526 */
3527 if (plat->xpc_cap)
3528 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
3529 MMC_CAP_SET_XPC_180);
3530
3531 if (plat->nonremovable)
3532 mmc->caps |= MMC_CAP_NONREMOVABLE;
3533#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
3534 mmc->caps |= MMC_CAP_SDIO_IRQ;
3535#endif
3536
3537 if (plat->is_sdio_al_client)
3538 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07003539
Martin K. Petersena36274e2010-09-10 01:33:59 -04003540 mmc->max_segs = NR_SG;
San Mehat9d2bd732009-09-22 16:44:22 -07003541 mmc->max_blk_size = 4096; /* MCI_DATA_CTL BLOCKSIZE up to 4096 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003542 mmc->max_blk_count = 65535;
San Mehat9d2bd732009-09-22 16:44:22 -07003543
3544 mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */
3545 mmc->max_seg_size = mmc->max_req_size;
3546
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003547 writel_relaxed(0, host->base + MMCIMASK0);
3548 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -07003549
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003550 /* Delay needed (MMCIMASK0 was just written above) */
3551 msmsdcc_delay(host);
3552 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
3553 mb();
3554 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07003555
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003556 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
3557 DRIVER_NAME " (cmd)", host);
3558 if (ret)
3559 goto dml_exit;
3560
3561 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
3562 DRIVER_NAME " (pio)", host);
3563 if (ret)
3564 goto irq_free;
3565
3566 /*
3567 * Enable SDCC IRQ only when host is powered on. Otherwise, this
3568 * IRQ is un-necessarily being monitored by MPM (Modem power
3569 * management block) during idle-power collapse. The MPM will be
3570 * configured to monitor the DATA1 GPIO line with level-low trigger
3571 * and thus depending on the GPIO status, it prevents TCXO shutdown
3572 * during idle-power collapse.
3573 */
3574 disable_irq(core_irqres->start);
3575 host->sdcc_irq_disabled = 1;
3576
3577 if (plat->sdiowakeup_irq) {
3578 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3579 mmc_hostname(mmc));
3580 ret = request_irq(plat->sdiowakeup_irq,
3581 msmsdcc_platform_sdiowakeup_irq,
3582 IRQF_SHARED | IRQF_TRIGGER_LOW,
3583 DRIVER_NAME "sdiowakeup", host);
3584 if (ret) {
3585 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
3586 plat->sdiowakeup_irq, ret);
3587 goto pio_irq_free;
3588 } else {
3589 spin_lock_irqsave(&host->lock, flags);
3590 if (!host->sdio_irq_disabled) {
3591 disable_irq_nosync(plat->sdiowakeup_irq);
3592 host->sdio_irq_disabled = 1;
3593 }
3594 spin_unlock_irqrestore(&host->lock, flags);
3595 }
3596 }
3597
3598 if (plat->cfg_mpm_sdiowakeup) {
3599 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3600 mmc_hostname(mmc));
3601 }
3602
3603 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
3604 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003605 /*
3606 * Setup card detect change
3607 */
3608
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003609 if (plat->status || plat->status_gpio) {
3610 if (plat->status)
3611 host->oldstat = plat->status(mmc_dev(host->mmc));
3612 else
3613 host->oldstat = msmsdcc_slot_status(host);
3614 host->eject = !host->oldstat;
3615 }
San Mehat9d2bd732009-09-22 16:44:22 -07003616
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003617 if (plat->status_irq) {
3618 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07003619 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003620 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07003621 DRIVER_NAME " (slot)",
3622 host);
3623 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003624 pr_err("Unable to get slot IRQ %d (%d)\n",
3625 plat->status_irq, ret);
3626 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003627 }
3628 } else if (plat->register_status_notify) {
3629 plat->register_status_notify(msmsdcc_status_notify_cb, host);
3630 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003631 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07003632 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003633
3634 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003635
3636 ret = pm_runtime_set_active(&(pdev)->dev);
3637 if (ret < 0)
3638 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3639 __func__, ret);
3640 /*
3641 * There is no notion of suspend/resume for SD/MMC/SDIO
3642 * cards. So host can be suspended/resumed with out
3643 * worrying about its children.
3644 */
3645 pm_suspend_ignore_children(&(pdev)->dev, true);
3646
3647 /*
3648 * MMC/SD/SDIO bus suspend/resume operations are defined
3649 * only for the slots that will be used for non-removable
3650 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
3651 * defined. Otherwise, they simply become card removal and
3652 * insertion events during suspend and resume respectively.
3653 * Hence, enable run-time PM only for slots for which bus
3654 * suspend/resume operations are defined.
3655 */
3656#ifdef CONFIG_MMC_UNSAFE_RESUME
3657 /*
3658 * If this capability is set, MMC core will enable/disable host
3659 * for every claim/release operation on a host. We use this
3660 * notification to increment/decrement runtime pm usage count.
3661 */
3662 mmc->caps |= MMC_CAP_DISABLE;
3663 pm_runtime_enable(&(pdev)->dev);
3664#else
3665 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
3666 mmc->caps |= MMC_CAP_DISABLE;
3667 pm_runtime_enable(&(pdev)->dev);
3668 }
3669#endif
3670 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
3671 (unsigned long)host);
3672
San Mehat9d2bd732009-09-22 16:44:22 -07003673 mmc_add_host(mmc);
3674
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003675#ifdef CONFIG_HAS_EARLYSUSPEND
3676 host->early_suspend.suspend = msmsdcc_early_suspend;
3677 host->early_suspend.resume = msmsdcc_late_resume;
3678 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
3679 register_early_suspend(&host->early_suspend);
3680#endif
San Mehat9d2bd732009-09-22 16:44:22 -07003681
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003682 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d\n",
3683 mmc_hostname(mmc), (unsigned long long)core_memres->start,
3684 (unsigned int) core_irqres->start,
3685 (unsigned int) plat->status_irq, host->dma.channel);
3686
3687 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
3688 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
3689 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
3690 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
3691 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
3692 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
3693 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
3694 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
3695 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
3696 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
3697 host->eject);
3698 pr_info("%s: Power save feature enable = %d\n",
3699 mmc_hostname(mmc), msmsdcc_pwrsave);
3700
3701 if (host->is_dma_mode && host->dma.channel != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003702 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003703 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003704 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003705 mmc_hostname(mmc), host->dma.cmd_busaddr,
3706 host->dma.cmdptr_busaddr);
3707 } else if (host->is_sps_mode) {
3708 pr_info("%s: SPS-BAM data transfer mode available\n",
3709 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003710 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003711 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003712
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003713#if defined(CONFIG_DEBUG_FS)
3714 msmsdcc_dbg_createhost(host);
3715#endif
3716 if (!plat->status_irq) {
3717 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
3718 if (ret)
3719 goto platform_irq_free;
3720 }
San Mehat9d2bd732009-09-22 16:44:22 -07003721 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003722
3723 platform_irq_free:
3724 del_timer_sync(&host->req_tout_timer);
3725 pm_runtime_disable(&(pdev)->dev);
3726 pm_runtime_set_suspended(&(pdev)->dev);
3727
3728 if (plat->status_irq)
3729 free_irq(plat->status_irq, host);
3730 sdiowakeup_irq_free:
3731 wake_lock_destroy(&host->sdio_suspend_wlock);
3732 if (plat->sdiowakeup_irq)
3733 free_irq(plat->sdiowakeup_irq, host);
3734 pio_irq_free:
3735 if (plat->sdiowakeup_irq)
3736 wake_lock_destroy(&host->sdio_wlock);
3737 free_irq(core_irqres->start, host);
3738 irq_free:
3739 free_irq(core_irqres->start, host);
3740 dml_exit:
3741 if (host->is_sps_mode)
3742 msmsdcc_dml_exit(host);
3743 sps_exit:
3744 if (host->is_sps_mode)
3745 msmsdcc_sps_exit(host);
3746 vreg_deinit:
3747 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07003748 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003749 clk_disable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003750 clk_put:
3751 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003752 pclk_disable:
3753 if (!IS_ERR(host->pclk))
3754 clk_disable(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07003755 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003756 if (!IS_ERR(host->pclk))
3757 clk_put(host->pclk);
3758 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3759 clk_disable(host->dfab_pclk);
3760 dfab_pclk_put:
3761 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3762 clk_put(host->dfab_pclk);
3763 dma_free:
3764 if (host->is_dma_mode) {
3765 if (host->dmares)
3766 dma_free_coherent(NULL,
3767 sizeof(struct msmsdcc_nc_dmadata),
3768 host->dma.nc, host->dma.nc_busaddr);
3769 }
3770 ioremap_free:
3771 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07003772 host_free:
3773 mmc_free_host(mmc);
3774 out:
3775 return ret;
3776}
3777
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003778static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07003779{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003780 struct mmc_host *mmc = mmc_get_drvdata(pdev);
3781 struct mmc_platform_data *plat;
3782 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07003783
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003784 if (!mmc)
3785 return -ENXIO;
3786
3787 if (pm_runtime_suspended(&(pdev)->dev))
3788 pm_runtime_resume(&(pdev)->dev);
3789
3790 host = mmc_priv(mmc);
3791
3792 DBG(host, "Removing SDCC device = %d\n", pdev->id);
3793 plat = host->plat;
3794
3795 if (!plat->status_irq)
3796 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
3797
3798 del_timer_sync(&host->req_tout_timer);
3799 tasklet_kill(&host->dma_tlet);
3800 tasklet_kill(&host->sps.tlet);
3801 mmc_remove_host(mmc);
3802
3803 if (plat->status_irq)
3804 free_irq(plat->status_irq, host);
3805
3806 wake_lock_destroy(&host->sdio_suspend_wlock);
3807 if (plat->sdiowakeup_irq) {
3808 wake_lock_destroy(&host->sdio_wlock);
3809 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
3810 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07003811 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003812
3813 free_irq(host->core_irqres->start, host);
3814 free_irq(host->core_irqres->start, host);
3815
3816 clk_put(host->clk);
3817 if (!IS_ERR(host->pclk))
3818 clk_put(host->pclk);
3819 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3820 clk_put(host->dfab_pclk);
3821
3822 msmsdcc_vreg_init(host, false);
3823
3824 if (host->is_dma_mode) {
3825 if (host->dmares)
3826 dma_free_coherent(NULL,
3827 sizeof(struct msmsdcc_nc_dmadata),
3828 host->dma.nc, host->dma.nc_busaddr);
3829 }
3830
3831 if (host->is_sps_mode) {
3832 msmsdcc_dml_exit(host);
3833 msmsdcc_sps_exit(host);
3834 }
3835
3836 iounmap(host->base);
3837 mmc_free_host(mmc);
3838
3839#ifdef CONFIG_HAS_EARLYSUSPEND
3840 unregister_early_suspend(&host->early_suspend);
3841#endif
3842 pm_runtime_disable(&(pdev)->dev);
3843 pm_runtime_set_suspended(&(pdev)->dev);
3844
3845 return 0;
3846}
3847
3848#ifdef CONFIG_MSM_SDIO_AL
3849int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
3850{
3851 struct msmsdcc_host *host = mmc_priv(mmc);
3852 unsigned long flags;
3853
3854 spin_lock_irqsave(&host->lock, flags);
3855 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
3856 enable ? "En" : "Dis");
3857
3858 if (enable) {
3859 if (!host->sdcc_irq_disabled) {
3860 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05303861 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003862 host->sdcc_irq_disabled = 1;
3863 }
3864
3865 if (host->clks_on) {
3866 msmsdcc_setup_clocks(host, false);
3867 host->clks_on = 0;
3868 }
3869
3870 if (!host->sdio_gpio_lpm) {
3871 spin_unlock_irqrestore(&host->lock, flags);
3872 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
3873 spin_lock_irqsave(&host->lock, flags);
3874 host->sdio_gpio_lpm = 1;
3875 }
3876
3877 if (host->sdio_irq_disabled) {
3878 msmsdcc_enable_irq_wake(host);
3879 enable_irq(host->plat->sdiowakeup_irq);
3880 host->sdio_irq_disabled = 0;
3881 }
3882 } else {
3883 if (!host->sdio_irq_disabled) {
3884 disable_irq_nosync(host->plat->sdiowakeup_irq);
3885 host->sdio_irq_disabled = 1;
3886 msmsdcc_disable_irq_wake(host);
3887 }
3888
3889 if (host->sdio_gpio_lpm) {
3890 spin_unlock_irqrestore(&host->lock, flags);
3891 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
3892 spin_lock_irqsave(&host->lock, flags);
3893 host->sdio_gpio_lpm = 0;
3894 }
3895
3896 if (!host->clks_on) {
3897 msmsdcc_setup_clocks(host, true);
3898 host->clks_on = 1;
3899 }
3900
3901 if (host->sdcc_irq_disabled) {
3902 writel_relaxed(host->mci_irqenable,
3903 host->base + MMCIMASK0);
3904 mb();
3905 enable_irq(host->core_irqres->start);
3906 host->sdcc_irq_disabled = 0;
3907 }
3908 wake_lock_timeout(&host->sdio_wlock, 1);
3909 }
3910 spin_unlock_irqrestore(&host->lock, flags);
3911 return 0;
3912}
3913#else
3914int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
3915{
3916 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07003917}
3918#endif
3919
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003920#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07003921static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003922msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07003923{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003924 struct mmc_host *mmc = dev_get_drvdata(dev);
3925 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07003926 int rc = 0;
3927
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003928 if (host->plat->is_sdio_al_client)
3929 return 0;
3930
Sahitya Tummala7661a452011-07-18 13:28:35 +05303931 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003932 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003933 host->sdcc_suspending = 1;
3934 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07003935
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003936 /*
3937 * If the clocks are already turned off by SDIO clients (as
3938 * part of LPM), then clocks should be turned on before
3939 * calling mmc_suspend_host() because mmc_suspend_host might
3940 * send some commands to the card. The clocks will be turned
3941 * off again after mmc_suspend_host. Thus for SD/MMC/SDIO
3942 * cards, clocks will be turned on before mmc_suspend_host
3943 * and turned off after mmc_suspend_host.
3944 */
3945 mmc->ios.clock = host->clk_rate;
3946 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07003947
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003948 /*
3949 * MMC core thinks that host is disabled by now since
3950 * runtime suspend is scheduled after msmsdcc_disable()
3951 * is called. Thus, MMC core will try to enable the host
3952 * while suspending it. This results in a synchronous
3953 * runtime resume request while in runtime suspending
3954 * context and hence inorder to complete this resume
3955 * requet, it will wait for suspend to be complete,
3956 * but runtime suspend also can not proceed further
3957 * until the host is resumed. Thus, it leads to a hang.
3958 * Hence, increase the pm usage count before suspending
3959 * the host so that any resume requests after this will
3960 * simple become pm usage counter increment operations.
3961 */
3962 pm_runtime_get_noresume(dev);
3963 rc = mmc_suspend_host(mmc);
3964 pm_runtime_put_noidle(dev);
3965
3966 if (!rc) {
3967 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
3968 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ)) {
3969 disable_irq(host->core_irqres->start);
3970 host->sdcc_irq_disabled = 1;
3971
3972 /*
3973 * If MMC core level suspend is not supported,
3974 * turn off clocks to allow deep sleep (TCXO
3975 * shutdown).
3976 */
3977 mmc->ios.clock = 0;
3978 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
3979 enable_irq(host->core_irqres->start);
3980 host->sdcc_irq_disabled = 0;
3981
3982 if (host->plat->sdiowakeup_irq) {
3983 host->sdio_irq_disabled = 0;
3984 msmsdcc_enable_irq_wake(host);
3985 enable_irq(host->plat->sdiowakeup_irq);
3986 }
3987 }
3988 }
3989 host->sdcc_suspending = 0;
3990 mmc->suspend_task = NULL;
3991 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
3992 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07003993 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05303994 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003995 return rc;
3996}
3997
3998static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003999msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004000{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004001 struct mmc_host *mmc = dev_get_drvdata(dev);
4002 struct msmsdcc_host *host = mmc_priv(mmc);
4003 unsigned long flags;
4004
4005 if (host->plat->is_sdio_al_client)
4006 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07004007
Sahitya Tummala7661a452011-07-18 13:28:35 +05304008 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004009 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004010 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
4011 if (host->sdcc_irq_disabled) {
4012 enable_irq(host->core_irqres->start);
4013 host->sdcc_irq_disabled = 0;
4014 }
4015 }
4016 mmc->ios.clock = host->clk_rate;
4017 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07004018
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004019 spin_lock_irqsave(&host->lock, flags);
4020 writel_relaxed(host->mci_irqenable, host->base + MMCIMASK0);
4021 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07004022
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004023 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
4024 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) &&
4025 !host->sdio_irq_disabled) {
4026 if (host->plat->sdiowakeup_irq) {
4027 disable_irq_nosync(
4028 host->plat->sdiowakeup_irq);
4029 msmsdcc_disable_irq_wake(host);
4030 host->sdio_irq_disabled = 1;
4031 }
4032 }
San Mehat9d2bd732009-09-22 16:44:22 -07004033
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004034 spin_unlock_irqrestore(&host->lock, flags);
4035
4036 mmc_resume_host(mmc);
4037
4038 /*
4039 * FIXME: Clearing of flags must be handled in clients
4040 * resume handler.
4041 */
4042 spin_lock_irqsave(&host->lock, flags);
4043 mmc->pm_flags = 0;
4044 spin_unlock_irqrestore(&host->lock, flags);
4045
4046 /*
4047 * After resuming the host wait for sometime so that
4048 * the SDIO work will be processed.
4049 */
4050 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO)) {
4051 if ((host->plat->cfg_mpm_sdiowakeup ||
4052 host->plat->sdiowakeup_irq) &&
4053 wake_lock_active(&host->sdio_wlock))
4054 wake_lock_timeout(&host->sdio_wlock, 1);
4055 }
4056
4057 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004058 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304059 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004060 return 0;
4061}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004062
4063static int msmsdcc_runtime_idle(struct device *dev)
4064{
4065 struct mmc_host *mmc = dev_get_drvdata(dev);
4066 struct msmsdcc_host *host = mmc_priv(mmc);
4067
4068 if (host->plat->is_sdio_al_client)
4069 return 0;
4070
4071 /* Idle timeout is not configurable for now */
4072 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
4073
4074 return -EAGAIN;
4075}
4076
4077static int msmsdcc_pm_suspend(struct device *dev)
4078{
4079 struct mmc_host *mmc = dev_get_drvdata(dev);
4080 struct msmsdcc_host *host = mmc_priv(mmc);
4081 int rc = 0;
4082
4083 if (host->plat->is_sdio_al_client)
4084 return 0;
4085
4086
4087 if (host->plat->status_irq)
4088 disable_irq(host->plat->status_irq);
4089
4090 if (!pm_runtime_suspended(dev))
4091 rc = msmsdcc_runtime_suspend(dev);
4092
4093 return rc;
4094}
4095
4096static int msmsdcc_pm_resume(struct device *dev)
4097{
4098 struct mmc_host *mmc = dev_get_drvdata(dev);
4099 struct msmsdcc_host *host = mmc_priv(mmc);
4100 int rc = 0;
4101
4102 if (host->plat->is_sdio_al_client)
4103 return 0;
4104
4105 rc = msmsdcc_runtime_resume(dev);
4106 if (host->plat->status_irq) {
4107 msmsdcc_check_status((unsigned long)host);
4108 enable_irq(host->plat->status_irq);
4109 }
4110
4111 /* Update the run-time PM status */
4112 pm_runtime_disable(dev);
4113 rc = pm_runtime_set_active(dev);
4114 if (rc < 0)
4115 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
4116 __func__, rc);
4117 pm_runtime_enable(dev);
4118
4119 return rc;
4120}
4121
Daniel Walker08ecfde2010-06-23 12:32:20 -07004122#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004123#define msmsdcc_runtime_suspend NULL
4124#define msmsdcc_runtime_resume NULL
4125#define msmsdcc_runtime_idle NULL
4126#define msmsdcc_pm_suspend NULL
4127#define msmsdcc_pm_resume NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07004128#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004129
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004130static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
4131 .runtime_suspend = msmsdcc_runtime_suspend,
4132 .runtime_resume = msmsdcc_runtime_resume,
4133 .runtime_idle = msmsdcc_runtime_idle,
4134 .suspend = msmsdcc_pm_suspend,
4135 .resume = msmsdcc_pm_resume,
4136};
4137
San Mehat9d2bd732009-09-22 16:44:22 -07004138static struct platform_driver msmsdcc_driver = {
4139 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004140 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07004141 .driver = {
4142 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004143 .pm = &msmsdcc_dev_pm_ops,
San Mehat9d2bd732009-09-22 16:44:22 -07004144 },
4145};
4146
4147static int __init msmsdcc_init(void)
4148{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004149#if defined(CONFIG_DEBUG_FS)
4150 int ret = 0;
4151 ret = msmsdcc_dbg_init();
4152 if (ret) {
4153 pr_err("Failed to create debug fs dir \n");
4154 return ret;
4155 }
4156#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004157 return platform_driver_register(&msmsdcc_driver);
4158}
4159
4160static void __exit msmsdcc_exit(void)
4161{
4162 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004163
4164#if defined(CONFIG_DEBUG_FS)
4165 debugfs_remove(debugfs_file);
4166 debugfs_remove(debugfs_dir);
4167#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004168}
4169
4170module_init(msmsdcc_init);
4171module_exit(msmsdcc_exit);
4172
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004173MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07004174MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004175
4176#if defined(CONFIG_DEBUG_FS)
4177
4178static int
4179msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
4180{
4181 file->private_data = inode->i_private;
4182 return 0;
4183}
4184
4185static ssize_t
4186msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
4187 size_t count, loff_t *ppos)
4188{
4189 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
4190 char buf[1024];
4191 int max, i;
4192
4193 i = 0;
4194 max = sizeof(buf) - 1;
4195
4196 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
4197 host->curr.cmd, host->curr.data);
4198 if (host->curr.cmd) {
4199 struct mmc_command *cmd = host->curr.cmd;
4200
4201 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
4202 cmd->opcode, cmd->arg, cmd->flags);
4203 }
4204 if (host->curr.data) {
4205 struct mmc_data *data = host->curr.data;
4206 i += scnprintf(buf + i, max - i,
4207 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
4208 data->timeout_ns, data->timeout_clks,
4209 data->blksz, data->blocks, data->error,
4210 data->flags);
4211 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
4212 host->curr.xfer_size, host->curr.xfer_remain,
4213 host->curr.data_xfered, host->dma.sg);
4214 }
4215
4216 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
4217}
4218
4219static const struct file_operations msmsdcc_dbg_state_ops = {
4220 .read = msmsdcc_dbg_state_read,
4221 .open = msmsdcc_dbg_state_open,
4222};
4223
4224static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
4225{
4226 if (debugfs_dir) {
4227 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
4228 0644, debugfs_dir, host,
4229 &msmsdcc_dbg_state_ops);
4230 }
4231}
4232
4233static int __init msmsdcc_dbg_init(void)
4234{
4235 int err;
4236
4237 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
4238 if (IS_ERR(debugfs_dir)) {
4239 err = PTR_ERR(debugfs_dir);
4240 debugfs_dir = NULL;
4241 return err;
4242 }
4243
4244 return 0;
4245}
4246#endif