blob: 1ed2abedd3c94435ae24f7153725c744caf66827 [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
Oluwafemi Adeyemif6c97c82011-08-22 10:53:44 -07001522 if (!host->plat->sdcc_v4_sup) {
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;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05303384
3385 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003386 host->is_sps_mode = 1;
3387 else if (dmares)
3388 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07003389
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003390 host->base = ioremap(core_memres->start,
3391 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07003392 if (!host->base) {
3393 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003394 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003395 }
3396
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003397 host->core_irqres = core_irqres;
3398 host->bam_irqres = bam_irqres;
3399 host->core_memres = core_memres;
3400 host->dml_memres = dml_memres;
3401 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07003402 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07003403 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07003404 spin_lock_init(&host->lock);
3405
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003406#ifdef CONFIG_MMC_EMBEDDED_SDIO
3407 if (plat->embedded_sdio)
3408 mmc_set_embedded_sdio_data(mmc,
3409 &plat->embedded_sdio->cis,
3410 &plat->embedded_sdio->cccr,
3411 plat->embedded_sdio->funcs,
3412 plat->embedded_sdio->num_funcs);
3413#endif
3414
Sahitya Tummala62612cf2010-12-08 15:03:03 +05303415 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
3416 (unsigned long)host);
3417
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003418 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
3419 (unsigned long)host);
3420 if (host->is_dma_mode) {
3421 /* Setup DMA */
3422 ret = msmsdcc_init_dma(host);
3423 if (ret)
3424 goto ioremap_free;
3425 } else {
3426 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003427 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003428 }
3429
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003430 /*
3431 * Setup SDCC clock if derived from Dayatona
3432 * fabric core clock.
3433 */
3434 if (plat->pclk_src_dfab) {
3435 host->dfab_pclk = clk_get(&pdev->dev, "dfab_sdc_clk");
3436 if (!IS_ERR(host->dfab_pclk)) {
3437 /* Set the clock rate to 64MHz for max. performance */
3438 ret = clk_set_rate(host->dfab_pclk, 64000000);
3439 if (ret)
3440 goto dfab_pclk_put;
3441 ret = clk_enable(host->dfab_pclk);
3442 if (ret)
3443 goto dfab_pclk_put;
3444 } else
3445 goto dma_free;
3446 }
3447
3448 /*
3449 * Setup main peripheral bus clock
3450 */
3451 host->pclk = clk_get(&pdev->dev, "sdc_pclk");
3452 if (!IS_ERR(host->pclk)) {
3453 ret = clk_enable(host->pclk);
3454 if (ret)
3455 goto pclk_put;
3456
3457 host->pclk_rate = clk_get_rate(host->pclk);
3458 }
3459
3460 /*
3461 * Setup SDC MMC clock
3462 */
San Mehat9d2bd732009-09-22 16:44:22 -07003463 host->clk = clk_get(&pdev->dev, "sdc_clk");
3464 if (IS_ERR(host->clk)) {
3465 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003466 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07003467 }
3468
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003469 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
3470 if (ret) {
3471 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
3472 goto clk_put;
3473 }
3474
3475 ret = clk_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003476 if (ret)
3477 goto clk_put;
3478
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003479 host->clk_rate = clk_get_rate(host->clk);
3480
3481 host->clks_on = 1;
3482
3483 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07003484 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003485 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07003486 goto clk_disable;
3487 }
3488
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003489
3490 /* Clocks has to be running before accessing SPS/DML HW blocks */
3491 if (host->is_sps_mode) {
3492 /* Initialize SPS */
3493 ret = msmsdcc_sps_init(host);
3494 if (ret)
3495 goto vreg_deinit;
3496 /* Initialize DML */
3497 ret = msmsdcc_dml_init(host);
3498 if (ret)
3499 goto sps_exit;
3500 }
San Mehat9d2bd732009-09-22 16:44:22 -07003501
San Mehat9d2bd732009-09-22 16:44:22 -07003502 /*
3503 * Setup MMC host structure
3504 */
3505 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003506 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
3507 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003508 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003509 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
3510 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07003511
San Mehat9d2bd732009-09-22 16:44:22 -07003512 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003513 mmc->caps |= plat->uhs_caps;
3514 /*
3515 * XPC controls the maximum current in the default speed mode of SDXC
3516 * card. XPC=0 means 100mA (max.) but speed class is not supported.
3517 * XPC=1 means 150mA (max.) and speed class is supported.
3518 */
3519 if (plat->xpc_cap)
3520 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
3521 MMC_CAP_SET_XPC_180);
3522
3523 if (plat->nonremovable)
3524 mmc->caps |= MMC_CAP_NONREMOVABLE;
3525#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
3526 mmc->caps |= MMC_CAP_SDIO_IRQ;
3527#endif
3528
3529 if (plat->is_sdio_al_client)
3530 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07003531
Martin K. Petersena36274e2010-09-10 01:33:59 -04003532 mmc->max_segs = NR_SG;
San Mehat9d2bd732009-09-22 16:44:22 -07003533 mmc->max_blk_size = 4096; /* MCI_DATA_CTL BLOCKSIZE up to 4096 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003534 mmc->max_blk_count = 65535;
San Mehat9d2bd732009-09-22 16:44:22 -07003535
3536 mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */
3537 mmc->max_seg_size = mmc->max_req_size;
3538
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003539 writel_relaxed(0, host->base + MMCIMASK0);
3540 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -07003541
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003542 /* Delay needed (MMCIMASK0 was just written above) */
3543 msmsdcc_delay(host);
3544 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
3545 mb();
3546 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07003547
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003548 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
3549 DRIVER_NAME " (cmd)", host);
3550 if (ret)
3551 goto dml_exit;
3552
3553 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
3554 DRIVER_NAME " (pio)", host);
3555 if (ret)
3556 goto irq_free;
3557
3558 /*
3559 * Enable SDCC IRQ only when host is powered on. Otherwise, this
3560 * IRQ is un-necessarily being monitored by MPM (Modem power
3561 * management block) during idle-power collapse. The MPM will be
3562 * configured to monitor the DATA1 GPIO line with level-low trigger
3563 * and thus depending on the GPIO status, it prevents TCXO shutdown
3564 * during idle-power collapse.
3565 */
3566 disable_irq(core_irqres->start);
3567 host->sdcc_irq_disabled = 1;
3568
3569 if (plat->sdiowakeup_irq) {
3570 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3571 mmc_hostname(mmc));
3572 ret = request_irq(plat->sdiowakeup_irq,
3573 msmsdcc_platform_sdiowakeup_irq,
3574 IRQF_SHARED | IRQF_TRIGGER_LOW,
3575 DRIVER_NAME "sdiowakeup", host);
3576 if (ret) {
3577 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
3578 plat->sdiowakeup_irq, ret);
3579 goto pio_irq_free;
3580 } else {
3581 spin_lock_irqsave(&host->lock, flags);
3582 if (!host->sdio_irq_disabled) {
3583 disable_irq_nosync(plat->sdiowakeup_irq);
3584 host->sdio_irq_disabled = 1;
3585 }
3586 spin_unlock_irqrestore(&host->lock, flags);
3587 }
3588 }
3589
3590 if (plat->cfg_mpm_sdiowakeup) {
3591 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3592 mmc_hostname(mmc));
3593 }
3594
3595 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
3596 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003597 /*
3598 * Setup card detect change
3599 */
3600
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003601 if (plat->status || plat->status_gpio) {
3602 if (plat->status)
3603 host->oldstat = plat->status(mmc_dev(host->mmc));
3604 else
3605 host->oldstat = msmsdcc_slot_status(host);
3606 host->eject = !host->oldstat;
3607 }
San Mehat9d2bd732009-09-22 16:44:22 -07003608
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003609 if (plat->status_irq) {
3610 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07003611 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003612 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07003613 DRIVER_NAME " (slot)",
3614 host);
3615 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003616 pr_err("Unable to get slot IRQ %d (%d)\n",
3617 plat->status_irq, ret);
3618 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003619 }
3620 } else if (plat->register_status_notify) {
3621 plat->register_status_notify(msmsdcc_status_notify_cb, host);
3622 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003623 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07003624 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003625
3626 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003627
3628 ret = pm_runtime_set_active(&(pdev)->dev);
3629 if (ret < 0)
3630 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3631 __func__, ret);
3632 /*
3633 * There is no notion of suspend/resume for SD/MMC/SDIO
3634 * cards. So host can be suspended/resumed with out
3635 * worrying about its children.
3636 */
3637 pm_suspend_ignore_children(&(pdev)->dev, true);
3638
3639 /*
3640 * MMC/SD/SDIO bus suspend/resume operations are defined
3641 * only for the slots that will be used for non-removable
3642 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
3643 * defined. Otherwise, they simply become card removal and
3644 * insertion events during suspend and resume respectively.
3645 * Hence, enable run-time PM only for slots for which bus
3646 * suspend/resume operations are defined.
3647 */
3648#ifdef CONFIG_MMC_UNSAFE_RESUME
3649 /*
3650 * If this capability is set, MMC core will enable/disable host
3651 * for every claim/release operation on a host. We use this
3652 * notification to increment/decrement runtime pm usage count.
3653 */
3654 mmc->caps |= MMC_CAP_DISABLE;
3655 pm_runtime_enable(&(pdev)->dev);
3656#else
3657 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
3658 mmc->caps |= MMC_CAP_DISABLE;
3659 pm_runtime_enable(&(pdev)->dev);
3660 }
3661#endif
3662 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
3663 (unsigned long)host);
3664
San Mehat9d2bd732009-09-22 16:44:22 -07003665 mmc_add_host(mmc);
3666
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003667#ifdef CONFIG_HAS_EARLYSUSPEND
3668 host->early_suspend.suspend = msmsdcc_early_suspend;
3669 host->early_suspend.resume = msmsdcc_late_resume;
3670 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
3671 register_early_suspend(&host->early_suspend);
3672#endif
San Mehat9d2bd732009-09-22 16:44:22 -07003673
Krishna Konda25786ec2011-07-25 16:21:36 -07003674 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
3675 " dmacrcri %d\n", mmc_hostname(mmc),
3676 (unsigned long long)core_memres->start,
3677 (unsigned int) core_irqres->start,
3678 (unsigned int) plat->status_irq, host->dma.channel,
3679 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003680
3681 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
3682 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
3683 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
3684 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
3685 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
3686 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
3687 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
3688 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
3689 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
3690 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
3691 host->eject);
3692 pr_info("%s: Power save feature enable = %d\n",
3693 mmc_hostname(mmc), msmsdcc_pwrsave);
3694
Krishna Konda25786ec2011-07-25 16:21:36 -07003695 if (host->is_dma_mode && host->dma.channel != -1
3696 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003697 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003698 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003699 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003700 mmc_hostname(mmc), host->dma.cmd_busaddr,
3701 host->dma.cmdptr_busaddr);
3702 } else if (host->is_sps_mode) {
3703 pr_info("%s: SPS-BAM data transfer mode available\n",
3704 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003705 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003706 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003707
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003708#if defined(CONFIG_DEBUG_FS)
3709 msmsdcc_dbg_createhost(host);
3710#endif
3711 if (!plat->status_irq) {
3712 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
3713 if (ret)
3714 goto platform_irq_free;
3715 }
San Mehat9d2bd732009-09-22 16:44:22 -07003716 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003717
3718 platform_irq_free:
3719 del_timer_sync(&host->req_tout_timer);
3720 pm_runtime_disable(&(pdev)->dev);
3721 pm_runtime_set_suspended(&(pdev)->dev);
3722
3723 if (plat->status_irq)
3724 free_irq(plat->status_irq, host);
3725 sdiowakeup_irq_free:
3726 wake_lock_destroy(&host->sdio_suspend_wlock);
3727 if (plat->sdiowakeup_irq)
3728 free_irq(plat->sdiowakeup_irq, host);
3729 pio_irq_free:
3730 if (plat->sdiowakeup_irq)
3731 wake_lock_destroy(&host->sdio_wlock);
3732 free_irq(core_irqres->start, host);
3733 irq_free:
3734 free_irq(core_irqres->start, host);
3735 dml_exit:
3736 if (host->is_sps_mode)
3737 msmsdcc_dml_exit(host);
3738 sps_exit:
3739 if (host->is_sps_mode)
3740 msmsdcc_sps_exit(host);
3741 vreg_deinit:
3742 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07003743 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003744 clk_disable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003745 clk_put:
3746 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003747 pclk_disable:
3748 if (!IS_ERR(host->pclk))
3749 clk_disable(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07003750 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003751 if (!IS_ERR(host->pclk))
3752 clk_put(host->pclk);
3753 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3754 clk_disable(host->dfab_pclk);
3755 dfab_pclk_put:
3756 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3757 clk_put(host->dfab_pclk);
3758 dma_free:
3759 if (host->is_dma_mode) {
3760 if (host->dmares)
3761 dma_free_coherent(NULL,
3762 sizeof(struct msmsdcc_nc_dmadata),
3763 host->dma.nc, host->dma.nc_busaddr);
3764 }
3765 ioremap_free:
3766 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07003767 host_free:
3768 mmc_free_host(mmc);
3769 out:
3770 return ret;
3771}
3772
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003773static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07003774{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003775 struct mmc_host *mmc = mmc_get_drvdata(pdev);
3776 struct mmc_platform_data *plat;
3777 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07003778
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003779 if (!mmc)
3780 return -ENXIO;
3781
3782 if (pm_runtime_suspended(&(pdev)->dev))
3783 pm_runtime_resume(&(pdev)->dev);
3784
3785 host = mmc_priv(mmc);
3786
3787 DBG(host, "Removing SDCC device = %d\n", pdev->id);
3788 plat = host->plat;
3789
3790 if (!plat->status_irq)
3791 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
3792
3793 del_timer_sync(&host->req_tout_timer);
3794 tasklet_kill(&host->dma_tlet);
3795 tasklet_kill(&host->sps.tlet);
3796 mmc_remove_host(mmc);
3797
3798 if (plat->status_irq)
3799 free_irq(plat->status_irq, host);
3800
3801 wake_lock_destroy(&host->sdio_suspend_wlock);
3802 if (plat->sdiowakeup_irq) {
3803 wake_lock_destroy(&host->sdio_wlock);
3804 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
3805 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07003806 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003807
3808 free_irq(host->core_irqres->start, host);
3809 free_irq(host->core_irqres->start, host);
3810
3811 clk_put(host->clk);
3812 if (!IS_ERR(host->pclk))
3813 clk_put(host->pclk);
3814 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3815 clk_put(host->dfab_pclk);
3816
3817 msmsdcc_vreg_init(host, false);
3818
3819 if (host->is_dma_mode) {
3820 if (host->dmares)
3821 dma_free_coherent(NULL,
3822 sizeof(struct msmsdcc_nc_dmadata),
3823 host->dma.nc, host->dma.nc_busaddr);
3824 }
3825
3826 if (host->is_sps_mode) {
3827 msmsdcc_dml_exit(host);
3828 msmsdcc_sps_exit(host);
3829 }
3830
3831 iounmap(host->base);
3832 mmc_free_host(mmc);
3833
3834#ifdef CONFIG_HAS_EARLYSUSPEND
3835 unregister_early_suspend(&host->early_suspend);
3836#endif
3837 pm_runtime_disable(&(pdev)->dev);
3838 pm_runtime_set_suspended(&(pdev)->dev);
3839
3840 return 0;
3841}
3842
3843#ifdef CONFIG_MSM_SDIO_AL
3844int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
3845{
3846 struct msmsdcc_host *host = mmc_priv(mmc);
3847 unsigned long flags;
3848
3849 spin_lock_irqsave(&host->lock, flags);
3850 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
3851 enable ? "En" : "Dis");
3852
3853 if (enable) {
3854 if (!host->sdcc_irq_disabled) {
3855 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05303856 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003857 host->sdcc_irq_disabled = 1;
3858 }
3859
3860 if (host->clks_on) {
3861 msmsdcc_setup_clocks(host, false);
3862 host->clks_on = 0;
3863 }
3864
3865 if (!host->sdio_gpio_lpm) {
3866 spin_unlock_irqrestore(&host->lock, flags);
3867 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
3868 spin_lock_irqsave(&host->lock, flags);
3869 host->sdio_gpio_lpm = 1;
3870 }
3871
3872 if (host->sdio_irq_disabled) {
3873 msmsdcc_enable_irq_wake(host);
3874 enable_irq(host->plat->sdiowakeup_irq);
3875 host->sdio_irq_disabled = 0;
3876 }
3877 } else {
3878 if (!host->sdio_irq_disabled) {
3879 disable_irq_nosync(host->plat->sdiowakeup_irq);
3880 host->sdio_irq_disabled = 1;
3881 msmsdcc_disable_irq_wake(host);
3882 }
3883
3884 if (host->sdio_gpio_lpm) {
3885 spin_unlock_irqrestore(&host->lock, flags);
3886 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
3887 spin_lock_irqsave(&host->lock, flags);
3888 host->sdio_gpio_lpm = 0;
3889 }
3890
3891 if (!host->clks_on) {
3892 msmsdcc_setup_clocks(host, true);
3893 host->clks_on = 1;
3894 }
3895
3896 if (host->sdcc_irq_disabled) {
3897 writel_relaxed(host->mci_irqenable,
3898 host->base + MMCIMASK0);
3899 mb();
3900 enable_irq(host->core_irqres->start);
3901 host->sdcc_irq_disabled = 0;
3902 }
3903 wake_lock_timeout(&host->sdio_wlock, 1);
3904 }
3905 spin_unlock_irqrestore(&host->lock, flags);
3906 return 0;
3907}
3908#else
3909int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
3910{
3911 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07003912}
3913#endif
3914
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003915#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07003916static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003917msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07003918{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003919 struct mmc_host *mmc = dev_get_drvdata(dev);
3920 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07003921 int rc = 0;
3922
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003923 if (host->plat->is_sdio_al_client)
3924 return 0;
3925
Sahitya Tummala7661a452011-07-18 13:28:35 +05303926 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003927 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003928 host->sdcc_suspending = 1;
3929 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07003930
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003931 /*
3932 * If the clocks are already turned off by SDIO clients (as
3933 * part of LPM), then clocks should be turned on before
3934 * calling mmc_suspend_host() because mmc_suspend_host might
3935 * send some commands to the card. The clocks will be turned
3936 * off again after mmc_suspend_host. Thus for SD/MMC/SDIO
3937 * cards, clocks will be turned on before mmc_suspend_host
3938 * and turned off after mmc_suspend_host.
3939 */
3940 mmc->ios.clock = host->clk_rate;
3941 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07003942
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003943 /*
3944 * MMC core thinks that host is disabled by now since
3945 * runtime suspend is scheduled after msmsdcc_disable()
3946 * is called. Thus, MMC core will try to enable the host
3947 * while suspending it. This results in a synchronous
3948 * runtime resume request while in runtime suspending
3949 * context and hence inorder to complete this resume
3950 * requet, it will wait for suspend to be complete,
3951 * but runtime suspend also can not proceed further
3952 * until the host is resumed. Thus, it leads to a hang.
3953 * Hence, increase the pm usage count before suspending
3954 * the host so that any resume requests after this will
3955 * simple become pm usage counter increment operations.
3956 */
3957 pm_runtime_get_noresume(dev);
3958 rc = mmc_suspend_host(mmc);
3959 pm_runtime_put_noidle(dev);
3960
3961 if (!rc) {
3962 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
3963 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ)) {
3964 disable_irq(host->core_irqres->start);
3965 host->sdcc_irq_disabled = 1;
3966
3967 /*
3968 * If MMC core level suspend is not supported,
3969 * turn off clocks to allow deep sleep (TCXO
3970 * shutdown).
3971 */
3972 mmc->ios.clock = 0;
3973 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
3974 enable_irq(host->core_irqres->start);
3975 host->sdcc_irq_disabled = 0;
3976
3977 if (host->plat->sdiowakeup_irq) {
3978 host->sdio_irq_disabled = 0;
3979 msmsdcc_enable_irq_wake(host);
3980 enable_irq(host->plat->sdiowakeup_irq);
3981 }
3982 }
3983 }
3984 host->sdcc_suspending = 0;
3985 mmc->suspend_task = NULL;
3986 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
3987 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07003988 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05303989 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003990 return rc;
3991}
3992
3993static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003994msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07003995{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003996 struct mmc_host *mmc = dev_get_drvdata(dev);
3997 struct msmsdcc_host *host = mmc_priv(mmc);
3998 unsigned long flags;
3999
4000 if (host->plat->is_sdio_al_client)
4001 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07004002
Sahitya Tummala7661a452011-07-18 13:28:35 +05304003 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004004 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004005 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
4006 if (host->sdcc_irq_disabled) {
4007 enable_irq(host->core_irqres->start);
4008 host->sdcc_irq_disabled = 0;
4009 }
4010 }
4011 mmc->ios.clock = host->clk_rate;
4012 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07004013
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004014 spin_lock_irqsave(&host->lock, flags);
4015 writel_relaxed(host->mci_irqenable, host->base + MMCIMASK0);
4016 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07004017
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004018 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
4019 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) &&
4020 !host->sdio_irq_disabled) {
4021 if (host->plat->sdiowakeup_irq) {
4022 disable_irq_nosync(
4023 host->plat->sdiowakeup_irq);
4024 msmsdcc_disable_irq_wake(host);
4025 host->sdio_irq_disabled = 1;
4026 }
4027 }
San Mehat9d2bd732009-09-22 16:44:22 -07004028
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004029 spin_unlock_irqrestore(&host->lock, flags);
4030
4031 mmc_resume_host(mmc);
4032
4033 /*
4034 * FIXME: Clearing of flags must be handled in clients
4035 * resume handler.
4036 */
4037 spin_lock_irqsave(&host->lock, flags);
4038 mmc->pm_flags = 0;
4039 spin_unlock_irqrestore(&host->lock, flags);
4040
4041 /*
4042 * After resuming the host wait for sometime so that
4043 * the SDIO work will be processed.
4044 */
4045 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO)) {
4046 if ((host->plat->cfg_mpm_sdiowakeup ||
4047 host->plat->sdiowakeup_irq) &&
4048 wake_lock_active(&host->sdio_wlock))
4049 wake_lock_timeout(&host->sdio_wlock, 1);
4050 }
4051
4052 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004053 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304054 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004055 return 0;
4056}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004057
4058static int msmsdcc_runtime_idle(struct device *dev)
4059{
4060 struct mmc_host *mmc = dev_get_drvdata(dev);
4061 struct msmsdcc_host *host = mmc_priv(mmc);
4062
4063 if (host->plat->is_sdio_al_client)
4064 return 0;
4065
4066 /* Idle timeout is not configurable for now */
4067 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
4068
4069 return -EAGAIN;
4070}
4071
4072static int msmsdcc_pm_suspend(struct device *dev)
4073{
4074 struct mmc_host *mmc = dev_get_drvdata(dev);
4075 struct msmsdcc_host *host = mmc_priv(mmc);
4076 int rc = 0;
4077
4078 if (host->plat->is_sdio_al_client)
4079 return 0;
4080
4081
4082 if (host->plat->status_irq)
4083 disable_irq(host->plat->status_irq);
4084
4085 if (!pm_runtime_suspended(dev))
4086 rc = msmsdcc_runtime_suspend(dev);
4087
4088 return rc;
4089}
4090
4091static int msmsdcc_pm_resume(struct device *dev)
4092{
4093 struct mmc_host *mmc = dev_get_drvdata(dev);
4094 struct msmsdcc_host *host = mmc_priv(mmc);
4095 int rc = 0;
4096
4097 if (host->plat->is_sdio_al_client)
4098 return 0;
4099
4100 rc = msmsdcc_runtime_resume(dev);
4101 if (host->plat->status_irq) {
4102 msmsdcc_check_status((unsigned long)host);
4103 enable_irq(host->plat->status_irq);
4104 }
4105
4106 /* Update the run-time PM status */
4107 pm_runtime_disable(dev);
4108 rc = pm_runtime_set_active(dev);
4109 if (rc < 0)
4110 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
4111 __func__, rc);
4112 pm_runtime_enable(dev);
4113
4114 return rc;
4115}
4116
Daniel Walker08ecfde2010-06-23 12:32:20 -07004117#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004118#define msmsdcc_runtime_suspend NULL
4119#define msmsdcc_runtime_resume NULL
4120#define msmsdcc_runtime_idle NULL
4121#define msmsdcc_pm_suspend NULL
4122#define msmsdcc_pm_resume NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07004123#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004124
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004125static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
4126 .runtime_suspend = msmsdcc_runtime_suspend,
4127 .runtime_resume = msmsdcc_runtime_resume,
4128 .runtime_idle = msmsdcc_runtime_idle,
4129 .suspend = msmsdcc_pm_suspend,
4130 .resume = msmsdcc_pm_resume,
4131};
4132
San Mehat9d2bd732009-09-22 16:44:22 -07004133static struct platform_driver msmsdcc_driver = {
4134 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004135 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07004136 .driver = {
4137 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004138 .pm = &msmsdcc_dev_pm_ops,
San Mehat9d2bd732009-09-22 16:44:22 -07004139 },
4140};
4141
4142static int __init msmsdcc_init(void)
4143{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004144#if defined(CONFIG_DEBUG_FS)
4145 int ret = 0;
4146 ret = msmsdcc_dbg_init();
4147 if (ret) {
4148 pr_err("Failed to create debug fs dir \n");
4149 return ret;
4150 }
4151#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004152 return platform_driver_register(&msmsdcc_driver);
4153}
4154
4155static void __exit msmsdcc_exit(void)
4156{
4157 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004158
4159#if defined(CONFIG_DEBUG_FS)
4160 debugfs_remove(debugfs_file);
4161 debugfs_remove(debugfs_dir);
4162#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004163}
4164
4165module_init(msmsdcc_init);
4166module_exit(msmsdcc_exit);
4167
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004168MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07004169MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004170
4171#if defined(CONFIG_DEBUG_FS)
4172
4173static int
4174msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
4175{
4176 file->private_data = inode->i_private;
4177 return 0;
4178}
4179
4180static ssize_t
4181msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
4182 size_t count, loff_t *ppos)
4183{
4184 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
4185 char buf[1024];
4186 int max, i;
4187
4188 i = 0;
4189 max = sizeof(buf) - 1;
4190
4191 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
4192 host->curr.cmd, host->curr.data);
4193 if (host->curr.cmd) {
4194 struct mmc_command *cmd = host->curr.cmd;
4195
4196 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
4197 cmd->opcode, cmd->arg, cmd->flags);
4198 }
4199 if (host->curr.data) {
4200 struct mmc_data *data = host->curr.data;
4201 i += scnprintf(buf + i, max - i,
4202 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
4203 data->timeout_ns, data->timeout_clks,
4204 data->blksz, data->blocks, data->error,
4205 data->flags);
4206 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
4207 host->curr.xfer_size, host->curr.xfer_remain,
4208 host->curr.data_xfered, host->dma.sg);
4209 }
4210
4211 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
4212}
4213
4214static const struct file_operations msmsdcc_dbg_state_ops = {
4215 .read = msmsdcc_dbg_state_read,
4216 .open = msmsdcc_dbg_state_open,
4217};
4218
4219static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
4220{
4221 if (debugfs_dir) {
4222 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
4223 0644, debugfs_dir, host,
4224 &msmsdcc_dbg_state_ops);
4225 }
4226}
4227
4228static int __init msmsdcc_dbg_init(void)
4229{
4230 int err;
4231
4232 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
4233 if (IS_ERR(debugfs_dir)) {
4234 err = PTR_ERR(debugfs_dir);
4235 debugfs_dir = NULL;
4236 return err;
4237 }
4238
4239 return 0;
4240}
4241#endif