blob: 92a3a39a1dcf3c5703027c8bd11ee2acc00f1e1e [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;
San Mehat9d2bd732009-09-22 16:44:22 -0700658 unsigned int n;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700659 int i;
San Mehat9d2bd732009-09-22 16:44:22 -0700660 struct scatterlist *sg = data->sg;
661
Krishna Konda25786ec2011-07-25 16:21:36 -0700662 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700663 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700664
Krishna Konda25786ec2011-07-25 16:21:36 -0700665 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
666
San Mehat9d2bd732009-09-22 16:44:22 -0700667 host->dma.sg = data->sg;
668 host->dma.num_ents = data->sg_len;
669
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700670 BUG_ON(host->dma.num_ents > NR_SG); /* Prevent memory corruption */
San Mehat56a8b5b2009-11-21 12:29:46 -0800671
San Mehat9d2bd732009-09-22 16:44:22 -0700672 nc = host->dma.nc;
673
San Mehat9d2bd732009-09-22 16:44:22 -0700674 if (data->flags & MMC_DATA_READ)
675 host->dma.dir = DMA_FROM_DEVICE;
676 else
677 host->dma.dir = DMA_TO_DEVICE;
678
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700679 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
San Mehat9d2bd732009-09-22 16:44:22 -0700680 host->curr.user_pages = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700681 box = &nc->cmd[0];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700682 for (i = 0; i < host->dma.num_ents; i++) {
San Mehat9d2bd732009-09-22 16:44:22 -0700683 box->cmd = CMD_MODE_BOX;
684
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700685 /* Initialize sg dma address */
686 sg->dma_address = pfn_to_dma(mmc_dev(host->mmc),
687 page_to_pfn(sg_page(sg)))
688 + sg->offset;
689
690 if (i == (host->dma.num_ents - 1))
San Mehat9d2bd732009-09-22 16:44:22 -0700691 box->cmd |= CMD_LC;
692 rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ?
693 (sg_dma_len(sg) / MCI_FIFOSIZE) + 1 :
694 (sg_dma_len(sg) / MCI_FIFOSIZE) ;
695
696 if (data->flags & MMC_DATA_READ) {
697 box->src_row_addr = msmsdcc_fifo_addr(host);
698 box->dst_row_addr = sg_dma_address(sg);
699
700 box->src_dst_len = (MCI_FIFOSIZE << 16) |
701 (MCI_FIFOSIZE);
702 box->row_offset = MCI_FIFOSIZE;
703
704 box->num_rows = rows * ((1 << 16) + 1);
Krishna Konda25786ec2011-07-25 16:21:36 -0700705 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
San Mehat9d2bd732009-09-22 16:44:22 -0700706 } else {
707 box->src_row_addr = sg_dma_address(sg);
708 box->dst_row_addr = msmsdcc_fifo_addr(host);
709
710 box->src_dst_len = (MCI_FIFOSIZE << 16) |
711 (MCI_FIFOSIZE);
712 box->row_offset = (MCI_FIFOSIZE << 16);
713
714 box->num_rows = rows * ((1 << 16) + 1);
Krishna Konda25786ec2011-07-25 16:21:36 -0700715 box->cmd |= CMD_DST_CRCI(host->dma.crci);
San Mehat9d2bd732009-09-22 16:44:22 -0700716 }
717 box++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700718 sg++;
719 }
720
721 /* location of command block must be 64 bit aligned */
722 BUG_ON(host->dma.cmd_busaddr & 0x07);
723
724 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
725 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
726 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
727 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
Krishna Konda25786ec2011-07-25 16:21:36 -0700728 host->dma.hdr.crci_mask = msm_dmov_build_crci_mask(1, host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700729
730 n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
731 host->dma.num_ents, host->dma.dir);
732 /* dsb inside dma_map_sg will write nc out to mem as well */
733
734 if (n != host->dma.num_ents) {
735 pr_err("%s: Unable to map in all sg elements\n",
736 mmc_hostname(host->mmc));
737 host->dma.sg = NULL;
738 host->dma.num_ents = 0;
739 return -ENOMEM;
San Mehat56a8b5b2009-11-21 12:29:46 -0800740 }
San Mehat9d2bd732009-09-22 16:44:22 -0700741
742 return 0;
743}
744
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700745#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
746/**
747 * Submits data transfer request to SPS driver
748 *
749 * This function make sg (scatter gather) data buffers
750 * DMA ready and then submits them to SPS driver for
751 * transfer.
752 *
753 * @host - Pointer to sdcc host structure
754 * @data - Pointer to mmc_data structure
755 *
756 * @return 0 if success else negative value
757 */
758static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
759 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -0800760{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700761 int rc = 0;
762 u32 flags;
763 int i;
764 u32 addr, len, data_cnt;
765 struct scatterlist *sg = data->sg;
766 struct sps_pipe *sps_pipe_handle;
767
768 BUG_ON(data->sg_len > NR_SG); /* Prevent memory corruption */
769
770 host->sps.sg = data->sg;
771 host->sps.num_ents = data->sg_len;
772 host->sps.xfer_req_cnt = 0;
773 if (data->flags & MMC_DATA_READ) {
774 host->sps.dir = DMA_FROM_DEVICE;
775 sps_pipe_handle = host->sps.prod.pipe_handle;
776 } else {
777 host->sps.dir = DMA_TO_DEVICE;
778 sps_pipe_handle = host->sps.cons.pipe_handle;
779 }
780
781 /* Make sg buffers DMA ready */
782 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
783 host->sps.dir);
784
785 if (rc != data->sg_len) {
786 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
787 mmc_hostname(host->mmc), rc);
788 host->sps.sg = NULL;
789 host->sps.num_ents = 0;
790 rc = -ENOMEM;
791 goto dma_map_err;
792 }
793
794 pr_debug("%s: %s: %s: pipe=0x%x, total_xfer=0x%x, sg_len=%d\n",
795 mmc_hostname(host->mmc), __func__,
796 host->sps.dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
797 (u32)sps_pipe_handle, host->curr.xfer_size, data->sg_len);
798
799 for (i = 0; i < data->sg_len; i++) {
800 /*
801 * Check if this is the last buffer to transfer?
802 * If yes then set the INT and EOT flags.
803 */
804 len = sg_dma_len(sg);
805 addr = sg_dma_address(sg);
806 flags = 0;
807 while (len > 0) {
808 if (len > SPS_MAX_DESC_SIZE) {
809 data_cnt = SPS_MAX_DESC_SIZE;
810 } else {
811 data_cnt = len;
812 if (i == data->sg_len - 1)
813 flags = SPS_IOVEC_FLAG_INT |
814 SPS_IOVEC_FLAG_EOT;
815 }
816 rc = sps_transfer_one(sps_pipe_handle, addr,
817 data_cnt, host, flags);
818 if (rc) {
819 pr_err("%s: sps_transfer_one() error! rc=%d,"
820 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
821 mmc_hostname(host->mmc), rc,
822 (u32)sps_pipe_handle, (u32)sg, i);
823 goto dma_map_err;
824 }
825 addr += data_cnt;
826 len -= data_cnt;
827 host->sps.xfer_req_cnt++;
828 }
829 sg++;
830 }
831 goto out;
832
833dma_map_err:
834 /* unmap sg buffers */
835 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
836 host->sps.dir);
837out:
838 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -0700839}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700840#else
841static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
842 struct mmc_data *data) { return 0; }
843#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -0700844
845static void
San Mehat56a8b5b2009-11-21 12:29:46 -0800846msmsdcc_start_command_deferred(struct msmsdcc_host *host,
847 struct mmc_command *cmd, u32 *c)
848{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700849 DBG(host, "op %02x arg %08x flags %08x\n",
850 cmd->opcode, cmd->arg, cmd->flags);
851
San Mehat56a8b5b2009-11-21 12:29:46 -0800852 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
853
854 if (cmd->flags & MMC_RSP_PRESENT) {
855 if (cmd->flags & MMC_RSP_136)
856 *c |= MCI_CPSM_LONGRSP;
857 *c |= MCI_CPSM_RESPONSE;
858 }
859
860 if (/*interrupt*/0)
861 *c |= MCI_CPSM_INTERRUPT;
862
863 if ((((cmd->opcode == 17) || (cmd->opcode == 18)) ||
864 ((cmd->opcode == 24) || (cmd->opcode == 25))) ||
865 (cmd->opcode == 53))
866 *c |= MCI_CSPM_DATCMD;
867
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700868 /* Check if AUTO CMD19 is required or not? */
869 if (((cmd->opcode == 17) || (cmd->opcode == 18)) &&
870 host->tuning_needed) {
871 msmsdcc_enable_cdr_cm_sdc4_dll(host);
872 *c |= MCI_CSPM_AUTO_CMD19;
873 }
874
Sahitya Tummalad5137bd2010-12-08 15:03:04 +0530875 if (host->prog_scan && (cmd->opcode == 12)) {
876 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700877 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +0530878 }
879
San Mehat56a8b5b2009-11-21 12:29:46 -0800880 if (cmd == cmd->mrq->stop)
881 *c |= MCI_CSPM_MCIABORT;
882
San Mehat56a8b5b2009-11-21 12:29:46 -0800883 if (host->curr.cmd != NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700884 pr_err("%s: Overlapping command requests\n",
885 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -0800886 }
887 host->curr.cmd = cmd;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700888
889 /*
890 * Kick the software command timeout timer here.
891 * Timer expires in 10 secs.
892 */
893 mod_timer(&host->req_tout_timer,
894 (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
San Mehat56a8b5b2009-11-21 12:29:46 -0800895}
896
897static void
898msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
899 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -0700900{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +0530901 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -0700902 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700903 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -0700904 unsigned int pio_irqmask = 0;
905
906 host->curr.data = data;
907 host->curr.xfer_size = data->blksz * data->blocks;
908 host->curr.xfer_remain = host->curr.xfer_size;
909 host->curr.data_xfered = 0;
910 host->curr.got_dataend = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700911
912 memset(&host->pio, 0, sizeof(host->pio));
913
San Mehat9d2bd732009-09-22 16:44:22 -0700914 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
915
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700916 if (!msmsdcc_check_dma_op_req(data)) {
917 if (host->is_dma_mode && !msmsdcc_config_dma(host, data)) {
918 datactrl |= MCI_DPSM_DMAENABLE;
919 } else if (host->is_sps_mode) {
920 if (!msmsdcc_is_dml_busy(host)) {
921 if (!msmsdcc_sps_start_xfer(host, data)) {
922 /* Now kick start DML transfer */
923 mb();
924 msmsdcc_dml_start_xfer(host, data);
925 datactrl |= MCI_DPSM_DMAENABLE;
926 host->sps.busy = 1;
927 }
928 } else {
929 /*
930 * Can't proceed with new transfer as
931 * previous trasnfer is already in progress.
932 * There is no point of going into PIO mode
933 * as well. Is this a time to do kernel panic?
934 */
935 pr_err("%s: %s: DML HW is busy!!!"
936 " Can't perform new SPS transfers"
937 " now\n", mmc_hostname(host->mmc),
938 __func__);
939 }
940 }
941 }
942
943 /* Is data transfer in PIO mode required? */
944 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700945 host->pio.sg = data->sg;
946 host->pio.sg_len = data->sg_len;
947 host->pio.sg_off = 0;
948
949 if (data->flags & MMC_DATA_READ) {
950 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
951 if (host->curr.xfer_remain < MCI_FIFOSIZE)
952 pio_irqmask |= MCI_RXDATAAVLBLMASK;
953 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700954 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
955 MCI_TXFIFOEMPTYMASK;
San Mehat9d2bd732009-09-22 16:44:22 -0700956 }
957
958 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +0530959 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
San Mehat9d2bd732009-09-22 16:44:22 -0700960
San Mehat56a8b5b2009-11-21 12:29:46 -0800961 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700962 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -0800963 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -0700964
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700965 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
966 /* Use ADM (Application Data Mover) HW for Data transfer */
967 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -0800968 host->cmd_timeout = timeout;
969 host->cmd_pio_irqmask = pio_irqmask;
970 host->cmd_datactrl = datactrl;
971 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -0700972
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700973 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
974 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -0700975 host->dma.busy = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700976 if (data->flags & MMC_DATA_WRITE)
977 host->prog_scan = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -0800978
979 if (cmd) {
980 msmsdcc_start_command_deferred(host, cmd, &c);
981 host->cmd_c = c;
982 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700983 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
984 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
985 host->base + MMCIMASK0);
986 mb();
987 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -0800988 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700989 /* SPS-BAM mode or PIO mode */
990 if (data->flags & MMC_DATA_WRITE)
991 host->prog_scan = 1;
992 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -0800993
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700994 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -0800995
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700996 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
997 (~(MCI_IRQ_PIO))) | pio_irqmask,
998 host->base + MMCIMASK0);
999 msmsdcc_delay(host); /* Allow parms to be applied */
1000 writel_relaxed(datactrl, base + MMCIDATACTRL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001001
1002 if (cmd) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001003 msmsdcc_delay(host); /* Delay between data/command */
San Mehat56a8b5b2009-11-21 12:29:46 -08001004 /* Daisy-chain the command if requested */
1005 msmsdcc_start_command(host, cmd, c);
1006 }
San Mehat9d2bd732009-09-22 16:44:22 -07001007 }
1008}
1009
1010static void
1011msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1012{
San Mehat56a8b5b2009-11-21 12:29:46 -08001013 msmsdcc_start_command_deferred(host, cmd, &c);
1014 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001015}
1016
1017static void
1018msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1019 unsigned int status)
1020{
1021 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001022 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1023 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1024 pr_err("%s: Data CRC error\n",
1025 mmc_hostname(host->mmc));
1026 pr_err("%s: opcode 0x%.8x\n", __func__,
1027 data->mrq->cmd->opcode);
1028 pr_err("%s: blksz %d, blocks %d\n", __func__,
1029 data->blksz, data->blocks);
1030 data->error = -EILSEQ;
1031 }
San Mehat9d2bd732009-09-22 16:44:22 -07001032 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001033 /* CRC is optional for the bus test commands, not all
1034 * cards respond back with CRC. However controller
1035 * waits for the CRC and times out. Hence ignore the
1036 * data timeouts during the Bustest.
1037 */
1038 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1039 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1040 pr_err("%s: Data timeout\n",
1041 mmc_hostname(host->mmc));
1042 data->error = -ETIMEDOUT;
1043 }
San Mehat9d2bd732009-09-22 16:44:22 -07001044 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001045 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001046 data->error = -EIO;
1047 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001048 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001049 data->error = -EIO;
1050 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001051 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001052 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001053 data->error = -EIO;
1054 }
San Mehat9d2bd732009-09-22 16:44:22 -07001055
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001056 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001057 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001058 host->dummy_52_needed = 0;
1059}
San Mehat9d2bd732009-09-22 16:44:22 -07001060
1061static int
1062msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1063{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001064 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001065 uint32_t *ptr = (uint32_t *) buffer;
1066 int count = 0;
1067
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301068 if (remain % 4)
1069 remain = ((remain >> 2) + 1) << 2;
1070
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001071 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1072
1073 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001074 ptr++;
1075 count += sizeof(uint32_t);
1076
1077 remain -= sizeof(uint32_t);
1078 if (remain == 0)
1079 break;
1080 }
1081 return count;
1082}
1083
1084static int
1085msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001086 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001087{
1088 void __iomem *base = host->base;
1089 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001090 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001091
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001092 while (readl_relaxed(base + MMCISTATUS) &
1093 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1094 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001095
San Mehat9d2bd732009-09-22 16:44:22 -07001096 count = min(remain, maxcnt);
1097
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301098 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1099 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001100 ptr += count;
1101 remain -= count;
1102
1103 if (remain == 0)
1104 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001105 }
1106 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001107
1108 return ptr - buffer;
1109}
1110
San Mehat1cd22962010-02-03 12:59:29 -08001111static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001112msmsdcc_pio_irq(int irq, void *dev_id)
1113{
1114 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001115 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001116 uint32_t status;
1117
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001118 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001119
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001120 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1121 (MCI_IRQ_PIO)) == 0)
1122 return IRQ_NONE;
1123
1124#if IRQ_DEBUG
1125 msmsdcc_print_status(host, "irq1-r", status);
1126#endif
1127
1128 spin_lock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001129
1130 do {
1131 unsigned long flags;
1132 unsigned int remain, len;
1133 char *buffer;
1134
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001135 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1136 | MCI_RXDATAAVLBL)))
1137 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001138
1139 /* Map the current scatter buffer */
1140 local_irq_save(flags);
1141 buffer = kmap_atomic(sg_page(host->pio.sg),
1142 KM_BIO_SRC_IRQ) + host->pio.sg->offset;
1143 buffer += host->pio.sg_off;
1144 remain = host->pio.sg->length - host->pio.sg_off;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001145
San Mehat9d2bd732009-09-22 16:44:22 -07001146 len = 0;
1147 if (status & MCI_RXACTIVE)
1148 len = msmsdcc_pio_read(host, buffer, remain);
1149 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001150 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001151
1152 /* Unmap the buffer */
1153 kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
1154 local_irq_restore(flags);
1155
1156 host->pio.sg_off += len;
1157 host->curr.xfer_remain -= len;
1158 host->curr.data_xfered += len;
1159 remain -= len;
1160
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001161 if (remain) /* Done with this page? */
1162 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001163
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001164 if (status & MCI_RXACTIVE && host->curr.user_pages)
1165 flush_dcache_page(sg_page(host->pio.sg));
San Mehat9d2bd732009-09-22 16:44:22 -07001166
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001167 if (!--host->pio.sg_len) {
1168 memset(&host->pio, 0, sizeof(host->pio));
1169 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001170 }
1171
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001172 /* Advance to next sg */
1173 host->pio.sg++;
1174 host->pio.sg_off = 0;
1175
1176 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001177 } while (1);
1178
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001179 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1180 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1181 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1182 host->base + MMCIMASK0);
1183 if (!host->curr.xfer_remain) {
1184 /* Delay needed (same port was just written) */
1185 msmsdcc_delay(host);
1186 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1187 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1188 }
1189 mb();
1190 } else if (!host->curr.xfer_remain) {
1191 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1192 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1193 mb();
1194 }
San Mehat9d2bd732009-09-22 16:44:22 -07001195
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001196 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001197
1198 return IRQ_HANDLED;
1199}
1200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001201static void
1202msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1203
1204static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1205 struct mmc_data *data)
1206{
1207 u32 loop_cnt = 0;
1208
1209 /*
1210 * For read commands with data less than fifo size, it is possible to
1211 * get DATAEND first and RXDATA_AVAIL might be set later because of
1212 * synchronization delay through the asynchronous RX FIFO. Thus, for
1213 * such cases, even after DATAEND interrupt is received software
1214 * should poll for RXDATA_AVAIL until the requested data is read out
1215 * of FIFO. This change is needed to get around this abnormal but
1216 * sometimes expected behavior of SDCC3 controller.
1217 *
1218 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1219 * after the data is loaded into RX FIFO. This would amount to less
1220 * than a microsecond and thus looping for 1000 times is good enough
1221 * for that delay.
1222 */
1223 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1224 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1225 spin_unlock(&host->lock);
1226 msmsdcc_pio_irq(1, host);
1227 spin_lock(&host->lock);
1228 }
1229 }
1230 if (loop_cnt == 1000) {
1231 pr_info("%s: Timed out while polling for Rx Data\n",
1232 mmc_hostname(host->mmc));
1233 data->error = -ETIMEDOUT;
1234 msmsdcc_reset_and_restore(host);
1235 }
1236}
1237
San Mehat9d2bd732009-09-22 16:44:22 -07001238static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1239{
1240 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001241
1242 host->curr.cmd = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001243 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1244 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1245 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1246 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -07001247
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001248 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Sahitya Tummala5a0ae912011-07-18 13:34:01 +05301249 pr_debug("%s: Command timeout\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001250 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001251 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
1252 !host->cmd19_tuning_in_progress) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001253 pr_err("%s: Command CRC error\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001254 cmd->error = -EILSEQ;
1255 }
1256
1257 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001258 if (host->curr.data && host->dma.sg &&
1259 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001260 msm_dmov_stop_cmd(host->dma.channel,
1261 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001262 else if (host->curr.data && host->sps.sg &&
1263 host->is_sps_mode){
1264 /* Stop current SPS transfer */
1265 msmsdcc_sps_exit_curr_xfer(host);
1266 }
San Mehat9d2bd732009-09-22 16:44:22 -07001267 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301268 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001269 msmsdcc_stop_data(host);
1270 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301271 } else { /* host->data == NULL */
1272 if (!cmd->error && host->prog_enable) {
1273 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001274 host->prog_scan = 0;
1275 host->prog_enable = 0;
1276 msmsdcc_request_end(host, cmd->mrq);
1277 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301278 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301279 } else {
1280 if (host->prog_enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001281 host->prog_scan = 0;
1282 host->prog_enable = 0;
1283 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001284 if (host->dummy_52_needed)
1285 host->dummy_52_needed = 0;
1286 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001287 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301288 msmsdcc_request_end(host, cmd->mrq);
1289 }
1290 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001291 } else if (cmd->data) {
San Mehat56a8b5b2009-11-21 12:29:46 -08001292 if (!(cmd->data->flags & MMC_DATA_READ))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001293 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001294 }
1295}
1296
San Mehat9d2bd732009-09-22 16:44:22 -07001297static irqreturn_t
1298msmsdcc_irq(int irq, void *dev_id)
1299{
1300 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001301 u32 status;
1302 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001303 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001304
1305 spin_lock(&host->lock);
1306
1307 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001308 struct mmc_command *cmd;
1309 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001310
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001311 if (timer) {
1312 timer = 0;
1313 msmsdcc_delay(host);
1314 }
San Mehat865c8062009-11-13 13:42:06 -08001315
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001316 if (!host->clks_on) {
1317 pr_debug("%s: %s: SDIO async irq received\n",
1318 mmc_hostname(host->mmc), __func__);
1319 host->mmc->ios.clock = host->clk_rate;
1320 spin_unlock(&host->lock);
1321 host->mmc->ops->set_ios(host->mmc, &host->mmc->ios);
1322 spin_lock(&host->lock);
1323 if (host->plat->cfg_mpm_sdiowakeup &&
1324 (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
1325 wake_lock(&host->sdio_wlock);
1326 /* only ansyc interrupt can come when clocks are off */
1327 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
1328 }
1329
1330 status = readl_relaxed(host->base + MMCISTATUS);
1331
1332 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1333 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001334 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001335
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001336#if IRQ_DEBUG
1337 msmsdcc_print_status(host, "irq0-r", status);
1338#endif
1339 status &= readl_relaxed(host->base + MMCIMASK0);
1340 writel_relaxed(status, host->base + MMCICLEAR);
1341 mb();
1342#if IRQ_DEBUG
1343 msmsdcc_print_status(host, "irq0-p", status);
1344#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001345
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001346#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
1347 if (status & MCI_SDIOINTROPE) {
1348 if (host->sdcc_suspending)
1349 wake_lock(&host->sdio_suspend_wlock);
1350 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001351 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001352#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001353 data = host->curr.data;
1354
1355 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001356 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1357 MCI_CMDTIMEOUT)) {
1358 if (status & MCI_CMDTIMEOUT)
1359 pr_debug("%s: dummy CMD52 timeout\n",
1360 mmc_hostname(host->mmc));
1361 if (status & MCI_CMDCRCFAIL)
1362 pr_debug("%s: dummy CMD52 CRC failed\n",
1363 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001364 host->dummy_52_sent = 0;
1365 host->dummy_52_needed = 0;
1366 if (data) {
1367 msmsdcc_stop_data(host);
1368 msmsdcc_request_end(host, data->mrq);
1369 }
1370 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001371 spin_unlock(&host->lock);
1372 return IRQ_HANDLED;
1373 }
1374 break;
1375 }
1376
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001377 /*
1378 * Check for proper command response
1379 */
1380 cmd = host->curr.cmd;
1381 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1382 MCI_CMDTIMEOUT | MCI_PROGDONE |
1383 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1384 msmsdcc_do_cmdirq(host, status);
1385 }
1386
1387 if (data) {
1388 /* Check for data errors */
1389 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1390 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1391 msmsdcc_data_err(host, data, status);
1392 host->curr.data_xfered = 0;
1393 if (host->dma.sg && host->is_dma_mode)
1394 msm_dmov_stop_cmd(host->dma.channel,
1395 &host->dma.hdr, 0);
1396 else if (host->sps.sg && host->is_sps_mode) {
1397 /* Stop current SPS transfer */
1398 msmsdcc_sps_exit_curr_xfer(host);
1399 }
1400 else {
1401 msmsdcc_reset_and_restore(host);
1402 if (host->curr.data)
1403 msmsdcc_stop_data(host);
1404 if (!data->stop)
1405 timer |=
1406 msmsdcc_request_end(host,
1407 data->mrq);
1408 else {
1409 msmsdcc_start_command(host,
1410 data->stop,
1411 0);
1412 timer = 1;
1413 }
1414 }
1415 }
1416
1417 /* Check for data done */
1418 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1419 host->curr.got_dataend = 1;
1420
1421 if (host->curr.got_dataend) {
1422 /*
1423 * If DMA is still in progress, we complete
1424 * via the completion handler
1425 */
1426 if (!host->dma.busy && !host->sps.busy) {
1427 /*
1428 * There appears to be an issue in the
1429 * controller where if you request a
1430 * small block transfer (< fifo size),
1431 * you may get your DATAEND/DATABLKEND
1432 * irq without the PIO data irq.
1433 *
1434 * Check to see if theres still data
1435 * to be read, and simulate a PIO irq.
1436 */
1437 if (data->flags & MMC_DATA_READ)
1438 msmsdcc_wait_for_rxdata(host,
1439 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001440 if (!data->error) {
1441 host->curr.data_xfered =
1442 host->curr.xfer_size;
1443 host->curr.xfer_remain -=
1444 host->curr.xfer_size;
1445 }
1446
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001447 if (!host->dummy_52_needed) {
1448 msmsdcc_stop_data(host);
1449 if (!data->stop) {
1450 msmsdcc_request_end(
1451 host,
1452 data->mrq);
1453 } else {
1454 msmsdcc_start_command(
1455 host,
1456 data->stop, 0);
1457 timer = 1;
1458 }
1459 } else {
1460 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001461 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001462 &dummy52cmd,
1463 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001464 }
1465 }
1466 }
1467 }
1468
San Mehat9d2bd732009-09-22 16:44:22 -07001469 ret = 1;
1470 } while (status);
1471
1472 spin_unlock(&host->lock);
1473
San Mehat9d2bd732009-09-22 16:44:22 -07001474 return IRQ_RETVAL(ret);
1475}
1476
1477static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001478msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1479{
1480 if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
1481 /* Queue/read data, daisy-chain command when data starts */
1482 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
1483 } else {
1484 msmsdcc_start_command(host, mrq->cmd, 0);
1485 }
1486}
1487
1488static void
San Mehat9d2bd732009-09-22 16:44:22 -07001489msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1490{
1491 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001492 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001493
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001494 /*
1495 * Get the SDIO AL client out of LPM.
1496 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001497 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001498 if (host->plat->is_sdio_al_client)
1499 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001500
1501 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001502 WARN(host->curr.mrq, "Request in progress\n");
1503 WARN(!host->pwr, "SDCC power is turned off\n");
1504 WARN(!host->clks_on, "SDCC clocks are turned off\n");
1505 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
San Mehat9d2bd732009-09-22 16:44:22 -07001506
1507 if (host->eject) {
1508 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1509 mrq->cmd->error = 0;
1510 mrq->data->bytes_xfered = mrq->data->blksz *
1511 mrq->data->blocks;
1512 } else
1513 mrq->cmd->error = -ENOMEDIUM;
1514
1515 spin_unlock_irqrestore(&host->lock, flags);
1516 mmc_request_done(mmc, mrq);
1517 return;
1518 }
1519
1520 host->curr.mrq = mrq;
1521
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001522 if (host->plat->dummy52_required) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001523 if (mrq->data && mrq->data->flags == MMC_DATA_WRITE) {
1524 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001525 mrq->cmd->opcode == 54) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001526 host->dummy_52_needed = 1;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001527 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001528 }
San Mehat9d2bd732009-09-22 16:44:22 -07001529 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001530 msmsdcc_request_start(host, mrq);
San Mehat9d2bd732009-09-22 16:44:22 -07001531 spin_unlock_irqrestore(&host->lock, flags);
1532}
1533
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001534static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1535 int min_uV, int max_uV)
1536{
1537 int rc = 0;
1538
1539 if (vreg->set_voltage_sup) {
1540 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1541 if (rc) {
1542 pr_err("%s: regulator_set_voltage(%s) failed."
1543 " min_uV=%d, max_uV=%d, rc=%d\n",
1544 __func__, vreg->name, min_uV, max_uV, rc);
1545 }
1546 }
1547
1548 return rc;
1549}
1550
1551static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1552 int uA_load)
1553{
1554 int rc = 0;
1555
1556 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1557 if (rc < 0)
1558 pr_err("%s: regulator_set_optimum_mode(reg=%s, uA_load=%d)"
1559 " failed. rc=%d\n", __func__, vreg->name,
1560 uA_load, rc);
1561 else
1562 /* regulator_set_optimum_mode() can return non zero value
1563 * even for success case.
1564 */
1565 rc = 0;
1566
1567 return rc;
1568}
1569
1570static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1571 struct device *dev)
1572{
1573 int rc = 0;
1574
1575 /* check if regulator is already initialized? */
1576 if (vreg->reg)
1577 goto out;
1578
1579 /* Get the regulator handle */
1580 vreg->reg = regulator_get(dev, vreg->name);
1581 if (IS_ERR(vreg->reg)) {
1582 rc = PTR_ERR(vreg->reg);
1583 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
1584 __func__, vreg->name, rc);
1585 }
1586out:
1587 return rc;
1588}
1589
1590static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
1591{
1592 if (vreg->reg)
1593 regulator_put(vreg->reg);
1594}
1595
1596/* This init function should be called only once for each SDCC slot */
1597static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
1598{
1599 int rc = 0;
1600 struct msm_mmc_slot_reg_data *curr_slot;
1601 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1602 struct device *dev = mmc_dev(host->mmc);
1603
1604 curr_slot = host->plat->vreg_data;
1605 if (!curr_slot)
1606 goto out;
1607
1608 curr_vdd_reg = curr_slot->vdd_data;
1609 curr_vccq_reg = curr_slot->vccq_data;
1610 curr_vddp_reg = curr_slot->vddp_data;
1611
1612 if (is_init) {
1613 /*
1614 * Get the regulator handle from voltage regulator framework
1615 * and then try to set the voltage level for the regulator
1616 */
1617 if (curr_vdd_reg) {
1618 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
1619 if (rc)
1620 goto out;
1621 }
1622 if (curr_vccq_reg) {
1623 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
1624 if (rc)
1625 goto vdd_reg_deinit;
1626 }
1627 if (curr_vddp_reg) {
1628 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
1629 if (rc)
1630 goto vccq_reg_deinit;
1631 }
1632 goto out;
1633 } else {
1634 /* Deregister all regulators from regulator framework */
1635 goto vddp_reg_deinit;
1636 }
1637vddp_reg_deinit:
1638 if (curr_vddp_reg)
1639 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
1640vccq_reg_deinit:
1641 if (curr_vccq_reg)
1642 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
1643vdd_reg_deinit:
1644 if (curr_vdd_reg)
1645 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
1646out:
1647 return rc;
1648}
1649
1650static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
1651{
1652 int rc = 0;
1653
Subhash Jadavanicc922692011-08-01 23:05:01 +05301654 /* Put regulator in HPM (high power mode) */
1655 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
1656 if (rc < 0)
1657 goto out;
1658
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001659 if (!vreg->is_enabled) {
1660 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301661 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
1662 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001663 if (rc)
1664 goto out;
1665
1666 rc = regulator_enable(vreg->reg);
1667 if (rc) {
1668 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
1669 __func__, vreg->name, rc);
1670 goto out;
1671 }
1672 vreg->is_enabled = true;
1673 }
1674
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001675out:
1676 return rc;
1677}
1678
1679static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
1680{
1681 int rc = 0;
1682
1683 /* Never disable regulator marked as always_on */
1684 if (vreg->is_enabled && !vreg->always_on) {
1685 rc = regulator_disable(vreg->reg);
1686 if (rc) {
1687 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
1688 __func__, vreg->name, rc);
1689 goto out;
1690 }
1691 vreg->is_enabled = false;
1692
1693 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
1694 if (rc < 0)
1695 goto out;
1696
1697 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301698 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001699 if (rc)
1700 goto out;
1701 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
1702 /* Put always_on regulator in LPM (low power mode) */
1703 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
1704 if (rc < 0)
1705 goto out;
1706 }
1707out:
1708 return rc;
1709}
1710
1711static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
1712{
1713 int rc = 0, i;
1714 struct msm_mmc_slot_reg_data *curr_slot;
1715 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1716 struct msm_mmc_reg_data *vreg_table[3];
1717
1718 curr_slot = host->plat->vreg_data;
1719 if (!curr_slot)
1720 goto out;
1721
1722 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
1723 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
1724 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
1725
1726 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
1727 if (vreg_table[i]) {
1728 if (enable)
1729 rc = msmsdcc_vreg_enable(vreg_table[i]);
1730 else
1731 rc = msmsdcc_vreg_disable(vreg_table[i]);
1732 if (rc)
1733 goto out;
1734 }
1735 }
1736out:
1737 return rc;
1738}
1739
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301740static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001741{
1742 int rc = 0;
1743
1744 if (host->plat->vreg_data) {
1745 struct msm_mmc_reg_data *vddp_reg =
1746 host->plat->vreg_data->vddp_data;
1747
1748 if (vddp_reg && vddp_reg->is_enabled)
1749 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
1750 }
1751
1752 return rc;
1753}
1754
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301755static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
1756{
1757 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1758 int rc = 0;
1759
1760 if (curr_slot && curr_slot->vddp_data) {
1761 rc = msmsdcc_set_vddp_level(host,
1762 curr_slot->vddp_data->low_vol_level);
1763
1764 if (rc)
1765 pr_err("%s: %s: failed to change vddp level to %d",
1766 mmc_hostname(host->mmc), __func__,
1767 curr_slot->vddp_data->low_vol_level);
1768 }
1769
1770 return rc;
1771}
1772
1773static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
1774{
1775 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1776 int rc = 0;
1777
1778 if (curr_slot && curr_slot->vddp_data) {
1779 rc = msmsdcc_set_vddp_level(host,
1780 curr_slot->vddp_data->high_vol_level);
1781
1782 if (rc)
1783 pr_err("%s: %s: failed to change vddp level to %d",
1784 mmc_hostname(host->mmc), __func__,
1785 curr_slot->vddp_data->high_vol_level);
1786 }
1787
1788 return rc;
1789}
1790
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001791static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
1792{
1793 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
1794 return 1;
1795 return 0;
1796}
1797
1798static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
1799{
1800 if (enable) {
1801 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1802 clk_enable(host->dfab_pclk);
1803 if (!IS_ERR(host->pclk))
1804 clk_enable(host->pclk);
1805 clk_enable(host->clk);
1806 } else {
1807 clk_disable(host->clk);
1808 if (!IS_ERR(host->pclk))
1809 clk_disable(host->pclk);
1810 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1811 clk_disable(host->dfab_pclk);
1812 }
1813}
1814
1815static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
1816 unsigned int req_clk)
1817{
1818 unsigned int sel_clk = -1;
1819
1820 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
1821 unsigned char cnt;
1822
1823 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
1824 if (host->plat->sup_clk_table[cnt] > req_clk)
1825 break;
1826 else if (host->plat->sup_clk_table[cnt] == req_clk) {
1827 sel_clk = host->plat->sup_clk_table[cnt];
1828 break;
1829 } else
1830 sel_clk = host->plat->sup_clk_table[cnt];
1831 }
1832 } else {
1833 if ((req_clk < host->plat->msmsdcc_fmax) &&
1834 (req_clk > host->plat->msmsdcc_fmid))
1835 sel_clk = host->plat->msmsdcc_fmid;
1836 else
1837 sel_clk = req_clk;
1838 }
1839
1840 return sel_clk;
1841}
1842
1843static inline unsigned int msmsdcc_get_min_sup_clk_rate(
1844 struct msmsdcc_host *host)
1845{
1846 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
1847 return host->plat->sup_clk_table[0];
1848 else
1849 return host->plat->msmsdcc_fmin;
1850}
1851
1852static inline unsigned int msmsdcc_get_max_sup_clk_rate(
1853 struct msmsdcc_host *host)
1854{
1855 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
1856 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
1857 else
1858 return host->plat->msmsdcc_fmax;
1859}
1860
1861static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05301862{
1863 struct msm_mmc_gpio_data *curr;
1864 int i, rc = 0;
1865
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001866 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301867 for (i = 0; i < curr->size; i++) {
1868 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001869 if (curr->gpio[i].is_always_on &&
1870 curr->gpio[i].is_enabled)
1871 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301872 rc = gpio_request(curr->gpio[i].no,
1873 curr->gpio[i].name);
1874 if (rc) {
1875 pr_err("%s: gpio_request(%d, %s) failed %d\n",
1876 mmc_hostname(host->mmc),
1877 curr->gpio[i].no,
1878 curr->gpio[i].name, rc);
1879 goto free_gpios;
1880 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001881 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301882 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001883 if (curr->gpio[i].is_always_on)
1884 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301885 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001886 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301887 }
1888 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001889 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301890
1891free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001892 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05301893 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001894 curr->gpio[i].is_enabled = false;
1895 }
1896out:
1897 return rc;
1898}
1899
1900static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
1901{
1902 struct msm_mmc_pad_data *curr;
1903 int i;
1904
1905 curr = host->plat->pin_data->pad_data;
1906 for (i = 0; i < curr->drv->size; i++) {
1907 if (enable)
1908 msm_tlmm_set_hdrive(curr->drv->on[i].no,
1909 curr->drv->on[i].val);
1910 else
1911 msm_tlmm_set_hdrive(curr->drv->off[i].no,
1912 curr->drv->off[i].val);
1913 }
1914
1915 for (i = 0; i < curr->pull->size; i++) {
1916 if (enable)
1917 msm_tlmm_set_hdrive(curr->pull->on[i].no,
1918 curr->pull->on[i].val);
1919 else
1920 msm_tlmm_set_hdrive(curr->pull->off[i].no,
1921 curr->pull->off[i].val);
1922 }
1923
1924 return 0;
1925}
1926
1927static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
1928{
1929 int rc = 0;
1930
1931 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
1932 return 0;
1933
1934 if (host->plat->pin_data->is_gpio)
1935 rc = msmsdcc_setup_gpio(host, enable);
1936 else
1937 rc = msmsdcc_setup_pad(host, enable);
1938
1939 if (!rc)
1940 host->plat->pin_data->cfg_sts = enable;
1941
1942 return rc;
1943}
1944
1945static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
1946{
1947 unsigned int wakeup_irq;
1948
1949 wakeup_irq = (host->plat->sdiowakeup_irq) ?
1950 host->plat->sdiowakeup_irq :
1951 host->core_irqres->start;
1952
1953 if (!host->irq_wake_enabled) {
1954 enable_irq_wake(wakeup_irq);
1955 host->irq_wake_enabled = true;
1956 }
1957}
1958
1959static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
1960{
1961 unsigned int wakeup_irq;
1962
1963 wakeup_irq = (host->plat->sdiowakeup_irq) ?
1964 host->plat->sdiowakeup_irq :
1965 host->core_irqres->start;
1966
1967 if (host->irq_wake_enabled) {
1968 disable_irq_wake(wakeup_irq);
1969 host->irq_wake_enabled = false;
1970 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05301971}
1972
San Mehat9d2bd732009-09-22 16:44:22 -07001973static void
1974msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
1975{
1976 struct msmsdcc_host *host = mmc_priv(mmc);
1977 u32 clk = 0, pwr = 0;
1978 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08001979 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001980 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07001981
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001982 DBG(host, "ios->clock = %u\n", ios->clock);
Sahitya Tummala7a892482011-01-18 11:22:49 +05301983
San Mehat9d2bd732009-09-22 16:44:22 -07001984 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001985 spin_lock_irqsave(&host->lock, flags);
1986 if (!host->clks_on) {
1987 msmsdcc_setup_clocks(host, true);
1988 host->clks_on = 1;
1989 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
1990 if (!host->plat->sdiowakeup_irq) {
1991 writel_relaxed(host->mci_irqenable,
1992 host->base + MMCIMASK0);
1993 mb();
1994 if (host->plat->cfg_mpm_sdiowakeup &&
1995 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
1996 host->plat->cfg_mpm_sdiowakeup(
1997 mmc_dev(mmc), SDC_DAT1_DISWAKE);
1998 msmsdcc_disable_irq_wake(host);
1999 } else if (!(mmc->pm_flags &
2000 MMC_PM_WAKE_SDIO_IRQ)) {
2001 writel_relaxed(host->mci_irqenable,
2002 host->base + MMCIMASK0);
2003 }
2004 }
San Mehat9d2bd732009-09-22 16:44:22 -07002005 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002006 spin_unlock_irqrestore(&host->lock, flags);
2007
2008 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2009 /*
2010 * For DDR50 mode, controller needs clock rate to be
2011 * double than what is required on the SD card CLK pin.
2012 */
Subhash Jadavanib808efac2011-06-27 15:14:07 -07002013 if (ios->ddr || (ios->timing == MMC_TIMING_UHS_DDR50)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002014 /*
2015 * Make sure that we don't double the clock if
2016 * doubled clock rate is already set
2017 */
2018 if (!host->ddr_doubled_clk_rate ||
2019 (host->ddr_doubled_clk_rate &&
2020 (host->ddr_doubled_clk_rate != ios->clock))) {
2021 host->ddr_doubled_clk_rate =
2022 msmsdcc_get_sup_clk_rate(
2023 host, (ios->clock * 2));
2024 clock = host->ddr_doubled_clk_rate;
2025 }
2026 } else {
2027 host->ddr_doubled_clk_rate = 0;
2028 }
2029
2030 if (clock != host->clk_rate) {
2031 rc = clk_set_rate(host->clk, clock);
2032 if (rc < 0)
2033 pr_debug("%s: failed to set clk rate %u\n",
2034 mmc_hostname(mmc), clock);
2035 host->clk_rate = clock;
2036 }
2037 /*
2038 * give atleast 2 MCLK cycles delay for clocks
2039 * and SDCC core to stabilize
2040 */
2041 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002042 clk |= MCI_CLK_ENABLE;
2043 }
2044
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002045 if (ios->bus_width == MMC_BUS_WIDTH_8)
2046 clk |= MCI_CLK_WIDEBUS_8;
2047 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2048 clk |= MCI_CLK_WIDEBUS_4;
2049 else
2050 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002051
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002052 if (msmsdcc_is_pwrsave(host))
2053 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002054
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002055 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002056
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002057 host->tuning_needed = 0;
2058 /*
2059 * Select the controller timing mode according
2060 * to current bus speed mode
2061 */
2062 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2063 (ios->timing == MMC_TIMING_UHS_SDR50)) {
2064 clk |= (4 << 14);
2065 host->tuning_needed = 1;
Subhash Jadavanib808efac2011-06-27 15:14:07 -07002066 } else if (ios->ddr || ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002067 clk |= (3 << 14);
2068 } else {
2069 clk |= (2 << 14); /* feedback clock */
2070 }
2071
2072 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2073 clk |= (2 << 23);
2074
2075 if (host->io_pad_pwr_switch)
2076 clk |= IO_PAD_PWR_SWITCH;
2077
2078 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
San Mehat9d2bd732009-09-22 16:44:22 -07002079 pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002080 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2081 pwr |= msmsdcc_setup_vreg(host, !!ios->vdd);
San Mehat9d2bd732009-09-22 16:44:22 -07002082
2083 switch (ios->power_mode) {
2084 case MMC_POWER_OFF:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002085 htc_pwrsink_set(PWRSINK_SDCARD, 0);
2086 if (!host->sdcc_irq_disabled) {
2087 if (host->plat->cfg_mpm_sdiowakeup)
2088 host->plat->cfg_mpm_sdiowakeup(
2089 mmc_dev(mmc), SDC_DAT1_DISABLE);
2090 disable_irq(host->core_irqres->start);
2091 host->sdcc_irq_disabled = 1;
2092 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302093 /*
2094 * As VDD pad rail is always on, set low voltage for VDD
2095 * pad rail when slot is unused (when card is not present
2096 * or during system suspend).
2097 */
2098 msmsdcc_set_vddp_low_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002099 msmsdcc_setup_pins(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002100 break;
2101 case MMC_POWER_UP:
2102 pwr |= MCI_PWR_UP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002103 if (host->sdcc_irq_disabled) {
2104 if (host->plat->cfg_mpm_sdiowakeup)
2105 host->plat->cfg_mpm_sdiowakeup(
2106 mmc_dev(mmc), SDC_DAT1_ENABLE);
2107 enable_irq(host->core_irqres->start);
2108 host->sdcc_irq_disabled = 0;
2109 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302110 msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002111 msmsdcc_setup_pins(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07002112 break;
2113 case MMC_POWER_ON:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002114 htc_pwrsink_set(PWRSINK_SDCARD, 100);
San Mehat9d2bd732009-09-22 16:44:22 -07002115 pwr |= MCI_PWR_ON;
2116 break;
2117 }
2118
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002119 spin_lock_irqsave(&host->lock, flags);
2120 if (!host->clks_on) {
2121 /* force the clocks to be on */
2122 msmsdcc_setup_clocks(host, true);
2123 /*
2124 * give atleast 2 MCLK cycles delay for clocks
2125 * and SDCC core to stabilize
2126 */
2127 msmsdcc_delay(host);
2128 }
2129 writel_relaxed(clk, host->base + MMCICLOCK);
2130 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002131
2132 if (host->pwr != pwr) {
2133 host->pwr = pwr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002134 writel_relaxed(pwr, host->base + MMCIPOWER);
2135 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07002136 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002137 if (!host->clks_on) {
2138 /* force the clocks to be off */
2139 msmsdcc_setup_clocks(host, false);
2140 /*
2141 * give atleast 2 MCLK cycles delay for clocks
2142 * and SDCC core to stabilize
2143 */
2144 msmsdcc_delay(host);
2145 }
2146
2147 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
2148 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2149 if (!host->plat->sdiowakeup_irq) {
2150 writel_relaxed(MCI_SDIOINTMASK,
2151 host->base + MMCIMASK0);
2152 mb();
2153 if (host->plat->cfg_mpm_sdiowakeup &&
2154 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2155 host->plat->cfg_mpm_sdiowakeup(
2156 mmc_dev(mmc), SDC_DAT1_ENWAKE);
2157 msmsdcc_enable_irq_wake(host);
2158 } else if (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2159 writel_relaxed(0, host->base + MMCIMASK0);
2160 } else {
2161 writel_relaxed(MCI_SDIOINTMASK,
2162 host->base + MMCIMASK0);
2163 }
2164 msmsdcc_delay(host);
2165 }
2166 msmsdcc_setup_clocks(host, false);
2167 host->clks_on = 0;
2168 }
San Mehat4adbbcc2009-11-08 13:00:37 -08002169 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002170}
2171
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002172int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2173{
2174 struct msmsdcc_host *host = mmc_priv(mmc);
2175 u32 clk;
2176
2177 clk = readl_relaxed(host->base + MMCICLOCK);
2178 pr_debug("Changing to pwr_save=%d", pwrsave);
2179 if (pwrsave && msmsdcc_is_pwrsave(host))
2180 clk |= MCI_CLK_PWRSAVE;
2181 else
2182 clk &= ~MCI_CLK_PWRSAVE;
2183 writel_relaxed(clk, host->base + MMCICLOCK);
2184 mb();
2185
2186 return 0;
2187}
2188
2189static int msmsdcc_get_ro(struct mmc_host *mmc)
2190{
2191 int status = -ENOSYS;
2192 struct msmsdcc_host *host = mmc_priv(mmc);
2193
2194 if (host->plat->wpswitch) {
2195 status = host->plat->wpswitch(mmc_dev(mmc));
2196 } else if (host->plat->wpswitch_gpio) {
2197 status = gpio_request(host->plat->wpswitch_gpio,
2198 "SD_WP_Switch");
2199 if (status) {
2200 pr_err("%s: %s: Failed to request GPIO %d\n",
2201 mmc_hostname(mmc), __func__,
2202 host->plat->wpswitch_gpio);
2203 } else {
2204 status = gpio_direction_input(
2205 host->plat->wpswitch_gpio);
2206 if (!status) {
2207 /*
2208 * Wait for atleast 300ms as debounce
2209 * time for GPIO input to stabilize.
2210 */
2211 msleep(300);
2212 status = gpio_get_value_cansleep(
2213 host->plat->wpswitch_gpio);
2214 status ^= !host->plat->wpswitch_polarity;
2215 }
2216 gpio_free(host->plat->wpswitch_gpio);
2217 }
2218 }
2219
2220 if (status < 0)
2221 status = -ENOSYS;
2222 pr_debug("%s: Card read-only status %d\n", __func__, status);
2223
2224 return status;
2225}
2226
2227#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002228static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2229{
2230 struct msmsdcc_host *host = mmc_priv(mmc);
2231 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002232
2233 if (enable) {
2234 spin_lock_irqsave(&host->lock, flags);
2235 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
2236 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
2237 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2238 spin_unlock_irqrestore(&host->lock, flags);
2239 } else {
2240 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
2241 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
2242 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2243 }
2244 mb();
2245}
2246#endif /* CONFIG_MMC_MSM_SDIO_SUPPORT */
2247
2248#ifdef CONFIG_PM_RUNTIME
2249static int msmsdcc_enable(struct mmc_host *mmc)
2250{
Sahitya Tummala8605fca2011-08-22 15:39:19 +05302251 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002252 struct device *dev = mmc->parent;
2253
Sahitya Tummala8605fca2011-08-22 15:39:19 +05302254 if (pm_runtime_suspended(dev))
2255 rc = pm_runtime_get_sync(dev);
2256 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002257 pm_runtime_get_noresume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002258
Sahitya Tummala8605fca2011-08-22 15:39:19 +05302259 if (rc < 0)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002260 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2261 __func__, rc);
Sahitya Tummala8605fca2011-08-22 15:39:19 +05302262 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002263}
2264
2265static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2266{
2267 int rc;
2268
2269 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO)
2270 return -ENOTSUPP;
2271
2272 rc = pm_runtime_put_sync(mmc->parent);
2273
2274 if (rc < 0)
2275 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2276 __func__, rc);
2277 return rc;
2278}
2279#else
2280#define msmsdcc_enable NULL
2281#define msmsdcc_disable NULL
2282#endif
2283
2284static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2285 struct mmc_ios *ios)
2286{
2287 struct msmsdcc_host *host = mmc_priv(mmc);
2288 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302289 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002290
2291 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2292 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302293 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002294 goto out;
2295 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2296 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302297 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002298 goto out;
2299 }
San Mehat9d2bd732009-09-22 16:44:22 -07002300
2301 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002302 /*
2303 * If we are here means voltage switch from high voltage to
2304 * low voltage is required
2305 */
2306
2307 /*
2308 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2309 * register until they become all zeros.
2310 */
2311 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302312 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002313 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2314 mmc_hostname(mmc), __func__);
2315 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002316 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002317
2318 /* Stop SD CLK output. */
2319 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2320 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2321
San Mehat9d2bd732009-09-22 16:44:22 -07002322 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002323
2324 /*
2325 * Switch VDDPX from high voltage to low voltage
2326 * to change the VDD of the SD IO pads.
2327 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302328 rc = msmsdcc_set_vddp_low_vol(host);
2329 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002330 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002331
2332 spin_lock_irqsave(&host->lock, flags);
2333 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2334 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
2335 host->io_pad_pwr_switch = 1;
2336 spin_unlock_irqrestore(&host->lock, flags);
2337
2338 /* Wait 5 ms for the voltage regulater in the card to become stable. */
2339 usleep_range(5000, 5500);
2340
2341 spin_lock_irqsave(&host->lock, flags);
2342 /* Start SD CLK output. */
2343 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2344 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2345 spin_unlock_irqrestore(&host->lock, flags);
2346
2347 /*
2348 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
2349 * don't become all ones within 1 ms then a Voltage Switch
2350 * sequence has failed and a power cycle to the card is required.
2351 * Otherwise Voltage Switch sequence is completed successfully.
2352 */
2353 usleep_range(1000, 1500);
2354
2355 spin_lock_irqsave(&host->lock, flags);
2356 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
2357 != (0xF << 1)) {
2358 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
2359 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302360 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002361 goto out_unlock;
2362 }
2363
2364out_unlock:
2365 spin_unlock_irqrestore(&host->lock, flags);
2366out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302367 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002368}
2369
2370static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2371 u8 phase);
2372/* Initialize the DLL (Programmable Delay Line ) */
2373static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
2374{
2375 int rc = 0;
2376 u32 wait_timeout;
2377
2378 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
2379 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2380 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2381
2382 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
2383 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2384 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2385
2386 msmsdcc_delay(host);
2387
2388 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
2389 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2390 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2391
2392 /* Initialize the phase to 0 */
2393 rc = msmsdcc_config_cm_sdc4_dll_phase(host, 0);
2394 if (rc)
2395 goto out;
2396
2397 wait_timeout = 1000;
2398 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
2399 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
2400 /* max. wait for 1 sec for LOCK bit to be set */
2401 if (--wait_timeout == 0) {
2402 pr_err("%s: %s: DLL failed to lock at phase: %d",
2403 mmc_hostname(host->mmc), __func__, 0);
2404 rc = -1;
2405 goto out;
2406 }
2407 /* wait for 1ms */
2408 usleep_range(1000, 1500);
2409 }
2410out:
2411 return rc;
2412}
2413
2414/*
2415 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
2416 * calibration sequence. This function should be called before
2417 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
2418 * commands (CMD17/CMD18).
2419 */
2420static void msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
2421{
2422 /* Set CDR_EN bit to 1. */
2423 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) |
2424 MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2425
2426 /* Set CDR_EXT_EN bit to 0. */
2427 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2428 & ~MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2429
2430 /* Set CK_OUT_EN bit to 0. */
2431 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2432 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2433
2434 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2435 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)
2436 ;
2437
2438 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2439 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2440 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2441
2442 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register is 1. */
2443 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN))
2444 ;
2445}
2446
2447static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2448 u8 phase)
2449{
2450 int rc = 0;
2451 u32 mclk_freq = 0;
2452 u32 wait_timeout;
2453
2454 /* Set CDR_EN bit to 0. */
2455 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2456 & ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2457
2458 /* Set CDR_EXT_EN bit to 1. */
2459 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2460 | MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2461
2462 /* Program the MCLK value to MCLK_FREQ bit field */
2463 if (host->clk_rate <= 112000000)
2464 mclk_freq = 0;
2465 else if (host->clk_rate <= 125000000)
2466 mclk_freq = 1;
2467 else if (host->clk_rate <= 137000000)
2468 mclk_freq = 2;
2469 else if (host->clk_rate <= 150000000)
2470 mclk_freq = 3;
2471 else if (host->clk_rate <= 162000000)
2472 mclk_freq = 4;
2473 else if (host->clk_rate <= 175000000)
2474 mclk_freq = 5;
2475 else if (host->clk_rate <= 187000000)
2476 mclk_freq = 6;
2477 else if (host->clk_rate <= 200000000)
2478 mclk_freq = 7;
2479
2480 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2481 & ~(7 << 24)) | (mclk_freq << 24)),
2482 host->base + MCI_DLL_CONFIG);
2483
2484 /* Set CK_OUT_EN bit to 0. */
2485 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2486 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2487
2488 /* Set DLL_EN bit to 1. */
2489 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2490 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
2491
2492 wait_timeout = 1000;
2493 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2494 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN) {
2495 /* max. wait for 1 sec for LOCK bit for be set */
2496 if (--wait_timeout == 0) {
2497 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 0",
2498 mmc_hostname(host->mmc), __func__, phase);
2499 rc = -1;
2500 goto out;
2501 }
2502 /* wait for 1ms */
2503 usleep_range(1000, 1500);
2504 }
2505
2506 /*
2507 * Write the selected DLL clock output phase (0 ... 15)
2508 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
2509 */
2510 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2511 & ~(0xF << 20)) | (phase << 20)),
2512 host->base + MCI_DLL_CONFIG);
2513
2514 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2515 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2516 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2517
2518 wait_timeout = 1000;
2519 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
2520 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)) {
2521 /* max. wait for 1 sec for LOCK bit for be set */
2522 if (--wait_timeout == 0) {
2523 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 1",
2524 mmc_hostname(host->mmc), __func__, phase);
2525 rc = -1;
2526 goto out;
2527 }
2528 /* wait for 1ms */
2529 usleep_range(1000, 1500);
2530 }
2531out:
2532 return rc;
2533}
2534
2535static int msmsdcc_execute_tuning(struct mmc_host *mmc)
2536{
2537 struct msmsdcc_host *host = mmc_priv(mmc);
2538 u8 phase;
2539 u8 *data_buf;
2540 u8 tuned_phases[16], tuned_phase_cnt = 0;
2541 int rc = 0;
2542
2543 /* Tuning is only required for SDR50 & SDR104 modes */
2544 if (!host->tuning_needed) {
2545 rc = 0;
2546 goto out;
2547 }
2548
2549 host->cmd19_tuning_in_progress = 1;
2550 /*
2551 * Make sure that clock is always enabled when DLL
2552 * tuning is in progress. Keeping PWRSAVE ON may
2553 * turn off the clock. So let's disable the PWRSAVE
2554 * here and re-enable it once tuning is completed.
2555 */
2556 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2557 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2558 /* first of all reset the tuning block */
2559 rc = msmsdcc_init_cm_sdc4_dll(host);
2560 if (rc)
2561 goto out;
2562
2563 data_buf = kmalloc(64, GFP_KERNEL);
2564 if (!data_buf) {
2565 rc = -ENOMEM;
2566 goto out;
2567 }
2568
2569 phase = 0;
2570 do {
2571 struct mmc_command cmd = {0};
2572 struct mmc_data data = {0};
2573 struct mmc_request mrq = {
2574 .cmd = &cmd,
2575 .data = &data
2576 };
2577 struct scatterlist sg;
2578
2579 /* set the phase in delay line hw block */
2580 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2581 if (rc)
2582 goto kfree;
2583
2584 cmd.opcode = MMC_SEND_TUNING_BLOCK;
2585 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
2586
2587 data.blksz = 64;
2588 data.blocks = 1;
2589 data.flags = MMC_DATA_READ;
2590 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
2591
2592 data.sg = &sg;
2593 data.sg_len = 1;
2594 sg_init_one(&sg, data_buf, 64);
2595 memset(data_buf, 0, 64);
2596 mmc_wait_for_req(mmc, &mrq);
2597
2598 if (!cmd.error && !data.error &&
2599 !memcmp(data_buf, cmd19_tuning_block, 64)) {
2600 /* tuning is successful with this tuning point */
2601 tuned_phases[tuned_phase_cnt++] = phase;
2602 }
2603 } while (++phase < 16);
2604
2605 kfree(data_buf);
2606
2607 if (tuned_phase_cnt) {
2608 tuned_phase_cnt--;
2609 tuned_phase_cnt = (tuned_phase_cnt * 3) / 4;
2610 phase = tuned_phases[tuned_phase_cnt];
2611 /*
2612 * Finally set the selected phase in delay
2613 * line hw block.
2614 */
2615 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2616 if (rc)
2617 goto out;
2618 } else {
2619 /* tuning failed */
2620 rc = -EAGAIN;
2621 pr_err("%s: %s: no tuning point found",
2622 mmc_hostname(mmc), __func__);
2623 }
2624 goto out;
2625
2626kfree:
2627 kfree(data_buf);
2628out:
2629 /* re-enable PWESAVE */
2630 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2631 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2632 host->cmd19_tuning_in_progress = 0;
2633 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07002634}
2635
2636static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002637 .enable = msmsdcc_enable,
2638 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07002639 .request = msmsdcc_request,
2640 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002641 .get_ro = msmsdcc_get_ro,
2642#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002643 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002644#endif
2645 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
2646 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07002647};
2648
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002649static unsigned int
2650msmsdcc_slot_status(struct msmsdcc_host *host)
2651{
2652 int status;
2653 unsigned int gpio_no = host->plat->status_gpio;
2654
2655 status = gpio_request(gpio_no, "SD_HW_Detect");
2656 if (status) {
2657 pr_err("%s: %s: Failed to request GPIO %d\n",
2658 mmc_hostname(host->mmc), __func__, gpio_no);
2659 } else {
2660 status = gpio_direction_input(gpio_no);
2661 if (!status)
2662 status = !gpio_get_value_cansleep(gpio_no);
2663 gpio_free(gpio_no);
2664 }
2665 return status;
2666}
2667
San Mehat9d2bd732009-09-22 16:44:22 -07002668static void
2669msmsdcc_check_status(unsigned long data)
2670{
2671 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
2672 unsigned int status;
2673
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002674 if (host->plat->status || host->plat->status_gpio) {
2675 if (host->plat->status)
2676 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07002677 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002678 status = msmsdcc_slot_status(host);
2679
2680 host->eject = !status;
2681 if (status ^ host->oldstat) {
2682 pr_info("%s: Slot status change detected (%d -> %d)\n",
2683 mmc_hostname(host->mmc), host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07002684 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002685 }
2686 host->oldstat = status;
2687 } else {
2688 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07002689 }
San Mehat9d2bd732009-09-22 16:44:22 -07002690}
2691
2692static irqreturn_t
2693msmsdcc_platform_status_irq(int irq, void *dev_id)
2694{
2695 struct msmsdcc_host *host = dev_id;
2696
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002697 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07002698 msmsdcc_check_status((unsigned long) host);
2699 return IRQ_HANDLED;
2700}
2701
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002702static irqreturn_t
2703msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
2704{
2705 struct msmsdcc_host *host = dev_id;
2706
2707 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
2708 spin_lock(&host->lock);
2709 if (!host->sdio_irq_disabled) {
2710 disable_irq_nosync(irq);
2711 if (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2712 wake_lock(&host->sdio_wlock);
2713 msmsdcc_disable_irq_wake(host);
2714 }
2715 host->sdio_irq_disabled = 1;
2716 }
2717 if (host->plat->is_sdio_al_client) {
2718 if (!host->clks_on) {
2719 msmsdcc_setup_clocks(host, true);
2720 host->clks_on = 1;
2721 }
2722 if (host->sdcc_irq_disabled) {
2723 writel_relaxed(host->mci_irqenable,
2724 host->base + MMCIMASK0);
2725 mb();
2726 enable_irq(host->core_irqres->start);
2727 host->sdcc_irq_disabled = 0;
2728 }
2729 wake_lock(&host->sdio_wlock);
2730 }
2731 spin_unlock(&host->lock);
2732
2733 return IRQ_HANDLED;
2734}
2735
San Mehat9d2bd732009-09-22 16:44:22 -07002736static void
2737msmsdcc_status_notify_cb(int card_present, void *dev_id)
2738{
2739 struct msmsdcc_host *host = dev_id;
2740
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002741 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07002742 card_present);
2743 msmsdcc_check_status((unsigned long) host);
2744}
2745
San Mehat9d2bd732009-09-22 16:44:22 -07002746static int
2747msmsdcc_init_dma(struct msmsdcc_host *host)
2748{
2749 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
2750 host->dma.host = host;
2751 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07002752 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07002753
2754 if (!host->dmares)
2755 return -ENODEV;
2756
2757 host->dma.nc = dma_alloc_coherent(NULL,
2758 sizeof(struct msmsdcc_nc_dmadata),
2759 &host->dma.nc_busaddr,
2760 GFP_KERNEL);
2761 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07002762 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07002763 return -ENOMEM;
2764 }
2765 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
2766 host->dma.cmd_busaddr = host->dma.nc_busaddr;
2767 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
2768 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
2769 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07002770 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07002771
2772 return 0;
2773}
2774
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002775#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
2776/**
2777 * Allocate and Connect a SDCC peripheral's SPS endpoint
2778 *
2779 * This function allocates endpoint context and
2780 * connect it with memory endpoint by calling
2781 * appropriate SPS driver APIs.
2782 *
2783 * Also registers a SPS callback function with
2784 * SPS driver
2785 *
2786 * This function should only be called once typically
2787 * during driver probe.
2788 *
2789 * @host - Pointer to sdcc host structure
2790 * @ep - Pointer to sps endpoint data structure
2791 * @is_produce - 1 means Producer endpoint
2792 * 0 means Consumer endpoint
2793 *
2794 * @return - 0 if successful else negative value.
2795 *
2796 */
2797static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
2798 struct msmsdcc_sps_ep_conn_data *ep,
2799 bool is_producer)
2800{
2801 int rc = 0;
2802 struct sps_pipe *sps_pipe_handle;
2803 struct sps_connect *sps_config = &ep->config;
2804 struct sps_register_event *sps_event = &ep->event;
2805
2806 /* Allocate endpoint context */
2807 sps_pipe_handle = sps_alloc_endpoint();
2808 if (!sps_pipe_handle) {
2809 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
2810 mmc_hostname(host->mmc), is_producer);
2811 rc = -ENOMEM;
2812 goto out;
2813 }
2814
2815 /* Get default connection configuration for an endpoint */
2816 rc = sps_get_config(sps_pipe_handle, sps_config);
2817 if (rc) {
2818 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
2819 " rc=%d", mmc_hostname(host->mmc),
2820 (u32)sps_pipe_handle, rc);
2821 goto get_config_err;
2822 }
2823
2824 /* Modify the default connection configuration */
2825 if (is_producer) {
2826 /*
2827 * For SDCC producer transfer, source should be
2828 * SDCC peripheral where as destination should
2829 * be system memory.
2830 */
2831 sps_config->source = host->sps.bam_handle;
2832 sps_config->destination = SPS_DEV_HANDLE_MEM;
2833 /* Producer pipe will handle this connection */
2834 sps_config->mode = SPS_MODE_SRC;
2835 sps_config->options =
2836 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
2837 } else {
2838 /*
2839 * For SDCC consumer transfer, source should be
2840 * system memory where as destination should
2841 * SDCC peripheral
2842 */
2843 sps_config->source = SPS_DEV_HANDLE_MEM;
2844 sps_config->destination = host->sps.bam_handle;
2845 sps_config->mode = SPS_MODE_DEST;
2846 sps_config->options =
2847 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
2848 }
2849
2850 /* Producer pipe index */
2851 sps_config->src_pipe_index = host->sps.src_pipe_index;
2852 /* Consumer pipe index */
2853 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
2854 /*
2855 * This event thresold value is only significant for BAM-to-BAM
2856 * transfer. It's ignored for BAM-to-System mode transfer.
2857 */
2858 sps_config->event_thresh = 0x10;
2859 /*
2860 * Max. no of scatter/gather buffers that can
2861 * be passed by block layer = 32 (NR_SG).
2862 * Each BAM descritor needs 64 bits (8 bytes).
2863 * One BAM descriptor is required per buffer transfer.
2864 * So we would require total 256 (32 * 8) bytes of descriptor FIFO.
2865 * But due to HW limitation we need to allocate atleast one extra
2866 * descriptor memory (256 bytes + 8 bytes). But in order to be
2867 * in power of 2, we are allocating 512 bytes of memory.
2868 */
2869 sps_config->desc.size = 512;
2870 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
2871 sps_config->desc.size,
2872 &sps_config->desc.phys_base,
2873 GFP_KERNEL);
2874
2875 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
2876
2877 /* Establish connection between peripheral and memory endpoint */
2878 rc = sps_connect(sps_pipe_handle, sps_config);
2879 if (rc) {
2880 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
2881 " rc=%d", mmc_hostname(host->mmc),
2882 (u32)sps_pipe_handle, rc);
2883 goto sps_connect_err;
2884 }
2885
2886 sps_event->mode = SPS_TRIGGER_CALLBACK;
2887 sps_event->options = SPS_O_EOT;
2888 sps_event->callback = msmsdcc_sps_complete_cb;
2889 sps_event->xfer_done = NULL;
2890 sps_event->user = (void *)host;
2891
2892 /* Register callback event for EOT (End of transfer) event. */
2893 rc = sps_register_event(sps_pipe_handle, sps_event);
2894 if (rc) {
2895 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
2896 " rc=%d", mmc_hostname(host->mmc),
2897 (u32)sps_pipe_handle, rc);
2898 goto reg_event_err;
2899 }
2900 /* Now save the sps pipe handle */
2901 ep->pipe_handle = sps_pipe_handle;
2902 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
2903 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
2904 __func__, is_producer ? "READ" : "WRITE",
2905 (u32)sps_pipe_handle, sps_config->desc.phys_base);
2906 goto out;
2907
2908reg_event_err:
2909 sps_disconnect(sps_pipe_handle);
2910sps_connect_err:
2911 dma_free_coherent(mmc_dev(host->mmc),
2912 sps_config->desc.size,
2913 sps_config->desc.base,
2914 sps_config->desc.phys_base);
2915get_config_err:
2916 sps_free_endpoint(sps_pipe_handle);
2917out:
2918 return rc;
2919}
2920
2921/**
2922 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
2923 *
2924 * This function disconnect endpoint and deallocates
2925 * endpoint context.
2926 *
2927 * This function should only be called once typically
2928 * during driver remove.
2929 *
2930 * @host - Pointer to sdcc host structure
2931 * @ep - Pointer to sps endpoint data structure
2932 *
2933 */
2934static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
2935 struct msmsdcc_sps_ep_conn_data *ep)
2936{
2937 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
2938 struct sps_connect *sps_config = &ep->config;
2939 struct sps_register_event *sps_event = &ep->event;
2940
2941 sps_event->xfer_done = NULL;
2942 sps_event->callback = NULL;
2943 sps_register_event(sps_pipe_handle, sps_event);
2944 sps_disconnect(sps_pipe_handle);
2945 dma_free_coherent(mmc_dev(host->mmc),
2946 sps_config->desc.size,
2947 sps_config->desc.base,
2948 sps_config->desc.phys_base);
2949 sps_free_endpoint(sps_pipe_handle);
2950}
2951
2952/**
2953 * Reset SDCC peripheral's SPS endpoint
2954 *
2955 * This function disconnects an endpoint.
2956 *
2957 * This function should be called for reseting
2958 * SPS endpoint when data transfer error is
2959 * encountered during data transfer. This
2960 * can be considered as soft reset to endpoint.
2961 *
2962 * This function should only be called if
2963 * msmsdcc_sps_init() is already called.
2964 *
2965 * @host - Pointer to sdcc host structure
2966 * @ep - Pointer to sps endpoint data structure
2967 *
2968 * @return - 0 if successful else negative value.
2969 */
2970static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
2971 struct msmsdcc_sps_ep_conn_data *ep)
2972{
2973 int rc = 0;
2974 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
2975
2976 rc = sps_disconnect(sps_pipe_handle);
2977 if (rc) {
2978 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
2979 " rc=%d", mmc_hostname(host->mmc), __func__,
2980 (u32)sps_pipe_handle, rc);
2981 goto out;
2982 }
2983 out:
2984 return rc;
2985}
2986
2987/**
2988 * Restore SDCC peripheral's SPS endpoint
2989 *
2990 * This function connects an endpoint.
2991 *
2992 * This function should be called for restoring
2993 * SPS endpoint after data transfer error is
2994 * encountered during data transfer. This
2995 * can be considered as soft reset to endpoint.
2996 *
2997 * This function should only be called if
2998 * msmsdcc_sps_reset_ep() is called before.
2999 *
3000 * @host - Pointer to sdcc host structure
3001 * @ep - Pointer to sps endpoint data structure
3002 *
3003 * @return - 0 if successful else negative value.
3004 */
3005static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3006 struct msmsdcc_sps_ep_conn_data *ep)
3007{
3008 int rc = 0;
3009 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3010 struct sps_connect *sps_config = &ep->config;
3011 struct sps_register_event *sps_event = &ep->event;
3012
3013 /* Establish connection between peripheral and memory endpoint */
3014 rc = sps_connect(sps_pipe_handle, sps_config);
3015 if (rc) {
3016 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3017 " rc=%d", mmc_hostname(host->mmc), __func__,
3018 (u32)sps_pipe_handle, rc);
3019 goto out;
3020 }
3021
3022 /* Register callback event for EOT (End of transfer) event. */
3023 rc = sps_register_event(sps_pipe_handle, sps_event);
3024 if (rc) {
3025 pr_err("%s: %s: sps_register_event() failed!!!"
3026 " pipe_handle=0x%x, rc=%d",
3027 mmc_hostname(host->mmc), __func__,
3028 (u32)sps_pipe_handle, rc);
3029 goto reg_event_err;
3030 }
3031 goto out;
3032
3033reg_event_err:
3034 sps_disconnect(sps_pipe_handle);
3035out:
3036 return rc;
3037}
3038
3039/**
3040 * Initialize SPS HW connected with SDCC core
3041 *
3042 * This function register BAM HW resources with
3043 * SPS driver and then initialize 2 SPS endpoints
3044 *
3045 * This function should only be called once typically
3046 * during driver probe.
3047 *
3048 * @host - Pointer to sdcc host structure
3049 *
3050 * @return - 0 if successful else negative value.
3051 *
3052 */
3053static int msmsdcc_sps_init(struct msmsdcc_host *host)
3054{
3055 int rc = 0;
3056 struct sps_bam_props bam = {0};
3057
3058 host->bam_base = ioremap(host->bam_memres->start,
3059 resource_size(host->bam_memres));
3060 if (!host->bam_base) {
3061 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3062 " size=0x%x", mmc_hostname(host->mmc),
3063 host->bam_memres->start,
3064 (host->bam_memres->end -
3065 host->bam_memres->start));
3066 rc = -ENOMEM;
3067 goto out;
3068 }
3069
3070 bam.phys_addr = host->bam_memres->start;
3071 bam.virt_addr = host->bam_base;
3072 /*
3073 * This event thresold value is only significant for BAM-to-BAM
3074 * transfer. It's ignored for BAM-to-System mode transfer.
3075 */
3076 bam.event_threshold = 0x10; /* Pipe event threshold */
3077 /*
3078 * This threshold controls when the BAM publish
3079 * the descriptor size on the sideband interface.
3080 * SPS HW will only be used when
3081 * data transfer size > MCI_FIFOSIZE (64 bytes).
3082 * PIO mode will be used when
3083 * data transfer size < MCI_FIFOSIZE (64 bytes).
3084 * So set this thresold value to 64 bytes.
3085 */
3086 bam.summing_threshold = 64;
3087 /* SPS driver wll handle the SDCC BAM IRQ */
3088 bam.irq = (u32)host->bam_irqres->start;
3089 bam.manage = SPS_BAM_MGR_LOCAL;
3090
3091 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3092 (u32)bam.phys_addr);
3093 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3094 (u32)bam.virt_addr);
3095
3096 /* Register SDCC Peripheral BAM device to SPS driver */
3097 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3098 if (rc) {
3099 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3100 mmc_hostname(host->mmc), rc);
3101 goto reg_bam_err;
3102 }
3103 pr_info("%s: BAM device registered. bam_handle=0x%x",
3104 mmc_hostname(host->mmc), host->sps.bam_handle);
3105
3106 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3107 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3108
3109 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3110 SPS_PROD_PERIPHERAL);
3111 if (rc)
3112 goto sps_reset_err;
3113 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3114 SPS_CONS_PERIPHERAL);
3115 if (rc)
3116 goto cons_conn_err;
3117
3118 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3119 mmc_hostname(host->mmc),
3120 (unsigned long long)host->bam_memres->start,
3121 (unsigned int)host->bam_irqres->start);
3122 goto out;
3123
3124cons_conn_err:
3125 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3126sps_reset_err:
3127 sps_deregister_bam_device(host->sps.bam_handle);
3128reg_bam_err:
3129 iounmap(host->bam_base);
3130out:
3131 return rc;
3132}
3133
3134/**
3135 * De-initialize SPS HW connected with SDCC core
3136 *
3137 * This function deinitialize SPS endpoints and then
3138 * deregisters BAM resources from SPS driver.
3139 *
3140 * This function should only be called once typically
3141 * during driver remove.
3142 *
3143 * @host - Pointer to sdcc host structure
3144 *
3145 */
3146static void msmsdcc_sps_exit(struct msmsdcc_host *host)
3147{
3148 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
3149 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3150 sps_deregister_bam_device(host->sps.bam_handle);
3151 iounmap(host->bam_base);
3152}
3153#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
3154
3155static ssize_t
3156show_polling(struct device *dev, struct device_attribute *attr, char *buf)
3157{
3158 struct mmc_host *mmc = dev_get_drvdata(dev);
3159 struct msmsdcc_host *host = mmc_priv(mmc);
3160 int poll;
3161 unsigned long flags;
3162
3163 spin_lock_irqsave(&host->lock, flags);
3164 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
3165 spin_unlock_irqrestore(&host->lock, flags);
3166
3167 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
3168}
3169
3170static ssize_t
3171set_polling(struct device *dev, struct device_attribute *attr,
3172 const char *buf, size_t count)
3173{
3174 struct mmc_host *mmc = dev_get_drvdata(dev);
3175 struct msmsdcc_host *host = mmc_priv(mmc);
3176 int value;
3177 unsigned long flags;
3178
3179 sscanf(buf, "%d", &value);
3180
3181 spin_lock_irqsave(&host->lock, flags);
3182 if (value) {
3183 mmc->caps |= MMC_CAP_NEEDS_POLL;
3184 mmc_detect_change(host->mmc, 0);
3185 } else {
3186 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3187 }
3188#ifdef CONFIG_HAS_EARLYSUSPEND
3189 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
3190#endif
3191 spin_unlock_irqrestore(&host->lock, flags);
3192 return count;
3193}
3194
3195static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
3196 show_polling, set_polling);
3197static struct attribute *dev_attrs[] = {
3198 &dev_attr_polling.attr,
3199 NULL,
3200};
3201static struct attribute_group dev_attr_grp = {
3202 .attrs = dev_attrs,
3203};
3204
3205#ifdef CONFIG_HAS_EARLYSUSPEND
3206static void msmsdcc_early_suspend(struct early_suspend *h)
3207{
3208 struct msmsdcc_host *host =
3209 container_of(h, struct msmsdcc_host, early_suspend);
3210 unsigned long flags;
3211
3212 spin_lock_irqsave(&host->lock, flags);
3213 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
3214 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3215 spin_unlock_irqrestore(&host->lock, flags);
3216};
3217static void msmsdcc_late_resume(struct early_suspend *h)
3218{
3219 struct msmsdcc_host *host =
3220 container_of(h, struct msmsdcc_host, early_suspend);
3221 unsigned long flags;
3222
3223 if (host->polling_enabled) {
3224 spin_lock_irqsave(&host->lock, flags);
3225 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
3226 mmc_detect_change(host->mmc, 0);
3227 spin_unlock_irqrestore(&host->lock, flags);
3228 }
3229};
3230#endif
3231
3232static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
3233{
3234 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3235 struct mmc_request *mrq;
3236 unsigned long flags;
3237
3238 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003239 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003240 pr_info("%s: %s: dummy CMD52 timeout\n",
3241 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003242 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003243 }
3244
3245 mrq = host->curr.mrq;
3246
3247 if (mrq && mrq->cmd) {
3248 pr_info("%s: %s CMD%d\n", mmc_hostname(host->mmc),
3249 __func__, mrq->cmd->opcode);
3250 if (!mrq->cmd->error)
3251 mrq->cmd->error = -ETIMEDOUT;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003252 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003253 host->dummy_52_needed = 0;
3254 if (host->curr.data) {
3255 pr_info("%s: %s Request timeout\n",
3256 mmc_hostname(host->mmc), __func__);
3257 if (mrq->data && !mrq->data->error)
3258 mrq->data->error = -ETIMEDOUT;
3259 host->curr.data_xfered = 0;
3260 if (host->dma.sg && host->is_dma_mode) {
3261 msm_dmov_stop_cmd(host->dma.channel,
3262 &host->dma.hdr, 0);
3263 } else if (host->sps.sg && host->is_sps_mode) {
3264 /* Stop current SPS transfer */
3265 msmsdcc_sps_exit_curr_xfer(host);
3266 } else {
3267 msmsdcc_reset_and_restore(host);
3268 msmsdcc_stop_data(host);
3269 if (mrq->data && mrq->data->stop)
3270 msmsdcc_start_command(host,
3271 mrq->data->stop, 0);
3272 else
3273 msmsdcc_request_end(host, mrq);
3274 }
3275 } else {
3276 if (host->prog_enable) {
3277 host->prog_scan = 0;
3278 host->prog_enable = 0;
3279 }
3280 msmsdcc_reset_and_restore(host);
3281 msmsdcc_request_end(host, mrq);
3282 }
3283 }
3284 spin_unlock_irqrestore(&host->lock, flags);
3285}
3286
San Mehat9d2bd732009-09-22 16:44:22 -07003287static int
3288msmsdcc_probe(struct platform_device *pdev)
3289{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003290 struct mmc_platform_data *plat = pdev->dev.platform_data;
San Mehat9d2bd732009-09-22 16:44:22 -07003291 struct msmsdcc_host *host;
3292 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003293 unsigned long flags;
3294 struct resource *core_irqres = NULL;
3295 struct resource *bam_irqres = NULL;
3296 struct resource *core_memres = NULL;
3297 struct resource *dml_memres = NULL;
3298 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07003299 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07003300 struct resource *dma_crci_res = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07003301 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003302 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07003303
3304 /* must have platform data */
3305 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003306 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003307 ret = -EINVAL;
3308 goto out;
3309 }
3310
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003311 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07003312 return -EINVAL;
3313
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003314 if (plat->is_sdio_al_client)
3315 if (!plat->sdio_lpm_gpio_setup || !plat->sdiowakeup_irq)
3316 return -EINVAL;
3317
San Mehat9d2bd732009-09-22 16:44:22 -07003318 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003319 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003320 return -ENXIO;
3321 }
3322
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003323 for (i = 0; i < pdev->num_resources; i++) {
3324 if (pdev->resource[i].flags & IORESOURCE_MEM) {
3325 if (!strcmp(pdev->resource[i].name,
3326 "sdcc_dml_addr"))
3327 dml_memres = &pdev->resource[i];
3328 else if (!strcmp(pdev->resource[i].name,
3329 "sdcc_bam_addr"))
3330 bam_memres = &pdev->resource[i];
3331 else
3332 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07003333
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003334 }
3335 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
3336 if (!strcmp(pdev->resource[i].name,
3337 "sdcc_bam_irq"))
3338 bam_irqres = &pdev->resource[i];
3339 else
3340 core_irqres = &pdev->resource[i];
3341 }
Krishna Konda25786ec2011-07-25 16:21:36 -07003342 if (pdev->resource[i].flags & IORESOURCE_DMA) {
3343 if (!strncmp(pdev->resource[i].name,
3344 "sdcc_dma_chnl",
3345 sizeof("sdcc_dma_chnl")))
3346 dmares = &pdev->resource[i];
3347 else if (!strncmp(pdev->resource[i].name,
3348 "sdcc_dma_crci",
3349 sizeof("sdcc_dma_crci")))
3350 dma_crci_res = &pdev->resource[i];
3351 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003352 }
3353
3354 if (!core_irqres || !core_memres) {
3355 pr_err("%s: Invalid sdcc core resource\n", __func__);
3356 return -ENXIO;
3357 }
3358
3359 /*
3360 * Both BAM and DML memory resource should be preset.
3361 * BAM IRQ resource should also be present.
3362 */
3363 if ((bam_memres && !dml_memres) ||
3364 (!bam_memres && dml_memres) ||
3365 ((bam_memres && dml_memres) && !bam_irqres)) {
3366 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003367 return -ENXIO;
3368 }
3369
3370 /*
3371 * Setup our host structure
3372 */
San Mehat9d2bd732009-09-22 16:44:22 -07003373 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
3374 if (!mmc) {
3375 ret = -ENOMEM;
3376 goto out;
3377 }
3378
3379 host = mmc_priv(mmc);
3380 host->pdev_id = pdev->id;
3381 host->plat = plat;
3382 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08003383 host->curr.cmd = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003384 if (bam_memres && dml_memres && bam_irqres)
3385 host->is_sps_mode = 1;
3386 else if (dmares)
3387 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07003388
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003389 host->base = ioremap(core_memres->start,
3390 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07003391 if (!host->base) {
3392 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003393 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003394 }
3395
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003396 host->core_irqres = core_irqres;
3397 host->bam_irqres = bam_irqres;
3398 host->core_memres = core_memres;
3399 host->dml_memres = dml_memres;
3400 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07003401 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07003402 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07003403 spin_lock_init(&host->lock);
3404
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003405#ifdef CONFIG_MMC_EMBEDDED_SDIO
3406 if (plat->embedded_sdio)
3407 mmc_set_embedded_sdio_data(mmc,
3408 &plat->embedded_sdio->cis,
3409 &plat->embedded_sdio->cccr,
3410 plat->embedded_sdio->funcs,
3411 plat->embedded_sdio->num_funcs);
3412#endif
3413
Sahitya Tummala62612cf2010-12-08 15:03:03 +05303414 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
3415 (unsigned long)host);
3416
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003417 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
3418 (unsigned long)host);
3419 if (host->is_dma_mode) {
3420 /* Setup DMA */
3421 ret = msmsdcc_init_dma(host);
3422 if (ret)
3423 goto ioremap_free;
3424 } else {
3425 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003426 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003427 }
3428
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003429 /*
3430 * Setup SDCC clock if derived from Dayatona
3431 * fabric core clock.
3432 */
3433 if (plat->pclk_src_dfab) {
3434 host->dfab_pclk = clk_get(&pdev->dev, "dfab_sdc_clk");
3435 if (!IS_ERR(host->dfab_pclk)) {
3436 /* Set the clock rate to 64MHz for max. performance */
3437 ret = clk_set_rate(host->dfab_pclk, 64000000);
3438 if (ret)
3439 goto dfab_pclk_put;
3440 ret = clk_enable(host->dfab_pclk);
3441 if (ret)
3442 goto dfab_pclk_put;
3443 } else
3444 goto dma_free;
3445 }
3446
3447 /*
3448 * Setup main peripheral bus clock
3449 */
3450 host->pclk = clk_get(&pdev->dev, "sdc_pclk");
3451 if (!IS_ERR(host->pclk)) {
3452 ret = clk_enable(host->pclk);
3453 if (ret)
3454 goto pclk_put;
3455
3456 host->pclk_rate = clk_get_rate(host->pclk);
3457 }
3458
3459 /*
3460 * Setup SDC MMC clock
3461 */
San Mehat9d2bd732009-09-22 16:44:22 -07003462 host->clk = clk_get(&pdev->dev, "sdc_clk");
3463 if (IS_ERR(host->clk)) {
3464 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003465 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07003466 }
3467
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003468 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
3469 if (ret) {
3470 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
3471 goto clk_put;
3472 }
3473
3474 ret = clk_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003475 if (ret)
3476 goto clk_put;
3477
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003478 host->clk_rate = clk_get_rate(host->clk);
3479
3480 host->clks_on = 1;
3481
3482 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07003483 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003484 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07003485 goto clk_disable;
3486 }
3487
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003488
3489 /* Clocks has to be running before accessing SPS/DML HW blocks */
3490 if (host->is_sps_mode) {
3491 /* Initialize SPS */
3492 ret = msmsdcc_sps_init(host);
3493 if (ret)
3494 goto vreg_deinit;
3495 /* Initialize DML */
3496 ret = msmsdcc_dml_init(host);
3497 if (ret)
3498 goto sps_exit;
3499 }
San Mehat9d2bd732009-09-22 16:44:22 -07003500
San Mehat9d2bd732009-09-22 16:44:22 -07003501 /*
3502 * Setup MMC host structure
3503 */
3504 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003505 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
3506 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003507 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003508 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
3509 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07003510
San Mehat9d2bd732009-09-22 16:44:22 -07003511 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003512 mmc->caps |= plat->uhs_caps;
3513 /*
3514 * XPC controls the maximum current in the default speed mode of SDXC
3515 * card. XPC=0 means 100mA (max.) but speed class is not supported.
3516 * XPC=1 means 150mA (max.) and speed class is supported.
3517 */
3518 if (plat->xpc_cap)
3519 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
3520 MMC_CAP_SET_XPC_180);
3521
3522 if (plat->nonremovable)
3523 mmc->caps |= MMC_CAP_NONREMOVABLE;
3524#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
3525 mmc->caps |= MMC_CAP_SDIO_IRQ;
3526#endif
3527
3528 if (plat->is_sdio_al_client)
3529 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07003530
Martin K. Petersena36274e2010-09-10 01:33:59 -04003531 mmc->max_segs = NR_SG;
San Mehat9d2bd732009-09-22 16:44:22 -07003532 mmc->max_blk_size = 4096; /* MCI_DATA_CTL BLOCKSIZE up to 4096 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003533 mmc->max_blk_count = 65535;
San Mehat9d2bd732009-09-22 16:44:22 -07003534
3535 mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */
3536 mmc->max_seg_size = mmc->max_req_size;
3537
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003538 writel_relaxed(0, host->base + MMCIMASK0);
3539 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -07003540
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003541 /* Delay needed (MMCIMASK0 was just written above) */
3542 msmsdcc_delay(host);
3543 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
3544 mb();
3545 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07003546
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003547 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
3548 DRIVER_NAME " (cmd)", host);
3549 if (ret)
3550 goto dml_exit;
3551
3552 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
3553 DRIVER_NAME " (pio)", host);
3554 if (ret)
3555 goto irq_free;
3556
3557 /*
3558 * Enable SDCC IRQ only when host is powered on. Otherwise, this
3559 * IRQ is un-necessarily being monitored by MPM (Modem power
3560 * management block) during idle-power collapse. The MPM will be
3561 * configured to monitor the DATA1 GPIO line with level-low trigger
3562 * and thus depending on the GPIO status, it prevents TCXO shutdown
3563 * during idle-power collapse.
3564 */
3565 disable_irq(core_irqres->start);
3566 host->sdcc_irq_disabled = 1;
3567
3568 if (plat->sdiowakeup_irq) {
3569 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3570 mmc_hostname(mmc));
3571 ret = request_irq(plat->sdiowakeup_irq,
3572 msmsdcc_platform_sdiowakeup_irq,
3573 IRQF_SHARED | IRQF_TRIGGER_LOW,
3574 DRIVER_NAME "sdiowakeup", host);
3575 if (ret) {
3576 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
3577 plat->sdiowakeup_irq, ret);
3578 goto pio_irq_free;
3579 } else {
3580 spin_lock_irqsave(&host->lock, flags);
3581 if (!host->sdio_irq_disabled) {
3582 disable_irq_nosync(plat->sdiowakeup_irq);
3583 host->sdio_irq_disabled = 1;
3584 }
3585 spin_unlock_irqrestore(&host->lock, flags);
3586 }
3587 }
3588
3589 if (plat->cfg_mpm_sdiowakeup) {
3590 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3591 mmc_hostname(mmc));
3592 }
3593
3594 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
3595 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003596 /*
3597 * Setup card detect change
3598 */
3599
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003600 if (plat->status || plat->status_gpio) {
3601 if (plat->status)
3602 host->oldstat = plat->status(mmc_dev(host->mmc));
3603 else
3604 host->oldstat = msmsdcc_slot_status(host);
3605 host->eject = !host->oldstat;
3606 }
San Mehat9d2bd732009-09-22 16:44:22 -07003607
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003608 if (plat->status_irq) {
3609 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07003610 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003611 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07003612 DRIVER_NAME " (slot)",
3613 host);
3614 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003615 pr_err("Unable to get slot IRQ %d (%d)\n",
3616 plat->status_irq, ret);
3617 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003618 }
3619 } else if (plat->register_status_notify) {
3620 plat->register_status_notify(msmsdcc_status_notify_cb, host);
3621 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003622 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07003623 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003624
3625 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003626
3627 ret = pm_runtime_set_active(&(pdev)->dev);
3628 if (ret < 0)
3629 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3630 __func__, ret);
3631 /*
3632 * There is no notion of suspend/resume for SD/MMC/SDIO
3633 * cards. So host can be suspended/resumed with out
3634 * worrying about its children.
3635 */
3636 pm_suspend_ignore_children(&(pdev)->dev, true);
3637
3638 /*
3639 * MMC/SD/SDIO bus suspend/resume operations are defined
3640 * only for the slots that will be used for non-removable
3641 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
3642 * defined. Otherwise, they simply become card removal and
3643 * insertion events during suspend and resume respectively.
3644 * Hence, enable run-time PM only for slots for which bus
3645 * suspend/resume operations are defined.
3646 */
3647#ifdef CONFIG_MMC_UNSAFE_RESUME
3648 /*
3649 * If this capability is set, MMC core will enable/disable host
3650 * for every claim/release operation on a host. We use this
3651 * notification to increment/decrement runtime pm usage count.
3652 */
3653 mmc->caps |= MMC_CAP_DISABLE;
3654 pm_runtime_enable(&(pdev)->dev);
3655#else
3656 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
3657 mmc->caps |= MMC_CAP_DISABLE;
3658 pm_runtime_enable(&(pdev)->dev);
3659 }
3660#endif
3661 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
3662 (unsigned long)host);
3663
San Mehat9d2bd732009-09-22 16:44:22 -07003664 mmc_add_host(mmc);
3665
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003666#ifdef CONFIG_HAS_EARLYSUSPEND
3667 host->early_suspend.suspend = msmsdcc_early_suspend;
3668 host->early_suspend.resume = msmsdcc_late_resume;
3669 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
3670 register_early_suspend(&host->early_suspend);
3671#endif
San Mehat9d2bd732009-09-22 16:44:22 -07003672
Krishna Konda25786ec2011-07-25 16:21:36 -07003673 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
3674 " dmacrcri %d\n", mmc_hostname(mmc),
3675 (unsigned long long)core_memres->start,
3676 (unsigned int) core_irqres->start,
3677 (unsigned int) plat->status_irq, host->dma.channel,
3678 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003679
3680 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
3681 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
3682 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
3683 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
3684 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
3685 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
3686 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
3687 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
3688 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
3689 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
3690 host->eject);
3691 pr_info("%s: Power save feature enable = %d\n",
3692 mmc_hostname(mmc), msmsdcc_pwrsave);
3693
Krishna Konda25786ec2011-07-25 16:21:36 -07003694 if (host->is_dma_mode && host->dma.channel != -1
3695 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003696 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003697 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003698 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003699 mmc_hostname(mmc), host->dma.cmd_busaddr,
3700 host->dma.cmdptr_busaddr);
3701 } else if (host->is_sps_mode) {
3702 pr_info("%s: SPS-BAM data transfer mode available\n",
3703 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003704 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003705 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003706
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003707#if defined(CONFIG_DEBUG_FS)
3708 msmsdcc_dbg_createhost(host);
3709#endif
3710 if (!plat->status_irq) {
3711 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
3712 if (ret)
3713 goto platform_irq_free;
3714 }
San Mehat9d2bd732009-09-22 16:44:22 -07003715 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003716
3717 platform_irq_free:
3718 del_timer_sync(&host->req_tout_timer);
3719 pm_runtime_disable(&(pdev)->dev);
3720 pm_runtime_set_suspended(&(pdev)->dev);
3721
3722 if (plat->status_irq)
3723 free_irq(plat->status_irq, host);
3724 sdiowakeup_irq_free:
3725 wake_lock_destroy(&host->sdio_suspend_wlock);
3726 if (plat->sdiowakeup_irq)
3727 free_irq(plat->sdiowakeup_irq, host);
3728 pio_irq_free:
3729 if (plat->sdiowakeup_irq)
3730 wake_lock_destroy(&host->sdio_wlock);
3731 free_irq(core_irqres->start, host);
3732 irq_free:
3733 free_irq(core_irqres->start, host);
3734 dml_exit:
3735 if (host->is_sps_mode)
3736 msmsdcc_dml_exit(host);
3737 sps_exit:
3738 if (host->is_sps_mode)
3739 msmsdcc_sps_exit(host);
3740 vreg_deinit:
3741 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07003742 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003743 clk_disable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003744 clk_put:
3745 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003746 pclk_disable:
3747 if (!IS_ERR(host->pclk))
3748 clk_disable(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07003749 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003750 if (!IS_ERR(host->pclk))
3751 clk_put(host->pclk);
3752 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3753 clk_disable(host->dfab_pclk);
3754 dfab_pclk_put:
3755 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3756 clk_put(host->dfab_pclk);
3757 dma_free:
3758 if (host->is_dma_mode) {
3759 if (host->dmares)
3760 dma_free_coherent(NULL,
3761 sizeof(struct msmsdcc_nc_dmadata),
3762 host->dma.nc, host->dma.nc_busaddr);
3763 }
3764 ioremap_free:
3765 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07003766 host_free:
3767 mmc_free_host(mmc);
3768 out:
3769 return ret;
3770}
3771
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003772static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07003773{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003774 struct mmc_host *mmc = mmc_get_drvdata(pdev);
3775 struct mmc_platform_data *plat;
3776 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07003777
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003778 if (!mmc)
3779 return -ENXIO;
3780
3781 if (pm_runtime_suspended(&(pdev)->dev))
3782 pm_runtime_resume(&(pdev)->dev);
3783
3784 host = mmc_priv(mmc);
3785
3786 DBG(host, "Removing SDCC device = %d\n", pdev->id);
3787 plat = host->plat;
3788
3789 if (!plat->status_irq)
3790 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
3791
3792 del_timer_sync(&host->req_tout_timer);
3793 tasklet_kill(&host->dma_tlet);
3794 tasklet_kill(&host->sps.tlet);
3795 mmc_remove_host(mmc);
3796
3797 if (plat->status_irq)
3798 free_irq(plat->status_irq, host);
3799
3800 wake_lock_destroy(&host->sdio_suspend_wlock);
3801 if (plat->sdiowakeup_irq) {
3802 wake_lock_destroy(&host->sdio_wlock);
3803 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
3804 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07003805 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003806
3807 free_irq(host->core_irqres->start, host);
3808 free_irq(host->core_irqres->start, host);
3809
3810 clk_put(host->clk);
3811 if (!IS_ERR(host->pclk))
3812 clk_put(host->pclk);
3813 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3814 clk_put(host->dfab_pclk);
3815
3816 msmsdcc_vreg_init(host, false);
3817
3818 if (host->is_dma_mode) {
3819 if (host->dmares)
3820 dma_free_coherent(NULL,
3821 sizeof(struct msmsdcc_nc_dmadata),
3822 host->dma.nc, host->dma.nc_busaddr);
3823 }
3824
3825 if (host->is_sps_mode) {
3826 msmsdcc_dml_exit(host);
3827 msmsdcc_sps_exit(host);
3828 }
3829
3830 iounmap(host->base);
3831 mmc_free_host(mmc);
3832
3833#ifdef CONFIG_HAS_EARLYSUSPEND
3834 unregister_early_suspend(&host->early_suspend);
3835#endif
3836 pm_runtime_disable(&(pdev)->dev);
3837 pm_runtime_set_suspended(&(pdev)->dev);
3838
3839 return 0;
3840}
3841
3842#ifdef CONFIG_MSM_SDIO_AL
3843int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
3844{
3845 struct msmsdcc_host *host = mmc_priv(mmc);
3846 unsigned long flags;
3847
3848 spin_lock_irqsave(&host->lock, flags);
3849 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
3850 enable ? "En" : "Dis");
3851
3852 if (enable) {
3853 if (!host->sdcc_irq_disabled) {
3854 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05303855 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003856 host->sdcc_irq_disabled = 1;
3857 }
3858
3859 if (host->clks_on) {
3860 msmsdcc_setup_clocks(host, false);
3861 host->clks_on = 0;
3862 }
3863
3864 if (!host->sdio_gpio_lpm) {
3865 spin_unlock_irqrestore(&host->lock, flags);
3866 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
3867 spin_lock_irqsave(&host->lock, flags);
3868 host->sdio_gpio_lpm = 1;
3869 }
3870
3871 if (host->sdio_irq_disabled) {
3872 msmsdcc_enable_irq_wake(host);
3873 enable_irq(host->plat->sdiowakeup_irq);
3874 host->sdio_irq_disabled = 0;
3875 }
3876 } else {
3877 if (!host->sdio_irq_disabled) {
3878 disable_irq_nosync(host->plat->sdiowakeup_irq);
3879 host->sdio_irq_disabled = 1;
3880 msmsdcc_disable_irq_wake(host);
3881 }
3882
3883 if (host->sdio_gpio_lpm) {
3884 spin_unlock_irqrestore(&host->lock, flags);
3885 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
3886 spin_lock_irqsave(&host->lock, flags);
3887 host->sdio_gpio_lpm = 0;
3888 }
3889
3890 if (!host->clks_on) {
3891 msmsdcc_setup_clocks(host, true);
3892 host->clks_on = 1;
3893 }
3894
3895 if (host->sdcc_irq_disabled) {
3896 writel_relaxed(host->mci_irqenable,
3897 host->base + MMCIMASK0);
3898 mb();
3899 enable_irq(host->core_irqres->start);
3900 host->sdcc_irq_disabled = 0;
3901 }
3902 wake_lock_timeout(&host->sdio_wlock, 1);
3903 }
3904 spin_unlock_irqrestore(&host->lock, flags);
3905 return 0;
3906}
3907#else
3908int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
3909{
3910 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07003911}
3912#endif
3913
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003914#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07003915static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003916msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07003917{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003918 struct mmc_host *mmc = dev_get_drvdata(dev);
3919 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07003920 int rc = 0;
3921
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003922 if (host->plat->is_sdio_al_client)
3923 return 0;
3924
Sahitya Tummala7661a452011-07-18 13:28:35 +05303925 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003926 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003927 host->sdcc_suspending = 1;
3928 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07003929
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003930 /*
3931 * If the clocks are already turned off by SDIO clients (as
3932 * part of LPM), then clocks should be turned on before
3933 * calling mmc_suspend_host() because mmc_suspend_host might
3934 * send some commands to the card. The clocks will be turned
3935 * off again after mmc_suspend_host. Thus for SD/MMC/SDIO
3936 * cards, clocks will be turned on before mmc_suspend_host
3937 * and turned off after mmc_suspend_host.
3938 */
3939 mmc->ios.clock = host->clk_rate;
3940 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07003941
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003942 /*
3943 * MMC core thinks that host is disabled by now since
3944 * runtime suspend is scheduled after msmsdcc_disable()
3945 * is called. Thus, MMC core will try to enable the host
3946 * while suspending it. This results in a synchronous
3947 * runtime resume request while in runtime suspending
3948 * context and hence inorder to complete this resume
3949 * requet, it will wait for suspend to be complete,
3950 * but runtime suspend also can not proceed further
3951 * until the host is resumed. Thus, it leads to a hang.
3952 * Hence, increase the pm usage count before suspending
3953 * the host so that any resume requests after this will
3954 * simple become pm usage counter increment operations.
3955 */
3956 pm_runtime_get_noresume(dev);
3957 rc = mmc_suspend_host(mmc);
3958 pm_runtime_put_noidle(dev);
3959
3960 if (!rc) {
3961 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
3962 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ)) {
3963 disable_irq(host->core_irqres->start);
3964 host->sdcc_irq_disabled = 1;
3965
3966 /*
3967 * If MMC core level suspend is not supported,
3968 * turn off clocks to allow deep sleep (TCXO
3969 * shutdown).
3970 */
3971 mmc->ios.clock = 0;
3972 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
3973 enable_irq(host->core_irqres->start);
3974 host->sdcc_irq_disabled = 0;
3975
3976 if (host->plat->sdiowakeup_irq) {
3977 host->sdio_irq_disabled = 0;
3978 msmsdcc_enable_irq_wake(host);
3979 enable_irq(host->plat->sdiowakeup_irq);
3980 }
3981 }
3982 }
3983 host->sdcc_suspending = 0;
3984 mmc->suspend_task = NULL;
3985 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
3986 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07003987 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05303988 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003989 return rc;
3990}
3991
3992static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003993msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07003994{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003995 struct mmc_host *mmc = dev_get_drvdata(dev);
3996 struct msmsdcc_host *host = mmc_priv(mmc);
3997 unsigned long flags;
3998
3999 if (host->plat->is_sdio_al_client)
4000 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07004001
Sahitya Tummala7661a452011-07-18 13:28:35 +05304002 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004003 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004004 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
4005 if (host->sdcc_irq_disabled) {
4006 enable_irq(host->core_irqres->start);
4007 host->sdcc_irq_disabled = 0;
4008 }
4009 }
4010 mmc->ios.clock = host->clk_rate;
4011 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07004012
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004013 spin_lock_irqsave(&host->lock, flags);
4014 writel_relaxed(host->mci_irqenable, host->base + MMCIMASK0);
4015 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07004016
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004017 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
4018 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) &&
4019 !host->sdio_irq_disabled) {
4020 if (host->plat->sdiowakeup_irq) {
4021 disable_irq_nosync(
4022 host->plat->sdiowakeup_irq);
4023 msmsdcc_disable_irq_wake(host);
4024 host->sdio_irq_disabled = 1;
4025 }
4026 }
San Mehat9d2bd732009-09-22 16:44:22 -07004027
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004028 spin_unlock_irqrestore(&host->lock, flags);
4029
4030 mmc_resume_host(mmc);
4031
4032 /*
4033 * FIXME: Clearing of flags must be handled in clients
4034 * resume handler.
4035 */
4036 spin_lock_irqsave(&host->lock, flags);
4037 mmc->pm_flags = 0;
4038 spin_unlock_irqrestore(&host->lock, flags);
4039
4040 /*
4041 * After resuming the host wait for sometime so that
4042 * the SDIO work will be processed.
4043 */
4044 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO)) {
4045 if ((host->plat->cfg_mpm_sdiowakeup ||
4046 host->plat->sdiowakeup_irq) &&
4047 wake_lock_active(&host->sdio_wlock))
4048 wake_lock_timeout(&host->sdio_wlock, 1);
4049 }
4050
4051 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004052 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304053 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004054 return 0;
4055}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004056
4057static int msmsdcc_runtime_idle(struct device *dev)
4058{
4059 struct mmc_host *mmc = dev_get_drvdata(dev);
4060 struct msmsdcc_host *host = mmc_priv(mmc);
4061
4062 if (host->plat->is_sdio_al_client)
4063 return 0;
4064
4065 /* Idle timeout is not configurable for now */
4066 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
4067
4068 return -EAGAIN;
4069}
4070
4071static int msmsdcc_pm_suspend(struct device *dev)
4072{
4073 struct mmc_host *mmc = dev_get_drvdata(dev);
4074 struct msmsdcc_host *host = mmc_priv(mmc);
4075 int rc = 0;
4076
4077 if (host->plat->is_sdio_al_client)
4078 return 0;
4079
4080
4081 if (host->plat->status_irq)
4082 disable_irq(host->plat->status_irq);
4083
4084 if (!pm_runtime_suspended(dev))
4085 rc = msmsdcc_runtime_suspend(dev);
4086
4087 return rc;
4088}
4089
4090static int msmsdcc_pm_resume(struct device *dev)
4091{
4092 struct mmc_host *mmc = dev_get_drvdata(dev);
4093 struct msmsdcc_host *host = mmc_priv(mmc);
4094 int rc = 0;
4095
4096 if (host->plat->is_sdio_al_client)
4097 return 0;
4098
4099 rc = msmsdcc_runtime_resume(dev);
4100 if (host->plat->status_irq) {
4101 msmsdcc_check_status((unsigned long)host);
4102 enable_irq(host->plat->status_irq);
4103 }
4104
4105 /* Update the run-time PM status */
4106 pm_runtime_disable(dev);
4107 rc = pm_runtime_set_active(dev);
4108 if (rc < 0)
4109 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
4110 __func__, rc);
4111 pm_runtime_enable(dev);
4112
4113 return rc;
4114}
4115
Daniel Walker08ecfde2010-06-23 12:32:20 -07004116#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004117#define msmsdcc_runtime_suspend NULL
4118#define msmsdcc_runtime_resume NULL
4119#define msmsdcc_runtime_idle NULL
4120#define msmsdcc_pm_suspend NULL
4121#define msmsdcc_pm_resume NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07004122#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004123
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004124static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
4125 .runtime_suspend = msmsdcc_runtime_suspend,
4126 .runtime_resume = msmsdcc_runtime_resume,
4127 .runtime_idle = msmsdcc_runtime_idle,
4128 .suspend = msmsdcc_pm_suspend,
4129 .resume = msmsdcc_pm_resume,
4130};
4131
San Mehat9d2bd732009-09-22 16:44:22 -07004132static struct platform_driver msmsdcc_driver = {
4133 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004134 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07004135 .driver = {
4136 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004137 .pm = &msmsdcc_dev_pm_ops,
San Mehat9d2bd732009-09-22 16:44:22 -07004138 },
4139};
4140
4141static int __init msmsdcc_init(void)
4142{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004143#if defined(CONFIG_DEBUG_FS)
4144 int ret = 0;
4145 ret = msmsdcc_dbg_init();
4146 if (ret) {
4147 pr_err("Failed to create debug fs dir \n");
4148 return ret;
4149 }
4150#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004151 return platform_driver_register(&msmsdcc_driver);
4152}
4153
4154static void __exit msmsdcc_exit(void)
4155{
4156 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004157
4158#if defined(CONFIG_DEBUG_FS)
4159 debugfs_remove(debugfs_file);
4160 debugfs_remove(debugfs_dir);
4161#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004162}
4163
4164module_init(msmsdcc_init);
4165module_exit(msmsdcc_exit);
4166
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004167MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07004168MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004169
4170#if defined(CONFIG_DEBUG_FS)
4171
4172static int
4173msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
4174{
4175 file->private_data = inode->i_private;
4176 return 0;
4177}
4178
4179static ssize_t
4180msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
4181 size_t count, loff_t *ppos)
4182{
4183 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
4184 char buf[1024];
4185 int max, i;
4186
4187 i = 0;
4188 max = sizeof(buf) - 1;
4189
4190 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
4191 host->curr.cmd, host->curr.data);
4192 if (host->curr.cmd) {
4193 struct mmc_command *cmd = host->curr.cmd;
4194
4195 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
4196 cmd->opcode, cmd->arg, cmd->flags);
4197 }
4198 if (host->curr.data) {
4199 struct mmc_data *data = host->curr.data;
4200 i += scnprintf(buf + i, max - i,
4201 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
4202 data->timeout_ns, data->timeout_clks,
4203 data->blksz, data->blocks, data->error,
4204 data->flags);
4205 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
4206 host->curr.xfer_size, host->curr.xfer_remain,
4207 host->curr.data_xfered, host->dma.sg);
4208 }
4209
4210 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
4211}
4212
4213static const struct file_operations msmsdcc_dbg_state_ops = {
4214 .read = msmsdcc_dbg_state_read,
4215 .open = msmsdcc_dbg_state_open,
4216};
4217
4218static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
4219{
4220 if (debugfs_dir) {
4221 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
4222 0644, debugfs_dir, host,
4223 &msmsdcc_dbg_state_ops);
4224 }
4225}
4226
4227static int __init msmsdcc_dbg_init(void)
4228{
4229 int err;
4230
4231 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
4232 if (IS_ERR(debugfs_dir)) {
4233 err = PTR_ERR(debugfs_dir);
4234 debugfs_dir = NULL;
4235 return err;
4236 }
4237
4238 return 0;
4239}
4240#endif