blob: 9d21c719672f62fbb5943185a50b5dfd827990e5 [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;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530300 host->curr.wait_for_auto_prog_done = 0;
301 host->curr.got_auto_prog_done = 0;
Krishna Konda3f5d48f2011-07-27 10:47:31 -0700302 writel_relaxed(readl_relaxed(host->base + MMCIDATACTRL) &
303 (~(MCI_DPSM_ENABLE)), host->base + MMCIDATACTRL);
Krishna Konda3e5c4d02011-07-11 16:31:45 -0700304 msmsdcc_delay(host); /* Allow the DPSM to be reset */
San Mehat9d2bd732009-09-22 16:44:22 -0700305}
306
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700307static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700308{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700309 return host->core_memres->start + MMCIFIFO;
310}
311
312static inline unsigned int msmsdcc_get_min_sup_clk_rate(
313 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530314
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700315static inline void msmsdcc_delay(struct msmsdcc_host *host)
316{
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530317 ktime_t start, diff;
318
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700319 mb();
320 udelay(1 + ((3 * USEC_PER_SEC) /
321 (host->clk_rate ? host->clk_rate :
322 msmsdcc_get_min_sup_clk_rate(host))));
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530323
324 if (host->plat->sdcc_v4_sup &&
325 (readl_relaxed(host->base + MCI_STATUS2) &
326 MCI_MCLK_REG_WR_ACTIVE)) {
327 start = ktime_get();
328 while (readl_relaxed(host->base + MCI_STATUS2) &
329 MCI_MCLK_REG_WR_ACTIVE) {
330 diff = ktime_sub(ktime_get(), start);
331 /* poll for max. 1 ms */
332 if (ktime_to_us(diff) > 1000) {
333 pr_warning("%s: previous reg. write is"
334 " still active\n",
335 mmc_hostname(host->mmc));
336 break;
337 }
338 }
339 }
San Mehat9d2bd732009-09-22 16:44:22 -0700340}
341
San Mehat56a8b5b2009-11-21 12:29:46 -0800342static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700343msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
344{
345 writel_relaxed(arg, host->base + MMCIARGUMENT);
346 msmsdcc_delay(host);
347 writel_relaxed(c, host->base + MMCICOMMAND);
348 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800349}
350
351static void
352msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
353{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700354 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800355
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700356 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
357 writel_relaxed((unsigned int)host->curr.xfer_size,
358 host->base + MMCIDATALENGTH);
359 msmsdcc_delay(host); /* Allow data parms to be applied */
360 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
361 msmsdcc_delay(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800362
San Mehat6ac9ea62009-12-02 17:24:58 -0800363 if (host->cmd_cmd) {
364 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700365 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800366 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800367}
368
San Mehat9d2bd732009-09-22 16:44:22 -0700369static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530370msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700371{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530372 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700373 unsigned long flags;
374 struct mmc_request *mrq;
375
376 spin_lock_irqsave(&host->lock, flags);
377 mrq = host->curr.mrq;
378 BUG_ON(!mrq);
379
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530380 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700381 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700382 goto out;
383 }
384
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530385 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700386 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700387 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700388 } else {
389 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530390 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700391 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530392 mmc_hostname(host->mmc), host->dma.result);
393 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700394 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530395 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530396 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700397 host->dma.err.flush[0], host->dma.err.flush[1],
398 host->dma.err.flush[2], host->dma.err.flush[3],
399 host->dma.err.flush[4],
400 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530401 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700402 if (!mrq->data->error)
403 mrq->data->error = -EIO;
404 }
San Mehat9d2bd732009-09-22 16:44:22 -0700405 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents,
406 host->dma.dir);
407
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700408 if (host->curr.user_pages) {
409 struct scatterlist *sg = host->dma.sg;
410 int i;
411
412 for (i = 0; i < host->dma.num_ents; i++, sg++)
413 flush_dcache_page(sg_page(sg));
414 }
415
San Mehat9d2bd732009-09-22 16:44:22 -0700416 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800417 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700418
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530419 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
420 (host->curr.wait_for_auto_prog_done &&
421 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700422 /*
423 * If we've already gotten our DATAEND / DATABLKEND
424 * for this request, then complete it through here.
425 */
San Mehat9d2bd732009-09-22 16:44:22 -0700426
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700427 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700428 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700429 host->curr.xfer_remain -= host->curr.xfer_size;
430 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700431 if (host->dummy_52_needed) {
432 mrq->data->bytes_xfered = host->curr.data_xfered;
433 host->dummy_52_sent = 1;
434 msmsdcc_start_command(host, &dummy52cmd,
435 MCI_CPSM_PROGENA);
436 goto out;
437 }
438 msmsdcc_stop_data(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700439 if (!mrq->data->stop || mrq->cmd->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700440 host->curr.mrq = NULL;
441 host->curr.cmd = NULL;
442 mrq->data->bytes_xfered = host->curr.data_xfered;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700443 del_timer(&host->req_tout_timer);
San Mehat9d2bd732009-09-22 16:44:22 -0700444 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700445
San Mehat9d2bd732009-09-22 16:44:22 -0700446 mmc_request_done(host->mmc, mrq);
447 return;
448 } else
449 msmsdcc_start_command(host, mrq->data->stop, 0);
450 }
451
452out:
453 spin_unlock_irqrestore(&host->lock, flags);
454 return;
455}
456
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700457#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
458/**
459 * Callback notification from SPS driver
460 *
461 * This callback function gets triggered called from
462 * SPS driver when requested SPS data transfer is
463 * completed.
464 *
465 * SPS driver invokes this callback in BAM irq context so
466 * SDCC driver schedule a tasklet for further processing
467 * this callback notification at later point of time in
468 * tasklet context and immediately returns control back
469 * to SPS driver.
470 *
471 * @nofity - Pointer to sps event notify sturcture
472 *
473 */
474static void
475msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
476{
477 struct msmsdcc_host *host =
478 (struct msmsdcc_host *)
479 ((struct sps_event_notify *)notify)->user;
480
481 host->sps.notify = *notify;
482 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
483 mmc_hostname(host->mmc), __func__, notify->event_id,
484 notify->data.transfer.iovec.addr,
485 notify->data.transfer.iovec.size,
486 notify->data.transfer.iovec.flags);
487 /* Schedule a tasklet for completing data transfer */
488 tasklet_schedule(&host->sps.tlet);
489}
490
491/**
492 * Tasklet handler for processing SPS callback event
493 *
494 * This function processing SPS event notification and
495 * checks if the SPS transfer is completed or not and
496 * then accordingly notifies status to MMC core layer.
497 *
498 * This function is called in tasklet context.
499 *
500 * @data - Pointer to sdcc driver data
501 *
502 */
503static void msmsdcc_sps_complete_tlet(unsigned long data)
504{
505 unsigned long flags;
506 int i, rc;
507 u32 data_xfered = 0;
508 struct mmc_request *mrq;
509 struct sps_iovec iovec;
510 struct sps_pipe *sps_pipe_handle;
511 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
512 struct sps_event_notify *notify = &host->sps.notify;
513
514 spin_lock_irqsave(&host->lock, flags);
515 if (host->sps.dir == DMA_FROM_DEVICE)
516 sps_pipe_handle = host->sps.prod.pipe_handle;
517 else
518 sps_pipe_handle = host->sps.cons.pipe_handle;
519 mrq = host->curr.mrq;
520
521 if (!mrq) {
522 spin_unlock_irqrestore(&host->lock, flags);
523 return;
524 }
525
526 pr_debug("%s: %s: sps event_id=%d\n",
527 mmc_hostname(host->mmc), __func__,
528 notify->event_id);
529
530 if (msmsdcc_is_dml_busy(host)) {
531 /* oops !!! this should never happen. */
532 pr_err("%s: %s: Received SPS EOT event"
533 " but DML HW is still busy !!!\n",
534 mmc_hostname(host->mmc), __func__);
535 }
536 /*
537 * Got End of transfer event!!! Check if all of the data
538 * has been transferred?
539 */
540 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
541 rc = sps_get_iovec(sps_pipe_handle, &iovec);
542 if (rc) {
543 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
544 mmc_hostname(host->mmc), __func__, rc, i);
545 break;
546 }
547 data_xfered += iovec.size;
548 }
549
550 if (data_xfered == host->curr.xfer_size) {
551 host->curr.data_xfered = host->curr.xfer_size;
552 host->curr.xfer_remain -= host->curr.xfer_size;
553 pr_debug("%s: Data xfer success. data_xfered=0x%x",
554 mmc_hostname(host->mmc),
555 host->curr.xfer_size);
556 } else {
557 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
558 " xfer_size=%d", mmc_hostname(host->mmc),
559 data_xfered, host->curr.xfer_size);
560 msmsdcc_reset_and_restore(host);
561 if (!mrq->data->error)
562 mrq->data->error = -EIO;
563 }
564
565 /* Unmap sg buffers */
566 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
567 host->sps.dir);
568
569 host->sps.sg = NULL;
570 host->sps.busy = 0;
571
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530572 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
573 (host->curr.wait_for_auto_prog_done &&
574 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700575 /*
576 * If we've already gotten our DATAEND / DATABLKEND
577 * for this request, then complete it through here.
578 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700579
580 if (!mrq->data->error) {
581 host->curr.data_xfered = host->curr.xfer_size;
582 host->curr.xfer_remain -= host->curr.xfer_size;
583 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700584 if (host->dummy_52_needed) {
585 mrq->data->bytes_xfered = host->curr.data_xfered;
586 host->dummy_52_sent = 1;
587 msmsdcc_start_command(host, &dummy52cmd,
588 MCI_CPSM_PROGENA);
589 return;
590 }
591 msmsdcc_stop_data(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700592 if (!mrq->data->stop || mrq->cmd->error) {
593 host->curr.mrq = NULL;
594 host->curr.cmd = NULL;
595 mrq->data->bytes_xfered = host->curr.data_xfered;
596 del_timer(&host->req_tout_timer);
597 spin_unlock_irqrestore(&host->lock, flags);
598
599 mmc_request_done(host->mmc, mrq);
600 return;
601 } else {
602 msmsdcc_start_command(host, mrq->data->stop, 0);
603 }
604 }
605 spin_unlock_irqrestore(&host->lock, flags);
606}
607
608/**
609 * Exit from current SPS data transfer
610 *
611 * This function exits from current SPS data transfer.
612 *
613 * This function should be called when error condition
614 * is encountered during data transfer.
615 *
616 * @host - Pointer to sdcc host structure
617 *
618 */
619static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
620{
621 struct mmc_request *mrq;
622
623 mrq = host->curr.mrq;
624 BUG_ON(!mrq);
625
626 msmsdcc_reset_and_restore(host);
627 if (!mrq->data->error)
628 mrq->data->error = -EIO;
629
630 /* Unmap sg buffers */
631 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
632 host->sps.dir);
633
634 host->sps.sg = NULL;
635 host->sps.busy = 0;
636 if (host->curr.data)
637 msmsdcc_stop_data(host);
638
639 if (!mrq->data->stop || mrq->cmd->error)
640 msmsdcc_request_end(host, mrq);
641 else
642 msmsdcc_start_command(host, mrq->data->stop, 0);
643
644}
645#else
646static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
647static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
648static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
649#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
650
651static void msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
652
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530653static void
654msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
655 unsigned int result,
656 struct msm_dmov_errdata *err)
657{
658 struct msmsdcc_dma_data *dma_data =
659 container_of(cmd, struct msmsdcc_dma_data, hdr);
660 struct msmsdcc_host *host = dma_data->host;
661
662 dma_data->result = result;
663 if (err)
664 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
665
666 tasklet_schedule(&host->dma_tlet);
667}
668
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700669static int msmsdcc_check_dma_op_req(struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700670{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700671 if (((data->blksz * data->blocks) < MCI_FIFOSIZE) ||
672 ((data->blksz * data->blocks) % MCI_FIFOSIZE))
San Mehat9d2bd732009-09-22 16:44:22 -0700673 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700674 else
675 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700676}
677
678static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
679{
680 struct msmsdcc_nc_dmadata *nc;
681 dmov_box *box;
682 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700683 unsigned int n;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700684 int i;
San Mehat9d2bd732009-09-22 16:44:22 -0700685 struct scatterlist *sg = data->sg;
686
Krishna Konda25786ec2011-07-25 16:21:36 -0700687 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700688 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700689
Krishna Konda25786ec2011-07-25 16:21:36 -0700690 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
691
San Mehat9d2bd732009-09-22 16:44:22 -0700692 host->dma.sg = data->sg;
693 host->dma.num_ents = data->sg_len;
694
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700695 BUG_ON(host->dma.num_ents > NR_SG); /* Prevent memory corruption */
San Mehat56a8b5b2009-11-21 12:29:46 -0800696
San Mehat9d2bd732009-09-22 16:44:22 -0700697 nc = host->dma.nc;
698
San Mehat9d2bd732009-09-22 16:44:22 -0700699 if (data->flags & MMC_DATA_READ)
700 host->dma.dir = DMA_FROM_DEVICE;
701 else
702 host->dma.dir = DMA_TO_DEVICE;
703
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700704 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
San Mehat9d2bd732009-09-22 16:44:22 -0700705 host->curr.user_pages = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700706 box = &nc->cmd[0];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700707 for (i = 0; i < host->dma.num_ents; i++) {
San Mehat9d2bd732009-09-22 16:44:22 -0700708 box->cmd = CMD_MODE_BOX;
709
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700710 /* Initialize sg dma address */
711 sg->dma_address = pfn_to_dma(mmc_dev(host->mmc),
712 page_to_pfn(sg_page(sg)))
713 + sg->offset;
714
715 if (i == (host->dma.num_ents - 1))
San Mehat9d2bd732009-09-22 16:44:22 -0700716 box->cmd |= CMD_LC;
717 rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ?
718 (sg_dma_len(sg) / MCI_FIFOSIZE) + 1 :
719 (sg_dma_len(sg) / MCI_FIFOSIZE) ;
720
721 if (data->flags & MMC_DATA_READ) {
722 box->src_row_addr = msmsdcc_fifo_addr(host);
723 box->dst_row_addr = sg_dma_address(sg);
724
725 box->src_dst_len = (MCI_FIFOSIZE << 16) |
726 (MCI_FIFOSIZE);
727 box->row_offset = MCI_FIFOSIZE;
728
729 box->num_rows = rows * ((1 << 16) + 1);
Krishna Konda25786ec2011-07-25 16:21:36 -0700730 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
San Mehat9d2bd732009-09-22 16:44:22 -0700731 } else {
732 box->src_row_addr = sg_dma_address(sg);
733 box->dst_row_addr = msmsdcc_fifo_addr(host);
734
735 box->src_dst_len = (MCI_FIFOSIZE << 16) |
736 (MCI_FIFOSIZE);
737 box->row_offset = (MCI_FIFOSIZE << 16);
738
739 box->num_rows = rows * ((1 << 16) + 1);
Krishna Konda25786ec2011-07-25 16:21:36 -0700740 box->cmd |= CMD_DST_CRCI(host->dma.crci);
San Mehat9d2bd732009-09-22 16:44:22 -0700741 }
742 box++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700743 sg++;
744 }
745
746 /* location of command block must be 64 bit aligned */
747 BUG_ON(host->dma.cmd_busaddr & 0x07);
748
749 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
750 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
751 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
752 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
Krishna Konda25786ec2011-07-25 16:21:36 -0700753 host->dma.hdr.crci_mask = msm_dmov_build_crci_mask(1, host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700754
755 n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
756 host->dma.num_ents, host->dma.dir);
757 /* dsb inside dma_map_sg will write nc out to mem as well */
758
759 if (n != host->dma.num_ents) {
760 pr_err("%s: Unable to map in all sg elements\n",
761 mmc_hostname(host->mmc));
762 host->dma.sg = NULL;
763 host->dma.num_ents = 0;
764 return -ENOMEM;
San Mehat56a8b5b2009-11-21 12:29:46 -0800765 }
San Mehat9d2bd732009-09-22 16:44:22 -0700766
767 return 0;
768}
769
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700770#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
771/**
772 * Submits data transfer request to SPS driver
773 *
774 * This function make sg (scatter gather) data buffers
775 * DMA ready and then submits them to SPS driver for
776 * transfer.
777 *
778 * @host - Pointer to sdcc host structure
779 * @data - Pointer to mmc_data structure
780 *
781 * @return 0 if success else negative value
782 */
783static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
784 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -0800785{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700786 int rc = 0;
787 u32 flags;
788 int i;
789 u32 addr, len, data_cnt;
790 struct scatterlist *sg = data->sg;
791 struct sps_pipe *sps_pipe_handle;
792
793 BUG_ON(data->sg_len > NR_SG); /* Prevent memory corruption */
794
795 host->sps.sg = data->sg;
796 host->sps.num_ents = data->sg_len;
797 host->sps.xfer_req_cnt = 0;
798 if (data->flags & MMC_DATA_READ) {
799 host->sps.dir = DMA_FROM_DEVICE;
800 sps_pipe_handle = host->sps.prod.pipe_handle;
801 } else {
802 host->sps.dir = DMA_TO_DEVICE;
803 sps_pipe_handle = host->sps.cons.pipe_handle;
804 }
805
806 /* Make sg buffers DMA ready */
807 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
808 host->sps.dir);
809
810 if (rc != data->sg_len) {
811 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
812 mmc_hostname(host->mmc), rc);
813 host->sps.sg = NULL;
814 host->sps.num_ents = 0;
815 rc = -ENOMEM;
816 goto dma_map_err;
817 }
818
819 pr_debug("%s: %s: %s: pipe=0x%x, total_xfer=0x%x, sg_len=%d\n",
820 mmc_hostname(host->mmc), __func__,
821 host->sps.dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
822 (u32)sps_pipe_handle, host->curr.xfer_size, data->sg_len);
823
824 for (i = 0; i < data->sg_len; i++) {
825 /*
826 * Check if this is the last buffer to transfer?
827 * If yes then set the INT and EOT flags.
828 */
829 len = sg_dma_len(sg);
830 addr = sg_dma_address(sg);
831 flags = 0;
832 while (len > 0) {
833 if (len > SPS_MAX_DESC_SIZE) {
834 data_cnt = SPS_MAX_DESC_SIZE;
835 } else {
836 data_cnt = len;
837 if (i == data->sg_len - 1)
838 flags = SPS_IOVEC_FLAG_INT |
839 SPS_IOVEC_FLAG_EOT;
840 }
841 rc = sps_transfer_one(sps_pipe_handle, addr,
842 data_cnt, host, flags);
843 if (rc) {
844 pr_err("%s: sps_transfer_one() error! rc=%d,"
845 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
846 mmc_hostname(host->mmc), rc,
847 (u32)sps_pipe_handle, (u32)sg, i);
848 goto dma_map_err;
849 }
850 addr += data_cnt;
851 len -= data_cnt;
852 host->sps.xfer_req_cnt++;
853 }
854 sg++;
855 }
856 goto out;
857
858dma_map_err:
859 /* unmap sg buffers */
860 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
861 host->sps.dir);
862out:
863 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -0700864}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700865#else
866static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
867 struct mmc_data *data) { return 0; }
868#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -0700869
870static void
San Mehat56a8b5b2009-11-21 12:29:46 -0800871msmsdcc_start_command_deferred(struct msmsdcc_host *host,
872 struct mmc_command *cmd, u32 *c)
873{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700874 DBG(host, "op %02x arg %08x flags %08x\n",
875 cmd->opcode, cmd->arg, cmd->flags);
876
San Mehat56a8b5b2009-11-21 12:29:46 -0800877 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
878
879 if (cmd->flags & MMC_RSP_PRESENT) {
880 if (cmd->flags & MMC_RSP_136)
881 *c |= MCI_CPSM_LONGRSP;
882 *c |= MCI_CPSM_RESPONSE;
883 }
884
885 if (/*interrupt*/0)
886 *c |= MCI_CPSM_INTERRUPT;
887
888 if ((((cmd->opcode == 17) || (cmd->opcode == 18)) ||
889 ((cmd->opcode == 24) || (cmd->opcode == 25))) ||
890 (cmd->opcode == 53))
891 *c |= MCI_CSPM_DATCMD;
892
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700893 /* Check if AUTO CMD19 is required or not? */
894 if (((cmd->opcode == 17) || (cmd->opcode == 18)) &&
895 host->tuning_needed) {
896 msmsdcc_enable_cdr_cm_sdc4_dll(host);
897 *c |= MCI_CSPM_AUTO_CMD19;
898 }
899
Sahitya Tummalad5137bd2010-12-08 15:03:04 +0530900 if (host->prog_scan && (cmd->opcode == 12)) {
901 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700902 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +0530903 }
904
San Mehat56a8b5b2009-11-21 12:29:46 -0800905 if (cmd == cmd->mrq->stop)
906 *c |= MCI_CSPM_MCIABORT;
907
San Mehat56a8b5b2009-11-21 12:29:46 -0800908 if (host->curr.cmd != NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700909 pr_err("%s: Overlapping command requests\n",
910 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -0800911 }
912 host->curr.cmd = cmd;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700913
914 /*
915 * Kick the software command timeout timer here.
916 * Timer expires in 10 secs.
917 */
918 mod_timer(&host->req_tout_timer,
919 (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
San Mehat56a8b5b2009-11-21 12:29:46 -0800920}
921
922static void
923msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
924 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -0700925{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +0530926 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -0700927 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700928 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -0700929 unsigned int pio_irqmask = 0;
930
931 host->curr.data = data;
932 host->curr.xfer_size = data->blksz * data->blocks;
933 host->curr.xfer_remain = host->curr.xfer_size;
934 host->curr.data_xfered = 0;
935 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530936 host->curr.got_auto_prog_done = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700937
938 memset(&host->pio, 0, sizeof(host->pio));
939
San Mehat9d2bd732009-09-22 16:44:22 -0700940 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
941
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530942 if (host->curr.wait_for_auto_prog_done)
943 datactrl |= MCI_AUTO_PROG_DONE;
944
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700945 if (!msmsdcc_check_dma_op_req(data)) {
946 if (host->is_dma_mode && !msmsdcc_config_dma(host, data)) {
947 datactrl |= MCI_DPSM_DMAENABLE;
948 } else if (host->is_sps_mode) {
949 if (!msmsdcc_is_dml_busy(host)) {
950 if (!msmsdcc_sps_start_xfer(host, data)) {
951 /* Now kick start DML transfer */
952 mb();
953 msmsdcc_dml_start_xfer(host, data);
954 datactrl |= MCI_DPSM_DMAENABLE;
955 host->sps.busy = 1;
956 }
957 } else {
958 /*
959 * Can't proceed with new transfer as
960 * previous trasnfer is already in progress.
961 * There is no point of going into PIO mode
962 * as well. Is this a time to do kernel panic?
963 */
964 pr_err("%s: %s: DML HW is busy!!!"
965 " Can't perform new SPS transfers"
966 " now\n", mmc_hostname(host->mmc),
967 __func__);
968 }
969 }
970 }
971
972 /* Is data transfer in PIO mode required? */
973 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700974 host->pio.sg = data->sg;
975 host->pio.sg_len = data->sg_len;
976 host->pio.sg_off = 0;
977
978 if (data->flags & MMC_DATA_READ) {
979 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
980 if (host->curr.xfer_remain < MCI_FIFOSIZE)
981 pio_irqmask |= MCI_RXDATAAVLBLMASK;
982 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700983 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
984 MCI_TXFIFOEMPTYMASK;
San Mehat9d2bd732009-09-22 16:44:22 -0700985 }
986
987 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +0530988 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
San Mehat9d2bd732009-09-22 16:44:22 -0700989
San Mehat56a8b5b2009-11-21 12:29:46 -0800990 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700991 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -0800992 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -0700993
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700994 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
995 /* Use ADM (Application Data Mover) HW for Data transfer */
996 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -0800997 host->cmd_timeout = timeout;
998 host->cmd_pio_irqmask = pio_irqmask;
999 host->cmd_datactrl = datactrl;
1000 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001001
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001002 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1003 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001004 host->dma.busy = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001005 if (data->flags & MMC_DATA_WRITE)
1006 host->prog_scan = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001007
1008 if (cmd) {
1009 msmsdcc_start_command_deferred(host, cmd, &c);
1010 host->cmd_c = c;
1011 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001012 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1013 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1014 host->base + MMCIMASK0);
1015 mb();
1016 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001017 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001018 /* SPS-BAM mode or PIO mode */
1019 if (data->flags & MMC_DATA_WRITE)
1020 host->prog_scan = 1;
1021 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001022
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001023 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001024
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001025 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1026 (~(MCI_IRQ_PIO))) | pio_irqmask,
1027 host->base + MMCIMASK0);
1028 msmsdcc_delay(host); /* Allow parms to be applied */
1029 writel_relaxed(datactrl, base + MMCIDATACTRL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001030
1031 if (cmd) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001032 msmsdcc_delay(host); /* Delay between data/command */
San Mehat56a8b5b2009-11-21 12:29:46 -08001033 /* Daisy-chain the command if requested */
1034 msmsdcc_start_command(host, cmd, c);
1035 }
San Mehat9d2bd732009-09-22 16:44:22 -07001036 }
1037}
1038
1039static void
1040msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1041{
San Mehat56a8b5b2009-11-21 12:29:46 -08001042 msmsdcc_start_command_deferred(host, cmd, &c);
1043 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001044}
1045
1046static void
1047msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1048 unsigned int status)
1049{
1050 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001051 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1052 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1053 pr_err("%s: Data CRC error\n",
1054 mmc_hostname(host->mmc));
1055 pr_err("%s: opcode 0x%.8x\n", __func__,
1056 data->mrq->cmd->opcode);
1057 pr_err("%s: blksz %d, blocks %d\n", __func__,
1058 data->blksz, data->blocks);
1059 data->error = -EILSEQ;
1060 }
San Mehat9d2bd732009-09-22 16:44:22 -07001061 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001062 /* CRC is optional for the bus test commands, not all
1063 * cards respond back with CRC. However controller
1064 * waits for the CRC and times out. Hence ignore the
1065 * data timeouts during the Bustest.
1066 */
1067 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1068 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1069 pr_err("%s: Data timeout\n",
1070 mmc_hostname(host->mmc));
1071 data->error = -ETIMEDOUT;
1072 }
San Mehat9d2bd732009-09-22 16:44:22 -07001073 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001074 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001075 data->error = -EIO;
1076 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001077 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001078 data->error = -EIO;
1079 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001080 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001081 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001082 data->error = -EIO;
1083 }
San Mehat9d2bd732009-09-22 16:44:22 -07001084
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001085 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001086 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001087 host->dummy_52_needed = 0;
1088}
San Mehat9d2bd732009-09-22 16:44:22 -07001089
1090static int
1091msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1092{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001093 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001094 uint32_t *ptr = (uint32_t *) buffer;
1095 int count = 0;
1096
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301097 if (remain % 4)
1098 remain = ((remain >> 2) + 1) << 2;
1099
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001100 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1101
1102 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001103 ptr++;
1104 count += sizeof(uint32_t);
1105
1106 remain -= sizeof(uint32_t);
1107 if (remain == 0)
1108 break;
1109 }
1110 return count;
1111}
1112
1113static int
1114msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001115 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001116{
1117 void __iomem *base = host->base;
1118 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001119 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001120
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001121 while (readl_relaxed(base + MMCISTATUS) &
1122 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1123 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001124
San Mehat9d2bd732009-09-22 16:44:22 -07001125 count = min(remain, maxcnt);
1126
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301127 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1128 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001129 ptr += count;
1130 remain -= count;
1131
1132 if (remain == 0)
1133 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001134 }
1135 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001136
1137 return ptr - buffer;
1138}
1139
San Mehat1cd22962010-02-03 12:59:29 -08001140static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001141msmsdcc_pio_irq(int irq, void *dev_id)
1142{
1143 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001144 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001145 uint32_t status;
1146
Murali Palnati36448a42011-09-02 15:06:18 +05301147 spin_lock(&host->lock);
1148
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001149 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001150
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001151 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301152 (MCI_IRQ_PIO)) == 0) {
1153 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001154 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301155 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001156
1157#if IRQ_DEBUG
1158 msmsdcc_print_status(host, "irq1-r", status);
1159#endif
1160
San Mehat9d2bd732009-09-22 16:44:22 -07001161 do {
1162 unsigned long flags;
1163 unsigned int remain, len;
1164 char *buffer;
1165
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001166 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1167 | MCI_RXDATAAVLBL)))
1168 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001169
1170 /* Map the current scatter buffer */
1171 local_irq_save(flags);
1172 buffer = kmap_atomic(sg_page(host->pio.sg),
1173 KM_BIO_SRC_IRQ) + host->pio.sg->offset;
1174 buffer += host->pio.sg_off;
1175 remain = host->pio.sg->length - host->pio.sg_off;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001176
San Mehat9d2bd732009-09-22 16:44:22 -07001177 len = 0;
1178 if (status & MCI_RXACTIVE)
1179 len = msmsdcc_pio_read(host, buffer, remain);
1180 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001181 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001182
1183 /* Unmap the buffer */
1184 kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
1185 local_irq_restore(flags);
1186
1187 host->pio.sg_off += len;
1188 host->curr.xfer_remain -= len;
1189 host->curr.data_xfered += len;
1190 remain -= len;
1191
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001192 if (remain) /* Done with this page? */
1193 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001194
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001195 if (status & MCI_RXACTIVE && host->curr.user_pages)
1196 flush_dcache_page(sg_page(host->pio.sg));
San Mehat9d2bd732009-09-22 16:44:22 -07001197
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001198 if (!--host->pio.sg_len) {
1199 memset(&host->pio, 0, sizeof(host->pio));
1200 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001201 }
1202
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001203 /* Advance to next sg */
1204 host->pio.sg++;
1205 host->pio.sg_off = 0;
1206
1207 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001208 } while (1);
1209
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001210 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1211 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1212 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1213 host->base + MMCIMASK0);
1214 if (!host->curr.xfer_remain) {
1215 /* Delay needed (same port was just written) */
1216 msmsdcc_delay(host);
1217 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1218 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1219 }
1220 mb();
1221 } else if (!host->curr.xfer_remain) {
1222 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1223 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1224 mb();
1225 }
San Mehat9d2bd732009-09-22 16:44:22 -07001226
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001227 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001228
1229 return IRQ_HANDLED;
1230}
1231
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001232static void
1233msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1234
1235static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1236 struct mmc_data *data)
1237{
1238 u32 loop_cnt = 0;
1239
1240 /*
1241 * For read commands with data less than fifo size, it is possible to
1242 * get DATAEND first and RXDATA_AVAIL might be set later because of
1243 * synchronization delay through the asynchronous RX FIFO. Thus, for
1244 * such cases, even after DATAEND interrupt is received software
1245 * should poll for RXDATA_AVAIL until the requested data is read out
1246 * of FIFO. This change is needed to get around this abnormal but
1247 * sometimes expected behavior of SDCC3 controller.
1248 *
1249 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1250 * after the data is loaded into RX FIFO. This would amount to less
1251 * than a microsecond and thus looping for 1000 times is good enough
1252 * for that delay.
1253 */
1254 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1255 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1256 spin_unlock(&host->lock);
1257 msmsdcc_pio_irq(1, host);
1258 spin_lock(&host->lock);
1259 }
1260 }
1261 if (loop_cnt == 1000) {
1262 pr_info("%s: Timed out while polling for Rx Data\n",
1263 mmc_hostname(host->mmc));
1264 data->error = -ETIMEDOUT;
1265 msmsdcc_reset_and_restore(host);
1266 }
1267}
1268
San Mehat9d2bd732009-09-22 16:44:22 -07001269static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1270{
1271 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001272
1273 host->curr.cmd = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001274 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1275 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1276 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1277 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -07001278
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001279 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Sahitya Tummala5a0ae912011-07-18 13:34:01 +05301280 pr_debug("%s: Command timeout\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001281 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001282 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
1283 !host->cmd19_tuning_in_progress) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001284 pr_err("%s: Command CRC error\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001285 cmd->error = -EILSEQ;
1286 }
1287
1288 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001289 if (host->curr.data && host->dma.sg &&
1290 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001291 msm_dmov_stop_cmd(host->dma.channel,
1292 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001293 else if (host->curr.data && host->sps.sg &&
1294 host->is_sps_mode){
1295 /* Stop current SPS transfer */
1296 msmsdcc_sps_exit_curr_xfer(host);
1297 }
San Mehat9d2bd732009-09-22 16:44:22 -07001298 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301299 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001300 msmsdcc_stop_data(host);
1301 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301302 } else { /* host->data == NULL */
1303 if (!cmd->error && host->prog_enable) {
1304 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001305 host->prog_scan = 0;
1306 host->prog_enable = 0;
1307 msmsdcc_request_end(host, cmd->mrq);
1308 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301309 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301310 } else {
1311 if (host->prog_enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001312 host->prog_scan = 0;
1313 host->prog_enable = 0;
1314 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001315 if (host->dummy_52_needed)
1316 host->dummy_52_needed = 0;
1317 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001318 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301319 msmsdcc_request_end(host, cmd->mrq);
1320 }
1321 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001322 } else if (cmd->data) {
San Mehat56a8b5b2009-11-21 12:29:46 -08001323 if (!(cmd->data->flags & MMC_DATA_READ))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001324 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001325 }
1326}
1327
San Mehat9d2bd732009-09-22 16:44:22 -07001328static irqreturn_t
1329msmsdcc_irq(int irq, void *dev_id)
1330{
1331 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001332 u32 status;
1333 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001334 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001335
1336 spin_lock(&host->lock);
1337
1338 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001339 struct mmc_command *cmd;
1340 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001341
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001342 if (timer) {
1343 timer = 0;
1344 msmsdcc_delay(host);
1345 }
San Mehat865c8062009-11-13 13:42:06 -08001346
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001347 if (!host->clks_on) {
1348 pr_debug("%s: %s: SDIO async irq received\n",
1349 mmc_hostname(host->mmc), __func__);
1350 host->mmc->ios.clock = host->clk_rate;
1351 spin_unlock(&host->lock);
1352 host->mmc->ops->set_ios(host->mmc, &host->mmc->ios);
1353 spin_lock(&host->lock);
1354 if (host->plat->cfg_mpm_sdiowakeup &&
1355 (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
1356 wake_lock(&host->sdio_wlock);
1357 /* only ansyc interrupt can come when clocks are off */
1358 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
1359 }
1360
1361 status = readl_relaxed(host->base + MMCISTATUS);
1362
1363 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1364 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001365 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001366
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001367#if IRQ_DEBUG
1368 msmsdcc_print_status(host, "irq0-r", status);
1369#endif
1370 status &= readl_relaxed(host->base + MMCIMASK0);
1371 writel_relaxed(status, host->base + MMCICLEAR);
1372 mb();
1373#if IRQ_DEBUG
1374 msmsdcc_print_status(host, "irq0-p", status);
1375#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001376
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001377#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
1378 if (status & MCI_SDIOINTROPE) {
1379 if (host->sdcc_suspending)
1380 wake_lock(&host->sdio_suspend_wlock);
1381 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001382 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001383#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001384 data = host->curr.data;
1385
1386 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001387 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1388 MCI_CMDTIMEOUT)) {
1389 if (status & MCI_CMDTIMEOUT)
1390 pr_debug("%s: dummy CMD52 timeout\n",
1391 mmc_hostname(host->mmc));
1392 if (status & MCI_CMDCRCFAIL)
1393 pr_debug("%s: dummy CMD52 CRC failed\n",
1394 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001395 host->dummy_52_sent = 0;
1396 host->dummy_52_needed = 0;
1397 if (data) {
1398 msmsdcc_stop_data(host);
1399 msmsdcc_request_end(host, data->mrq);
1400 }
1401 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001402 spin_unlock(&host->lock);
1403 return IRQ_HANDLED;
1404 }
1405 break;
1406 }
1407
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001408 /*
1409 * Check for proper command response
1410 */
1411 cmd = host->curr.cmd;
1412 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1413 MCI_CMDTIMEOUT | MCI_PROGDONE |
1414 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1415 msmsdcc_do_cmdirq(host, status);
1416 }
1417
1418 if (data) {
1419 /* Check for data errors */
1420 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1421 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1422 msmsdcc_data_err(host, data, status);
1423 host->curr.data_xfered = 0;
1424 if (host->dma.sg && host->is_dma_mode)
1425 msm_dmov_stop_cmd(host->dma.channel,
1426 &host->dma.hdr, 0);
1427 else if (host->sps.sg && host->is_sps_mode) {
1428 /* Stop current SPS transfer */
1429 msmsdcc_sps_exit_curr_xfer(host);
1430 }
1431 else {
1432 msmsdcc_reset_and_restore(host);
1433 if (host->curr.data)
1434 msmsdcc_stop_data(host);
1435 if (!data->stop)
1436 timer |=
1437 msmsdcc_request_end(host,
1438 data->mrq);
1439 else {
1440 msmsdcc_start_command(host,
1441 data->stop,
1442 0);
1443 timer = 1;
1444 }
1445 }
1446 }
1447
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301448 /* Check for prog done */
1449 if (host->curr.wait_for_auto_prog_done &&
1450 (status & MCI_PROGDONE))
1451 host->curr.got_auto_prog_done = 1;
1452
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001453 /* Check for data done */
1454 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1455 host->curr.got_dataend = 1;
1456
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301457 if (host->curr.got_dataend &&
1458 (!host->curr.wait_for_auto_prog_done ||
1459 (host->curr.wait_for_auto_prog_done &&
1460 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001461 /*
1462 * If DMA is still in progress, we complete
1463 * via the completion handler
1464 */
1465 if (!host->dma.busy && !host->sps.busy) {
1466 /*
1467 * There appears to be an issue in the
1468 * controller where if you request a
1469 * small block transfer (< fifo size),
1470 * you may get your DATAEND/DATABLKEND
1471 * irq without the PIO data irq.
1472 *
1473 * Check to see if theres still data
1474 * to be read, and simulate a PIO irq.
1475 */
1476 if (data->flags & MMC_DATA_READ)
1477 msmsdcc_wait_for_rxdata(host,
1478 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001479 if (!data->error) {
1480 host->curr.data_xfered =
1481 host->curr.xfer_size;
1482 host->curr.xfer_remain -=
1483 host->curr.xfer_size;
1484 }
1485
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001486 if (!host->dummy_52_needed) {
1487 msmsdcc_stop_data(host);
1488 if (!data->stop) {
1489 msmsdcc_request_end(
1490 host,
1491 data->mrq);
1492 } else {
1493 msmsdcc_start_command(
1494 host,
1495 data->stop, 0);
1496 timer = 1;
1497 }
1498 } else {
1499 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001500 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001501 &dummy52cmd,
1502 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001503 }
1504 }
1505 }
1506 }
1507
San Mehat9d2bd732009-09-22 16:44:22 -07001508 ret = 1;
1509 } while (status);
1510
1511 spin_unlock(&host->lock);
1512
San Mehat9d2bd732009-09-22 16:44:22 -07001513 return IRQ_RETVAL(ret);
1514}
1515
1516static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001517msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1518{
1519 if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
1520 /* Queue/read data, daisy-chain command when data starts */
1521 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
1522 } else {
1523 msmsdcc_start_command(host, mrq->cmd, 0);
1524 }
1525}
1526
1527static void
San Mehat9d2bd732009-09-22 16:44:22 -07001528msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1529{
1530 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001531 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001532
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001533 /*
1534 * Get the SDIO AL client out of LPM.
1535 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001536 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001537 if (host->plat->is_sdio_al_client)
1538 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001539
1540 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001541 WARN(host->curr.mrq, "Request in progress\n");
1542 WARN(!host->pwr, "SDCC power is turned off\n");
1543 WARN(!host->clks_on, "SDCC clocks are turned off\n");
1544 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
San Mehat9d2bd732009-09-22 16:44:22 -07001545
1546 if (host->eject) {
1547 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1548 mrq->cmd->error = 0;
1549 mrq->data->bytes_xfered = mrq->data->blksz *
1550 mrq->data->blocks;
1551 } else
1552 mrq->cmd->error = -ENOMEDIUM;
1553
1554 spin_unlock_irqrestore(&host->lock, flags);
1555 mmc_request_done(mmc, mrq);
1556 return;
1557 }
1558
1559 host->curr.mrq = mrq;
1560
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301561 if (mrq->data && mrq->data->flags == MMC_DATA_WRITE) {
1562 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
1563 mrq->cmd->opcode == 54) {
1564 if (!host->plat->sdcc_v4_sup)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001565 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301566 else
1567 /*
1568 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
1569 * write operations using CMD53 and CMD54.
1570 * Setting this bit with CMD53 would
1571 * automatically triggers PROG_DONE interrupt
1572 * without the need of sending dummy CMD52.
1573 */
1574 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001575 }
San Mehat9d2bd732009-09-22 16:44:22 -07001576 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301577
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001578 msmsdcc_request_start(host, mrq);
San Mehat9d2bd732009-09-22 16:44:22 -07001579 spin_unlock_irqrestore(&host->lock, flags);
1580}
1581
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001582static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1583 int min_uV, int max_uV)
1584{
1585 int rc = 0;
1586
1587 if (vreg->set_voltage_sup) {
1588 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1589 if (rc) {
1590 pr_err("%s: regulator_set_voltage(%s) failed."
1591 " min_uV=%d, max_uV=%d, rc=%d\n",
1592 __func__, vreg->name, min_uV, max_uV, rc);
1593 }
1594 }
1595
1596 return rc;
1597}
1598
1599static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1600 int uA_load)
1601{
1602 int rc = 0;
1603
1604 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1605 if (rc < 0)
1606 pr_err("%s: regulator_set_optimum_mode(reg=%s, uA_load=%d)"
1607 " failed. rc=%d\n", __func__, vreg->name,
1608 uA_load, rc);
1609 else
1610 /* regulator_set_optimum_mode() can return non zero value
1611 * even for success case.
1612 */
1613 rc = 0;
1614
1615 return rc;
1616}
1617
1618static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1619 struct device *dev)
1620{
1621 int rc = 0;
1622
1623 /* check if regulator is already initialized? */
1624 if (vreg->reg)
1625 goto out;
1626
1627 /* Get the regulator handle */
1628 vreg->reg = regulator_get(dev, vreg->name);
1629 if (IS_ERR(vreg->reg)) {
1630 rc = PTR_ERR(vreg->reg);
1631 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
1632 __func__, vreg->name, rc);
1633 }
1634out:
1635 return rc;
1636}
1637
1638static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
1639{
1640 if (vreg->reg)
1641 regulator_put(vreg->reg);
1642}
1643
1644/* This init function should be called only once for each SDCC slot */
1645static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
1646{
1647 int rc = 0;
1648 struct msm_mmc_slot_reg_data *curr_slot;
1649 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1650 struct device *dev = mmc_dev(host->mmc);
1651
1652 curr_slot = host->plat->vreg_data;
1653 if (!curr_slot)
1654 goto out;
1655
1656 curr_vdd_reg = curr_slot->vdd_data;
1657 curr_vccq_reg = curr_slot->vccq_data;
1658 curr_vddp_reg = curr_slot->vddp_data;
1659
1660 if (is_init) {
1661 /*
1662 * Get the regulator handle from voltage regulator framework
1663 * and then try to set the voltage level for the regulator
1664 */
1665 if (curr_vdd_reg) {
1666 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
1667 if (rc)
1668 goto out;
1669 }
1670 if (curr_vccq_reg) {
1671 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
1672 if (rc)
1673 goto vdd_reg_deinit;
1674 }
1675 if (curr_vddp_reg) {
1676 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
1677 if (rc)
1678 goto vccq_reg_deinit;
1679 }
1680 goto out;
1681 } else {
1682 /* Deregister all regulators from regulator framework */
1683 goto vddp_reg_deinit;
1684 }
1685vddp_reg_deinit:
1686 if (curr_vddp_reg)
1687 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
1688vccq_reg_deinit:
1689 if (curr_vccq_reg)
1690 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
1691vdd_reg_deinit:
1692 if (curr_vdd_reg)
1693 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
1694out:
1695 return rc;
1696}
1697
1698static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
1699{
1700 int rc = 0;
1701
Subhash Jadavanicc922692011-08-01 23:05:01 +05301702 /* Put regulator in HPM (high power mode) */
1703 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
1704 if (rc < 0)
1705 goto out;
1706
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001707 if (!vreg->is_enabled) {
1708 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301709 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
1710 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001711 if (rc)
1712 goto out;
1713
1714 rc = regulator_enable(vreg->reg);
1715 if (rc) {
1716 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
1717 __func__, vreg->name, rc);
1718 goto out;
1719 }
1720 vreg->is_enabled = true;
1721 }
1722
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001723out:
1724 return rc;
1725}
1726
1727static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
1728{
1729 int rc = 0;
1730
1731 /* Never disable regulator marked as always_on */
1732 if (vreg->is_enabled && !vreg->always_on) {
1733 rc = regulator_disable(vreg->reg);
1734 if (rc) {
1735 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
1736 __func__, vreg->name, rc);
1737 goto out;
1738 }
1739 vreg->is_enabled = false;
1740
1741 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
1742 if (rc < 0)
1743 goto out;
1744
1745 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301746 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001747 if (rc)
1748 goto out;
1749 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
1750 /* Put always_on regulator in LPM (low power mode) */
1751 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
1752 if (rc < 0)
1753 goto out;
1754 }
1755out:
1756 return rc;
1757}
1758
1759static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
1760{
1761 int rc = 0, i;
1762 struct msm_mmc_slot_reg_data *curr_slot;
1763 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1764 struct msm_mmc_reg_data *vreg_table[3];
1765
1766 curr_slot = host->plat->vreg_data;
1767 if (!curr_slot)
1768 goto out;
1769
1770 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
1771 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
1772 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
1773
1774 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
1775 if (vreg_table[i]) {
1776 if (enable)
1777 rc = msmsdcc_vreg_enable(vreg_table[i]);
1778 else
1779 rc = msmsdcc_vreg_disable(vreg_table[i]);
1780 if (rc)
1781 goto out;
1782 }
1783 }
1784out:
1785 return rc;
1786}
1787
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301788static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001789{
1790 int rc = 0;
1791
1792 if (host->plat->vreg_data) {
1793 struct msm_mmc_reg_data *vddp_reg =
1794 host->plat->vreg_data->vddp_data;
1795
1796 if (vddp_reg && vddp_reg->is_enabled)
1797 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
1798 }
1799
1800 return rc;
1801}
1802
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301803static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
1804{
1805 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1806 int rc = 0;
1807
1808 if (curr_slot && curr_slot->vddp_data) {
1809 rc = msmsdcc_set_vddp_level(host,
1810 curr_slot->vddp_data->low_vol_level);
1811
1812 if (rc)
1813 pr_err("%s: %s: failed to change vddp level to %d",
1814 mmc_hostname(host->mmc), __func__,
1815 curr_slot->vddp_data->low_vol_level);
1816 }
1817
1818 return rc;
1819}
1820
1821static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
1822{
1823 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1824 int rc = 0;
1825
1826 if (curr_slot && curr_slot->vddp_data) {
1827 rc = msmsdcc_set_vddp_level(host,
1828 curr_slot->vddp_data->high_vol_level);
1829
1830 if (rc)
1831 pr_err("%s: %s: failed to change vddp level to %d",
1832 mmc_hostname(host->mmc), __func__,
1833 curr_slot->vddp_data->high_vol_level);
1834 }
1835
1836 return rc;
1837}
1838
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001839static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
1840{
1841 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
1842 return 1;
1843 return 0;
1844}
1845
1846static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
1847{
1848 if (enable) {
1849 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1850 clk_enable(host->dfab_pclk);
1851 if (!IS_ERR(host->pclk))
1852 clk_enable(host->pclk);
1853 clk_enable(host->clk);
1854 } else {
1855 clk_disable(host->clk);
1856 if (!IS_ERR(host->pclk))
1857 clk_disable(host->pclk);
1858 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1859 clk_disable(host->dfab_pclk);
1860 }
1861}
1862
1863static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
1864 unsigned int req_clk)
1865{
1866 unsigned int sel_clk = -1;
1867
1868 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
1869 unsigned char cnt;
1870
1871 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
1872 if (host->plat->sup_clk_table[cnt] > req_clk)
1873 break;
1874 else if (host->plat->sup_clk_table[cnt] == req_clk) {
1875 sel_clk = host->plat->sup_clk_table[cnt];
1876 break;
1877 } else
1878 sel_clk = host->plat->sup_clk_table[cnt];
1879 }
1880 } else {
1881 if ((req_clk < host->plat->msmsdcc_fmax) &&
1882 (req_clk > host->plat->msmsdcc_fmid))
1883 sel_clk = host->plat->msmsdcc_fmid;
1884 else
1885 sel_clk = req_clk;
1886 }
1887
1888 return sel_clk;
1889}
1890
1891static inline unsigned int msmsdcc_get_min_sup_clk_rate(
1892 struct msmsdcc_host *host)
1893{
1894 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
1895 return host->plat->sup_clk_table[0];
1896 else
1897 return host->plat->msmsdcc_fmin;
1898}
1899
1900static inline unsigned int msmsdcc_get_max_sup_clk_rate(
1901 struct msmsdcc_host *host)
1902{
1903 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
1904 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
1905 else
1906 return host->plat->msmsdcc_fmax;
1907}
1908
1909static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05301910{
1911 struct msm_mmc_gpio_data *curr;
1912 int i, rc = 0;
1913
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001914 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301915 for (i = 0; i < curr->size; i++) {
1916 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001917 if (curr->gpio[i].is_always_on &&
1918 curr->gpio[i].is_enabled)
1919 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301920 rc = gpio_request(curr->gpio[i].no,
1921 curr->gpio[i].name);
1922 if (rc) {
1923 pr_err("%s: gpio_request(%d, %s) failed %d\n",
1924 mmc_hostname(host->mmc),
1925 curr->gpio[i].no,
1926 curr->gpio[i].name, rc);
1927 goto free_gpios;
1928 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001929 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301930 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001931 if (curr->gpio[i].is_always_on)
1932 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301933 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001934 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301935 }
1936 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001937 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301938
1939free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001940 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05301941 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001942 curr->gpio[i].is_enabled = false;
1943 }
1944out:
1945 return rc;
1946}
1947
1948static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
1949{
1950 struct msm_mmc_pad_data *curr;
1951 int i;
1952
1953 curr = host->plat->pin_data->pad_data;
1954 for (i = 0; i < curr->drv->size; i++) {
1955 if (enable)
1956 msm_tlmm_set_hdrive(curr->drv->on[i].no,
1957 curr->drv->on[i].val);
1958 else
1959 msm_tlmm_set_hdrive(curr->drv->off[i].no,
1960 curr->drv->off[i].val);
1961 }
1962
1963 for (i = 0; i < curr->pull->size; i++) {
1964 if (enable)
1965 msm_tlmm_set_hdrive(curr->pull->on[i].no,
1966 curr->pull->on[i].val);
1967 else
1968 msm_tlmm_set_hdrive(curr->pull->off[i].no,
1969 curr->pull->off[i].val);
1970 }
1971
1972 return 0;
1973}
1974
1975static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
1976{
1977 int rc = 0;
1978
1979 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
1980 return 0;
1981
1982 if (host->plat->pin_data->is_gpio)
1983 rc = msmsdcc_setup_gpio(host, enable);
1984 else
1985 rc = msmsdcc_setup_pad(host, enable);
1986
1987 if (!rc)
1988 host->plat->pin_data->cfg_sts = enable;
1989
1990 return rc;
1991}
1992
1993static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
1994{
1995 unsigned int wakeup_irq;
1996
1997 wakeup_irq = (host->plat->sdiowakeup_irq) ?
1998 host->plat->sdiowakeup_irq :
1999 host->core_irqres->start;
2000
2001 if (!host->irq_wake_enabled) {
2002 enable_irq_wake(wakeup_irq);
2003 host->irq_wake_enabled = true;
2004 }
2005}
2006
2007static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2008{
2009 unsigned int wakeup_irq;
2010
2011 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2012 host->plat->sdiowakeup_irq :
2013 host->core_irqres->start;
2014
2015 if (host->irq_wake_enabled) {
2016 disable_irq_wake(wakeup_irq);
2017 host->irq_wake_enabled = false;
2018 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302019}
2020
San Mehat9d2bd732009-09-22 16:44:22 -07002021static void
2022msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2023{
2024 struct msmsdcc_host *host = mmc_priv(mmc);
2025 u32 clk = 0, pwr = 0;
2026 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002027 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002028 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002029
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002030 DBG(host, "ios->clock = %u\n", ios->clock);
Sahitya Tummala7a892482011-01-18 11:22:49 +05302031
San Mehat9d2bd732009-09-22 16:44:22 -07002032 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002033 spin_lock_irqsave(&host->lock, flags);
2034 if (!host->clks_on) {
2035 msmsdcc_setup_clocks(host, true);
2036 host->clks_on = 1;
2037 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2038 if (!host->plat->sdiowakeup_irq) {
2039 writel_relaxed(host->mci_irqenable,
2040 host->base + MMCIMASK0);
2041 mb();
2042 if (host->plat->cfg_mpm_sdiowakeup &&
2043 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2044 host->plat->cfg_mpm_sdiowakeup(
2045 mmc_dev(mmc), SDC_DAT1_DISWAKE);
2046 msmsdcc_disable_irq_wake(host);
2047 } else if (!(mmc->pm_flags &
2048 MMC_PM_WAKE_SDIO_IRQ)) {
2049 writel_relaxed(host->mci_irqenable,
2050 host->base + MMCIMASK0);
2051 }
2052 }
San Mehat9d2bd732009-09-22 16:44:22 -07002053 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002054 spin_unlock_irqrestore(&host->lock, flags);
2055
2056 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2057 /*
2058 * For DDR50 mode, controller needs clock rate to be
2059 * double than what is required on the SD card CLK pin.
2060 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302061 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002062 /*
2063 * Make sure that we don't double the clock if
2064 * doubled clock rate is already set
2065 */
2066 if (!host->ddr_doubled_clk_rate ||
2067 (host->ddr_doubled_clk_rate &&
2068 (host->ddr_doubled_clk_rate != ios->clock))) {
2069 host->ddr_doubled_clk_rate =
2070 msmsdcc_get_sup_clk_rate(
2071 host, (ios->clock * 2));
2072 clock = host->ddr_doubled_clk_rate;
2073 }
2074 } else {
2075 host->ddr_doubled_clk_rate = 0;
2076 }
2077
2078 if (clock != host->clk_rate) {
2079 rc = clk_set_rate(host->clk, clock);
2080 if (rc < 0)
2081 pr_debug("%s: failed to set clk rate %u\n",
2082 mmc_hostname(mmc), clock);
2083 host->clk_rate = clock;
2084 }
2085 /*
2086 * give atleast 2 MCLK cycles delay for clocks
2087 * and SDCC core to stabilize
2088 */
2089 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002090 clk |= MCI_CLK_ENABLE;
2091 }
2092
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002093 if (ios->bus_width == MMC_BUS_WIDTH_8)
2094 clk |= MCI_CLK_WIDEBUS_8;
2095 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2096 clk |= MCI_CLK_WIDEBUS_4;
2097 else
2098 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002099
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002100 if (msmsdcc_is_pwrsave(host))
2101 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002102
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002103 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002104
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002105 host->tuning_needed = 0;
2106 /*
2107 * Select the controller timing mode according
2108 * to current bus speed mode
2109 */
2110 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2111 (ios->timing == MMC_TIMING_UHS_SDR50)) {
2112 clk |= (4 << 14);
2113 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302114 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002115 clk |= (3 << 14);
2116 } else {
2117 clk |= (2 << 14); /* feedback clock */
2118 }
2119
2120 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2121 clk |= (2 << 23);
2122
2123 if (host->io_pad_pwr_switch)
2124 clk |= IO_PAD_PWR_SWITCH;
2125
2126 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
San Mehat9d2bd732009-09-22 16:44:22 -07002127 pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002128 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2129 pwr |= msmsdcc_setup_vreg(host, !!ios->vdd);
San Mehat9d2bd732009-09-22 16:44:22 -07002130
2131 switch (ios->power_mode) {
2132 case MMC_POWER_OFF:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002133 htc_pwrsink_set(PWRSINK_SDCARD, 0);
2134 if (!host->sdcc_irq_disabled) {
2135 if (host->plat->cfg_mpm_sdiowakeup)
2136 host->plat->cfg_mpm_sdiowakeup(
2137 mmc_dev(mmc), SDC_DAT1_DISABLE);
2138 disable_irq(host->core_irqres->start);
2139 host->sdcc_irq_disabled = 1;
2140 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302141 /*
2142 * As VDD pad rail is always on, set low voltage for VDD
2143 * pad rail when slot is unused (when card is not present
2144 * or during system suspend).
2145 */
2146 msmsdcc_set_vddp_low_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002147 msmsdcc_setup_pins(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002148 break;
2149 case MMC_POWER_UP:
2150 pwr |= MCI_PWR_UP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002151 if (host->sdcc_irq_disabled) {
2152 if (host->plat->cfg_mpm_sdiowakeup)
2153 host->plat->cfg_mpm_sdiowakeup(
2154 mmc_dev(mmc), SDC_DAT1_ENABLE);
2155 enable_irq(host->core_irqres->start);
2156 host->sdcc_irq_disabled = 0;
2157 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302158 msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002159 msmsdcc_setup_pins(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07002160 break;
2161 case MMC_POWER_ON:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002162 htc_pwrsink_set(PWRSINK_SDCARD, 100);
San Mehat9d2bd732009-09-22 16:44:22 -07002163 pwr |= MCI_PWR_ON;
2164 break;
2165 }
2166
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002167 spin_lock_irqsave(&host->lock, flags);
2168 if (!host->clks_on) {
2169 /* force the clocks to be on */
2170 msmsdcc_setup_clocks(host, true);
2171 /*
2172 * give atleast 2 MCLK cycles delay for clocks
2173 * and SDCC core to stabilize
2174 */
2175 msmsdcc_delay(host);
2176 }
2177 writel_relaxed(clk, host->base + MMCICLOCK);
2178 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002179
2180 if (host->pwr != pwr) {
2181 host->pwr = pwr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002182 writel_relaxed(pwr, host->base + MMCIPOWER);
2183 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07002184 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002185 if (!host->clks_on) {
2186 /* force the clocks to be off */
2187 msmsdcc_setup_clocks(host, false);
2188 /*
2189 * give atleast 2 MCLK cycles delay for clocks
2190 * and SDCC core to stabilize
2191 */
2192 msmsdcc_delay(host);
2193 }
2194
2195 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
2196 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2197 if (!host->plat->sdiowakeup_irq) {
2198 writel_relaxed(MCI_SDIOINTMASK,
2199 host->base + MMCIMASK0);
2200 mb();
2201 if (host->plat->cfg_mpm_sdiowakeup &&
2202 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2203 host->plat->cfg_mpm_sdiowakeup(
2204 mmc_dev(mmc), SDC_DAT1_ENWAKE);
2205 msmsdcc_enable_irq_wake(host);
2206 } else if (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2207 writel_relaxed(0, host->base + MMCIMASK0);
2208 } else {
2209 writel_relaxed(MCI_SDIOINTMASK,
2210 host->base + MMCIMASK0);
2211 }
2212 msmsdcc_delay(host);
2213 }
2214 msmsdcc_setup_clocks(host, false);
2215 host->clks_on = 0;
2216 }
San Mehat4adbbcc2009-11-08 13:00:37 -08002217 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002218}
2219
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002220int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2221{
2222 struct msmsdcc_host *host = mmc_priv(mmc);
2223 u32 clk;
2224
2225 clk = readl_relaxed(host->base + MMCICLOCK);
2226 pr_debug("Changing to pwr_save=%d", pwrsave);
2227 if (pwrsave && msmsdcc_is_pwrsave(host))
2228 clk |= MCI_CLK_PWRSAVE;
2229 else
2230 clk &= ~MCI_CLK_PWRSAVE;
2231 writel_relaxed(clk, host->base + MMCICLOCK);
2232 mb();
2233
2234 return 0;
2235}
2236
2237static int msmsdcc_get_ro(struct mmc_host *mmc)
2238{
2239 int status = -ENOSYS;
2240 struct msmsdcc_host *host = mmc_priv(mmc);
2241
2242 if (host->plat->wpswitch) {
2243 status = host->plat->wpswitch(mmc_dev(mmc));
2244 } else if (host->plat->wpswitch_gpio) {
2245 status = gpio_request(host->plat->wpswitch_gpio,
2246 "SD_WP_Switch");
2247 if (status) {
2248 pr_err("%s: %s: Failed to request GPIO %d\n",
2249 mmc_hostname(mmc), __func__,
2250 host->plat->wpswitch_gpio);
2251 } else {
2252 status = gpio_direction_input(
2253 host->plat->wpswitch_gpio);
2254 if (!status) {
2255 /*
2256 * Wait for atleast 300ms as debounce
2257 * time for GPIO input to stabilize.
2258 */
2259 msleep(300);
2260 status = gpio_get_value_cansleep(
2261 host->plat->wpswitch_gpio);
2262 status ^= !host->plat->wpswitch_polarity;
2263 }
2264 gpio_free(host->plat->wpswitch_gpio);
2265 }
2266 }
2267
2268 if (status < 0)
2269 status = -ENOSYS;
2270 pr_debug("%s: Card read-only status %d\n", __func__, status);
2271
2272 return status;
2273}
2274
2275#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002276static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2277{
2278 struct msmsdcc_host *host = mmc_priv(mmc);
2279 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002280
2281 if (enable) {
2282 spin_lock_irqsave(&host->lock, flags);
2283 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
2284 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
2285 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2286 spin_unlock_irqrestore(&host->lock, flags);
2287 } else {
2288 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
2289 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
2290 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2291 }
2292 mb();
2293}
2294#endif /* CONFIG_MMC_MSM_SDIO_SUPPORT */
2295
2296#ifdef CONFIG_PM_RUNTIME
2297static int msmsdcc_enable(struct mmc_host *mmc)
2298{
Sahitya Tummala8605fca2011-08-22 15:39:19 +05302299 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002300 struct device *dev = mmc->parent;
2301
Sahitya Tummala8605fca2011-08-22 15:39:19 +05302302 if (pm_runtime_suspended(dev))
2303 rc = pm_runtime_get_sync(dev);
2304 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002305 pm_runtime_get_noresume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002306
Sahitya Tummala8605fca2011-08-22 15:39:19 +05302307 if (rc < 0)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002308 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2309 __func__, rc);
Sahitya Tummala8605fca2011-08-22 15:39:19 +05302310 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002311}
2312
2313static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2314{
2315 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302316 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002317
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302318 if (host->plat->disable_runtime_pm)
2319 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002320 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO)
2321 return -ENOTSUPP;
2322
2323 rc = pm_runtime_put_sync(mmc->parent);
2324
2325 if (rc < 0)
2326 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2327 __func__, rc);
2328 return rc;
2329}
2330#else
2331#define msmsdcc_enable NULL
2332#define msmsdcc_disable NULL
2333#endif
2334
2335static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2336 struct mmc_ios *ios)
2337{
2338 struct msmsdcc_host *host = mmc_priv(mmc);
2339 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302340 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002341
2342 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2343 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302344 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002345 goto out;
2346 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2347 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302348 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002349 goto out;
2350 }
San Mehat9d2bd732009-09-22 16:44:22 -07002351
2352 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002353 /*
2354 * If we are here means voltage switch from high voltage to
2355 * low voltage is required
2356 */
2357
2358 /*
2359 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2360 * register until they become all zeros.
2361 */
2362 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302363 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002364 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2365 mmc_hostname(mmc), __func__);
2366 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002367 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002368
2369 /* Stop SD CLK output. */
2370 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2371 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2372
San Mehat9d2bd732009-09-22 16:44:22 -07002373 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002374
2375 /*
2376 * Switch VDDPX from high voltage to low voltage
2377 * to change the VDD of the SD IO pads.
2378 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302379 rc = msmsdcc_set_vddp_low_vol(host);
2380 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002381 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002382
2383 spin_lock_irqsave(&host->lock, flags);
2384 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2385 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
2386 host->io_pad_pwr_switch = 1;
2387 spin_unlock_irqrestore(&host->lock, flags);
2388
2389 /* Wait 5 ms for the voltage regulater in the card to become stable. */
2390 usleep_range(5000, 5500);
2391
2392 spin_lock_irqsave(&host->lock, flags);
2393 /* Start SD CLK output. */
2394 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2395 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2396 spin_unlock_irqrestore(&host->lock, flags);
2397
2398 /*
2399 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
2400 * don't become all ones within 1 ms then a Voltage Switch
2401 * sequence has failed and a power cycle to the card is required.
2402 * Otherwise Voltage Switch sequence is completed successfully.
2403 */
2404 usleep_range(1000, 1500);
2405
2406 spin_lock_irqsave(&host->lock, flags);
2407 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
2408 != (0xF << 1)) {
2409 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
2410 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302411 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002412 goto out_unlock;
2413 }
2414
2415out_unlock:
2416 spin_unlock_irqrestore(&host->lock, flags);
2417out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302418 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002419}
2420
2421static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2422 u8 phase);
2423/* Initialize the DLL (Programmable Delay Line ) */
2424static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
2425{
2426 int rc = 0;
2427 u32 wait_timeout;
2428
2429 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
2430 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2431 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2432
2433 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
2434 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2435 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2436
2437 msmsdcc_delay(host);
2438
2439 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
2440 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2441 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2442
2443 /* Initialize the phase to 0 */
2444 rc = msmsdcc_config_cm_sdc4_dll_phase(host, 0);
2445 if (rc)
2446 goto out;
2447
2448 wait_timeout = 1000;
2449 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
2450 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
2451 /* max. wait for 1 sec for LOCK bit to be set */
2452 if (--wait_timeout == 0) {
2453 pr_err("%s: %s: DLL failed to lock at phase: %d",
2454 mmc_hostname(host->mmc), __func__, 0);
2455 rc = -1;
2456 goto out;
2457 }
2458 /* wait for 1ms */
2459 usleep_range(1000, 1500);
2460 }
2461out:
2462 return rc;
2463}
2464
2465/*
2466 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
2467 * calibration sequence. This function should be called before
2468 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
2469 * commands (CMD17/CMD18).
2470 */
2471static void msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
2472{
2473 /* Set CDR_EN bit to 1. */
2474 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) |
2475 MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2476
2477 /* Set CDR_EXT_EN bit to 0. */
2478 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2479 & ~MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2480
2481 /* Set CK_OUT_EN bit to 0. */
2482 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2483 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2484
2485 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2486 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)
2487 ;
2488
2489 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2490 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2491 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2492
2493 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register is 1. */
2494 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN))
2495 ;
2496}
2497
2498static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2499 u8 phase)
2500{
2501 int rc = 0;
2502 u32 mclk_freq = 0;
2503 u32 wait_timeout;
2504
2505 /* Set CDR_EN bit to 0. */
2506 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2507 & ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2508
2509 /* Set CDR_EXT_EN bit to 1. */
2510 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2511 | MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2512
2513 /* Program the MCLK value to MCLK_FREQ bit field */
2514 if (host->clk_rate <= 112000000)
2515 mclk_freq = 0;
2516 else if (host->clk_rate <= 125000000)
2517 mclk_freq = 1;
2518 else if (host->clk_rate <= 137000000)
2519 mclk_freq = 2;
2520 else if (host->clk_rate <= 150000000)
2521 mclk_freq = 3;
2522 else if (host->clk_rate <= 162000000)
2523 mclk_freq = 4;
2524 else if (host->clk_rate <= 175000000)
2525 mclk_freq = 5;
2526 else if (host->clk_rate <= 187000000)
2527 mclk_freq = 6;
2528 else if (host->clk_rate <= 200000000)
2529 mclk_freq = 7;
2530
2531 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2532 & ~(7 << 24)) | (mclk_freq << 24)),
2533 host->base + MCI_DLL_CONFIG);
2534
2535 /* Set CK_OUT_EN bit to 0. */
2536 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2537 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2538
2539 /* Set DLL_EN bit to 1. */
2540 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2541 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
2542
2543 wait_timeout = 1000;
2544 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2545 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN) {
2546 /* max. wait for 1 sec for LOCK bit for be set */
2547 if (--wait_timeout == 0) {
2548 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 0",
2549 mmc_hostname(host->mmc), __func__, phase);
2550 rc = -1;
2551 goto out;
2552 }
2553 /* wait for 1ms */
2554 usleep_range(1000, 1500);
2555 }
2556
2557 /*
2558 * Write the selected DLL clock output phase (0 ... 15)
2559 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
2560 */
2561 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2562 & ~(0xF << 20)) | (phase << 20)),
2563 host->base + MCI_DLL_CONFIG);
2564
2565 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2566 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2567 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2568
2569 wait_timeout = 1000;
2570 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
2571 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)) {
2572 /* max. wait for 1 sec for LOCK bit for be set */
2573 if (--wait_timeout == 0) {
2574 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 1",
2575 mmc_hostname(host->mmc), __func__, phase);
2576 rc = -1;
2577 goto out;
2578 }
2579 /* wait for 1ms */
2580 usleep_range(1000, 1500);
2581 }
2582out:
2583 return rc;
2584}
2585
2586static int msmsdcc_execute_tuning(struct mmc_host *mmc)
2587{
2588 struct msmsdcc_host *host = mmc_priv(mmc);
2589 u8 phase;
2590 u8 *data_buf;
2591 u8 tuned_phases[16], tuned_phase_cnt = 0;
2592 int rc = 0;
2593
2594 /* Tuning is only required for SDR50 & SDR104 modes */
2595 if (!host->tuning_needed) {
2596 rc = 0;
2597 goto out;
2598 }
2599
2600 host->cmd19_tuning_in_progress = 1;
2601 /*
2602 * Make sure that clock is always enabled when DLL
2603 * tuning is in progress. Keeping PWRSAVE ON may
2604 * turn off the clock. So let's disable the PWRSAVE
2605 * here and re-enable it once tuning is completed.
2606 */
2607 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2608 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2609 /* first of all reset the tuning block */
2610 rc = msmsdcc_init_cm_sdc4_dll(host);
2611 if (rc)
2612 goto out;
2613
2614 data_buf = kmalloc(64, GFP_KERNEL);
2615 if (!data_buf) {
2616 rc = -ENOMEM;
2617 goto out;
2618 }
2619
2620 phase = 0;
2621 do {
2622 struct mmc_command cmd = {0};
2623 struct mmc_data data = {0};
2624 struct mmc_request mrq = {
2625 .cmd = &cmd,
2626 .data = &data
2627 };
2628 struct scatterlist sg;
2629
2630 /* set the phase in delay line hw block */
2631 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2632 if (rc)
2633 goto kfree;
2634
2635 cmd.opcode = MMC_SEND_TUNING_BLOCK;
2636 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
2637
2638 data.blksz = 64;
2639 data.blocks = 1;
2640 data.flags = MMC_DATA_READ;
2641 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
2642
2643 data.sg = &sg;
2644 data.sg_len = 1;
2645 sg_init_one(&sg, data_buf, 64);
2646 memset(data_buf, 0, 64);
2647 mmc_wait_for_req(mmc, &mrq);
2648
2649 if (!cmd.error && !data.error &&
2650 !memcmp(data_buf, cmd19_tuning_block, 64)) {
2651 /* tuning is successful with this tuning point */
2652 tuned_phases[tuned_phase_cnt++] = phase;
2653 }
2654 } while (++phase < 16);
2655
2656 kfree(data_buf);
2657
2658 if (tuned_phase_cnt) {
2659 tuned_phase_cnt--;
2660 tuned_phase_cnt = (tuned_phase_cnt * 3) / 4;
2661 phase = tuned_phases[tuned_phase_cnt];
2662 /*
2663 * Finally set the selected phase in delay
2664 * line hw block.
2665 */
2666 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2667 if (rc)
2668 goto out;
2669 } else {
2670 /* tuning failed */
2671 rc = -EAGAIN;
2672 pr_err("%s: %s: no tuning point found",
2673 mmc_hostname(mmc), __func__);
2674 }
2675 goto out;
2676
2677kfree:
2678 kfree(data_buf);
2679out:
2680 /* re-enable PWESAVE */
2681 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2682 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2683 host->cmd19_tuning_in_progress = 0;
2684 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07002685}
2686
2687static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002688 .enable = msmsdcc_enable,
2689 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07002690 .request = msmsdcc_request,
2691 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002692 .get_ro = msmsdcc_get_ro,
2693#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002694 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002695#endif
2696 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
2697 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07002698};
2699
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002700static unsigned int
2701msmsdcc_slot_status(struct msmsdcc_host *host)
2702{
2703 int status;
2704 unsigned int gpio_no = host->plat->status_gpio;
2705
2706 status = gpio_request(gpio_no, "SD_HW_Detect");
2707 if (status) {
2708 pr_err("%s: %s: Failed to request GPIO %d\n",
2709 mmc_hostname(host->mmc), __func__, gpio_no);
2710 } else {
2711 status = gpio_direction_input(gpio_no);
2712 if (!status)
2713 status = !gpio_get_value_cansleep(gpio_no);
2714 gpio_free(gpio_no);
2715 }
2716 return status;
2717}
2718
San Mehat9d2bd732009-09-22 16:44:22 -07002719static void
2720msmsdcc_check_status(unsigned long data)
2721{
2722 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
2723 unsigned int status;
2724
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002725 if (host->plat->status || host->plat->status_gpio) {
2726 if (host->plat->status)
2727 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07002728 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002729 status = msmsdcc_slot_status(host);
2730
2731 host->eject = !status;
2732 if (status ^ host->oldstat) {
2733 pr_info("%s: Slot status change detected (%d -> %d)\n",
2734 mmc_hostname(host->mmc), host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07002735 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002736 }
2737 host->oldstat = status;
2738 } else {
2739 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07002740 }
San Mehat9d2bd732009-09-22 16:44:22 -07002741}
2742
2743static irqreturn_t
2744msmsdcc_platform_status_irq(int irq, void *dev_id)
2745{
2746 struct msmsdcc_host *host = dev_id;
2747
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002748 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07002749 msmsdcc_check_status((unsigned long) host);
2750 return IRQ_HANDLED;
2751}
2752
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002753static irqreturn_t
2754msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
2755{
2756 struct msmsdcc_host *host = dev_id;
2757
2758 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
2759 spin_lock(&host->lock);
2760 if (!host->sdio_irq_disabled) {
2761 disable_irq_nosync(irq);
2762 if (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2763 wake_lock(&host->sdio_wlock);
2764 msmsdcc_disable_irq_wake(host);
2765 }
2766 host->sdio_irq_disabled = 1;
2767 }
2768 if (host->plat->is_sdio_al_client) {
2769 if (!host->clks_on) {
2770 msmsdcc_setup_clocks(host, true);
2771 host->clks_on = 1;
2772 }
2773 if (host->sdcc_irq_disabled) {
2774 writel_relaxed(host->mci_irqenable,
2775 host->base + MMCIMASK0);
2776 mb();
2777 enable_irq(host->core_irqres->start);
2778 host->sdcc_irq_disabled = 0;
2779 }
2780 wake_lock(&host->sdio_wlock);
2781 }
2782 spin_unlock(&host->lock);
2783
2784 return IRQ_HANDLED;
2785}
2786
San Mehat9d2bd732009-09-22 16:44:22 -07002787static void
2788msmsdcc_status_notify_cb(int card_present, void *dev_id)
2789{
2790 struct msmsdcc_host *host = dev_id;
2791
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002792 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07002793 card_present);
2794 msmsdcc_check_status((unsigned long) host);
2795}
2796
San Mehat9d2bd732009-09-22 16:44:22 -07002797static int
2798msmsdcc_init_dma(struct msmsdcc_host *host)
2799{
2800 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
2801 host->dma.host = host;
2802 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07002803 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07002804
2805 if (!host->dmares)
2806 return -ENODEV;
2807
2808 host->dma.nc = dma_alloc_coherent(NULL,
2809 sizeof(struct msmsdcc_nc_dmadata),
2810 &host->dma.nc_busaddr,
2811 GFP_KERNEL);
2812 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07002813 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07002814 return -ENOMEM;
2815 }
2816 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
2817 host->dma.cmd_busaddr = host->dma.nc_busaddr;
2818 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
2819 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
2820 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07002821 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07002822
2823 return 0;
2824}
2825
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002826#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
2827/**
2828 * Allocate and Connect a SDCC peripheral's SPS endpoint
2829 *
2830 * This function allocates endpoint context and
2831 * connect it with memory endpoint by calling
2832 * appropriate SPS driver APIs.
2833 *
2834 * Also registers a SPS callback function with
2835 * SPS driver
2836 *
2837 * This function should only be called once typically
2838 * during driver probe.
2839 *
2840 * @host - Pointer to sdcc host structure
2841 * @ep - Pointer to sps endpoint data structure
2842 * @is_produce - 1 means Producer endpoint
2843 * 0 means Consumer endpoint
2844 *
2845 * @return - 0 if successful else negative value.
2846 *
2847 */
2848static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
2849 struct msmsdcc_sps_ep_conn_data *ep,
2850 bool is_producer)
2851{
2852 int rc = 0;
2853 struct sps_pipe *sps_pipe_handle;
2854 struct sps_connect *sps_config = &ep->config;
2855 struct sps_register_event *sps_event = &ep->event;
2856
2857 /* Allocate endpoint context */
2858 sps_pipe_handle = sps_alloc_endpoint();
2859 if (!sps_pipe_handle) {
2860 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
2861 mmc_hostname(host->mmc), is_producer);
2862 rc = -ENOMEM;
2863 goto out;
2864 }
2865
2866 /* Get default connection configuration for an endpoint */
2867 rc = sps_get_config(sps_pipe_handle, sps_config);
2868 if (rc) {
2869 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
2870 " rc=%d", mmc_hostname(host->mmc),
2871 (u32)sps_pipe_handle, rc);
2872 goto get_config_err;
2873 }
2874
2875 /* Modify the default connection configuration */
2876 if (is_producer) {
2877 /*
2878 * For SDCC producer transfer, source should be
2879 * SDCC peripheral where as destination should
2880 * be system memory.
2881 */
2882 sps_config->source = host->sps.bam_handle;
2883 sps_config->destination = SPS_DEV_HANDLE_MEM;
2884 /* Producer pipe will handle this connection */
2885 sps_config->mode = SPS_MODE_SRC;
2886 sps_config->options =
2887 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
2888 } else {
2889 /*
2890 * For SDCC consumer transfer, source should be
2891 * system memory where as destination should
2892 * SDCC peripheral
2893 */
2894 sps_config->source = SPS_DEV_HANDLE_MEM;
2895 sps_config->destination = host->sps.bam_handle;
2896 sps_config->mode = SPS_MODE_DEST;
2897 sps_config->options =
2898 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
2899 }
2900
2901 /* Producer pipe index */
2902 sps_config->src_pipe_index = host->sps.src_pipe_index;
2903 /* Consumer pipe index */
2904 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
2905 /*
2906 * This event thresold value is only significant for BAM-to-BAM
2907 * transfer. It's ignored for BAM-to-System mode transfer.
2908 */
2909 sps_config->event_thresh = 0x10;
2910 /*
2911 * Max. no of scatter/gather buffers that can
2912 * be passed by block layer = 32 (NR_SG).
2913 * Each BAM descritor needs 64 bits (8 bytes).
2914 * One BAM descriptor is required per buffer transfer.
2915 * So we would require total 256 (32 * 8) bytes of descriptor FIFO.
2916 * But due to HW limitation we need to allocate atleast one extra
2917 * descriptor memory (256 bytes + 8 bytes). But in order to be
2918 * in power of 2, we are allocating 512 bytes of memory.
2919 */
2920 sps_config->desc.size = 512;
2921 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
2922 sps_config->desc.size,
2923 &sps_config->desc.phys_base,
2924 GFP_KERNEL);
2925
2926 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
2927
2928 /* Establish connection between peripheral and memory endpoint */
2929 rc = sps_connect(sps_pipe_handle, sps_config);
2930 if (rc) {
2931 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
2932 " rc=%d", mmc_hostname(host->mmc),
2933 (u32)sps_pipe_handle, rc);
2934 goto sps_connect_err;
2935 }
2936
2937 sps_event->mode = SPS_TRIGGER_CALLBACK;
2938 sps_event->options = SPS_O_EOT;
2939 sps_event->callback = msmsdcc_sps_complete_cb;
2940 sps_event->xfer_done = NULL;
2941 sps_event->user = (void *)host;
2942
2943 /* Register callback event for EOT (End of transfer) event. */
2944 rc = sps_register_event(sps_pipe_handle, sps_event);
2945 if (rc) {
2946 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
2947 " rc=%d", mmc_hostname(host->mmc),
2948 (u32)sps_pipe_handle, rc);
2949 goto reg_event_err;
2950 }
2951 /* Now save the sps pipe handle */
2952 ep->pipe_handle = sps_pipe_handle;
2953 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
2954 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
2955 __func__, is_producer ? "READ" : "WRITE",
2956 (u32)sps_pipe_handle, sps_config->desc.phys_base);
2957 goto out;
2958
2959reg_event_err:
2960 sps_disconnect(sps_pipe_handle);
2961sps_connect_err:
2962 dma_free_coherent(mmc_dev(host->mmc),
2963 sps_config->desc.size,
2964 sps_config->desc.base,
2965 sps_config->desc.phys_base);
2966get_config_err:
2967 sps_free_endpoint(sps_pipe_handle);
2968out:
2969 return rc;
2970}
2971
2972/**
2973 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
2974 *
2975 * This function disconnect endpoint and deallocates
2976 * endpoint context.
2977 *
2978 * This function should only be called once typically
2979 * during driver remove.
2980 *
2981 * @host - Pointer to sdcc host structure
2982 * @ep - Pointer to sps endpoint data structure
2983 *
2984 */
2985static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
2986 struct msmsdcc_sps_ep_conn_data *ep)
2987{
2988 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
2989 struct sps_connect *sps_config = &ep->config;
2990 struct sps_register_event *sps_event = &ep->event;
2991
2992 sps_event->xfer_done = NULL;
2993 sps_event->callback = NULL;
2994 sps_register_event(sps_pipe_handle, sps_event);
2995 sps_disconnect(sps_pipe_handle);
2996 dma_free_coherent(mmc_dev(host->mmc),
2997 sps_config->desc.size,
2998 sps_config->desc.base,
2999 sps_config->desc.phys_base);
3000 sps_free_endpoint(sps_pipe_handle);
3001}
3002
3003/**
3004 * Reset SDCC peripheral's SPS endpoint
3005 *
3006 * This function disconnects an endpoint.
3007 *
3008 * This function should be called for reseting
3009 * SPS endpoint when data transfer error is
3010 * encountered during data transfer. This
3011 * can be considered as soft reset to endpoint.
3012 *
3013 * This function should only be called if
3014 * msmsdcc_sps_init() is already called.
3015 *
3016 * @host - Pointer to sdcc host structure
3017 * @ep - Pointer to sps endpoint data structure
3018 *
3019 * @return - 0 if successful else negative value.
3020 */
3021static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3022 struct msmsdcc_sps_ep_conn_data *ep)
3023{
3024 int rc = 0;
3025 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3026
3027 rc = sps_disconnect(sps_pipe_handle);
3028 if (rc) {
3029 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3030 " rc=%d", mmc_hostname(host->mmc), __func__,
3031 (u32)sps_pipe_handle, rc);
3032 goto out;
3033 }
3034 out:
3035 return rc;
3036}
3037
3038/**
3039 * Restore SDCC peripheral's SPS endpoint
3040 *
3041 * This function connects an endpoint.
3042 *
3043 * This function should be called for restoring
3044 * SPS endpoint after data transfer error is
3045 * encountered during data transfer. This
3046 * can be considered as soft reset to endpoint.
3047 *
3048 * This function should only be called if
3049 * msmsdcc_sps_reset_ep() is called before.
3050 *
3051 * @host - Pointer to sdcc host structure
3052 * @ep - Pointer to sps endpoint data structure
3053 *
3054 * @return - 0 if successful else negative value.
3055 */
3056static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3057 struct msmsdcc_sps_ep_conn_data *ep)
3058{
3059 int rc = 0;
3060 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3061 struct sps_connect *sps_config = &ep->config;
3062 struct sps_register_event *sps_event = &ep->event;
3063
3064 /* Establish connection between peripheral and memory endpoint */
3065 rc = sps_connect(sps_pipe_handle, sps_config);
3066 if (rc) {
3067 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3068 " rc=%d", mmc_hostname(host->mmc), __func__,
3069 (u32)sps_pipe_handle, rc);
3070 goto out;
3071 }
3072
3073 /* Register callback event for EOT (End of transfer) event. */
3074 rc = sps_register_event(sps_pipe_handle, sps_event);
3075 if (rc) {
3076 pr_err("%s: %s: sps_register_event() failed!!!"
3077 " pipe_handle=0x%x, rc=%d",
3078 mmc_hostname(host->mmc), __func__,
3079 (u32)sps_pipe_handle, rc);
3080 goto reg_event_err;
3081 }
3082 goto out;
3083
3084reg_event_err:
3085 sps_disconnect(sps_pipe_handle);
3086out:
3087 return rc;
3088}
3089
3090/**
3091 * Initialize SPS HW connected with SDCC core
3092 *
3093 * This function register BAM HW resources with
3094 * SPS driver and then initialize 2 SPS endpoints
3095 *
3096 * This function should only be called once typically
3097 * during driver probe.
3098 *
3099 * @host - Pointer to sdcc host structure
3100 *
3101 * @return - 0 if successful else negative value.
3102 *
3103 */
3104static int msmsdcc_sps_init(struct msmsdcc_host *host)
3105{
3106 int rc = 0;
3107 struct sps_bam_props bam = {0};
3108
3109 host->bam_base = ioremap(host->bam_memres->start,
3110 resource_size(host->bam_memres));
3111 if (!host->bam_base) {
3112 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3113 " size=0x%x", mmc_hostname(host->mmc),
3114 host->bam_memres->start,
3115 (host->bam_memres->end -
3116 host->bam_memres->start));
3117 rc = -ENOMEM;
3118 goto out;
3119 }
3120
3121 bam.phys_addr = host->bam_memres->start;
3122 bam.virt_addr = host->bam_base;
3123 /*
3124 * This event thresold value is only significant for BAM-to-BAM
3125 * transfer. It's ignored for BAM-to-System mode transfer.
3126 */
3127 bam.event_threshold = 0x10; /* Pipe event threshold */
3128 /*
3129 * This threshold controls when the BAM publish
3130 * the descriptor size on the sideband interface.
3131 * SPS HW will only be used when
3132 * data transfer size > MCI_FIFOSIZE (64 bytes).
3133 * PIO mode will be used when
3134 * data transfer size < MCI_FIFOSIZE (64 bytes).
3135 * So set this thresold value to 64 bytes.
3136 */
3137 bam.summing_threshold = 64;
3138 /* SPS driver wll handle the SDCC BAM IRQ */
3139 bam.irq = (u32)host->bam_irqres->start;
3140 bam.manage = SPS_BAM_MGR_LOCAL;
3141
3142 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3143 (u32)bam.phys_addr);
3144 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3145 (u32)bam.virt_addr);
3146
3147 /* Register SDCC Peripheral BAM device to SPS driver */
3148 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3149 if (rc) {
3150 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3151 mmc_hostname(host->mmc), rc);
3152 goto reg_bam_err;
3153 }
3154 pr_info("%s: BAM device registered. bam_handle=0x%x",
3155 mmc_hostname(host->mmc), host->sps.bam_handle);
3156
3157 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3158 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3159
3160 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3161 SPS_PROD_PERIPHERAL);
3162 if (rc)
3163 goto sps_reset_err;
3164 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3165 SPS_CONS_PERIPHERAL);
3166 if (rc)
3167 goto cons_conn_err;
3168
3169 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3170 mmc_hostname(host->mmc),
3171 (unsigned long long)host->bam_memres->start,
3172 (unsigned int)host->bam_irqres->start);
3173 goto out;
3174
3175cons_conn_err:
3176 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3177sps_reset_err:
3178 sps_deregister_bam_device(host->sps.bam_handle);
3179reg_bam_err:
3180 iounmap(host->bam_base);
3181out:
3182 return rc;
3183}
3184
3185/**
3186 * De-initialize SPS HW connected with SDCC core
3187 *
3188 * This function deinitialize SPS endpoints and then
3189 * deregisters BAM resources from SPS driver.
3190 *
3191 * This function should only be called once typically
3192 * during driver remove.
3193 *
3194 * @host - Pointer to sdcc host structure
3195 *
3196 */
3197static void msmsdcc_sps_exit(struct msmsdcc_host *host)
3198{
3199 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
3200 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3201 sps_deregister_bam_device(host->sps.bam_handle);
3202 iounmap(host->bam_base);
3203}
3204#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
3205
3206static ssize_t
3207show_polling(struct device *dev, struct device_attribute *attr, char *buf)
3208{
3209 struct mmc_host *mmc = dev_get_drvdata(dev);
3210 struct msmsdcc_host *host = mmc_priv(mmc);
3211 int poll;
3212 unsigned long flags;
3213
3214 spin_lock_irqsave(&host->lock, flags);
3215 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
3216 spin_unlock_irqrestore(&host->lock, flags);
3217
3218 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
3219}
3220
3221static ssize_t
3222set_polling(struct device *dev, struct device_attribute *attr,
3223 const char *buf, size_t count)
3224{
3225 struct mmc_host *mmc = dev_get_drvdata(dev);
3226 struct msmsdcc_host *host = mmc_priv(mmc);
3227 int value;
3228 unsigned long flags;
3229
3230 sscanf(buf, "%d", &value);
3231
3232 spin_lock_irqsave(&host->lock, flags);
3233 if (value) {
3234 mmc->caps |= MMC_CAP_NEEDS_POLL;
3235 mmc_detect_change(host->mmc, 0);
3236 } else {
3237 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3238 }
3239#ifdef CONFIG_HAS_EARLYSUSPEND
3240 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
3241#endif
3242 spin_unlock_irqrestore(&host->lock, flags);
3243 return count;
3244}
3245
3246static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
3247 show_polling, set_polling);
3248static struct attribute *dev_attrs[] = {
3249 &dev_attr_polling.attr,
3250 NULL,
3251};
3252static struct attribute_group dev_attr_grp = {
3253 .attrs = dev_attrs,
3254};
3255
3256#ifdef CONFIG_HAS_EARLYSUSPEND
3257static void msmsdcc_early_suspend(struct early_suspend *h)
3258{
3259 struct msmsdcc_host *host =
3260 container_of(h, struct msmsdcc_host, early_suspend);
3261 unsigned long flags;
3262
3263 spin_lock_irqsave(&host->lock, flags);
3264 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
3265 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3266 spin_unlock_irqrestore(&host->lock, flags);
3267};
3268static void msmsdcc_late_resume(struct early_suspend *h)
3269{
3270 struct msmsdcc_host *host =
3271 container_of(h, struct msmsdcc_host, early_suspend);
3272 unsigned long flags;
3273
3274 if (host->polling_enabled) {
3275 spin_lock_irqsave(&host->lock, flags);
3276 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
3277 mmc_detect_change(host->mmc, 0);
3278 spin_unlock_irqrestore(&host->lock, flags);
3279 }
3280};
3281#endif
3282
3283static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
3284{
3285 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3286 struct mmc_request *mrq;
3287 unsigned long flags;
3288
3289 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003290 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003291 pr_info("%s: %s: dummy CMD52 timeout\n",
3292 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003293 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003294 }
3295
3296 mrq = host->curr.mrq;
3297
3298 if (mrq && mrq->cmd) {
3299 pr_info("%s: %s CMD%d\n", mmc_hostname(host->mmc),
3300 __func__, mrq->cmd->opcode);
3301 if (!mrq->cmd->error)
3302 mrq->cmd->error = -ETIMEDOUT;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003303 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003304 host->dummy_52_needed = 0;
3305 if (host->curr.data) {
3306 pr_info("%s: %s Request timeout\n",
3307 mmc_hostname(host->mmc), __func__);
3308 if (mrq->data && !mrq->data->error)
3309 mrq->data->error = -ETIMEDOUT;
3310 host->curr.data_xfered = 0;
3311 if (host->dma.sg && host->is_dma_mode) {
3312 msm_dmov_stop_cmd(host->dma.channel,
3313 &host->dma.hdr, 0);
3314 } else if (host->sps.sg && host->is_sps_mode) {
3315 /* Stop current SPS transfer */
3316 msmsdcc_sps_exit_curr_xfer(host);
3317 } else {
3318 msmsdcc_reset_and_restore(host);
3319 msmsdcc_stop_data(host);
3320 if (mrq->data && mrq->data->stop)
3321 msmsdcc_start_command(host,
3322 mrq->data->stop, 0);
3323 else
3324 msmsdcc_request_end(host, mrq);
3325 }
3326 } else {
3327 if (host->prog_enable) {
3328 host->prog_scan = 0;
3329 host->prog_enable = 0;
3330 }
3331 msmsdcc_reset_and_restore(host);
3332 msmsdcc_request_end(host, mrq);
3333 }
3334 }
3335 spin_unlock_irqrestore(&host->lock, flags);
3336}
3337
San Mehat9d2bd732009-09-22 16:44:22 -07003338static int
3339msmsdcc_probe(struct platform_device *pdev)
3340{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003341 struct mmc_platform_data *plat = pdev->dev.platform_data;
San Mehat9d2bd732009-09-22 16:44:22 -07003342 struct msmsdcc_host *host;
3343 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003344 unsigned long flags;
3345 struct resource *core_irqres = NULL;
3346 struct resource *bam_irqres = NULL;
3347 struct resource *core_memres = NULL;
3348 struct resource *dml_memres = NULL;
3349 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07003350 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07003351 struct resource *dma_crci_res = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07003352 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003353 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07003354
3355 /* must have platform data */
3356 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003357 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003358 ret = -EINVAL;
3359 goto out;
3360 }
3361
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003362 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07003363 return -EINVAL;
3364
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003365 if (plat->is_sdio_al_client)
3366 if (!plat->sdio_lpm_gpio_setup || !plat->sdiowakeup_irq)
3367 return -EINVAL;
3368
San Mehat9d2bd732009-09-22 16:44:22 -07003369 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003370 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003371 return -ENXIO;
3372 }
3373
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003374 for (i = 0; i < pdev->num_resources; i++) {
3375 if (pdev->resource[i].flags & IORESOURCE_MEM) {
3376 if (!strcmp(pdev->resource[i].name,
3377 "sdcc_dml_addr"))
3378 dml_memres = &pdev->resource[i];
3379 else if (!strcmp(pdev->resource[i].name,
3380 "sdcc_bam_addr"))
3381 bam_memres = &pdev->resource[i];
3382 else
3383 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07003384
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003385 }
3386 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
3387 if (!strcmp(pdev->resource[i].name,
3388 "sdcc_bam_irq"))
3389 bam_irqres = &pdev->resource[i];
3390 else
3391 core_irqres = &pdev->resource[i];
3392 }
Krishna Konda25786ec2011-07-25 16:21:36 -07003393 if (pdev->resource[i].flags & IORESOURCE_DMA) {
3394 if (!strncmp(pdev->resource[i].name,
3395 "sdcc_dma_chnl",
3396 sizeof("sdcc_dma_chnl")))
3397 dmares = &pdev->resource[i];
3398 else if (!strncmp(pdev->resource[i].name,
3399 "sdcc_dma_crci",
3400 sizeof("sdcc_dma_crci")))
3401 dma_crci_res = &pdev->resource[i];
3402 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003403 }
3404
3405 if (!core_irqres || !core_memres) {
3406 pr_err("%s: Invalid sdcc core resource\n", __func__);
3407 return -ENXIO;
3408 }
3409
3410 /*
3411 * Both BAM and DML memory resource should be preset.
3412 * BAM IRQ resource should also be present.
3413 */
3414 if ((bam_memres && !dml_memres) ||
3415 (!bam_memres && dml_memres) ||
3416 ((bam_memres && dml_memres) && !bam_irqres)) {
3417 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003418 return -ENXIO;
3419 }
3420
3421 /*
3422 * Setup our host structure
3423 */
San Mehat9d2bd732009-09-22 16:44:22 -07003424 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
3425 if (!mmc) {
3426 ret = -ENOMEM;
3427 goto out;
3428 }
3429
3430 host = mmc_priv(mmc);
3431 host->pdev_id = pdev->id;
3432 host->plat = plat;
3433 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08003434 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05303435
3436 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003437 host->is_sps_mode = 1;
3438 else if (dmares)
3439 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07003440
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003441 host->base = ioremap(core_memres->start,
3442 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07003443 if (!host->base) {
3444 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003445 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003446 }
3447
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003448 host->core_irqres = core_irqres;
3449 host->bam_irqres = bam_irqres;
3450 host->core_memres = core_memres;
3451 host->dml_memres = dml_memres;
3452 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07003453 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07003454 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07003455 spin_lock_init(&host->lock);
3456
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003457#ifdef CONFIG_MMC_EMBEDDED_SDIO
3458 if (plat->embedded_sdio)
3459 mmc_set_embedded_sdio_data(mmc,
3460 &plat->embedded_sdio->cis,
3461 &plat->embedded_sdio->cccr,
3462 plat->embedded_sdio->funcs,
3463 plat->embedded_sdio->num_funcs);
3464#endif
3465
Sahitya Tummala62612cf2010-12-08 15:03:03 +05303466 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
3467 (unsigned long)host);
3468
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003469 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
3470 (unsigned long)host);
3471 if (host->is_dma_mode) {
3472 /* Setup DMA */
3473 ret = msmsdcc_init_dma(host);
3474 if (ret)
3475 goto ioremap_free;
3476 } else {
3477 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003478 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003479 }
3480
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003481 /*
3482 * Setup SDCC clock if derived from Dayatona
3483 * fabric core clock.
3484 */
3485 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07003486 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003487 if (!IS_ERR(host->dfab_pclk)) {
3488 /* Set the clock rate to 64MHz for max. performance */
3489 ret = clk_set_rate(host->dfab_pclk, 64000000);
3490 if (ret)
3491 goto dfab_pclk_put;
3492 ret = clk_enable(host->dfab_pclk);
3493 if (ret)
3494 goto dfab_pclk_put;
3495 } else
3496 goto dma_free;
3497 }
3498
3499 /*
3500 * Setup main peripheral bus clock
3501 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003502 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003503 if (!IS_ERR(host->pclk)) {
3504 ret = clk_enable(host->pclk);
3505 if (ret)
3506 goto pclk_put;
3507
3508 host->pclk_rate = clk_get_rate(host->pclk);
3509 }
3510
3511 /*
3512 * Setup SDC MMC clock
3513 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003514 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07003515 if (IS_ERR(host->clk)) {
3516 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003517 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07003518 }
3519
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003520 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
3521 if (ret) {
3522 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
3523 goto clk_put;
3524 }
3525
3526 ret = clk_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003527 if (ret)
3528 goto clk_put;
3529
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003530 host->clk_rate = clk_get_rate(host->clk);
3531
3532 host->clks_on = 1;
3533
3534 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07003535 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003536 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07003537 goto clk_disable;
3538 }
3539
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003540
3541 /* Clocks has to be running before accessing SPS/DML HW blocks */
3542 if (host->is_sps_mode) {
3543 /* Initialize SPS */
3544 ret = msmsdcc_sps_init(host);
3545 if (ret)
3546 goto vreg_deinit;
3547 /* Initialize DML */
3548 ret = msmsdcc_dml_init(host);
3549 if (ret)
3550 goto sps_exit;
3551 }
San Mehat9d2bd732009-09-22 16:44:22 -07003552
San Mehat9d2bd732009-09-22 16:44:22 -07003553 /*
3554 * Setup MMC host structure
3555 */
3556 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003557 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
3558 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003559 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003560 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
3561 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07003562
San Mehat9d2bd732009-09-22 16:44:22 -07003563 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003564 mmc->caps |= plat->uhs_caps;
3565 /*
3566 * XPC controls the maximum current in the default speed mode of SDXC
3567 * card. XPC=0 means 100mA (max.) but speed class is not supported.
3568 * XPC=1 means 150mA (max.) and speed class is supported.
3569 */
3570 if (plat->xpc_cap)
3571 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
3572 MMC_CAP_SET_XPC_180);
3573
3574 if (plat->nonremovable)
3575 mmc->caps |= MMC_CAP_NONREMOVABLE;
3576#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
3577 mmc->caps |= MMC_CAP_SDIO_IRQ;
3578#endif
3579
3580 if (plat->is_sdio_al_client)
3581 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07003582
Martin K. Petersena36274e2010-09-10 01:33:59 -04003583 mmc->max_segs = NR_SG;
San Mehat9d2bd732009-09-22 16:44:22 -07003584 mmc->max_blk_size = 4096; /* MCI_DATA_CTL BLOCKSIZE up to 4096 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003585 mmc->max_blk_count = 65535;
San Mehat9d2bd732009-09-22 16:44:22 -07003586
3587 mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */
3588 mmc->max_seg_size = mmc->max_req_size;
3589
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003590 writel_relaxed(0, host->base + MMCIMASK0);
3591 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -07003592
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003593 /* Delay needed (MMCIMASK0 was just written above) */
3594 msmsdcc_delay(host);
3595 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
3596 mb();
3597 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07003598
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003599 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
3600 DRIVER_NAME " (cmd)", host);
3601 if (ret)
3602 goto dml_exit;
3603
3604 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
3605 DRIVER_NAME " (pio)", host);
3606 if (ret)
3607 goto irq_free;
3608
3609 /*
3610 * Enable SDCC IRQ only when host is powered on. Otherwise, this
3611 * IRQ is un-necessarily being monitored by MPM (Modem power
3612 * management block) during idle-power collapse. The MPM will be
3613 * configured to monitor the DATA1 GPIO line with level-low trigger
3614 * and thus depending on the GPIO status, it prevents TCXO shutdown
3615 * during idle-power collapse.
3616 */
3617 disable_irq(core_irqres->start);
3618 host->sdcc_irq_disabled = 1;
3619
3620 if (plat->sdiowakeup_irq) {
3621 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3622 mmc_hostname(mmc));
3623 ret = request_irq(plat->sdiowakeup_irq,
3624 msmsdcc_platform_sdiowakeup_irq,
3625 IRQF_SHARED | IRQF_TRIGGER_LOW,
3626 DRIVER_NAME "sdiowakeup", host);
3627 if (ret) {
3628 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
3629 plat->sdiowakeup_irq, ret);
3630 goto pio_irq_free;
3631 } else {
3632 spin_lock_irqsave(&host->lock, flags);
3633 if (!host->sdio_irq_disabled) {
3634 disable_irq_nosync(plat->sdiowakeup_irq);
3635 host->sdio_irq_disabled = 1;
3636 }
3637 spin_unlock_irqrestore(&host->lock, flags);
3638 }
3639 }
3640
3641 if (plat->cfg_mpm_sdiowakeup) {
3642 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3643 mmc_hostname(mmc));
3644 }
3645
3646 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
3647 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003648 /*
3649 * Setup card detect change
3650 */
3651
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003652 if (plat->status || plat->status_gpio) {
3653 if (plat->status)
3654 host->oldstat = plat->status(mmc_dev(host->mmc));
3655 else
3656 host->oldstat = msmsdcc_slot_status(host);
3657 host->eject = !host->oldstat;
3658 }
San Mehat9d2bd732009-09-22 16:44:22 -07003659
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003660 if (plat->status_irq) {
3661 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07003662 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003663 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07003664 DRIVER_NAME " (slot)",
3665 host);
3666 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003667 pr_err("Unable to get slot IRQ %d (%d)\n",
3668 plat->status_irq, ret);
3669 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003670 }
3671 } else if (plat->register_status_notify) {
3672 plat->register_status_notify(msmsdcc_status_notify_cb, host);
3673 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003674 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07003675 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003676
3677 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003678
3679 ret = pm_runtime_set_active(&(pdev)->dev);
3680 if (ret < 0)
3681 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3682 __func__, ret);
3683 /*
3684 * There is no notion of suspend/resume for SD/MMC/SDIO
3685 * cards. So host can be suspended/resumed with out
3686 * worrying about its children.
3687 */
3688 pm_suspend_ignore_children(&(pdev)->dev, true);
3689
3690 /*
3691 * MMC/SD/SDIO bus suspend/resume operations are defined
3692 * only for the slots that will be used for non-removable
3693 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
3694 * defined. Otherwise, they simply become card removal and
3695 * insertion events during suspend and resume respectively.
3696 * Hence, enable run-time PM only for slots for which bus
3697 * suspend/resume operations are defined.
3698 */
3699#ifdef CONFIG_MMC_UNSAFE_RESUME
3700 /*
3701 * If this capability is set, MMC core will enable/disable host
3702 * for every claim/release operation on a host. We use this
3703 * notification to increment/decrement runtime pm usage count.
3704 */
3705 mmc->caps |= MMC_CAP_DISABLE;
3706 pm_runtime_enable(&(pdev)->dev);
3707#else
3708 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
3709 mmc->caps |= MMC_CAP_DISABLE;
3710 pm_runtime_enable(&(pdev)->dev);
3711 }
3712#endif
3713 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
3714 (unsigned long)host);
3715
San Mehat9d2bd732009-09-22 16:44:22 -07003716 mmc_add_host(mmc);
3717
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003718#ifdef CONFIG_HAS_EARLYSUSPEND
3719 host->early_suspend.suspend = msmsdcc_early_suspend;
3720 host->early_suspend.resume = msmsdcc_late_resume;
3721 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
3722 register_early_suspend(&host->early_suspend);
3723#endif
San Mehat9d2bd732009-09-22 16:44:22 -07003724
Krishna Konda25786ec2011-07-25 16:21:36 -07003725 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
3726 " dmacrcri %d\n", mmc_hostname(mmc),
3727 (unsigned long long)core_memres->start,
3728 (unsigned int) core_irqres->start,
3729 (unsigned int) plat->status_irq, host->dma.channel,
3730 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003731
3732 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
3733 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
3734 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
3735 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
3736 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
3737 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
3738 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
3739 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
3740 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
3741 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
3742 host->eject);
3743 pr_info("%s: Power save feature enable = %d\n",
3744 mmc_hostname(mmc), msmsdcc_pwrsave);
3745
Krishna Konda25786ec2011-07-25 16:21:36 -07003746 if (host->is_dma_mode && host->dma.channel != -1
3747 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003748 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003749 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003750 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003751 mmc_hostname(mmc), host->dma.cmd_busaddr,
3752 host->dma.cmdptr_busaddr);
3753 } else if (host->is_sps_mode) {
3754 pr_info("%s: SPS-BAM data transfer mode available\n",
3755 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003756 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003757 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003758
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003759#if defined(CONFIG_DEBUG_FS)
3760 msmsdcc_dbg_createhost(host);
3761#endif
3762 if (!plat->status_irq) {
3763 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
3764 if (ret)
3765 goto platform_irq_free;
3766 }
San Mehat9d2bd732009-09-22 16:44:22 -07003767 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003768
3769 platform_irq_free:
3770 del_timer_sync(&host->req_tout_timer);
3771 pm_runtime_disable(&(pdev)->dev);
3772 pm_runtime_set_suspended(&(pdev)->dev);
3773
3774 if (plat->status_irq)
3775 free_irq(plat->status_irq, host);
3776 sdiowakeup_irq_free:
3777 wake_lock_destroy(&host->sdio_suspend_wlock);
3778 if (plat->sdiowakeup_irq)
3779 free_irq(plat->sdiowakeup_irq, host);
3780 pio_irq_free:
3781 if (plat->sdiowakeup_irq)
3782 wake_lock_destroy(&host->sdio_wlock);
3783 free_irq(core_irqres->start, host);
3784 irq_free:
3785 free_irq(core_irqres->start, host);
3786 dml_exit:
3787 if (host->is_sps_mode)
3788 msmsdcc_dml_exit(host);
3789 sps_exit:
3790 if (host->is_sps_mode)
3791 msmsdcc_sps_exit(host);
3792 vreg_deinit:
3793 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07003794 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003795 clk_disable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003796 clk_put:
3797 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003798 pclk_disable:
3799 if (!IS_ERR(host->pclk))
3800 clk_disable(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07003801 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003802 if (!IS_ERR(host->pclk))
3803 clk_put(host->pclk);
3804 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3805 clk_disable(host->dfab_pclk);
3806 dfab_pclk_put:
3807 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3808 clk_put(host->dfab_pclk);
3809 dma_free:
3810 if (host->is_dma_mode) {
3811 if (host->dmares)
3812 dma_free_coherent(NULL,
3813 sizeof(struct msmsdcc_nc_dmadata),
3814 host->dma.nc, host->dma.nc_busaddr);
3815 }
3816 ioremap_free:
3817 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07003818 host_free:
3819 mmc_free_host(mmc);
3820 out:
3821 return ret;
3822}
3823
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003824static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07003825{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003826 struct mmc_host *mmc = mmc_get_drvdata(pdev);
3827 struct mmc_platform_data *plat;
3828 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07003829
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003830 if (!mmc)
3831 return -ENXIO;
3832
3833 if (pm_runtime_suspended(&(pdev)->dev))
3834 pm_runtime_resume(&(pdev)->dev);
3835
3836 host = mmc_priv(mmc);
3837
3838 DBG(host, "Removing SDCC device = %d\n", pdev->id);
3839 plat = host->plat;
3840
3841 if (!plat->status_irq)
3842 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
3843
3844 del_timer_sync(&host->req_tout_timer);
3845 tasklet_kill(&host->dma_tlet);
3846 tasklet_kill(&host->sps.tlet);
3847 mmc_remove_host(mmc);
3848
3849 if (plat->status_irq)
3850 free_irq(plat->status_irq, host);
3851
3852 wake_lock_destroy(&host->sdio_suspend_wlock);
3853 if (plat->sdiowakeup_irq) {
3854 wake_lock_destroy(&host->sdio_wlock);
3855 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
3856 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07003857 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003858
3859 free_irq(host->core_irqres->start, host);
3860 free_irq(host->core_irqres->start, host);
3861
3862 clk_put(host->clk);
3863 if (!IS_ERR(host->pclk))
3864 clk_put(host->pclk);
3865 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3866 clk_put(host->dfab_pclk);
3867
3868 msmsdcc_vreg_init(host, false);
3869
3870 if (host->is_dma_mode) {
3871 if (host->dmares)
3872 dma_free_coherent(NULL,
3873 sizeof(struct msmsdcc_nc_dmadata),
3874 host->dma.nc, host->dma.nc_busaddr);
3875 }
3876
3877 if (host->is_sps_mode) {
3878 msmsdcc_dml_exit(host);
3879 msmsdcc_sps_exit(host);
3880 }
3881
3882 iounmap(host->base);
3883 mmc_free_host(mmc);
3884
3885#ifdef CONFIG_HAS_EARLYSUSPEND
3886 unregister_early_suspend(&host->early_suspend);
3887#endif
3888 pm_runtime_disable(&(pdev)->dev);
3889 pm_runtime_set_suspended(&(pdev)->dev);
3890
3891 return 0;
3892}
3893
3894#ifdef CONFIG_MSM_SDIO_AL
3895int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
3896{
3897 struct msmsdcc_host *host = mmc_priv(mmc);
3898 unsigned long flags;
3899
3900 spin_lock_irqsave(&host->lock, flags);
3901 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
3902 enable ? "En" : "Dis");
3903
3904 if (enable) {
3905 if (!host->sdcc_irq_disabled) {
3906 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05303907 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003908 host->sdcc_irq_disabled = 1;
3909 }
3910
3911 if (host->clks_on) {
3912 msmsdcc_setup_clocks(host, false);
3913 host->clks_on = 0;
3914 }
3915
3916 if (!host->sdio_gpio_lpm) {
3917 spin_unlock_irqrestore(&host->lock, flags);
3918 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
3919 spin_lock_irqsave(&host->lock, flags);
3920 host->sdio_gpio_lpm = 1;
3921 }
3922
3923 if (host->sdio_irq_disabled) {
3924 msmsdcc_enable_irq_wake(host);
3925 enable_irq(host->plat->sdiowakeup_irq);
3926 host->sdio_irq_disabled = 0;
3927 }
3928 } else {
3929 if (!host->sdio_irq_disabled) {
3930 disable_irq_nosync(host->plat->sdiowakeup_irq);
3931 host->sdio_irq_disabled = 1;
3932 msmsdcc_disable_irq_wake(host);
3933 }
3934
3935 if (host->sdio_gpio_lpm) {
3936 spin_unlock_irqrestore(&host->lock, flags);
3937 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
3938 spin_lock_irqsave(&host->lock, flags);
3939 host->sdio_gpio_lpm = 0;
3940 }
3941
3942 if (!host->clks_on) {
3943 msmsdcc_setup_clocks(host, true);
3944 host->clks_on = 1;
3945 }
3946
3947 if (host->sdcc_irq_disabled) {
3948 writel_relaxed(host->mci_irqenable,
3949 host->base + MMCIMASK0);
3950 mb();
3951 enable_irq(host->core_irqres->start);
3952 host->sdcc_irq_disabled = 0;
3953 }
3954 wake_lock_timeout(&host->sdio_wlock, 1);
3955 }
3956 spin_unlock_irqrestore(&host->lock, flags);
3957 return 0;
3958}
3959#else
3960int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
3961{
3962 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07003963}
3964#endif
3965
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003966#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07003967static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003968msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07003969{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003970 struct mmc_host *mmc = dev_get_drvdata(dev);
3971 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07003972 int rc = 0;
3973
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003974 if (host->plat->is_sdio_al_client)
3975 return 0;
3976
Sahitya Tummala7661a452011-07-18 13:28:35 +05303977 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003978 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003979 host->sdcc_suspending = 1;
3980 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07003981
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003982 /*
3983 * If the clocks are already turned off by SDIO clients (as
3984 * part of LPM), then clocks should be turned on before
3985 * calling mmc_suspend_host() because mmc_suspend_host might
3986 * send some commands to the card. The clocks will be turned
3987 * off again after mmc_suspend_host. Thus for SD/MMC/SDIO
3988 * cards, clocks will be turned on before mmc_suspend_host
3989 * and turned off after mmc_suspend_host.
3990 */
3991 mmc->ios.clock = host->clk_rate;
3992 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07003993
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003994 /*
3995 * MMC core thinks that host is disabled by now since
3996 * runtime suspend is scheduled after msmsdcc_disable()
3997 * is called. Thus, MMC core will try to enable the host
3998 * while suspending it. This results in a synchronous
3999 * runtime resume request while in runtime suspending
4000 * context and hence inorder to complete this resume
4001 * requet, it will wait for suspend to be complete,
4002 * but runtime suspend also can not proceed further
4003 * until the host is resumed. Thus, it leads to a hang.
4004 * Hence, increase the pm usage count before suspending
4005 * the host so that any resume requests after this will
4006 * simple become pm usage counter increment operations.
4007 */
4008 pm_runtime_get_noresume(dev);
4009 rc = mmc_suspend_host(mmc);
4010 pm_runtime_put_noidle(dev);
4011
4012 if (!rc) {
4013 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
4014 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ)) {
4015 disable_irq(host->core_irqres->start);
4016 host->sdcc_irq_disabled = 1;
4017
4018 /*
4019 * If MMC core level suspend is not supported,
4020 * turn off clocks to allow deep sleep (TCXO
4021 * shutdown).
4022 */
4023 mmc->ios.clock = 0;
4024 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4025 enable_irq(host->core_irqres->start);
4026 host->sdcc_irq_disabled = 0;
4027
4028 if (host->plat->sdiowakeup_irq) {
4029 host->sdio_irq_disabled = 0;
4030 msmsdcc_enable_irq_wake(host);
4031 enable_irq(host->plat->sdiowakeup_irq);
4032 }
4033 }
4034 }
4035 host->sdcc_suspending = 0;
4036 mmc->suspend_task = NULL;
4037 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
4038 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004039 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304040 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004041 return rc;
4042}
4043
4044static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004045msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004046{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004047 struct mmc_host *mmc = dev_get_drvdata(dev);
4048 struct msmsdcc_host *host = mmc_priv(mmc);
4049 unsigned long flags;
4050
4051 if (host->plat->is_sdio_al_client)
4052 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07004053
Sahitya Tummala7661a452011-07-18 13:28:35 +05304054 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004055 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004056 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
4057 if (host->sdcc_irq_disabled) {
4058 enable_irq(host->core_irqres->start);
4059 host->sdcc_irq_disabled = 0;
4060 }
4061 }
4062 mmc->ios.clock = host->clk_rate;
4063 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07004064
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004065 spin_lock_irqsave(&host->lock, flags);
4066 writel_relaxed(host->mci_irqenable, host->base + MMCIMASK0);
4067 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07004068
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004069 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
4070 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) &&
4071 !host->sdio_irq_disabled) {
4072 if (host->plat->sdiowakeup_irq) {
4073 disable_irq_nosync(
4074 host->plat->sdiowakeup_irq);
4075 msmsdcc_disable_irq_wake(host);
4076 host->sdio_irq_disabled = 1;
4077 }
4078 }
San Mehat9d2bd732009-09-22 16:44:22 -07004079
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004080 spin_unlock_irqrestore(&host->lock, flags);
4081
4082 mmc_resume_host(mmc);
4083
4084 /*
4085 * FIXME: Clearing of flags must be handled in clients
4086 * resume handler.
4087 */
4088 spin_lock_irqsave(&host->lock, flags);
4089 mmc->pm_flags = 0;
4090 spin_unlock_irqrestore(&host->lock, flags);
4091
4092 /*
4093 * After resuming the host wait for sometime so that
4094 * the SDIO work will be processed.
4095 */
4096 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO)) {
4097 if ((host->plat->cfg_mpm_sdiowakeup ||
4098 host->plat->sdiowakeup_irq) &&
4099 wake_lock_active(&host->sdio_wlock))
4100 wake_lock_timeout(&host->sdio_wlock, 1);
4101 }
4102
4103 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004104 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304105 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004106 return 0;
4107}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004108
4109static int msmsdcc_runtime_idle(struct device *dev)
4110{
4111 struct mmc_host *mmc = dev_get_drvdata(dev);
4112 struct msmsdcc_host *host = mmc_priv(mmc);
4113
4114 if (host->plat->is_sdio_al_client)
4115 return 0;
4116
4117 /* Idle timeout is not configurable for now */
4118 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
4119
4120 return -EAGAIN;
4121}
4122
4123static int msmsdcc_pm_suspend(struct device *dev)
4124{
4125 struct mmc_host *mmc = dev_get_drvdata(dev);
4126 struct msmsdcc_host *host = mmc_priv(mmc);
4127 int rc = 0;
4128
4129 if (host->plat->is_sdio_al_client)
4130 return 0;
4131
4132
4133 if (host->plat->status_irq)
4134 disable_irq(host->plat->status_irq);
4135
4136 if (!pm_runtime_suspended(dev))
4137 rc = msmsdcc_runtime_suspend(dev);
4138
4139 return rc;
4140}
4141
4142static int msmsdcc_pm_resume(struct device *dev)
4143{
4144 struct mmc_host *mmc = dev_get_drvdata(dev);
4145 struct msmsdcc_host *host = mmc_priv(mmc);
4146 int rc = 0;
4147
4148 if (host->plat->is_sdio_al_client)
4149 return 0;
4150
Sahitya Tummalafb486372011-09-02 19:01:49 +05304151 if (!pm_runtime_suspended(dev))
4152 rc = msmsdcc_runtime_resume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004153 if (host->plat->status_irq) {
4154 msmsdcc_check_status((unsigned long)host);
4155 enable_irq(host->plat->status_irq);
4156 }
4157
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004158 return rc;
4159}
4160
Daniel Walker08ecfde2010-06-23 12:32:20 -07004161#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004162#define msmsdcc_runtime_suspend NULL
4163#define msmsdcc_runtime_resume NULL
4164#define msmsdcc_runtime_idle NULL
4165#define msmsdcc_pm_suspend NULL
4166#define msmsdcc_pm_resume NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07004167#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004168
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004169static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
4170 .runtime_suspend = msmsdcc_runtime_suspend,
4171 .runtime_resume = msmsdcc_runtime_resume,
4172 .runtime_idle = msmsdcc_runtime_idle,
4173 .suspend = msmsdcc_pm_suspend,
4174 .resume = msmsdcc_pm_resume,
4175};
4176
San Mehat9d2bd732009-09-22 16:44:22 -07004177static struct platform_driver msmsdcc_driver = {
4178 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004179 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07004180 .driver = {
4181 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004182 .pm = &msmsdcc_dev_pm_ops,
San Mehat9d2bd732009-09-22 16:44:22 -07004183 },
4184};
4185
4186static int __init msmsdcc_init(void)
4187{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004188#if defined(CONFIG_DEBUG_FS)
4189 int ret = 0;
4190 ret = msmsdcc_dbg_init();
4191 if (ret) {
4192 pr_err("Failed to create debug fs dir \n");
4193 return ret;
4194 }
4195#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004196 return platform_driver_register(&msmsdcc_driver);
4197}
4198
4199static void __exit msmsdcc_exit(void)
4200{
4201 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004202
4203#if defined(CONFIG_DEBUG_FS)
4204 debugfs_remove(debugfs_file);
4205 debugfs_remove(debugfs_dir);
4206#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004207}
4208
4209module_init(msmsdcc_init);
4210module_exit(msmsdcc_exit);
4211
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004212MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07004213MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004214
4215#if defined(CONFIG_DEBUG_FS)
4216
4217static int
4218msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
4219{
4220 file->private_data = inode->i_private;
4221 return 0;
4222}
4223
4224static ssize_t
4225msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
4226 size_t count, loff_t *ppos)
4227{
4228 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
4229 char buf[1024];
4230 int max, i;
4231
4232 i = 0;
4233 max = sizeof(buf) - 1;
4234
4235 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
4236 host->curr.cmd, host->curr.data);
4237 if (host->curr.cmd) {
4238 struct mmc_command *cmd = host->curr.cmd;
4239
4240 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
4241 cmd->opcode, cmd->arg, cmd->flags);
4242 }
4243 if (host->curr.data) {
4244 struct mmc_data *data = host->curr.data;
4245 i += scnprintf(buf + i, max - i,
4246 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
4247 data->timeout_ns, data->timeout_clks,
4248 data->blksz, data->blocks, data->error,
4249 data->flags);
4250 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
4251 host->curr.xfer_size, host->curr.xfer_remain,
4252 host->curr.data_xfered, host->dma.sg);
4253 }
4254
4255 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
4256}
4257
4258static const struct file_operations msmsdcc_dbg_state_ops = {
4259 .read = msmsdcc_dbg_state_read,
4260 .open = msmsdcc_dbg_state_open,
4261};
4262
4263static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
4264{
4265 if (debugfs_dir) {
4266 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
4267 0644, debugfs_dir, host,
4268 &msmsdcc_dbg_state_ops);
4269 }
4270}
4271
4272static int __init msmsdcc_dbg_init(void)
4273{
4274 int err;
4275
4276 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
4277 if (IS_ERR(debugfs_dir)) {
4278 err = PTR_ERR(debugfs_dir);
4279 debugfs_dir = NULL;
4280 return err;
4281 }
4282
4283 return 0;
4284}
4285#endif