blob: ab252c9d2661da47abe706a96ffab3a051c3c2df [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);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530135static inline void msmsdcc_delay(struct msmsdcc_host *host);
136
San Mehat9d2bd732009-09-22 16:44:22 -0700137
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700138#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
139static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
140 struct msmsdcc_sps_ep_conn_data *ep);
141static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
142 struct msmsdcc_sps_ep_conn_data *ep);
143#else
144static inline int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
145 struct msmsdcc_sps_ep_conn_data *ep,
146 bool is_producer) { return 0; }
147static inline void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
148 struct msmsdcc_sps_ep_conn_data *ep) { }
149static inline int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
150 struct msmsdcc_sps_ep_conn_data *ep)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530151{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700152 return 0;
153}
154static inline int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
155 struct msmsdcc_sps_ep_conn_data *ep)
156{
157 return 0;
158}
159static inline int msmsdcc_sps_init(struct msmsdcc_host *host) { return 0; }
160static inline void msmsdcc_sps_exit(struct msmsdcc_host *host) {}
161#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530162
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700163/**
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530164 * Apply soft reset to all SDCC BAM pipes
165 *
166 * This function applies soft reset to SDCC BAM pipe.
167 *
168 * This function should be called to recover from error
169 * conditions encountered during CMD/DATA tranfsers with card.
170 *
171 * @host - Pointer to driver's host structure
172 *
173 */
174static void msmsdcc_sps_pipes_reset_and_restore(struct msmsdcc_host *host)
175{
176 int rc;
177
178 /* Reset all SDCC BAM pipes */
179 rc = msmsdcc_sps_reset_ep(host, &host->sps.prod);
180 if (rc)
181 pr_err("%s:msmsdcc_sps_reset_ep(prod) error=%d\n",
182 mmc_hostname(host->mmc), rc);
183 rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
184 if (rc)
185 pr_err("%s:msmsdcc_sps_reset_ep(cons) error=%d\n",
186 mmc_hostname(host->mmc), rc);
187
188 /* Restore all BAM pipes connections */
189 rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
190 if (rc)
191 pr_err("%s:msmsdcc_sps_restore_ep(prod) error=%d\n",
192 mmc_hostname(host->mmc), rc);
193 rc = msmsdcc_sps_restore_ep(host, &host->sps.cons);
194 if (rc)
195 pr_err("%s:msmsdcc_sps_restore_ep(cons) error=%d\n",
196 mmc_hostname(host->mmc), rc);
197}
198
199/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700200 * Apply soft reset
201 *
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530202 * This function applies soft reset to SDCC core and DML core.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700203 *
204 * This function should be called to recover from error
205 * conditions encountered with CMD/DATA tranfsers with card.
206 *
207 * Soft reset should only be used with SDCC controller v4.
208 *
209 * @host - Pointer to driver's host structure
210 *
211 */
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530212static void msmsdcc_soft_reset(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700213{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700214 /*
215 * Reset SDCC controller's DPSM (data path state machine
216 * and CPSM (command path state machine).
217 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700218 writel_relaxed(0, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530219 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700220 writel_relaxed(0, host->base + MMCIDATACTRL);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530221 msmsdcc_delay(host);
222}
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530223
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530224static void msmsdcc_hard_reset(struct msmsdcc_host *host)
225{
226 int ret;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530227
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530228 /* Reset the controller */
229 ret = clk_reset(host->clk, CLK_RESET_ASSERT);
230 if (ret)
231 pr_err("%s: Clock assert failed at %u Hz"
232 " with err %d\n", mmc_hostname(host->mmc),
233 host->clk_rate, ret);
234
235 ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
236 if (ret)
237 pr_err("%s: Clock deassert failed at %u Hz"
238 " with err %d\n", mmc_hostname(host->mmc),
239 host->clk_rate, ret);
240
241 /* Give some delay for clock reset to propogate to controller */
242 msmsdcc_delay(host);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530243}
244
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700245static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
246{
247 if (host->plat->sdcc_v4_sup) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530248 if (host->is_sps_mode) {
249 /* Reset DML first */
250 msmsdcc_dml_reset(host);
251 /*
252 * delay the SPS pipe reset in thread context as
253 * sps_connect/sps_disconnect APIs can be called
254 * only from non-atomic context.
255 */
256 host->sps.pipe_reset_pending = true;
257 }
258 mb();
259 msmsdcc_soft_reset(host);
260
261 pr_debug("%s: Applied soft reset to Controller\n",
262 mmc_hostname(host->mmc));
263
264 if (host->is_sps_mode)
265 msmsdcc_dml_init(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700266 } else {
267 /* Give Clock reset (hard reset) to controller */
268 u32 mci_clk = 0;
269 u32 mci_mask0 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700270
271 /* Save the controller state */
272 mci_clk = readl_relaxed(host->base + MMCICLOCK);
273 mci_mask0 = readl_relaxed(host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700274 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700275
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530276 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700277 pr_debug("%s: Controller has been reinitialized\n",
278 mmc_hostname(host->mmc));
279
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700280 /* Restore the contoller state */
281 writel_relaxed(host->pwr, host->base + MMCIPOWER);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530282 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700283 writel_relaxed(mci_clk, host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530284 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700285 writel_relaxed(mci_mask0, host->base + MMCIMASK0);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530286 mb(); /* no delay required after writing to MASK0 register */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700287 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530288
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700289 if (host->dummy_52_needed)
290 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700291}
292
293static int
San Mehat9d2bd732009-09-22 16:44:22 -0700294msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
295{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700296 int retval = 0;
297
San Mehat9d2bd732009-09-22 16:44:22 -0700298 BUG_ON(host->curr.data);
299
300 host->curr.mrq = NULL;
301 host->curr.cmd = NULL;
302
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700303 del_timer(&host->req_tout_timer);
304
San Mehat9d2bd732009-09-22 16:44:22 -0700305 if (mrq->data)
306 mrq->data->bytes_xfered = host->curr.data_xfered;
307 if (mrq->cmd->error == -ETIMEDOUT)
308 mdelay(5);
309
310 /*
311 * Need to drop the host lock here; mmc_request_done may call
312 * back into the driver...
313 */
314 spin_unlock(&host->lock);
315 mmc_request_done(host->mmc, mrq);
316 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700317
318 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700319}
320
321static void
322msmsdcc_stop_data(struct msmsdcc_host *host)
323{
San Mehat9d2bd732009-09-22 16:44:22 -0700324 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530325 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530326 host->curr.wait_for_auto_prog_done = 0;
327 host->curr.got_auto_prog_done = 0;
Krishna Konda3f5d48f2011-07-27 10:47:31 -0700328 writel_relaxed(readl_relaxed(host->base + MMCIDATACTRL) &
329 (~(MCI_DPSM_ENABLE)), host->base + MMCIDATACTRL);
Krishna Konda3e5c4d02011-07-11 16:31:45 -0700330 msmsdcc_delay(host); /* Allow the DPSM to be reset */
San Mehat9d2bd732009-09-22 16:44:22 -0700331}
332
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700333static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700334{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700335 return host->core_memres->start + MMCIFIFO;
336}
337
338static inline unsigned int msmsdcc_get_min_sup_clk_rate(
339 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530340
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700341static inline void msmsdcc_delay(struct msmsdcc_host *host)
342{
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530343 ktime_t start, diff;
344
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700345 mb();
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +0530346 udelay(host->reg_write_delay);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530347
348 if (host->plat->sdcc_v4_sup &&
349 (readl_relaxed(host->base + MCI_STATUS2) &
350 MCI_MCLK_REG_WR_ACTIVE)) {
351 start = ktime_get();
352 while (readl_relaxed(host->base + MCI_STATUS2) &
353 MCI_MCLK_REG_WR_ACTIVE) {
354 diff = ktime_sub(ktime_get(), start);
355 /* poll for max. 1 ms */
356 if (ktime_to_us(diff) > 1000) {
357 pr_warning("%s: previous reg. write is"
358 " still active\n",
359 mmc_hostname(host->mmc));
360 break;
361 }
362 }
363 }
San Mehat9d2bd732009-09-22 16:44:22 -0700364}
365
San Mehat56a8b5b2009-11-21 12:29:46 -0800366static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700367msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
368{
369 writel_relaxed(arg, host->base + MMCIARGUMENT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700370 writel_relaxed(c, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530371 /*
372 * As after sending the command, we don't write any of the
373 * controller registers and just wait for the
374 * CMD_RESPOND_END/CMD_SENT/Command failure notication
375 * from Controller.
376 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700377 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800378}
379
380static void
381msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
382{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700383 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800384
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700385 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
386 writel_relaxed((unsigned int)host->curr.xfer_size,
387 host->base + MMCIDATALENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700388 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
389 msmsdcc_delay(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800390
San Mehat6ac9ea62009-12-02 17:24:58 -0800391 if (host->cmd_cmd) {
392 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700393 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800394 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800395}
396
San Mehat9d2bd732009-09-22 16:44:22 -0700397static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530398msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700399{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530400 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700401 unsigned long flags;
402 struct mmc_request *mrq;
403
404 spin_lock_irqsave(&host->lock, flags);
405 mrq = host->curr.mrq;
406 BUG_ON(!mrq);
407
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530408 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700409 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700410 goto out;
411 }
412
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530413 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700414 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700415 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700416 } else {
417 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530418 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700419 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530420 mmc_hostname(host->mmc), host->dma.result);
421 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700422 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530423 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530424 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700425 host->dma.err.flush[0], host->dma.err.flush[1],
426 host->dma.err.flush[2], host->dma.err.flush[3],
427 host->dma.err.flush[4],
428 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530429 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700430 if (!mrq->data->error)
431 mrq->data->error = -EIO;
432 }
San Mehat9d2bd732009-09-22 16:44:22 -0700433 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents,
434 host->dma.dir);
435
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700436 if (host->curr.user_pages) {
437 struct scatterlist *sg = host->dma.sg;
438 int i;
439
440 for (i = 0; i < host->dma.num_ents; i++, sg++)
441 flush_dcache_page(sg_page(sg));
442 }
443
San Mehat9d2bd732009-09-22 16:44:22 -0700444 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800445 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700446
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530447 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
448 (host->curr.wait_for_auto_prog_done &&
449 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700450 /*
451 * If we've already gotten our DATAEND / DATABLKEND
452 * for this request, then complete it through here.
453 */
San Mehat9d2bd732009-09-22 16:44:22 -0700454
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700455 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700456 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700457 host->curr.xfer_remain -= host->curr.xfer_size;
458 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700459 if (host->dummy_52_needed) {
460 mrq->data->bytes_xfered = host->curr.data_xfered;
461 host->dummy_52_sent = 1;
462 msmsdcc_start_command(host, &dummy52cmd,
463 MCI_CPSM_PROGENA);
464 goto out;
465 }
466 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530467 if (!mrq->data->stop || mrq->cmd->error ||
468 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700469 host->curr.mrq = NULL;
470 host->curr.cmd = NULL;
471 mrq->data->bytes_xfered = host->curr.data_xfered;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700472 del_timer(&host->req_tout_timer);
San Mehat9d2bd732009-09-22 16:44:22 -0700473 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700474
San Mehat9d2bd732009-09-22 16:44:22 -0700475 mmc_request_done(host->mmc, mrq);
476 return;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530477 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
478 || !mrq->sbc)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700479 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530480 }
San Mehat9d2bd732009-09-22 16:44:22 -0700481 }
482
483out:
484 spin_unlock_irqrestore(&host->lock, flags);
485 return;
486}
487
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700488#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
489/**
490 * Callback notification from SPS driver
491 *
492 * This callback function gets triggered called from
493 * SPS driver when requested SPS data transfer is
494 * completed.
495 *
496 * SPS driver invokes this callback in BAM irq context so
497 * SDCC driver schedule a tasklet for further processing
498 * this callback notification at later point of time in
499 * tasklet context and immediately returns control back
500 * to SPS driver.
501 *
502 * @nofity - Pointer to sps event notify sturcture
503 *
504 */
505static void
506msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
507{
508 struct msmsdcc_host *host =
509 (struct msmsdcc_host *)
510 ((struct sps_event_notify *)notify)->user;
511
512 host->sps.notify = *notify;
513 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
514 mmc_hostname(host->mmc), __func__, notify->event_id,
515 notify->data.transfer.iovec.addr,
516 notify->data.transfer.iovec.size,
517 notify->data.transfer.iovec.flags);
518 /* Schedule a tasklet for completing data transfer */
519 tasklet_schedule(&host->sps.tlet);
520}
521
522/**
523 * Tasklet handler for processing SPS callback event
524 *
525 * This function processing SPS event notification and
526 * checks if the SPS transfer is completed or not and
527 * then accordingly notifies status to MMC core layer.
528 *
529 * This function is called in tasklet context.
530 *
531 * @data - Pointer to sdcc driver data
532 *
533 */
534static void msmsdcc_sps_complete_tlet(unsigned long data)
535{
536 unsigned long flags;
537 int i, rc;
538 u32 data_xfered = 0;
539 struct mmc_request *mrq;
540 struct sps_iovec iovec;
541 struct sps_pipe *sps_pipe_handle;
542 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
543 struct sps_event_notify *notify = &host->sps.notify;
544
545 spin_lock_irqsave(&host->lock, flags);
546 if (host->sps.dir == DMA_FROM_DEVICE)
547 sps_pipe_handle = host->sps.prod.pipe_handle;
548 else
549 sps_pipe_handle = host->sps.cons.pipe_handle;
550 mrq = host->curr.mrq;
551
552 if (!mrq) {
553 spin_unlock_irqrestore(&host->lock, flags);
554 return;
555 }
556
557 pr_debug("%s: %s: sps event_id=%d\n",
558 mmc_hostname(host->mmc), __func__,
559 notify->event_id);
560
561 if (msmsdcc_is_dml_busy(host)) {
562 /* oops !!! this should never happen. */
563 pr_err("%s: %s: Received SPS EOT event"
564 " but DML HW is still busy !!!\n",
565 mmc_hostname(host->mmc), __func__);
566 }
567 /*
568 * Got End of transfer event!!! Check if all of the data
569 * has been transferred?
570 */
571 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
572 rc = sps_get_iovec(sps_pipe_handle, &iovec);
573 if (rc) {
574 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
575 mmc_hostname(host->mmc), __func__, rc, i);
576 break;
577 }
578 data_xfered += iovec.size;
579 }
580
581 if (data_xfered == host->curr.xfer_size) {
582 host->curr.data_xfered = host->curr.xfer_size;
583 host->curr.xfer_remain -= host->curr.xfer_size;
584 pr_debug("%s: Data xfer success. data_xfered=0x%x",
585 mmc_hostname(host->mmc),
586 host->curr.xfer_size);
587 } else {
588 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
589 " xfer_size=%d", mmc_hostname(host->mmc),
590 data_xfered, host->curr.xfer_size);
591 msmsdcc_reset_and_restore(host);
592 if (!mrq->data->error)
593 mrq->data->error = -EIO;
594 }
595
596 /* Unmap sg buffers */
597 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
598 host->sps.dir);
599
600 host->sps.sg = NULL;
601 host->sps.busy = 0;
602
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530603 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
604 (host->curr.wait_for_auto_prog_done &&
605 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700606 /*
607 * If we've already gotten our DATAEND / DATABLKEND
608 * for this request, then complete it through here.
609 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700610
611 if (!mrq->data->error) {
612 host->curr.data_xfered = host->curr.xfer_size;
613 host->curr.xfer_remain -= host->curr.xfer_size;
614 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700615 if (host->dummy_52_needed) {
616 mrq->data->bytes_xfered = host->curr.data_xfered;
617 host->dummy_52_sent = 1;
618 msmsdcc_start_command(host, &dummy52cmd,
619 MCI_CPSM_PROGENA);
620 return;
621 }
622 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530623 if (!mrq->data->stop || mrq->cmd->error ||
624 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700625 host->curr.mrq = NULL;
626 host->curr.cmd = NULL;
627 mrq->data->bytes_xfered = host->curr.data_xfered;
628 del_timer(&host->req_tout_timer);
629 spin_unlock_irqrestore(&host->lock, flags);
630
631 mmc_request_done(host->mmc, mrq);
632 return;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530633 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
634 || !mrq->sbc)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700635 msmsdcc_start_command(host, mrq->data->stop, 0);
636 }
637 }
638 spin_unlock_irqrestore(&host->lock, flags);
639}
640
641/**
642 * Exit from current SPS data transfer
643 *
644 * This function exits from current SPS data transfer.
645 *
646 * This function should be called when error condition
647 * is encountered during data transfer.
648 *
649 * @host - Pointer to sdcc host structure
650 *
651 */
652static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
653{
654 struct mmc_request *mrq;
655
656 mrq = host->curr.mrq;
657 BUG_ON(!mrq);
658
659 msmsdcc_reset_and_restore(host);
660 if (!mrq->data->error)
661 mrq->data->error = -EIO;
662
663 /* Unmap sg buffers */
664 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
665 host->sps.dir);
666
667 host->sps.sg = NULL;
668 host->sps.busy = 0;
669 if (host->curr.data)
670 msmsdcc_stop_data(host);
671
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530672 if (!mrq->data->stop || mrq->cmd->error ||
673 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700674 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530675 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
676 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700677 msmsdcc_start_command(host, mrq->data->stop, 0);
678
679}
680#else
681static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
682static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
683static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
684#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
685
686static void msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
687
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530688static void
689msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
690 unsigned int result,
691 struct msm_dmov_errdata *err)
692{
693 struct msmsdcc_dma_data *dma_data =
694 container_of(cmd, struct msmsdcc_dma_data, hdr);
695 struct msmsdcc_host *host = dma_data->host;
696
697 dma_data->result = result;
698 if (err)
699 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
700
701 tasklet_schedule(&host->dma_tlet);
702}
703
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700704static int msmsdcc_check_dma_op_req(struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700705{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700706 if (((data->blksz * data->blocks) < MCI_FIFOSIZE) ||
707 ((data->blksz * data->blocks) % MCI_FIFOSIZE))
San Mehat9d2bd732009-09-22 16:44:22 -0700708 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700709 else
710 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700711}
712
713static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
714{
715 struct msmsdcc_nc_dmadata *nc;
716 dmov_box *box;
717 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700718 unsigned int n;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700719 int i;
San Mehat9d2bd732009-09-22 16:44:22 -0700720 struct scatterlist *sg = data->sg;
721
Krishna Konda25786ec2011-07-25 16:21:36 -0700722 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700723 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700724
Krishna Konda25786ec2011-07-25 16:21:36 -0700725 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
726
San Mehat9d2bd732009-09-22 16:44:22 -0700727 host->dma.sg = data->sg;
728 host->dma.num_ents = data->sg_len;
729
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700730 BUG_ON(host->dma.num_ents > NR_SG); /* Prevent memory corruption */
San Mehat56a8b5b2009-11-21 12:29:46 -0800731
San Mehat9d2bd732009-09-22 16:44:22 -0700732 nc = host->dma.nc;
733
San Mehat9d2bd732009-09-22 16:44:22 -0700734 if (data->flags & MMC_DATA_READ)
735 host->dma.dir = DMA_FROM_DEVICE;
736 else
737 host->dma.dir = DMA_TO_DEVICE;
738
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700739 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
San Mehat9d2bd732009-09-22 16:44:22 -0700740 host->curr.user_pages = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700741 box = &nc->cmd[0];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700742 for (i = 0; i < host->dma.num_ents; i++) {
San Mehat9d2bd732009-09-22 16:44:22 -0700743 box->cmd = CMD_MODE_BOX;
744
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700745 /* Initialize sg dma address */
746 sg->dma_address = pfn_to_dma(mmc_dev(host->mmc),
747 page_to_pfn(sg_page(sg)))
748 + sg->offset;
749
750 if (i == (host->dma.num_ents - 1))
San Mehat9d2bd732009-09-22 16:44:22 -0700751 box->cmd |= CMD_LC;
752 rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ?
753 (sg_dma_len(sg) / MCI_FIFOSIZE) + 1 :
754 (sg_dma_len(sg) / MCI_FIFOSIZE) ;
755
756 if (data->flags & MMC_DATA_READ) {
757 box->src_row_addr = msmsdcc_fifo_addr(host);
758 box->dst_row_addr = sg_dma_address(sg);
759
760 box->src_dst_len = (MCI_FIFOSIZE << 16) |
761 (MCI_FIFOSIZE);
762 box->row_offset = MCI_FIFOSIZE;
763
764 box->num_rows = rows * ((1 << 16) + 1);
Krishna Konda25786ec2011-07-25 16:21:36 -0700765 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
San Mehat9d2bd732009-09-22 16:44:22 -0700766 } else {
767 box->src_row_addr = sg_dma_address(sg);
768 box->dst_row_addr = msmsdcc_fifo_addr(host);
769
770 box->src_dst_len = (MCI_FIFOSIZE << 16) |
771 (MCI_FIFOSIZE);
772 box->row_offset = (MCI_FIFOSIZE << 16);
773
774 box->num_rows = rows * ((1 << 16) + 1);
Krishna Konda25786ec2011-07-25 16:21:36 -0700775 box->cmd |= CMD_DST_CRCI(host->dma.crci);
San Mehat9d2bd732009-09-22 16:44:22 -0700776 }
777 box++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700778 sg++;
779 }
780
781 /* location of command block must be 64 bit aligned */
782 BUG_ON(host->dma.cmd_busaddr & 0x07);
783
784 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
785 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
786 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
787 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700788
789 n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
790 host->dma.num_ents, host->dma.dir);
791 /* dsb inside dma_map_sg will write nc out to mem as well */
792
793 if (n != host->dma.num_ents) {
794 pr_err("%s: Unable to map in all sg elements\n",
795 mmc_hostname(host->mmc));
796 host->dma.sg = NULL;
797 host->dma.num_ents = 0;
798 return -ENOMEM;
San Mehat56a8b5b2009-11-21 12:29:46 -0800799 }
San Mehat9d2bd732009-09-22 16:44:22 -0700800
801 return 0;
802}
803
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700804#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
805/**
806 * Submits data transfer request to SPS driver
807 *
808 * This function make sg (scatter gather) data buffers
809 * DMA ready and then submits them to SPS driver for
810 * transfer.
811 *
812 * @host - Pointer to sdcc host structure
813 * @data - Pointer to mmc_data structure
814 *
815 * @return 0 if success else negative value
816 */
817static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
818 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -0800819{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700820 int rc = 0;
821 u32 flags;
822 int i;
823 u32 addr, len, data_cnt;
824 struct scatterlist *sg = data->sg;
825 struct sps_pipe *sps_pipe_handle;
826
827 BUG_ON(data->sg_len > NR_SG); /* Prevent memory corruption */
828
829 host->sps.sg = data->sg;
830 host->sps.num_ents = data->sg_len;
831 host->sps.xfer_req_cnt = 0;
832 if (data->flags & MMC_DATA_READ) {
833 host->sps.dir = DMA_FROM_DEVICE;
834 sps_pipe_handle = host->sps.prod.pipe_handle;
835 } else {
836 host->sps.dir = DMA_TO_DEVICE;
837 sps_pipe_handle = host->sps.cons.pipe_handle;
838 }
839
840 /* Make sg buffers DMA ready */
841 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
842 host->sps.dir);
843
844 if (rc != data->sg_len) {
845 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
846 mmc_hostname(host->mmc), rc);
847 host->sps.sg = NULL;
848 host->sps.num_ents = 0;
849 rc = -ENOMEM;
850 goto dma_map_err;
851 }
852
853 pr_debug("%s: %s: %s: pipe=0x%x, total_xfer=0x%x, sg_len=%d\n",
854 mmc_hostname(host->mmc), __func__,
855 host->sps.dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
856 (u32)sps_pipe_handle, host->curr.xfer_size, data->sg_len);
857
858 for (i = 0; i < data->sg_len; i++) {
859 /*
860 * Check if this is the last buffer to transfer?
861 * If yes then set the INT and EOT flags.
862 */
863 len = sg_dma_len(sg);
864 addr = sg_dma_address(sg);
865 flags = 0;
866 while (len > 0) {
867 if (len > SPS_MAX_DESC_SIZE) {
868 data_cnt = SPS_MAX_DESC_SIZE;
869 } else {
870 data_cnt = len;
871 if (i == data->sg_len - 1)
872 flags = SPS_IOVEC_FLAG_INT |
873 SPS_IOVEC_FLAG_EOT;
874 }
875 rc = sps_transfer_one(sps_pipe_handle, addr,
876 data_cnt, host, flags);
877 if (rc) {
878 pr_err("%s: sps_transfer_one() error! rc=%d,"
879 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
880 mmc_hostname(host->mmc), rc,
881 (u32)sps_pipe_handle, (u32)sg, i);
882 goto dma_map_err;
883 }
884 addr += data_cnt;
885 len -= data_cnt;
886 host->sps.xfer_req_cnt++;
887 }
888 sg++;
889 }
890 goto out;
891
892dma_map_err:
893 /* unmap sg buffers */
894 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
895 host->sps.dir);
896out:
897 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -0700898}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700899#else
900static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
901 struct mmc_data *data) { return 0; }
902#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -0700903
904static void
San Mehat56a8b5b2009-11-21 12:29:46 -0800905msmsdcc_start_command_deferred(struct msmsdcc_host *host,
906 struct mmc_command *cmd, u32 *c)
907{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700908 DBG(host, "op %02x arg %08x flags %08x\n",
909 cmd->opcode, cmd->arg, cmd->flags);
910
San Mehat56a8b5b2009-11-21 12:29:46 -0800911 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
912
913 if (cmd->flags & MMC_RSP_PRESENT) {
914 if (cmd->flags & MMC_RSP_136)
915 *c |= MCI_CPSM_LONGRSP;
916 *c |= MCI_CPSM_RESPONSE;
917 }
918
919 if (/*interrupt*/0)
920 *c |= MCI_CPSM_INTERRUPT;
921
922 if ((((cmd->opcode == 17) || (cmd->opcode == 18)) ||
923 ((cmd->opcode == 24) || (cmd->opcode == 25))) ||
924 (cmd->opcode == 53))
925 *c |= MCI_CSPM_DATCMD;
926
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700927 /* Check if AUTO CMD19 is required or not? */
Subhash Jadavani1d6ba602011-09-21 18:10:54 +0530928 if (host->tuning_needed) {
929 /*
930 * For open ended block read operation (without CMD23),
931 * AUTO_CMD19 bit should be set while sending the READ command.
932 * For close ended block read operation (with CMD23),
933 * AUTO_CMD19 bit should be set while sending CMD23.
934 */
935 if ((cmd->opcode == 23 && (host->curr.mrq->cmd->opcode == 17 ||
936 host->curr.mrq->cmd->opcode == 18)) ||
937 (!host->curr.mrq->sbc &&
938 (cmd->opcode == 17 || cmd->opcode == 18))) {
939 msmsdcc_enable_cdr_cm_sdc4_dll(host);
940 *c |= MCI_CSPM_AUTO_CMD19;
941 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700942 }
943
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +0530944 if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +0530945 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700946 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +0530947 }
948
San Mehat56a8b5b2009-11-21 12:29:46 -0800949 if (cmd == cmd->mrq->stop)
950 *c |= MCI_CSPM_MCIABORT;
951
San Mehat56a8b5b2009-11-21 12:29:46 -0800952 if (host->curr.cmd != NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700953 pr_err("%s: Overlapping command requests\n",
954 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -0800955 }
956 host->curr.cmd = cmd;
957}
958
959static void
960msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
961 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -0700962{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +0530963 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -0700964 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700965 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -0700966 unsigned int pio_irqmask = 0;
967
968 host->curr.data = data;
969 host->curr.xfer_size = data->blksz * data->blocks;
970 host->curr.xfer_remain = host->curr.xfer_size;
971 host->curr.data_xfered = 0;
972 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530973 host->curr.got_auto_prog_done = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700974
975 memset(&host->pio, 0, sizeof(host->pio));
976
San Mehat9d2bd732009-09-22 16:44:22 -0700977 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
978
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530979 if (host->curr.wait_for_auto_prog_done)
980 datactrl |= MCI_AUTO_PROG_DONE;
981
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700982 if (!msmsdcc_check_dma_op_req(data)) {
983 if (host->is_dma_mode && !msmsdcc_config_dma(host, data)) {
984 datactrl |= MCI_DPSM_DMAENABLE;
985 } else if (host->is_sps_mode) {
986 if (!msmsdcc_is_dml_busy(host)) {
987 if (!msmsdcc_sps_start_xfer(host, data)) {
988 /* Now kick start DML transfer */
989 mb();
990 msmsdcc_dml_start_xfer(host, data);
991 datactrl |= MCI_DPSM_DMAENABLE;
992 host->sps.busy = 1;
993 }
994 } else {
995 /*
996 * Can't proceed with new transfer as
997 * previous trasnfer is already in progress.
998 * There is no point of going into PIO mode
999 * as well. Is this a time to do kernel panic?
1000 */
1001 pr_err("%s: %s: DML HW is busy!!!"
1002 " Can't perform new SPS transfers"
1003 " now\n", mmc_hostname(host->mmc),
1004 __func__);
1005 }
1006 }
1007 }
1008
1009 /* Is data transfer in PIO mode required? */
1010 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001011 host->pio.sg = data->sg;
1012 host->pio.sg_len = data->sg_len;
1013 host->pio.sg_off = 0;
1014
1015 if (data->flags & MMC_DATA_READ) {
1016 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1017 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1018 pio_irqmask |= MCI_RXDATAAVLBLMASK;
1019 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001020 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1021 MCI_TXFIFOEMPTYMASK;
San Mehat9d2bd732009-09-22 16:44:22 -07001022 }
1023
1024 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301025 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
Subhash Jadavanibbf38a32011-10-12 16:47:52 +05301026 else if (data->flags & MMC_DATA_WRITE)
1027 datactrl |= MCI_DATA_PEND;
San Mehat9d2bd732009-09-22 16:44:22 -07001028
San Mehat56a8b5b2009-11-21 12:29:46 -08001029 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001030 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001031 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -07001032
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001033 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
1034 /* Use ADM (Application Data Mover) HW for Data transfer */
1035 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001036 host->cmd_timeout = timeout;
1037 host->cmd_pio_irqmask = pio_irqmask;
1038 host->cmd_datactrl = datactrl;
1039 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001040
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001041 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1042 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001043 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001044
1045 if (cmd) {
1046 msmsdcc_start_command_deferred(host, cmd, &c);
1047 host->cmd_c = c;
1048 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001049 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1050 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1051 host->base + MMCIMASK0);
1052 mb();
1053 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001054 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001055 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001056 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001057
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001058 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001059
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001060 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1061 (~(MCI_IRQ_PIO))) | pio_irqmask,
1062 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001063 writel_relaxed(datactrl, base + MMCIDATACTRL);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301064 /*
1065 * We don't need delay after writing to DATA_CTRL register
1066 * if we are not writing to CMD register immediately after
1067 * this. As we already have delay before sending the
1068 * command, we just need mb() here.
1069 */
1070 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001071
1072 if (cmd) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001073 msmsdcc_delay(host); /* Delay between data/command */
San Mehat56a8b5b2009-11-21 12:29:46 -08001074 /* Daisy-chain the command if requested */
1075 msmsdcc_start_command(host, cmd, c);
1076 }
San Mehat9d2bd732009-09-22 16:44:22 -07001077 }
1078}
1079
1080static void
1081msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1082{
San Mehat56a8b5b2009-11-21 12:29:46 -08001083 msmsdcc_start_command_deferred(host, cmd, &c);
1084 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001085}
1086
1087static void
1088msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1089 unsigned int status)
1090{
1091 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001092 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1093 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1094 pr_err("%s: Data CRC error\n",
1095 mmc_hostname(host->mmc));
1096 pr_err("%s: opcode 0x%.8x\n", __func__,
1097 data->mrq->cmd->opcode);
1098 pr_err("%s: blksz %d, blocks %d\n", __func__,
1099 data->blksz, data->blocks);
1100 data->error = -EILSEQ;
1101 }
San Mehat9d2bd732009-09-22 16:44:22 -07001102 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001103 /* CRC is optional for the bus test commands, not all
1104 * cards respond back with CRC. However controller
1105 * waits for the CRC and times out. Hence ignore the
1106 * data timeouts during the Bustest.
1107 */
1108 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1109 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1110 pr_err("%s: Data timeout\n",
1111 mmc_hostname(host->mmc));
1112 data->error = -ETIMEDOUT;
1113 }
San Mehat9d2bd732009-09-22 16:44:22 -07001114 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001115 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001116 data->error = -EIO;
1117 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001118 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001119 data->error = -EIO;
1120 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001121 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001122 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001123 data->error = -EIO;
1124 }
San Mehat9d2bd732009-09-22 16:44:22 -07001125
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001126 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001127 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001128 host->dummy_52_needed = 0;
1129}
San Mehat9d2bd732009-09-22 16:44:22 -07001130
1131static int
1132msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1133{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001134 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001135 uint32_t *ptr = (uint32_t *) buffer;
1136 int count = 0;
1137
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301138 if (remain % 4)
1139 remain = ((remain >> 2) + 1) << 2;
1140
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001141 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1142
1143 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001144 ptr++;
1145 count += sizeof(uint32_t);
1146
1147 remain -= sizeof(uint32_t);
1148 if (remain == 0)
1149 break;
1150 }
1151 return count;
1152}
1153
1154static int
1155msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001156 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001157{
1158 void __iomem *base = host->base;
1159 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001160 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001161
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001162 while (readl_relaxed(base + MMCISTATUS) &
1163 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1164 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001165
San Mehat9d2bd732009-09-22 16:44:22 -07001166 count = min(remain, maxcnt);
1167
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301168 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1169 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001170 ptr += count;
1171 remain -= count;
1172
1173 if (remain == 0)
1174 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001175 }
1176 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001177
1178 return ptr - buffer;
1179}
1180
San Mehat1cd22962010-02-03 12:59:29 -08001181static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001182msmsdcc_pio_irq(int irq, void *dev_id)
1183{
1184 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001185 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001186 uint32_t status;
1187
Murali Palnati36448a42011-09-02 15:06:18 +05301188 spin_lock(&host->lock);
1189
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001190 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001191
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001192 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301193 (MCI_IRQ_PIO)) == 0) {
1194 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001195 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301196 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001197
1198#if IRQ_DEBUG
1199 msmsdcc_print_status(host, "irq1-r", status);
1200#endif
1201
San Mehat9d2bd732009-09-22 16:44:22 -07001202 do {
1203 unsigned long flags;
1204 unsigned int remain, len;
1205 char *buffer;
1206
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001207 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1208 | MCI_RXDATAAVLBL)))
1209 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001210
1211 /* Map the current scatter buffer */
1212 local_irq_save(flags);
1213 buffer = kmap_atomic(sg_page(host->pio.sg),
1214 KM_BIO_SRC_IRQ) + host->pio.sg->offset;
1215 buffer += host->pio.sg_off;
1216 remain = host->pio.sg->length - host->pio.sg_off;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001217
San Mehat9d2bd732009-09-22 16:44:22 -07001218 len = 0;
1219 if (status & MCI_RXACTIVE)
1220 len = msmsdcc_pio_read(host, buffer, remain);
1221 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001222 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001223
1224 /* Unmap the buffer */
1225 kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
1226 local_irq_restore(flags);
1227
1228 host->pio.sg_off += len;
1229 host->curr.xfer_remain -= len;
1230 host->curr.data_xfered += len;
1231 remain -= len;
1232
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001233 if (remain) /* Done with this page? */
1234 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001235
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001236 if (status & MCI_RXACTIVE && host->curr.user_pages)
1237 flush_dcache_page(sg_page(host->pio.sg));
San Mehat9d2bd732009-09-22 16:44:22 -07001238
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001239 if (!--host->pio.sg_len) {
1240 memset(&host->pio, 0, sizeof(host->pio));
1241 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001242 }
1243
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001244 /* Advance to next sg */
1245 host->pio.sg++;
1246 host->pio.sg_off = 0;
1247
1248 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001249 } while (1);
1250
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001251 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1252 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1253 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1254 host->base + MMCIMASK0);
1255 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301256 /*
1257 * back to back write to MASK0 register don't need
1258 * synchronization delay.
1259 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001260 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1261 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1262 }
1263 mb();
1264 } else if (!host->curr.xfer_remain) {
1265 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1266 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1267 mb();
1268 }
San Mehat9d2bd732009-09-22 16:44:22 -07001269
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001270 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001271
1272 return IRQ_HANDLED;
1273}
1274
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001275static void
1276msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1277
1278static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1279 struct mmc_data *data)
1280{
1281 u32 loop_cnt = 0;
1282
1283 /*
1284 * For read commands with data less than fifo size, it is possible to
1285 * get DATAEND first and RXDATA_AVAIL might be set later because of
1286 * synchronization delay through the asynchronous RX FIFO. Thus, for
1287 * such cases, even after DATAEND interrupt is received software
1288 * should poll for RXDATA_AVAIL until the requested data is read out
1289 * of FIFO. This change is needed to get around this abnormal but
1290 * sometimes expected behavior of SDCC3 controller.
1291 *
1292 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1293 * after the data is loaded into RX FIFO. This would amount to less
1294 * than a microsecond and thus looping for 1000 times is good enough
1295 * for that delay.
1296 */
1297 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1298 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1299 spin_unlock(&host->lock);
1300 msmsdcc_pio_irq(1, host);
1301 spin_lock(&host->lock);
1302 }
1303 }
1304 if (loop_cnt == 1000) {
1305 pr_info("%s: Timed out while polling for Rx Data\n",
1306 mmc_hostname(host->mmc));
1307 data->error = -ETIMEDOUT;
1308 msmsdcc_reset_and_restore(host);
1309 }
1310}
1311
San Mehat9d2bd732009-09-22 16:44:22 -07001312static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1313{
1314 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001315
1316 host->curr.cmd = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001317 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1318 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1319 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1320 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -07001321
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001322 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Sahitya Tummala5a0ae912011-07-18 13:34:01 +05301323 pr_debug("%s: Command timeout\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001324 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001325 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
1326 !host->cmd19_tuning_in_progress) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001327 pr_err("%s: Command CRC error\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001328 cmd->error = -EILSEQ;
1329 }
1330
1331 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001332 if (host->curr.data && host->dma.sg &&
1333 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001334 msm_dmov_stop_cmd(host->dma.channel,
1335 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001336 else if (host->curr.data && host->sps.sg &&
1337 host->is_sps_mode){
1338 /* Stop current SPS transfer */
1339 msmsdcc_sps_exit_curr_xfer(host);
1340 }
San Mehat9d2bd732009-09-22 16:44:22 -07001341 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301342 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001343 msmsdcc_stop_data(host);
1344 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301345 } else { /* host->data == NULL */
1346 if (!cmd->error && host->prog_enable) {
1347 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001348 host->prog_enable = 0;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301349 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001350 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301351 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301352 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301353 host->prog_enable = 0;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001354 if (host->dummy_52_needed)
1355 host->dummy_52_needed = 0;
1356 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001357 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301358 msmsdcc_request_end(host, cmd->mrq);
1359 }
1360 }
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301361 } else if ((cmd == host->curr.mrq->sbc) && cmd->data) {
1362 if (cmd->data->flags & MMC_DATA_READ)
1363 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1364 else
1365 msmsdcc_request_start(host, host->curr.mrq);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001366 }
1367}
1368
San Mehat9d2bd732009-09-22 16:44:22 -07001369static irqreturn_t
1370msmsdcc_irq(int irq, void *dev_id)
1371{
1372 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001373 u32 status;
1374 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001375 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001376
1377 spin_lock(&host->lock);
1378
1379 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001380 struct mmc_command *cmd;
1381 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001382
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001383 if (timer) {
1384 timer = 0;
1385 msmsdcc_delay(host);
1386 }
San Mehat865c8062009-11-13 13:42:06 -08001387
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001388 if (!host->clks_on) {
1389 pr_debug("%s: %s: SDIO async irq received\n",
1390 mmc_hostname(host->mmc), __func__);
1391 host->mmc->ios.clock = host->clk_rate;
1392 spin_unlock(&host->lock);
1393 host->mmc->ops->set_ios(host->mmc, &host->mmc->ios);
1394 spin_lock(&host->lock);
1395 if (host->plat->cfg_mpm_sdiowakeup &&
1396 (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
1397 wake_lock(&host->sdio_wlock);
1398 /* only ansyc interrupt can come when clocks are off */
1399 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301400 if (host->clk_rate <=
1401 msmsdcc_get_min_sup_clk_rate(host))
1402 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001403 }
1404
1405 status = readl_relaxed(host->base + MMCISTATUS);
1406
1407 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1408 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001409 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001410
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001411#if IRQ_DEBUG
1412 msmsdcc_print_status(host, "irq0-r", status);
1413#endif
1414 status &= readl_relaxed(host->base + MMCIMASK0);
1415 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301416 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301417 if (host->clk_rate <=
1418 msmsdcc_get_min_sup_clk_rate(host))
1419 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001420#if IRQ_DEBUG
1421 msmsdcc_print_status(host, "irq0-p", status);
1422#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001423
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001424#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
1425 if (status & MCI_SDIOINTROPE) {
1426 if (host->sdcc_suspending)
1427 wake_lock(&host->sdio_suspend_wlock);
1428 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001429 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001430#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001431 data = host->curr.data;
1432
1433 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001434 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1435 MCI_CMDTIMEOUT)) {
1436 if (status & MCI_CMDTIMEOUT)
1437 pr_debug("%s: dummy CMD52 timeout\n",
1438 mmc_hostname(host->mmc));
1439 if (status & MCI_CMDCRCFAIL)
1440 pr_debug("%s: dummy CMD52 CRC failed\n",
1441 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001442 host->dummy_52_sent = 0;
1443 host->dummy_52_needed = 0;
1444 if (data) {
1445 msmsdcc_stop_data(host);
1446 msmsdcc_request_end(host, data->mrq);
1447 }
1448 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001449 spin_unlock(&host->lock);
1450 return IRQ_HANDLED;
1451 }
1452 break;
1453 }
1454
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001455 /*
1456 * Check for proper command response
1457 */
1458 cmd = host->curr.cmd;
1459 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1460 MCI_CMDTIMEOUT | MCI_PROGDONE |
1461 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1462 msmsdcc_do_cmdirq(host, status);
1463 }
1464
1465 if (data) {
1466 /* Check for data errors */
1467 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1468 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1469 msmsdcc_data_err(host, data, status);
1470 host->curr.data_xfered = 0;
1471 if (host->dma.sg && host->is_dma_mode)
1472 msm_dmov_stop_cmd(host->dma.channel,
1473 &host->dma.hdr, 0);
1474 else if (host->sps.sg && host->is_sps_mode) {
1475 /* Stop current SPS transfer */
1476 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301477 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001478 msmsdcc_reset_and_restore(host);
1479 if (host->curr.data)
1480 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301481 if (!data->stop || (host->curr.mrq->sbc
1482 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001483 timer |=
1484 msmsdcc_request_end(host,
1485 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301486 else if ((host->curr.mrq->sbc
1487 && data->error) ||
1488 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001489 msmsdcc_start_command(host,
1490 data->stop,
1491 0);
1492 timer = 1;
1493 }
1494 }
1495 }
1496
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301497 /* Check for prog done */
1498 if (host->curr.wait_for_auto_prog_done &&
1499 (status & MCI_PROGDONE))
1500 host->curr.got_auto_prog_done = 1;
1501
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001502 /* Check for data done */
1503 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1504 host->curr.got_dataend = 1;
1505
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301506 if (host->curr.got_dataend &&
1507 (!host->curr.wait_for_auto_prog_done ||
1508 (host->curr.wait_for_auto_prog_done &&
1509 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001510 /*
1511 * If DMA is still in progress, we complete
1512 * via the completion handler
1513 */
1514 if (!host->dma.busy && !host->sps.busy) {
1515 /*
1516 * There appears to be an issue in the
1517 * controller where if you request a
1518 * small block transfer (< fifo size),
1519 * you may get your DATAEND/DATABLKEND
1520 * irq without the PIO data irq.
1521 *
1522 * Check to see if theres still data
1523 * to be read, and simulate a PIO irq.
1524 */
1525 if (data->flags & MMC_DATA_READ)
1526 msmsdcc_wait_for_rxdata(host,
1527 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001528 if (!data->error) {
1529 host->curr.data_xfered =
1530 host->curr.xfer_size;
1531 host->curr.xfer_remain -=
1532 host->curr.xfer_size;
1533 }
1534
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001535 if (!host->dummy_52_needed) {
1536 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301537 if (!data->stop ||
1538 (host->curr.mrq->sbc
1539 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001540 msmsdcc_request_end(
1541 host,
1542 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301543 else if ((host->curr.mrq->sbc
1544 && data->error) ||
1545 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001546 msmsdcc_start_command(
1547 host,
1548 data->stop, 0);
1549 timer = 1;
1550 }
1551 } else {
1552 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001553 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001554 &dummy52cmd,
1555 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001556 }
1557 }
1558 }
1559 }
1560
San Mehat9d2bd732009-09-22 16:44:22 -07001561 ret = 1;
1562 } while (status);
1563
1564 spin_unlock(&host->lock);
1565
San Mehat9d2bd732009-09-22 16:44:22 -07001566 return IRQ_RETVAL(ret);
1567}
1568
1569static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001570msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1571{
Subhash Jadavanibbf38a32011-10-12 16:47:52 +05301572 if (mrq->data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001573 /* Queue/read data, daisy-chain command when data starts */
Subhash Jadavanibbf38a32011-10-12 16:47:52 +05301574 if (mrq->sbc && (mrq->data->flags & MMC_DATA_READ))
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301575 msmsdcc_start_data(host, mrq->data, mrq->sbc, 0);
1576 else
1577 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001578 } else {
1579 msmsdcc_start_command(host, mrq->cmd, 0);
1580 }
1581}
1582
1583static void
San Mehat9d2bd732009-09-22 16:44:22 -07001584msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1585{
1586 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001587 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001588
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001589 /*
1590 * Get the SDIO AL client out of LPM.
1591 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001592 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001593 if (host->plat->is_sdio_al_client)
1594 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001595
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301596 /* check if sps pipe reset is pending? */
1597 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1598 msmsdcc_sps_pipes_reset_and_restore(host);
1599 host->sps.pipe_reset_pending = false;
1600 }
1601
San Mehat9d2bd732009-09-22 16:44:22 -07001602 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001603 WARN(host->curr.mrq, "Request in progress\n");
1604 WARN(!host->pwr, "SDCC power is turned off\n");
1605 WARN(!host->clks_on, "SDCC clocks are turned off\n");
1606 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
San Mehat9d2bd732009-09-22 16:44:22 -07001607
1608 if (host->eject) {
1609 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1610 mrq->cmd->error = 0;
1611 mrq->data->bytes_xfered = mrq->data->blksz *
1612 mrq->data->blocks;
1613 } else
1614 mrq->cmd->error = -ENOMEDIUM;
1615
1616 spin_unlock_irqrestore(&host->lock, flags);
1617 mmc_request_done(mmc, mrq);
1618 return;
1619 }
1620
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301621 /*
1622 * Kick the software command timeout timer here.
1623 * Timer expires in 10 secs.
1624 */
1625 mod_timer(&host->req_tout_timer,
1626 (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
San Mehat9d2bd732009-09-22 16:44:22 -07001627
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301628 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301629 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301630 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
1631 mrq->cmd->opcode == 54) {
1632 if (!host->plat->sdcc_v4_sup)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001633 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301634 else
1635 /*
1636 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
1637 * write operations using CMD53 and CMD54.
1638 * Setting this bit with CMD53 would
1639 * automatically triggers PROG_DONE interrupt
1640 * without the need of sending dummy CMD52.
1641 */
1642 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001643 }
San Mehat9d2bd732009-09-22 16:44:22 -07001644 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301645
Pratibhasagar V00b94332011-10-18 14:57:27 +05301646 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301647 mrq->sbc->mrq = mrq;
1648 mrq->sbc->data = mrq->data;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301649 if (mrq->data->flags & MMC_DATA_WRITE) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301650 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301651 msmsdcc_start_command(host, mrq->sbc, 0);
1652 } else {
1653 msmsdcc_request_start(host, mrq);
1654 }
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301655 } else {
1656 msmsdcc_request_start(host, mrq);
1657 }
1658
San Mehat9d2bd732009-09-22 16:44:22 -07001659 spin_unlock_irqrestore(&host->lock, flags);
1660}
1661
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001662static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1663 int min_uV, int max_uV)
1664{
1665 int rc = 0;
1666
1667 if (vreg->set_voltage_sup) {
1668 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1669 if (rc) {
1670 pr_err("%s: regulator_set_voltage(%s) failed."
1671 " min_uV=%d, max_uV=%d, rc=%d\n",
1672 __func__, vreg->name, min_uV, max_uV, rc);
1673 }
1674 }
1675
1676 return rc;
1677}
1678
1679static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1680 int uA_load)
1681{
1682 int rc = 0;
1683
1684 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1685 if (rc < 0)
1686 pr_err("%s: regulator_set_optimum_mode(reg=%s, uA_load=%d)"
1687 " failed. rc=%d\n", __func__, vreg->name,
1688 uA_load, rc);
1689 else
1690 /* regulator_set_optimum_mode() can return non zero value
1691 * even for success case.
1692 */
1693 rc = 0;
1694
1695 return rc;
1696}
1697
1698static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1699 struct device *dev)
1700{
1701 int rc = 0;
1702
1703 /* check if regulator is already initialized? */
1704 if (vreg->reg)
1705 goto out;
1706
1707 /* Get the regulator handle */
1708 vreg->reg = regulator_get(dev, vreg->name);
1709 if (IS_ERR(vreg->reg)) {
1710 rc = PTR_ERR(vreg->reg);
1711 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
1712 __func__, vreg->name, rc);
1713 }
1714out:
1715 return rc;
1716}
1717
1718static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
1719{
1720 if (vreg->reg)
1721 regulator_put(vreg->reg);
1722}
1723
1724/* This init function should be called only once for each SDCC slot */
1725static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
1726{
1727 int rc = 0;
1728 struct msm_mmc_slot_reg_data *curr_slot;
1729 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1730 struct device *dev = mmc_dev(host->mmc);
1731
1732 curr_slot = host->plat->vreg_data;
1733 if (!curr_slot)
1734 goto out;
1735
1736 curr_vdd_reg = curr_slot->vdd_data;
1737 curr_vccq_reg = curr_slot->vccq_data;
1738 curr_vddp_reg = curr_slot->vddp_data;
1739
1740 if (is_init) {
1741 /*
1742 * Get the regulator handle from voltage regulator framework
1743 * and then try to set the voltage level for the regulator
1744 */
1745 if (curr_vdd_reg) {
1746 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
1747 if (rc)
1748 goto out;
1749 }
1750 if (curr_vccq_reg) {
1751 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
1752 if (rc)
1753 goto vdd_reg_deinit;
1754 }
1755 if (curr_vddp_reg) {
1756 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
1757 if (rc)
1758 goto vccq_reg_deinit;
1759 }
1760 goto out;
1761 } else {
1762 /* Deregister all regulators from regulator framework */
1763 goto vddp_reg_deinit;
1764 }
1765vddp_reg_deinit:
1766 if (curr_vddp_reg)
1767 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
1768vccq_reg_deinit:
1769 if (curr_vccq_reg)
1770 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
1771vdd_reg_deinit:
1772 if (curr_vdd_reg)
1773 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
1774out:
1775 return rc;
1776}
1777
1778static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
1779{
1780 int rc = 0;
1781
Subhash Jadavanicc922692011-08-01 23:05:01 +05301782 /* Put regulator in HPM (high power mode) */
1783 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
1784 if (rc < 0)
1785 goto out;
1786
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001787 if (!vreg->is_enabled) {
1788 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301789 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
1790 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001791 if (rc)
1792 goto out;
1793
1794 rc = regulator_enable(vreg->reg);
1795 if (rc) {
1796 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
1797 __func__, vreg->name, rc);
1798 goto out;
1799 }
1800 vreg->is_enabled = true;
1801 }
1802
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001803out:
1804 return rc;
1805}
1806
1807static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
1808{
1809 int rc = 0;
1810
1811 /* Never disable regulator marked as always_on */
1812 if (vreg->is_enabled && !vreg->always_on) {
1813 rc = regulator_disable(vreg->reg);
1814 if (rc) {
1815 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
1816 __func__, vreg->name, rc);
1817 goto out;
1818 }
1819 vreg->is_enabled = false;
1820
1821 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
1822 if (rc < 0)
1823 goto out;
1824
1825 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301826 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001827 if (rc)
1828 goto out;
1829 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
1830 /* Put always_on regulator in LPM (low power mode) */
1831 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
1832 if (rc < 0)
1833 goto out;
1834 }
1835out:
1836 return rc;
1837}
1838
1839static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
1840{
1841 int rc = 0, i;
1842 struct msm_mmc_slot_reg_data *curr_slot;
1843 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1844 struct msm_mmc_reg_data *vreg_table[3];
1845
1846 curr_slot = host->plat->vreg_data;
1847 if (!curr_slot)
1848 goto out;
1849
1850 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
1851 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
1852 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
1853
1854 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
1855 if (vreg_table[i]) {
1856 if (enable)
1857 rc = msmsdcc_vreg_enable(vreg_table[i]);
1858 else
1859 rc = msmsdcc_vreg_disable(vreg_table[i]);
1860 if (rc)
1861 goto out;
1862 }
1863 }
1864out:
1865 return rc;
1866}
1867
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301868static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001869{
1870 int rc = 0;
1871
1872 if (host->plat->vreg_data) {
1873 struct msm_mmc_reg_data *vddp_reg =
1874 host->plat->vreg_data->vddp_data;
1875
1876 if (vddp_reg && vddp_reg->is_enabled)
1877 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
1878 }
1879
1880 return rc;
1881}
1882
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301883static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
1884{
1885 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1886 int rc = 0;
1887
1888 if (curr_slot && curr_slot->vddp_data) {
1889 rc = msmsdcc_set_vddp_level(host,
1890 curr_slot->vddp_data->low_vol_level);
1891
1892 if (rc)
1893 pr_err("%s: %s: failed to change vddp level to %d",
1894 mmc_hostname(host->mmc), __func__,
1895 curr_slot->vddp_data->low_vol_level);
1896 }
1897
1898 return rc;
1899}
1900
1901static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
1902{
1903 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1904 int rc = 0;
1905
1906 if (curr_slot && curr_slot->vddp_data) {
1907 rc = msmsdcc_set_vddp_level(host,
1908 curr_slot->vddp_data->high_vol_level);
1909
1910 if (rc)
1911 pr_err("%s: %s: failed to change vddp level to %d",
1912 mmc_hostname(host->mmc), __func__,
1913 curr_slot->vddp_data->high_vol_level);
1914 }
1915
1916 return rc;
1917}
1918
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001919static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
1920{
1921 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
1922 return 1;
1923 return 0;
1924}
1925
1926static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
1927{
1928 if (enable) {
1929 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1930 clk_enable(host->dfab_pclk);
1931 if (!IS_ERR(host->pclk))
1932 clk_enable(host->pclk);
1933 clk_enable(host->clk);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301934 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001935 } else {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301936 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001937 clk_disable(host->clk);
1938 if (!IS_ERR(host->pclk))
1939 clk_disable(host->pclk);
1940 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1941 clk_disable(host->dfab_pclk);
1942 }
1943}
1944
1945static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
1946 unsigned int req_clk)
1947{
1948 unsigned int sel_clk = -1;
1949
1950 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
1951 unsigned char cnt;
1952
1953 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
1954 if (host->plat->sup_clk_table[cnt] > req_clk)
1955 break;
1956 else if (host->plat->sup_clk_table[cnt] == req_clk) {
1957 sel_clk = host->plat->sup_clk_table[cnt];
1958 break;
1959 } else
1960 sel_clk = host->plat->sup_clk_table[cnt];
1961 }
1962 } else {
1963 if ((req_clk < host->plat->msmsdcc_fmax) &&
1964 (req_clk > host->plat->msmsdcc_fmid))
1965 sel_clk = host->plat->msmsdcc_fmid;
1966 else
1967 sel_clk = req_clk;
1968 }
1969
1970 return sel_clk;
1971}
1972
1973static inline unsigned int msmsdcc_get_min_sup_clk_rate(
1974 struct msmsdcc_host *host)
1975{
1976 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
1977 return host->plat->sup_clk_table[0];
1978 else
1979 return host->plat->msmsdcc_fmin;
1980}
1981
1982static inline unsigned int msmsdcc_get_max_sup_clk_rate(
1983 struct msmsdcc_host *host)
1984{
1985 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
1986 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
1987 else
1988 return host->plat->msmsdcc_fmax;
1989}
1990
1991static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05301992{
1993 struct msm_mmc_gpio_data *curr;
1994 int i, rc = 0;
1995
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001996 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301997 for (i = 0; i < curr->size; i++) {
1998 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001999 if (curr->gpio[i].is_always_on &&
2000 curr->gpio[i].is_enabled)
2001 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302002 rc = gpio_request(curr->gpio[i].no,
2003 curr->gpio[i].name);
2004 if (rc) {
2005 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2006 mmc_hostname(host->mmc),
2007 curr->gpio[i].no,
2008 curr->gpio[i].name, rc);
2009 goto free_gpios;
2010 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002011 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302012 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002013 if (curr->gpio[i].is_always_on)
2014 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302015 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002016 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302017 }
2018 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002019 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302020
2021free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002022 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302023 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002024 curr->gpio[i].is_enabled = false;
2025 }
2026out:
2027 return rc;
2028}
2029
2030static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2031{
2032 struct msm_mmc_pad_data *curr;
2033 int i;
2034
2035 curr = host->plat->pin_data->pad_data;
2036 for (i = 0; i < curr->drv->size; i++) {
2037 if (enable)
2038 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2039 curr->drv->on[i].val);
2040 else
2041 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2042 curr->drv->off[i].val);
2043 }
2044
2045 for (i = 0; i < curr->pull->size; i++) {
2046 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002047 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002048 curr->pull->on[i].val);
2049 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002050 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002051 curr->pull->off[i].val);
2052 }
2053
2054 return 0;
2055}
2056
2057static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2058{
2059 int rc = 0;
2060
2061 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2062 return 0;
2063
2064 if (host->plat->pin_data->is_gpio)
2065 rc = msmsdcc_setup_gpio(host, enable);
2066 else
2067 rc = msmsdcc_setup_pad(host, enable);
2068
2069 if (!rc)
2070 host->plat->pin_data->cfg_sts = enable;
2071
2072 return rc;
2073}
2074
2075static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2076{
2077 unsigned int wakeup_irq;
2078
2079 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2080 host->plat->sdiowakeup_irq :
2081 host->core_irqres->start;
2082
2083 if (!host->irq_wake_enabled) {
2084 enable_irq_wake(wakeup_irq);
2085 host->irq_wake_enabled = true;
2086 }
2087}
2088
2089static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2090{
2091 unsigned int wakeup_irq;
2092
2093 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2094 host->plat->sdiowakeup_irq :
2095 host->core_irqres->start;
2096
2097 if (host->irq_wake_enabled) {
2098 disable_irq_wake(wakeup_irq);
2099 host->irq_wake_enabled = false;
2100 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302101}
2102
San Mehat9d2bd732009-09-22 16:44:22 -07002103static void
2104msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2105{
2106 struct msmsdcc_host *host = mmc_priv(mmc);
2107 u32 clk = 0, pwr = 0;
2108 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002109 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002110 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002111
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002112 DBG(host, "ios->clock = %u\n", ios->clock);
Sahitya Tummala7a892482011-01-18 11:22:49 +05302113
San Mehat9d2bd732009-09-22 16:44:22 -07002114 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002115 spin_lock_irqsave(&host->lock, flags);
2116 if (!host->clks_on) {
2117 msmsdcc_setup_clocks(host, true);
2118 host->clks_on = 1;
2119 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2120 if (!host->plat->sdiowakeup_irq) {
2121 writel_relaxed(host->mci_irqenable,
2122 host->base + MMCIMASK0);
2123 mb();
2124 if (host->plat->cfg_mpm_sdiowakeup &&
2125 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2126 host->plat->cfg_mpm_sdiowakeup(
2127 mmc_dev(mmc), SDC_DAT1_DISWAKE);
2128 msmsdcc_disable_irq_wake(host);
2129 } else if (!(mmc->pm_flags &
2130 MMC_PM_WAKE_SDIO_IRQ)) {
2131 writel_relaxed(host->mci_irqenable,
2132 host->base + MMCIMASK0);
2133 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05302134 } else {
2135 writel_relaxed(host->mci_irqenable,
2136 host->base + MMCIMASK0);
2137 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002138 }
San Mehat9d2bd732009-09-22 16:44:22 -07002139 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002140 spin_unlock_irqrestore(&host->lock, flags);
2141
2142 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2143 /*
2144 * For DDR50 mode, controller needs clock rate to be
2145 * double than what is required on the SD card CLK pin.
2146 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302147 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002148 /*
2149 * Make sure that we don't double the clock if
2150 * doubled clock rate is already set
2151 */
2152 if (!host->ddr_doubled_clk_rate ||
2153 (host->ddr_doubled_clk_rate &&
2154 (host->ddr_doubled_clk_rate != ios->clock))) {
2155 host->ddr_doubled_clk_rate =
2156 msmsdcc_get_sup_clk_rate(
2157 host, (ios->clock * 2));
2158 clock = host->ddr_doubled_clk_rate;
2159 }
2160 } else {
2161 host->ddr_doubled_clk_rate = 0;
2162 }
2163
2164 if (clock != host->clk_rate) {
2165 rc = clk_set_rate(host->clk, clock);
2166 if (rc < 0)
2167 pr_debug("%s: failed to set clk rate %u\n",
2168 mmc_hostname(mmc), clock);
2169 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302170 host->reg_write_delay =
2171 (1 + ((3 * USEC_PER_SEC) /
2172 (host->clk_rate ? host->clk_rate :
2173 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002174 }
2175 /*
2176 * give atleast 2 MCLK cycles delay for clocks
2177 * and SDCC core to stabilize
2178 */
2179 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002180 clk |= MCI_CLK_ENABLE;
2181 }
2182
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002183 if (ios->bus_width == MMC_BUS_WIDTH_8)
2184 clk |= MCI_CLK_WIDEBUS_8;
2185 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2186 clk |= MCI_CLK_WIDEBUS_4;
2187 else
2188 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002189
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002190 if (msmsdcc_is_pwrsave(host))
2191 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002192
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002193 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002194
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002195 host->tuning_needed = 0;
2196 /*
2197 * Select the controller timing mode according
2198 * to current bus speed mode
2199 */
2200 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2201 (ios->timing == MMC_TIMING_UHS_SDR50)) {
2202 clk |= (4 << 14);
2203 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302204 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002205 clk |= (3 << 14);
2206 } else {
2207 clk |= (2 << 14); /* feedback clock */
2208 }
2209
2210 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2211 clk |= (2 << 23);
2212
2213 if (host->io_pad_pwr_switch)
2214 clk |= IO_PAD_PWR_SWITCH;
2215
2216 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
San Mehat9d2bd732009-09-22 16:44:22 -07002217 pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002218 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2219 pwr |= msmsdcc_setup_vreg(host, !!ios->vdd);
San Mehat9d2bd732009-09-22 16:44:22 -07002220
2221 switch (ios->power_mode) {
2222 case MMC_POWER_OFF:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002223 htc_pwrsink_set(PWRSINK_SDCARD, 0);
2224 if (!host->sdcc_irq_disabled) {
2225 if (host->plat->cfg_mpm_sdiowakeup)
2226 host->plat->cfg_mpm_sdiowakeup(
2227 mmc_dev(mmc), SDC_DAT1_DISABLE);
2228 disable_irq(host->core_irqres->start);
2229 host->sdcc_irq_disabled = 1;
2230 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302231 /*
2232 * As VDD pad rail is always on, set low voltage for VDD
2233 * pad rail when slot is unused (when card is not present
2234 * or during system suspend).
2235 */
2236 msmsdcc_set_vddp_low_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002237 msmsdcc_setup_pins(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002238 break;
2239 case MMC_POWER_UP:
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302240 /* writing PWR_UP bit is redundant */
San Mehat9d2bd732009-09-22 16:44:22 -07002241 pwr |= MCI_PWR_UP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002242 if (host->sdcc_irq_disabled) {
2243 if (host->plat->cfg_mpm_sdiowakeup)
2244 host->plat->cfg_mpm_sdiowakeup(
2245 mmc_dev(mmc), SDC_DAT1_ENABLE);
2246 enable_irq(host->core_irqres->start);
2247 host->sdcc_irq_disabled = 0;
2248 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302249 msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002250 msmsdcc_setup_pins(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07002251 break;
2252 case MMC_POWER_ON:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002253 htc_pwrsink_set(PWRSINK_SDCARD, 100);
San Mehat9d2bd732009-09-22 16:44:22 -07002254 pwr |= MCI_PWR_ON;
2255 break;
2256 }
2257
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002258 spin_lock_irqsave(&host->lock, flags);
2259 if (!host->clks_on) {
2260 /* force the clocks to be on */
2261 msmsdcc_setup_clocks(host, true);
2262 /*
2263 * give atleast 2 MCLK cycles delay for clocks
2264 * and SDCC core to stabilize
2265 */
2266 msmsdcc_delay(host);
2267 }
2268 writel_relaxed(clk, host->base + MMCICLOCK);
2269 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002270
2271 if (host->pwr != pwr) {
2272 host->pwr = pwr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002273 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302274 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002275 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002276 if (!host->clks_on) {
2277 /* force the clocks to be off */
2278 msmsdcc_setup_clocks(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002279 }
2280
2281 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
2282 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2283 if (!host->plat->sdiowakeup_irq) {
2284 writel_relaxed(MCI_SDIOINTMASK,
2285 host->base + MMCIMASK0);
2286 mb();
2287 if (host->plat->cfg_mpm_sdiowakeup &&
2288 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2289 host->plat->cfg_mpm_sdiowakeup(
2290 mmc_dev(mmc), SDC_DAT1_ENWAKE);
2291 msmsdcc_enable_irq_wake(host);
2292 } else if (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2293 writel_relaxed(0, host->base + MMCIMASK0);
2294 } else {
2295 writel_relaxed(MCI_SDIOINTMASK,
2296 host->base + MMCIMASK0);
2297 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302298 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002299 }
2300 msmsdcc_setup_clocks(host, false);
2301 host->clks_on = 0;
2302 }
San Mehat4adbbcc2009-11-08 13:00:37 -08002303 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002304}
2305
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002306int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2307{
2308 struct msmsdcc_host *host = mmc_priv(mmc);
2309 u32 clk;
2310
2311 clk = readl_relaxed(host->base + MMCICLOCK);
2312 pr_debug("Changing to pwr_save=%d", pwrsave);
2313 if (pwrsave && msmsdcc_is_pwrsave(host))
2314 clk |= MCI_CLK_PWRSAVE;
2315 else
2316 clk &= ~MCI_CLK_PWRSAVE;
2317 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302318 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002319
2320 return 0;
2321}
2322
2323static int msmsdcc_get_ro(struct mmc_host *mmc)
2324{
2325 int status = -ENOSYS;
2326 struct msmsdcc_host *host = mmc_priv(mmc);
2327
2328 if (host->plat->wpswitch) {
2329 status = host->plat->wpswitch(mmc_dev(mmc));
2330 } else if (host->plat->wpswitch_gpio) {
2331 status = gpio_request(host->plat->wpswitch_gpio,
2332 "SD_WP_Switch");
2333 if (status) {
2334 pr_err("%s: %s: Failed to request GPIO %d\n",
2335 mmc_hostname(mmc), __func__,
2336 host->plat->wpswitch_gpio);
2337 } else {
2338 status = gpio_direction_input(
2339 host->plat->wpswitch_gpio);
2340 if (!status) {
2341 /*
2342 * Wait for atleast 300ms as debounce
2343 * time for GPIO input to stabilize.
2344 */
2345 msleep(300);
2346 status = gpio_get_value_cansleep(
2347 host->plat->wpswitch_gpio);
2348 status ^= !host->plat->wpswitch_polarity;
2349 }
2350 gpio_free(host->plat->wpswitch_gpio);
2351 }
2352 }
2353
2354 if (status < 0)
2355 status = -ENOSYS;
2356 pr_debug("%s: Card read-only status %d\n", __func__, status);
2357
2358 return status;
2359}
2360
2361#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002362static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2363{
2364 struct msmsdcc_host *host = mmc_priv(mmc);
2365 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002366
2367 if (enable) {
2368 spin_lock_irqsave(&host->lock, flags);
2369 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
2370 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
2371 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2372 spin_unlock_irqrestore(&host->lock, flags);
2373 } else {
2374 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
2375 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
2376 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2377 }
2378 mb();
2379}
2380#endif /* CONFIG_MMC_MSM_SDIO_SUPPORT */
2381
2382#ifdef CONFIG_PM_RUNTIME
2383static int msmsdcc_enable(struct mmc_host *mmc)
2384{
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302385 int rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002386 struct device *dev = mmc->parent;
2387
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302388 if (dev->power.runtime_status == RPM_SUSPENDING) {
2389 if (mmc->suspend_task == current) {
2390 pm_runtime_get_noresume(dev);
2391 goto out;
2392 }
2393 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002394
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302395 rc = pm_runtime_get_sync(dev);
2396
2397 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002398 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2399 __func__, rc);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302400 return rc;
2401 }
2402out:
2403 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002404}
2405
2406static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2407{
2408 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302409 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002410
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302411 if (host->plat->disable_runtime_pm)
2412 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002413 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO)
2414 return -ENOTSUPP;
2415
2416 rc = pm_runtime_put_sync(mmc->parent);
2417
2418 if (rc < 0)
2419 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2420 __func__, rc);
2421 return rc;
2422}
2423#else
2424#define msmsdcc_enable NULL
2425#define msmsdcc_disable NULL
2426#endif
2427
2428static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2429 struct mmc_ios *ios)
2430{
2431 struct msmsdcc_host *host = mmc_priv(mmc);
2432 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302433 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002434
2435 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2436 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302437 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002438 goto out;
2439 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2440 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302441 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002442 goto out;
2443 }
San Mehat9d2bd732009-09-22 16:44:22 -07002444
2445 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002446 /*
2447 * If we are here means voltage switch from high voltage to
2448 * low voltage is required
2449 */
2450
2451 /*
2452 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2453 * register until they become all zeros.
2454 */
2455 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302456 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002457 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2458 mmc_hostname(mmc), __func__);
2459 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002460 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002461
2462 /* Stop SD CLK output. */
2463 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2464 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302465 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002466 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002467
2468 /*
2469 * Switch VDDPX from high voltage to low voltage
2470 * to change the VDD of the SD IO pads.
2471 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302472 rc = msmsdcc_set_vddp_low_vol(host);
2473 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002474 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002475
2476 spin_lock_irqsave(&host->lock, flags);
2477 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2478 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302479 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002480 host->io_pad_pwr_switch = 1;
2481 spin_unlock_irqrestore(&host->lock, flags);
2482
2483 /* Wait 5 ms for the voltage regulater in the card to become stable. */
2484 usleep_range(5000, 5500);
2485
2486 spin_lock_irqsave(&host->lock, flags);
2487 /* Start SD CLK output. */
2488 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2489 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302490 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002491 spin_unlock_irqrestore(&host->lock, flags);
2492
2493 /*
2494 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
2495 * don't become all ones within 1 ms then a Voltage Switch
2496 * sequence has failed and a power cycle to the card is required.
2497 * Otherwise Voltage Switch sequence is completed successfully.
2498 */
2499 usleep_range(1000, 1500);
2500
2501 spin_lock_irqsave(&host->lock, flags);
2502 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
2503 != (0xF << 1)) {
2504 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
2505 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302506 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002507 goto out_unlock;
2508 }
2509
2510out_unlock:
2511 spin_unlock_irqrestore(&host->lock, flags);
2512out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302513 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002514}
2515
2516static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2517 u8 phase);
2518/* Initialize the DLL (Programmable Delay Line ) */
2519static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
2520{
2521 int rc = 0;
2522 u32 wait_timeout;
2523
2524 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
2525 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2526 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2527
2528 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
2529 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2530 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2531
2532 msmsdcc_delay(host);
2533
2534 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
2535 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2536 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2537
2538 /* Initialize the phase to 0 */
2539 rc = msmsdcc_config_cm_sdc4_dll_phase(host, 0);
2540 if (rc)
2541 goto out;
2542
2543 wait_timeout = 1000;
2544 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
2545 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
2546 /* max. wait for 1 sec for LOCK bit to be set */
2547 if (--wait_timeout == 0) {
2548 pr_err("%s: %s: DLL failed to lock at phase: %d",
2549 mmc_hostname(host->mmc), __func__, 0);
2550 rc = -1;
2551 goto out;
2552 }
2553 /* wait for 1ms */
2554 usleep_range(1000, 1500);
2555 }
2556out:
2557 return rc;
2558}
2559
2560/*
2561 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
2562 * calibration sequence. This function should be called before
2563 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
2564 * commands (CMD17/CMD18).
2565 */
2566static void msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
2567{
2568 /* Set CDR_EN bit to 1. */
2569 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) |
2570 MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2571
2572 /* Set CDR_EXT_EN bit to 0. */
2573 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2574 & ~MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2575
2576 /* Set CK_OUT_EN bit to 0. */
2577 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2578 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2579
2580 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2581 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)
2582 ;
2583
2584 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2585 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2586 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2587
2588 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register is 1. */
2589 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN))
2590 ;
2591}
2592
2593static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2594 u8 phase)
2595{
2596 int rc = 0;
2597 u32 mclk_freq = 0;
2598 u32 wait_timeout;
2599
2600 /* Set CDR_EN bit to 0. */
2601 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2602 & ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2603
2604 /* Set CDR_EXT_EN bit to 1. */
2605 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2606 | MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2607
2608 /* Program the MCLK value to MCLK_FREQ bit field */
2609 if (host->clk_rate <= 112000000)
2610 mclk_freq = 0;
2611 else if (host->clk_rate <= 125000000)
2612 mclk_freq = 1;
2613 else if (host->clk_rate <= 137000000)
2614 mclk_freq = 2;
2615 else if (host->clk_rate <= 150000000)
2616 mclk_freq = 3;
2617 else if (host->clk_rate <= 162000000)
2618 mclk_freq = 4;
2619 else if (host->clk_rate <= 175000000)
2620 mclk_freq = 5;
2621 else if (host->clk_rate <= 187000000)
2622 mclk_freq = 6;
2623 else if (host->clk_rate <= 200000000)
2624 mclk_freq = 7;
2625
2626 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2627 & ~(7 << 24)) | (mclk_freq << 24)),
2628 host->base + MCI_DLL_CONFIG);
2629
2630 /* Set CK_OUT_EN bit to 0. */
2631 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2632 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2633
2634 /* Set DLL_EN bit to 1. */
2635 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2636 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
2637
2638 wait_timeout = 1000;
2639 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2640 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN) {
2641 /* max. wait for 1 sec for LOCK bit for be set */
2642 if (--wait_timeout == 0) {
2643 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 0",
2644 mmc_hostname(host->mmc), __func__, phase);
2645 rc = -1;
2646 goto out;
2647 }
2648 /* wait for 1ms */
2649 usleep_range(1000, 1500);
2650 }
2651
2652 /*
2653 * Write the selected DLL clock output phase (0 ... 15)
2654 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
2655 */
2656 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2657 & ~(0xF << 20)) | (phase << 20)),
2658 host->base + MCI_DLL_CONFIG);
2659
2660 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2661 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2662 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2663
2664 wait_timeout = 1000;
2665 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
2666 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)) {
2667 /* max. wait for 1 sec for LOCK bit for be set */
2668 if (--wait_timeout == 0) {
2669 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 1",
2670 mmc_hostname(host->mmc), __func__, phase);
2671 rc = -1;
2672 goto out;
2673 }
2674 /* wait for 1ms */
2675 usleep_range(1000, 1500);
2676 }
2677out:
2678 return rc;
2679}
2680
2681static int msmsdcc_execute_tuning(struct mmc_host *mmc)
2682{
2683 struct msmsdcc_host *host = mmc_priv(mmc);
2684 u8 phase;
2685 u8 *data_buf;
2686 u8 tuned_phases[16], tuned_phase_cnt = 0;
2687 int rc = 0;
2688
2689 /* Tuning is only required for SDR50 & SDR104 modes */
2690 if (!host->tuning_needed) {
2691 rc = 0;
2692 goto out;
2693 }
2694
2695 host->cmd19_tuning_in_progress = 1;
2696 /*
2697 * Make sure that clock is always enabled when DLL
2698 * tuning is in progress. Keeping PWRSAVE ON may
2699 * turn off the clock. So let's disable the PWRSAVE
2700 * here and re-enable it once tuning is completed.
2701 */
2702 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2703 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302704 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002705 /* first of all reset the tuning block */
2706 rc = msmsdcc_init_cm_sdc4_dll(host);
2707 if (rc)
2708 goto out;
2709
2710 data_buf = kmalloc(64, GFP_KERNEL);
2711 if (!data_buf) {
2712 rc = -ENOMEM;
2713 goto out;
2714 }
2715
2716 phase = 0;
2717 do {
2718 struct mmc_command cmd = {0};
2719 struct mmc_data data = {0};
2720 struct mmc_request mrq = {
2721 .cmd = &cmd,
2722 .data = &data
2723 };
2724 struct scatterlist sg;
2725
2726 /* set the phase in delay line hw block */
2727 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2728 if (rc)
2729 goto kfree;
2730
2731 cmd.opcode = MMC_SEND_TUNING_BLOCK;
2732 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
2733
2734 data.blksz = 64;
2735 data.blocks = 1;
2736 data.flags = MMC_DATA_READ;
2737 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
2738
2739 data.sg = &sg;
2740 data.sg_len = 1;
2741 sg_init_one(&sg, data_buf, 64);
2742 memset(data_buf, 0, 64);
2743 mmc_wait_for_req(mmc, &mrq);
2744
2745 if (!cmd.error && !data.error &&
2746 !memcmp(data_buf, cmd19_tuning_block, 64)) {
2747 /* tuning is successful with this tuning point */
2748 tuned_phases[tuned_phase_cnt++] = phase;
2749 }
2750 } while (++phase < 16);
2751
2752 kfree(data_buf);
2753
2754 if (tuned_phase_cnt) {
2755 tuned_phase_cnt--;
2756 tuned_phase_cnt = (tuned_phase_cnt * 3) / 4;
2757 phase = tuned_phases[tuned_phase_cnt];
2758 /*
2759 * Finally set the selected phase in delay
2760 * line hw block.
2761 */
2762 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2763 if (rc)
2764 goto out;
2765 } else {
2766 /* tuning failed */
2767 rc = -EAGAIN;
2768 pr_err("%s: %s: no tuning point found",
2769 mmc_hostname(mmc), __func__);
2770 }
2771 goto out;
2772
2773kfree:
2774 kfree(data_buf);
2775out:
2776 /* re-enable PWESAVE */
2777 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2778 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302779 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002780 host->cmd19_tuning_in_progress = 0;
2781 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07002782}
2783
2784static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002785 .enable = msmsdcc_enable,
2786 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07002787 .request = msmsdcc_request,
2788 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002789 .get_ro = msmsdcc_get_ro,
2790#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002791 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002792#endif
2793 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
2794 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07002795};
2796
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002797static unsigned int
2798msmsdcc_slot_status(struct msmsdcc_host *host)
2799{
2800 int status;
2801 unsigned int gpio_no = host->plat->status_gpio;
2802
2803 status = gpio_request(gpio_no, "SD_HW_Detect");
2804 if (status) {
2805 pr_err("%s: %s: Failed to request GPIO %d\n",
2806 mmc_hostname(host->mmc), __func__, gpio_no);
2807 } else {
2808 status = gpio_direction_input(gpio_no);
2809 if (!status)
2810 status = !gpio_get_value_cansleep(gpio_no);
2811 gpio_free(gpio_no);
2812 }
2813 return status;
2814}
2815
San Mehat9d2bd732009-09-22 16:44:22 -07002816static void
2817msmsdcc_check_status(unsigned long data)
2818{
2819 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
2820 unsigned int status;
2821
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002822 if (host->plat->status || host->plat->status_gpio) {
2823 if (host->plat->status)
2824 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07002825 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002826 status = msmsdcc_slot_status(host);
2827
2828 host->eject = !status;
2829 if (status ^ host->oldstat) {
2830 pr_info("%s: Slot status change detected (%d -> %d)\n",
2831 mmc_hostname(host->mmc), host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07002832 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002833 }
2834 host->oldstat = status;
2835 } else {
2836 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07002837 }
San Mehat9d2bd732009-09-22 16:44:22 -07002838}
2839
2840static irqreturn_t
2841msmsdcc_platform_status_irq(int irq, void *dev_id)
2842{
2843 struct msmsdcc_host *host = dev_id;
2844
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002845 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07002846 msmsdcc_check_status((unsigned long) host);
2847 return IRQ_HANDLED;
2848}
2849
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002850static irqreturn_t
2851msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
2852{
2853 struct msmsdcc_host *host = dev_id;
2854
2855 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
2856 spin_lock(&host->lock);
2857 if (!host->sdio_irq_disabled) {
2858 disable_irq_nosync(irq);
2859 if (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2860 wake_lock(&host->sdio_wlock);
2861 msmsdcc_disable_irq_wake(host);
2862 }
2863 host->sdio_irq_disabled = 1;
2864 }
2865 if (host->plat->is_sdio_al_client) {
2866 if (!host->clks_on) {
2867 msmsdcc_setup_clocks(host, true);
2868 host->clks_on = 1;
2869 }
2870 if (host->sdcc_irq_disabled) {
2871 writel_relaxed(host->mci_irqenable,
2872 host->base + MMCIMASK0);
2873 mb();
2874 enable_irq(host->core_irqres->start);
2875 host->sdcc_irq_disabled = 0;
2876 }
2877 wake_lock(&host->sdio_wlock);
2878 }
2879 spin_unlock(&host->lock);
2880
2881 return IRQ_HANDLED;
2882}
2883
San Mehat9d2bd732009-09-22 16:44:22 -07002884static void
2885msmsdcc_status_notify_cb(int card_present, void *dev_id)
2886{
2887 struct msmsdcc_host *host = dev_id;
2888
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002889 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07002890 card_present);
2891 msmsdcc_check_status((unsigned long) host);
2892}
2893
San Mehat9d2bd732009-09-22 16:44:22 -07002894static int
2895msmsdcc_init_dma(struct msmsdcc_host *host)
2896{
2897 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
2898 host->dma.host = host;
2899 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07002900 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07002901
2902 if (!host->dmares)
2903 return -ENODEV;
2904
2905 host->dma.nc = dma_alloc_coherent(NULL,
2906 sizeof(struct msmsdcc_nc_dmadata),
2907 &host->dma.nc_busaddr,
2908 GFP_KERNEL);
2909 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07002910 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07002911 return -ENOMEM;
2912 }
2913 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
2914 host->dma.cmd_busaddr = host->dma.nc_busaddr;
2915 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
2916 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
2917 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07002918 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07002919
2920 return 0;
2921}
2922
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002923#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
2924/**
2925 * Allocate and Connect a SDCC peripheral's SPS endpoint
2926 *
2927 * This function allocates endpoint context and
2928 * connect it with memory endpoint by calling
2929 * appropriate SPS driver APIs.
2930 *
2931 * Also registers a SPS callback function with
2932 * SPS driver
2933 *
2934 * This function should only be called once typically
2935 * during driver probe.
2936 *
2937 * @host - Pointer to sdcc host structure
2938 * @ep - Pointer to sps endpoint data structure
2939 * @is_produce - 1 means Producer endpoint
2940 * 0 means Consumer endpoint
2941 *
2942 * @return - 0 if successful else negative value.
2943 *
2944 */
2945static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
2946 struct msmsdcc_sps_ep_conn_data *ep,
2947 bool is_producer)
2948{
2949 int rc = 0;
2950 struct sps_pipe *sps_pipe_handle;
2951 struct sps_connect *sps_config = &ep->config;
2952 struct sps_register_event *sps_event = &ep->event;
2953
2954 /* Allocate endpoint context */
2955 sps_pipe_handle = sps_alloc_endpoint();
2956 if (!sps_pipe_handle) {
2957 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
2958 mmc_hostname(host->mmc), is_producer);
2959 rc = -ENOMEM;
2960 goto out;
2961 }
2962
2963 /* Get default connection configuration for an endpoint */
2964 rc = sps_get_config(sps_pipe_handle, sps_config);
2965 if (rc) {
2966 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
2967 " rc=%d", mmc_hostname(host->mmc),
2968 (u32)sps_pipe_handle, rc);
2969 goto get_config_err;
2970 }
2971
2972 /* Modify the default connection configuration */
2973 if (is_producer) {
2974 /*
2975 * For SDCC producer transfer, source should be
2976 * SDCC peripheral where as destination should
2977 * be system memory.
2978 */
2979 sps_config->source = host->sps.bam_handle;
2980 sps_config->destination = SPS_DEV_HANDLE_MEM;
2981 /* Producer pipe will handle this connection */
2982 sps_config->mode = SPS_MODE_SRC;
2983 sps_config->options =
2984 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
2985 } else {
2986 /*
2987 * For SDCC consumer transfer, source should be
2988 * system memory where as destination should
2989 * SDCC peripheral
2990 */
2991 sps_config->source = SPS_DEV_HANDLE_MEM;
2992 sps_config->destination = host->sps.bam_handle;
2993 sps_config->mode = SPS_MODE_DEST;
2994 sps_config->options =
2995 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
2996 }
2997
2998 /* Producer pipe index */
2999 sps_config->src_pipe_index = host->sps.src_pipe_index;
3000 /* Consumer pipe index */
3001 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
3002 /*
3003 * This event thresold value is only significant for BAM-to-BAM
3004 * transfer. It's ignored for BAM-to-System mode transfer.
3005 */
3006 sps_config->event_thresh = 0x10;
3007 /*
3008 * Max. no of scatter/gather buffers that can
3009 * be passed by block layer = 32 (NR_SG).
3010 * Each BAM descritor needs 64 bits (8 bytes).
3011 * One BAM descriptor is required per buffer transfer.
3012 * So we would require total 256 (32 * 8) bytes of descriptor FIFO.
3013 * But due to HW limitation we need to allocate atleast one extra
3014 * descriptor memory (256 bytes + 8 bytes). But in order to be
3015 * in power of 2, we are allocating 512 bytes of memory.
3016 */
3017 sps_config->desc.size = 512;
3018 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
3019 sps_config->desc.size,
3020 &sps_config->desc.phys_base,
3021 GFP_KERNEL);
3022
Pratibhasagar V00b94332011-10-18 14:57:27 +05303023 if (!sps_config->desc.base) {
3024 rc = -ENOMEM;
3025 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3026 , mmc_hostname(host->mmc));
3027 goto get_config_err;
3028 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003029 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3030
3031 /* Establish connection between peripheral and memory endpoint */
3032 rc = sps_connect(sps_pipe_handle, sps_config);
3033 if (rc) {
3034 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3035 " rc=%d", mmc_hostname(host->mmc),
3036 (u32)sps_pipe_handle, rc);
3037 goto sps_connect_err;
3038 }
3039
3040 sps_event->mode = SPS_TRIGGER_CALLBACK;
3041 sps_event->options = SPS_O_EOT;
3042 sps_event->callback = msmsdcc_sps_complete_cb;
3043 sps_event->xfer_done = NULL;
3044 sps_event->user = (void *)host;
3045
3046 /* Register callback event for EOT (End of transfer) event. */
3047 rc = sps_register_event(sps_pipe_handle, sps_event);
3048 if (rc) {
3049 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3050 " rc=%d", mmc_hostname(host->mmc),
3051 (u32)sps_pipe_handle, rc);
3052 goto reg_event_err;
3053 }
3054 /* Now save the sps pipe handle */
3055 ep->pipe_handle = sps_pipe_handle;
3056 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3057 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3058 __func__, is_producer ? "READ" : "WRITE",
3059 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3060 goto out;
3061
3062reg_event_err:
3063 sps_disconnect(sps_pipe_handle);
3064sps_connect_err:
3065 dma_free_coherent(mmc_dev(host->mmc),
3066 sps_config->desc.size,
3067 sps_config->desc.base,
3068 sps_config->desc.phys_base);
3069get_config_err:
3070 sps_free_endpoint(sps_pipe_handle);
3071out:
3072 return rc;
3073}
3074
3075/**
3076 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3077 *
3078 * This function disconnect endpoint and deallocates
3079 * endpoint context.
3080 *
3081 * This function should only be called once typically
3082 * during driver remove.
3083 *
3084 * @host - Pointer to sdcc host structure
3085 * @ep - Pointer to sps endpoint data structure
3086 *
3087 */
3088static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3089 struct msmsdcc_sps_ep_conn_data *ep)
3090{
3091 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3092 struct sps_connect *sps_config = &ep->config;
3093 struct sps_register_event *sps_event = &ep->event;
3094
3095 sps_event->xfer_done = NULL;
3096 sps_event->callback = NULL;
3097 sps_register_event(sps_pipe_handle, sps_event);
3098 sps_disconnect(sps_pipe_handle);
3099 dma_free_coherent(mmc_dev(host->mmc),
3100 sps_config->desc.size,
3101 sps_config->desc.base,
3102 sps_config->desc.phys_base);
3103 sps_free_endpoint(sps_pipe_handle);
3104}
3105
3106/**
3107 * Reset SDCC peripheral's SPS endpoint
3108 *
3109 * This function disconnects an endpoint.
3110 *
3111 * This function should be called for reseting
3112 * SPS endpoint when data transfer error is
3113 * encountered during data transfer. This
3114 * can be considered as soft reset to endpoint.
3115 *
3116 * This function should only be called if
3117 * msmsdcc_sps_init() is already called.
3118 *
3119 * @host - Pointer to sdcc host structure
3120 * @ep - Pointer to sps endpoint data structure
3121 *
3122 * @return - 0 if successful else negative value.
3123 */
3124static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3125 struct msmsdcc_sps_ep_conn_data *ep)
3126{
3127 int rc = 0;
3128 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3129
3130 rc = sps_disconnect(sps_pipe_handle);
3131 if (rc) {
3132 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3133 " rc=%d", mmc_hostname(host->mmc), __func__,
3134 (u32)sps_pipe_handle, rc);
3135 goto out;
3136 }
3137 out:
3138 return rc;
3139}
3140
3141/**
3142 * Restore SDCC peripheral's SPS endpoint
3143 *
3144 * This function connects an endpoint.
3145 *
3146 * This function should be called for restoring
3147 * SPS endpoint after data transfer error is
3148 * encountered during data transfer. This
3149 * can be considered as soft reset to endpoint.
3150 *
3151 * This function should only be called if
3152 * msmsdcc_sps_reset_ep() is called before.
3153 *
3154 * @host - Pointer to sdcc host structure
3155 * @ep - Pointer to sps endpoint data structure
3156 *
3157 * @return - 0 if successful else negative value.
3158 */
3159static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3160 struct msmsdcc_sps_ep_conn_data *ep)
3161{
3162 int rc = 0;
3163 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3164 struct sps_connect *sps_config = &ep->config;
3165 struct sps_register_event *sps_event = &ep->event;
3166
3167 /* Establish connection between peripheral and memory endpoint */
3168 rc = sps_connect(sps_pipe_handle, sps_config);
3169 if (rc) {
3170 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3171 " rc=%d", mmc_hostname(host->mmc), __func__,
3172 (u32)sps_pipe_handle, rc);
3173 goto out;
3174 }
3175
3176 /* Register callback event for EOT (End of transfer) event. */
3177 rc = sps_register_event(sps_pipe_handle, sps_event);
3178 if (rc) {
3179 pr_err("%s: %s: sps_register_event() failed!!!"
3180 " pipe_handle=0x%x, rc=%d",
3181 mmc_hostname(host->mmc), __func__,
3182 (u32)sps_pipe_handle, rc);
3183 goto reg_event_err;
3184 }
3185 goto out;
3186
3187reg_event_err:
3188 sps_disconnect(sps_pipe_handle);
3189out:
3190 return rc;
3191}
3192
3193/**
3194 * Initialize SPS HW connected with SDCC core
3195 *
3196 * This function register BAM HW resources with
3197 * SPS driver and then initialize 2 SPS endpoints
3198 *
3199 * This function should only be called once typically
3200 * during driver probe.
3201 *
3202 * @host - Pointer to sdcc host structure
3203 *
3204 * @return - 0 if successful else negative value.
3205 *
3206 */
3207static int msmsdcc_sps_init(struct msmsdcc_host *host)
3208{
3209 int rc = 0;
3210 struct sps_bam_props bam = {0};
3211
3212 host->bam_base = ioremap(host->bam_memres->start,
3213 resource_size(host->bam_memres));
3214 if (!host->bam_base) {
3215 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3216 " size=0x%x", mmc_hostname(host->mmc),
3217 host->bam_memres->start,
3218 (host->bam_memres->end -
3219 host->bam_memres->start));
3220 rc = -ENOMEM;
3221 goto out;
3222 }
3223
3224 bam.phys_addr = host->bam_memres->start;
3225 bam.virt_addr = host->bam_base;
3226 /*
3227 * This event thresold value is only significant for BAM-to-BAM
3228 * transfer. It's ignored for BAM-to-System mode transfer.
3229 */
3230 bam.event_threshold = 0x10; /* Pipe event threshold */
3231 /*
3232 * This threshold controls when the BAM publish
3233 * the descriptor size on the sideband interface.
3234 * SPS HW will only be used when
3235 * data transfer size > MCI_FIFOSIZE (64 bytes).
3236 * PIO mode will be used when
3237 * data transfer size < MCI_FIFOSIZE (64 bytes).
3238 * So set this thresold value to 64 bytes.
3239 */
3240 bam.summing_threshold = 64;
3241 /* SPS driver wll handle the SDCC BAM IRQ */
3242 bam.irq = (u32)host->bam_irqres->start;
3243 bam.manage = SPS_BAM_MGR_LOCAL;
3244
3245 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3246 (u32)bam.phys_addr);
3247 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3248 (u32)bam.virt_addr);
3249
3250 /* Register SDCC Peripheral BAM device to SPS driver */
3251 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3252 if (rc) {
3253 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3254 mmc_hostname(host->mmc), rc);
3255 goto reg_bam_err;
3256 }
3257 pr_info("%s: BAM device registered. bam_handle=0x%x",
3258 mmc_hostname(host->mmc), host->sps.bam_handle);
3259
3260 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3261 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3262
3263 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3264 SPS_PROD_PERIPHERAL);
3265 if (rc)
3266 goto sps_reset_err;
3267 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3268 SPS_CONS_PERIPHERAL);
3269 if (rc)
3270 goto cons_conn_err;
3271
3272 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3273 mmc_hostname(host->mmc),
3274 (unsigned long long)host->bam_memres->start,
3275 (unsigned int)host->bam_irqres->start);
3276 goto out;
3277
3278cons_conn_err:
3279 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3280sps_reset_err:
3281 sps_deregister_bam_device(host->sps.bam_handle);
3282reg_bam_err:
3283 iounmap(host->bam_base);
3284out:
3285 return rc;
3286}
3287
3288/**
3289 * De-initialize SPS HW connected with SDCC core
3290 *
3291 * This function deinitialize SPS endpoints and then
3292 * deregisters BAM resources from SPS driver.
3293 *
3294 * This function should only be called once typically
3295 * during driver remove.
3296 *
3297 * @host - Pointer to sdcc host structure
3298 *
3299 */
3300static void msmsdcc_sps_exit(struct msmsdcc_host *host)
3301{
3302 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
3303 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3304 sps_deregister_bam_device(host->sps.bam_handle);
3305 iounmap(host->bam_base);
3306}
3307#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
3308
3309static ssize_t
3310show_polling(struct device *dev, struct device_attribute *attr, char *buf)
3311{
3312 struct mmc_host *mmc = dev_get_drvdata(dev);
3313 struct msmsdcc_host *host = mmc_priv(mmc);
3314 int poll;
3315 unsigned long flags;
3316
3317 spin_lock_irqsave(&host->lock, flags);
3318 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
3319 spin_unlock_irqrestore(&host->lock, flags);
3320
3321 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
3322}
3323
3324static ssize_t
3325set_polling(struct device *dev, struct device_attribute *attr,
3326 const char *buf, size_t count)
3327{
3328 struct mmc_host *mmc = dev_get_drvdata(dev);
3329 struct msmsdcc_host *host = mmc_priv(mmc);
3330 int value;
3331 unsigned long flags;
3332
3333 sscanf(buf, "%d", &value);
3334
3335 spin_lock_irqsave(&host->lock, flags);
3336 if (value) {
3337 mmc->caps |= MMC_CAP_NEEDS_POLL;
3338 mmc_detect_change(host->mmc, 0);
3339 } else {
3340 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3341 }
3342#ifdef CONFIG_HAS_EARLYSUSPEND
3343 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
3344#endif
3345 spin_unlock_irqrestore(&host->lock, flags);
3346 return count;
3347}
3348
3349static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
3350 show_polling, set_polling);
3351static struct attribute *dev_attrs[] = {
3352 &dev_attr_polling.attr,
3353 NULL,
3354};
3355static struct attribute_group dev_attr_grp = {
3356 .attrs = dev_attrs,
3357};
3358
3359#ifdef CONFIG_HAS_EARLYSUSPEND
3360static void msmsdcc_early_suspend(struct early_suspend *h)
3361{
3362 struct msmsdcc_host *host =
3363 container_of(h, struct msmsdcc_host, early_suspend);
3364 unsigned long flags;
3365
3366 spin_lock_irqsave(&host->lock, flags);
3367 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
3368 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3369 spin_unlock_irqrestore(&host->lock, flags);
3370};
3371static void msmsdcc_late_resume(struct early_suspend *h)
3372{
3373 struct msmsdcc_host *host =
3374 container_of(h, struct msmsdcc_host, early_suspend);
3375 unsigned long flags;
3376
3377 if (host->polling_enabled) {
3378 spin_lock_irqsave(&host->lock, flags);
3379 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
3380 mmc_detect_change(host->mmc, 0);
3381 spin_unlock_irqrestore(&host->lock, flags);
3382 }
3383};
3384#endif
3385
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303386void msmsdcc_print_regs(const char *name, void __iomem *base,
3387 unsigned int no_of_regs)
3388{
3389 unsigned int i;
3390
3391 if (!base)
3392 return;
3393 pr_info("===== %s: Register Dumps @base=0x%x =====\n",
3394 name, (u32)base);
3395 for (i = 0; i < no_of_regs; i = i + 4) {
3396 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x.\n", i*4,
3397 (u32)readl_relaxed(base + i*4),
3398 (u32)readl_relaxed(base + ((i+1)*4)),
3399 (u32)readl_relaxed(base + ((i+2)*4)),
3400 (u32)readl_relaxed(base + ((i+3)*4)));
3401 }
3402}
3403
3404static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
3405{
3406 /* Dump current state of SDCC clocks, power and irq */
3407 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
3408 (host->pwr ? "ON" : "OFF"));
3409 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
3410 mmc_hostname(host->mmc),
3411 (host->clks_on ? "ON" : "OFF"),
3412 (u32)clk_get_rate(host->clk));
3413 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
3414 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
3415
3416 /* Now dump SDCC registers. Don't print FIFO registers */
3417 if (host->clks_on)
3418 msmsdcc_print_regs("SDCC-CORE", host->base, 28);
3419
3420 if (host->curr.data) {
3421 if (msmsdcc_check_dma_op_req(host->curr.data))
3422 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
3423 else if (host->is_dma_mode)
3424 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
3425 mmc_hostname(host->mmc), host->dma.busy,
3426 host->dma.channel, host->dma.crci);
3427 else if (host->is_sps_mode)
3428 pr_info("%s: SPS mode: busy=%d\n",
3429 mmc_hostname(host->mmc), host->sps.busy);
3430
3431 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
3432 mmc_hostname(host->mmc), host->curr.xfer_size,
3433 host->curr.data_xfered, host->curr.xfer_remain);
3434 pr_info("%s: got_dataend=%d, prog_enable=%d,"
3435 " wait_for_auto_prog_done=%d,"
3436 " got_auto_prog_done=%d\n",
3437 mmc_hostname(host->mmc), host->curr.got_dataend,
3438 host->prog_enable, host->curr.wait_for_auto_prog_done,
3439 host->curr.got_auto_prog_done);
3440 }
3441
3442}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003443static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
3444{
3445 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3446 struct mmc_request *mrq;
3447 unsigned long flags;
3448
3449 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003450 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003451 pr_info("%s: %s: dummy CMD52 timeout\n",
3452 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003453 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003454 }
3455
3456 mrq = host->curr.mrq;
3457
3458 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303459 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
3460 mrq->cmd->opcode);
3461 msmsdcc_dump_sdcc_state(host);
3462
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003463 if (!mrq->cmd->error)
3464 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303465 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003466 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003467 if (mrq->data && !mrq->data->error)
3468 mrq->data->error = -ETIMEDOUT;
3469 host->curr.data_xfered = 0;
3470 if (host->dma.sg && host->is_dma_mode) {
3471 msm_dmov_stop_cmd(host->dma.channel,
3472 &host->dma.hdr, 0);
3473 } else if (host->sps.sg && host->is_sps_mode) {
3474 /* Stop current SPS transfer */
3475 msmsdcc_sps_exit_curr_xfer(host);
3476 } else {
3477 msmsdcc_reset_and_restore(host);
3478 msmsdcc_stop_data(host);
3479 if (mrq->data && mrq->data->stop)
3480 msmsdcc_start_command(host,
3481 mrq->data->stop, 0);
3482 else
3483 msmsdcc_request_end(host, mrq);
3484 }
3485 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05303486 host->prog_enable = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003487 msmsdcc_reset_and_restore(host);
3488 msmsdcc_request_end(host, mrq);
3489 }
3490 }
3491 spin_unlock_irqrestore(&host->lock, flags);
3492}
3493
San Mehat9d2bd732009-09-22 16:44:22 -07003494static int
3495msmsdcc_probe(struct platform_device *pdev)
3496{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003497 struct mmc_platform_data *plat = pdev->dev.platform_data;
San Mehat9d2bd732009-09-22 16:44:22 -07003498 struct msmsdcc_host *host;
3499 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003500 unsigned long flags;
3501 struct resource *core_irqres = NULL;
3502 struct resource *bam_irqres = NULL;
3503 struct resource *core_memres = NULL;
3504 struct resource *dml_memres = NULL;
3505 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07003506 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07003507 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05303508 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003509 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07003510
3511 /* must have platform data */
3512 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003513 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003514 ret = -EINVAL;
3515 goto out;
3516 }
3517
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003518 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07003519 return -EINVAL;
3520
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003521 if (plat->is_sdio_al_client)
3522 if (!plat->sdio_lpm_gpio_setup || !plat->sdiowakeup_irq)
3523 return -EINVAL;
3524
San Mehat9d2bd732009-09-22 16:44:22 -07003525 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003526 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003527 return -ENXIO;
3528 }
3529
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003530 for (i = 0; i < pdev->num_resources; i++) {
3531 if (pdev->resource[i].flags & IORESOURCE_MEM) {
3532 if (!strcmp(pdev->resource[i].name,
3533 "sdcc_dml_addr"))
3534 dml_memres = &pdev->resource[i];
3535 else if (!strcmp(pdev->resource[i].name,
3536 "sdcc_bam_addr"))
3537 bam_memres = &pdev->resource[i];
3538 else
3539 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07003540
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003541 }
3542 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
3543 if (!strcmp(pdev->resource[i].name,
3544 "sdcc_bam_irq"))
3545 bam_irqres = &pdev->resource[i];
3546 else
3547 core_irqres = &pdev->resource[i];
3548 }
Krishna Konda25786ec2011-07-25 16:21:36 -07003549 if (pdev->resource[i].flags & IORESOURCE_DMA) {
3550 if (!strncmp(pdev->resource[i].name,
3551 "sdcc_dma_chnl",
3552 sizeof("sdcc_dma_chnl")))
3553 dmares = &pdev->resource[i];
3554 else if (!strncmp(pdev->resource[i].name,
3555 "sdcc_dma_crci",
3556 sizeof("sdcc_dma_crci")))
3557 dma_crci_res = &pdev->resource[i];
3558 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003559 }
3560
3561 if (!core_irqres || !core_memres) {
3562 pr_err("%s: Invalid sdcc core resource\n", __func__);
3563 return -ENXIO;
3564 }
3565
3566 /*
3567 * Both BAM and DML memory resource should be preset.
3568 * BAM IRQ resource should also be present.
3569 */
3570 if ((bam_memres && !dml_memres) ||
3571 (!bam_memres && dml_memres) ||
3572 ((bam_memres && dml_memres) && !bam_irqres)) {
3573 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003574 return -ENXIO;
3575 }
3576
3577 /*
3578 * Setup our host structure
3579 */
San Mehat9d2bd732009-09-22 16:44:22 -07003580 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
3581 if (!mmc) {
3582 ret = -ENOMEM;
3583 goto out;
3584 }
3585
3586 host = mmc_priv(mmc);
3587 host->pdev_id = pdev->id;
3588 host->plat = plat;
3589 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08003590 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05303591
3592 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003593 host->is_sps_mode = 1;
3594 else if (dmares)
3595 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07003596
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003597 host->base = ioremap(core_memres->start,
3598 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07003599 if (!host->base) {
3600 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003601 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003602 }
3603
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003604 host->core_irqres = core_irqres;
3605 host->bam_irqres = bam_irqres;
3606 host->core_memres = core_memres;
3607 host->dml_memres = dml_memres;
3608 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07003609 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07003610 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07003611 spin_lock_init(&host->lock);
3612
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003613#ifdef CONFIG_MMC_EMBEDDED_SDIO
3614 if (plat->embedded_sdio)
3615 mmc_set_embedded_sdio_data(mmc,
3616 &plat->embedded_sdio->cis,
3617 &plat->embedded_sdio->cccr,
3618 plat->embedded_sdio->funcs,
3619 plat->embedded_sdio->num_funcs);
3620#endif
3621
Sahitya Tummala62612cf2010-12-08 15:03:03 +05303622 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
3623 (unsigned long)host);
3624
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003625 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
3626 (unsigned long)host);
3627 if (host->is_dma_mode) {
3628 /* Setup DMA */
3629 ret = msmsdcc_init_dma(host);
3630 if (ret)
3631 goto ioremap_free;
3632 } else {
3633 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003634 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003635 }
3636
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003637 /*
3638 * Setup SDCC clock if derived from Dayatona
3639 * fabric core clock.
3640 */
3641 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07003642 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003643 if (!IS_ERR(host->dfab_pclk)) {
3644 /* Set the clock rate to 64MHz for max. performance */
3645 ret = clk_set_rate(host->dfab_pclk, 64000000);
3646 if (ret)
3647 goto dfab_pclk_put;
3648 ret = clk_enable(host->dfab_pclk);
3649 if (ret)
3650 goto dfab_pclk_put;
3651 } else
3652 goto dma_free;
3653 }
3654
3655 /*
3656 * Setup main peripheral bus clock
3657 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003658 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003659 if (!IS_ERR(host->pclk)) {
3660 ret = clk_enable(host->pclk);
3661 if (ret)
3662 goto pclk_put;
3663
3664 host->pclk_rate = clk_get_rate(host->pclk);
3665 }
3666
3667 /*
3668 * Setup SDC MMC clock
3669 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003670 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07003671 if (IS_ERR(host->clk)) {
3672 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003673 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07003674 }
3675
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003676 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
3677 if (ret) {
3678 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
3679 goto clk_put;
3680 }
3681
3682 ret = clk_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003683 if (ret)
3684 goto clk_put;
3685
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003686 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303687 if (!host->clk_rate)
3688 dev_err(&pdev->dev, "Failed to read MCLK\n");
3689 /*
3690 * Set the register write delay according to min. clock frequency
3691 * supported and update later when the host->clk_rate changes.
3692 */
3693 host->reg_write_delay =
3694 (1 + ((3 * USEC_PER_SEC) /
3695 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003696
3697 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05303698 /* Apply Hard reset to SDCC to put it in power on default state */
3699 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003700
3701 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07003702 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003703 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07003704 goto clk_disable;
3705 }
3706
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003707
3708 /* Clocks has to be running before accessing SPS/DML HW blocks */
3709 if (host->is_sps_mode) {
3710 /* Initialize SPS */
3711 ret = msmsdcc_sps_init(host);
3712 if (ret)
3713 goto vreg_deinit;
3714 /* Initialize DML */
3715 ret = msmsdcc_dml_init(host);
3716 if (ret)
3717 goto sps_exit;
3718 }
San Mehat9d2bd732009-09-22 16:44:22 -07003719
San Mehat9d2bd732009-09-22 16:44:22 -07003720 /*
3721 * Setup MMC host structure
3722 */
3723 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003724 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
3725 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003726 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003727 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
3728 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07003729
San Mehat9d2bd732009-09-22 16:44:22 -07003730 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05303731 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05303732
3733 /*
3734 * If we send the CMD23 before multi block write/read command
3735 * then we need not to send CMD12 at the end of the transfer.
3736 * If we don't send the CMD12 then only way to detect the PROG_DONE
3737 * status is to use the AUTO_PROG_DONE status provided by SDCC4
3738 * controller. So let's enable the CMD23 for SDCC4 only.
3739 */
Sahitya Tummala85fa0702011-09-15 09:39:37 +05303740 if (!plat->disable_cmd23 && host->plat->sdcc_v4_sup)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05303741 mmc->caps |= MMC_CAP_CMD23;
3742
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003743 mmc->caps |= plat->uhs_caps;
3744 /*
3745 * XPC controls the maximum current in the default speed mode of SDXC
3746 * card. XPC=0 means 100mA (max.) but speed class is not supported.
3747 * XPC=1 means 150mA (max.) and speed class is supported.
3748 */
3749 if (plat->xpc_cap)
3750 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
3751 MMC_CAP_SET_XPC_180);
3752
3753 if (plat->nonremovable)
3754 mmc->caps |= MMC_CAP_NONREMOVABLE;
3755#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
3756 mmc->caps |= MMC_CAP_SDIO_IRQ;
3757#endif
3758
3759 if (plat->is_sdio_al_client)
3760 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07003761
Martin K. Petersena36274e2010-09-10 01:33:59 -04003762 mmc->max_segs = NR_SG;
San Mehat9d2bd732009-09-22 16:44:22 -07003763 mmc->max_blk_size = 4096; /* MCI_DATA_CTL BLOCKSIZE up to 4096 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003764 mmc->max_blk_count = 65535;
San Mehat9d2bd732009-09-22 16:44:22 -07003765
3766 mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */
3767 mmc->max_seg_size = mmc->max_req_size;
3768
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003769 writel_relaxed(0, host->base + MMCIMASK0);
3770 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -07003771
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003772 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
3773 mb();
3774 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07003775
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003776 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
3777 DRIVER_NAME " (cmd)", host);
3778 if (ret)
3779 goto dml_exit;
3780
3781 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
3782 DRIVER_NAME " (pio)", host);
3783 if (ret)
3784 goto irq_free;
3785
3786 /*
3787 * Enable SDCC IRQ only when host is powered on. Otherwise, this
3788 * IRQ is un-necessarily being monitored by MPM (Modem power
3789 * management block) during idle-power collapse. The MPM will be
3790 * configured to monitor the DATA1 GPIO line with level-low trigger
3791 * and thus depending on the GPIO status, it prevents TCXO shutdown
3792 * during idle-power collapse.
3793 */
3794 disable_irq(core_irqres->start);
3795 host->sdcc_irq_disabled = 1;
3796
3797 if (plat->sdiowakeup_irq) {
3798 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3799 mmc_hostname(mmc));
3800 ret = request_irq(plat->sdiowakeup_irq,
3801 msmsdcc_platform_sdiowakeup_irq,
3802 IRQF_SHARED | IRQF_TRIGGER_LOW,
3803 DRIVER_NAME "sdiowakeup", host);
3804 if (ret) {
3805 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
3806 plat->sdiowakeup_irq, ret);
3807 goto pio_irq_free;
3808 } else {
3809 spin_lock_irqsave(&host->lock, flags);
3810 if (!host->sdio_irq_disabled) {
3811 disable_irq_nosync(plat->sdiowakeup_irq);
3812 host->sdio_irq_disabled = 1;
3813 }
3814 spin_unlock_irqrestore(&host->lock, flags);
3815 }
3816 }
3817
3818 if (plat->cfg_mpm_sdiowakeup) {
3819 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3820 mmc_hostname(mmc));
3821 }
3822
3823 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
3824 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003825 /*
3826 * Setup card detect change
3827 */
3828
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003829 if (plat->status || plat->status_gpio) {
3830 if (plat->status)
3831 host->oldstat = plat->status(mmc_dev(host->mmc));
3832 else
3833 host->oldstat = msmsdcc_slot_status(host);
3834 host->eject = !host->oldstat;
3835 }
San Mehat9d2bd732009-09-22 16:44:22 -07003836
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003837 if (plat->status_irq) {
3838 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07003839 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003840 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07003841 DRIVER_NAME " (slot)",
3842 host);
3843 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003844 pr_err("Unable to get slot IRQ %d (%d)\n",
3845 plat->status_irq, ret);
3846 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003847 }
3848 } else if (plat->register_status_notify) {
3849 plat->register_status_notify(msmsdcc_status_notify_cb, host);
3850 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003851 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07003852 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003853
3854 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003855
3856 ret = pm_runtime_set_active(&(pdev)->dev);
3857 if (ret < 0)
3858 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3859 __func__, ret);
3860 /*
3861 * There is no notion of suspend/resume for SD/MMC/SDIO
3862 * cards. So host can be suspended/resumed with out
3863 * worrying about its children.
3864 */
3865 pm_suspend_ignore_children(&(pdev)->dev, true);
3866
3867 /*
3868 * MMC/SD/SDIO bus suspend/resume operations are defined
3869 * only for the slots that will be used for non-removable
3870 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
3871 * defined. Otherwise, they simply become card removal and
3872 * insertion events during suspend and resume respectively.
3873 * Hence, enable run-time PM only for slots for which bus
3874 * suspend/resume operations are defined.
3875 */
3876#ifdef CONFIG_MMC_UNSAFE_RESUME
3877 /*
3878 * If this capability is set, MMC core will enable/disable host
3879 * for every claim/release operation on a host. We use this
3880 * notification to increment/decrement runtime pm usage count.
3881 */
3882 mmc->caps |= MMC_CAP_DISABLE;
3883 pm_runtime_enable(&(pdev)->dev);
3884#else
3885 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
3886 mmc->caps |= MMC_CAP_DISABLE;
3887 pm_runtime_enable(&(pdev)->dev);
3888 }
3889#endif
3890 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
3891 (unsigned long)host);
3892
San Mehat9d2bd732009-09-22 16:44:22 -07003893 mmc_add_host(mmc);
3894
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003895#ifdef CONFIG_HAS_EARLYSUSPEND
3896 host->early_suspend.suspend = msmsdcc_early_suspend;
3897 host->early_suspend.resume = msmsdcc_late_resume;
3898 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
3899 register_early_suspend(&host->early_suspend);
3900#endif
San Mehat9d2bd732009-09-22 16:44:22 -07003901
Krishna Konda25786ec2011-07-25 16:21:36 -07003902 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
3903 " dmacrcri %d\n", mmc_hostname(mmc),
3904 (unsigned long long)core_memres->start,
3905 (unsigned int) core_irqres->start,
3906 (unsigned int) plat->status_irq, host->dma.channel,
3907 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003908
3909 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
3910 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
3911 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
3912 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
3913 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
3914 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
3915 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
3916 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
3917 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
3918 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
3919 host->eject);
3920 pr_info("%s: Power save feature enable = %d\n",
3921 mmc_hostname(mmc), msmsdcc_pwrsave);
3922
Krishna Konda25786ec2011-07-25 16:21:36 -07003923 if (host->is_dma_mode && host->dma.channel != -1
3924 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003925 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003926 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003927 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003928 mmc_hostname(mmc), host->dma.cmd_busaddr,
3929 host->dma.cmdptr_busaddr);
3930 } else if (host->is_sps_mode) {
3931 pr_info("%s: SPS-BAM data transfer mode available\n",
3932 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003933 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003934 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003935
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003936#if defined(CONFIG_DEBUG_FS)
3937 msmsdcc_dbg_createhost(host);
3938#endif
3939 if (!plat->status_irq) {
3940 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
3941 if (ret)
3942 goto platform_irq_free;
3943 }
San Mehat9d2bd732009-09-22 16:44:22 -07003944 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003945
3946 platform_irq_free:
3947 del_timer_sync(&host->req_tout_timer);
3948 pm_runtime_disable(&(pdev)->dev);
3949 pm_runtime_set_suspended(&(pdev)->dev);
3950
3951 if (plat->status_irq)
3952 free_irq(plat->status_irq, host);
3953 sdiowakeup_irq_free:
3954 wake_lock_destroy(&host->sdio_suspend_wlock);
3955 if (plat->sdiowakeup_irq)
3956 free_irq(plat->sdiowakeup_irq, host);
3957 pio_irq_free:
3958 if (plat->sdiowakeup_irq)
3959 wake_lock_destroy(&host->sdio_wlock);
3960 free_irq(core_irqres->start, host);
3961 irq_free:
3962 free_irq(core_irqres->start, host);
3963 dml_exit:
3964 if (host->is_sps_mode)
3965 msmsdcc_dml_exit(host);
3966 sps_exit:
3967 if (host->is_sps_mode)
3968 msmsdcc_sps_exit(host);
3969 vreg_deinit:
3970 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07003971 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003972 clk_disable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003973 clk_put:
3974 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003975 pclk_disable:
3976 if (!IS_ERR(host->pclk))
3977 clk_disable(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07003978 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003979 if (!IS_ERR(host->pclk))
3980 clk_put(host->pclk);
3981 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3982 clk_disable(host->dfab_pclk);
3983 dfab_pclk_put:
3984 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3985 clk_put(host->dfab_pclk);
3986 dma_free:
3987 if (host->is_dma_mode) {
3988 if (host->dmares)
3989 dma_free_coherent(NULL,
3990 sizeof(struct msmsdcc_nc_dmadata),
3991 host->dma.nc, host->dma.nc_busaddr);
3992 }
3993 ioremap_free:
3994 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07003995 host_free:
3996 mmc_free_host(mmc);
3997 out:
3998 return ret;
3999}
4000
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004001static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07004002{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004003 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4004 struct mmc_platform_data *plat;
4005 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004006
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004007 if (!mmc)
4008 return -ENXIO;
4009
4010 if (pm_runtime_suspended(&(pdev)->dev))
4011 pm_runtime_resume(&(pdev)->dev);
4012
4013 host = mmc_priv(mmc);
4014
4015 DBG(host, "Removing SDCC device = %d\n", pdev->id);
4016 plat = host->plat;
4017
4018 if (!plat->status_irq)
4019 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
4020
4021 del_timer_sync(&host->req_tout_timer);
4022 tasklet_kill(&host->dma_tlet);
4023 tasklet_kill(&host->sps.tlet);
4024 mmc_remove_host(mmc);
4025
4026 if (plat->status_irq)
4027 free_irq(plat->status_irq, host);
4028
4029 wake_lock_destroy(&host->sdio_suspend_wlock);
4030 if (plat->sdiowakeup_irq) {
4031 wake_lock_destroy(&host->sdio_wlock);
4032 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
4033 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07004034 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004035
4036 free_irq(host->core_irqres->start, host);
4037 free_irq(host->core_irqres->start, host);
4038
4039 clk_put(host->clk);
4040 if (!IS_ERR(host->pclk))
4041 clk_put(host->pclk);
4042 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4043 clk_put(host->dfab_pclk);
4044
4045 msmsdcc_vreg_init(host, false);
4046
4047 if (host->is_dma_mode) {
4048 if (host->dmares)
4049 dma_free_coherent(NULL,
4050 sizeof(struct msmsdcc_nc_dmadata),
4051 host->dma.nc, host->dma.nc_busaddr);
4052 }
4053
4054 if (host->is_sps_mode) {
4055 msmsdcc_dml_exit(host);
4056 msmsdcc_sps_exit(host);
4057 }
4058
4059 iounmap(host->base);
4060 mmc_free_host(mmc);
4061
4062#ifdef CONFIG_HAS_EARLYSUSPEND
4063 unregister_early_suspend(&host->early_suspend);
4064#endif
4065 pm_runtime_disable(&(pdev)->dev);
4066 pm_runtime_set_suspended(&(pdev)->dev);
4067
4068 return 0;
4069}
4070
4071#ifdef CONFIG_MSM_SDIO_AL
4072int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4073{
4074 struct msmsdcc_host *host = mmc_priv(mmc);
4075 unsigned long flags;
4076
4077 spin_lock_irqsave(&host->lock, flags);
4078 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
4079 enable ? "En" : "Dis");
4080
4081 if (enable) {
4082 if (!host->sdcc_irq_disabled) {
4083 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05304084 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004085 host->sdcc_irq_disabled = 1;
4086 }
4087
4088 if (host->clks_on) {
4089 msmsdcc_setup_clocks(host, false);
4090 host->clks_on = 0;
4091 }
4092
4093 if (!host->sdio_gpio_lpm) {
4094 spin_unlock_irqrestore(&host->lock, flags);
4095 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
4096 spin_lock_irqsave(&host->lock, flags);
4097 host->sdio_gpio_lpm = 1;
4098 }
4099
4100 if (host->sdio_irq_disabled) {
4101 msmsdcc_enable_irq_wake(host);
4102 enable_irq(host->plat->sdiowakeup_irq);
4103 host->sdio_irq_disabled = 0;
4104 }
4105 } else {
4106 if (!host->sdio_irq_disabled) {
4107 disable_irq_nosync(host->plat->sdiowakeup_irq);
4108 host->sdio_irq_disabled = 1;
4109 msmsdcc_disable_irq_wake(host);
4110 }
4111
4112 if (host->sdio_gpio_lpm) {
4113 spin_unlock_irqrestore(&host->lock, flags);
4114 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
4115 spin_lock_irqsave(&host->lock, flags);
4116 host->sdio_gpio_lpm = 0;
4117 }
4118
4119 if (!host->clks_on) {
4120 msmsdcc_setup_clocks(host, true);
4121 host->clks_on = 1;
4122 }
4123
4124 if (host->sdcc_irq_disabled) {
4125 writel_relaxed(host->mci_irqenable,
4126 host->base + MMCIMASK0);
4127 mb();
4128 enable_irq(host->core_irqres->start);
4129 host->sdcc_irq_disabled = 0;
4130 }
4131 wake_lock_timeout(&host->sdio_wlock, 1);
4132 }
4133 spin_unlock_irqrestore(&host->lock, flags);
4134 return 0;
4135}
4136#else
4137int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4138{
4139 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004140}
4141#endif
4142
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004143#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07004144static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004145msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004146{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004147 struct mmc_host *mmc = dev_get_drvdata(dev);
4148 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07004149 int rc = 0;
4150
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004151 if (host->plat->is_sdio_al_client)
4152 return 0;
4153
Sahitya Tummala7661a452011-07-18 13:28:35 +05304154 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004155 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004156 host->sdcc_suspending = 1;
4157 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07004158
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004159 /*
4160 * If the clocks are already turned off by SDIO clients (as
4161 * part of LPM), then clocks should be turned on before
4162 * calling mmc_suspend_host() because mmc_suspend_host might
4163 * send some commands to the card. The clocks will be turned
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304164 * off again after mmc_suspend_host. Thus for SDIO
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004165 * cards, clocks will be turned on before mmc_suspend_host
4166 * and turned off after mmc_suspend_host.
4167 */
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304168 if (mmc->card && mmc_card_sdio(mmc->card)) {
4169 mmc->ios.clock = host->clk_rate;
4170 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4171 }
San Mehat9d2bd732009-09-22 16:44:22 -07004172
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004173 /*
4174 * MMC core thinks that host is disabled by now since
4175 * runtime suspend is scheduled after msmsdcc_disable()
4176 * is called. Thus, MMC core will try to enable the host
4177 * while suspending it. This results in a synchronous
4178 * runtime resume request while in runtime suspending
4179 * context and hence inorder to complete this resume
4180 * requet, it will wait for suspend to be complete,
4181 * but runtime suspend also can not proceed further
4182 * until the host is resumed. Thus, it leads to a hang.
4183 * Hence, increase the pm usage count before suspending
4184 * the host so that any resume requests after this will
4185 * simple become pm usage counter increment operations.
4186 */
4187 pm_runtime_get_noresume(dev);
4188 rc = mmc_suspend_host(mmc);
4189 pm_runtime_put_noidle(dev);
4190
4191 if (!rc) {
4192 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
4193 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ)) {
4194 disable_irq(host->core_irqres->start);
4195 host->sdcc_irq_disabled = 1;
4196
4197 /*
4198 * If MMC core level suspend is not supported,
4199 * turn off clocks to allow deep sleep (TCXO
4200 * shutdown).
4201 */
4202 mmc->ios.clock = 0;
4203 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4204 enable_irq(host->core_irqres->start);
4205 host->sdcc_irq_disabled = 0;
4206
4207 if (host->plat->sdiowakeup_irq) {
4208 host->sdio_irq_disabled = 0;
4209 msmsdcc_enable_irq_wake(host);
4210 enable_irq(host->plat->sdiowakeup_irq);
4211 }
4212 }
4213 }
4214 host->sdcc_suspending = 0;
4215 mmc->suspend_task = NULL;
4216 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
4217 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004218 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304219 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004220 return rc;
4221}
4222
4223static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004224msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004225{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004226 struct mmc_host *mmc = dev_get_drvdata(dev);
4227 struct msmsdcc_host *host = mmc_priv(mmc);
4228 unsigned long flags;
4229
4230 if (host->plat->is_sdio_al_client)
4231 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07004232
Sahitya Tummala7661a452011-07-18 13:28:35 +05304233 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004234 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004235 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
4236 if (host->sdcc_irq_disabled) {
4237 enable_irq(host->core_irqres->start);
4238 host->sdcc_irq_disabled = 0;
4239 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304240 mmc->ios.clock = host->clk_rate;
4241 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07004242
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304243 spin_lock_irqsave(&host->lock, flags);
4244 writel_relaxed(host->mci_irqenable,
4245 host->base + MMCIMASK0);
4246 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07004247
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304248 if ((mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) &&
4249 !host->sdio_irq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004250 if (host->plat->sdiowakeup_irq) {
4251 disable_irq_nosync(
4252 host->plat->sdiowakeup_irq);
4253 msmsdcc_disable_irq_wake(host);
4254 host->sdio_irq_disabled = 1;
4255 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304256 }
San Mehat9d2bd732009-09-22 16:44:22 -07004257
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304258 spin_unlock_irqrestore(&host->lock, flags);
4259 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004260
4261 mmc_resume_host(mmc);
4262
4263 /*
4264 * FIXME: Clearing of flags must be handled in clients
4265 * resume handler.
4266 */
4267 spin_lock_irqsave(&host->lock, flags);
4268 mmc->pm_flags = 0;
4269 spin_unlock_irqrestore(&host->lock, flags);
4270
4271 /*
4272 * After resuming the host wait for sometime so that
4273 * the SDIO work will be processed.
4274 */
4275 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO)) {
4276 if ((host->plat->cfg_mpm_sdiowakeup ||
4277 host->plat->sdiowakeup_irq) &&
4278 wake_lock_active(&host->sdio_wlock))
4279 wake_lock_timeout(&host->sdio_wlock, 1);
4280 }
4281
4282 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004283 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304284 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004285 return 0;
4286}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004287
4288static int msmsdcc_runtime_idle(struct device *dev)
4289{
4290 struct mmc_host *mmc = dev_get_drvdata(dev);
4291 struct msmsdcc_host *host = mmc_priv(mmc);
4292
4293 if (host->plat->is_sdio_al_client)
4294 return 0;
4295
4296 /* Idle timeout is not configurable for now */
4297 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
4298
4299 return -EAGAIN;
4300}
4301
4302static int msmsdcc_pm_suspend(struct device *dev)
4303{
4304 struct mmc_host *mmc = dev_get_drvdata(dev);
4305 struct msmsdcc_host *host = mmc_priv(mmc);
4306 int rc = 0;
4307
4308 if (host->plat->is_sdio_al_client)
4309 return 0;
4310
4311
4312 if (host->plat->status_irq)
4313 disable_irq(host->plat->status_irq);
4314
4315 if (!pm_runtime_suspended(dev))
4316 rc = msmsdcc_runtime_suspend(dev);
4317
4318 return rc;
4319}
4320
4321static int msmsdcc_pm_resume(struct device *dev)
4322{
4323 struct mmc_host *mmc = dev_get_drvdata(dev);
4324 struct msmsdcc_host *host = mmc_priv(mmc);
4325 int rc = 0;
4326
4327 if (host->plat->is_sdio_al_client)
4328 return 0;
4329
Sahitya Tummalafb486372011-09-02 19:01:49 +05304330 if (!pm_runtime_suspended(dev))
4331 rc = msmsdcc_runtime_resume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004332 if (host->plat->status_irq) {
4333 msmsdcc_check_status((unsigned long)host);
4334 enable_irq(host->plat->status_irq);
4335 }
4336
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004337 return rc;
4338}
4339
Daniel Walker08ecfde2010-06-23 12:32:20 -07004340#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004341#define msmsdcc_runtime_suspend NULL
4342#define msmsdcc_runtime_resume NULL
4343#define msmsdcc_runtime_idle NULL
4344#define msmsdcc_pm_suspend NULL
4345#define msmsdcc_pm_resume NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07004346#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004347
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004348static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
4349 .runtime_suspend = msmsdcc_runtime_suspend,
4350 .runtime_resume = msmsdcc_runtime_resume,
4351 .runtime_idle = msmsdcc_runtime_idle,
4352 .suspend = msmsdcc_pm_suspend,
4353 .resume = msmsdcc_pm_resume,
4354};
4355
San Mehat9d2bd732009-09-22 16:44:22 -07004356static struct platform_driver msmsdcc_driver = {
4357 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004358 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07004359 .driver = {
4360 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004361 .pm = &msmsdcc_dev_pm_ops,
San Mehat9d2bd732009-09-22 16:44:22 -07004362 },
4363};
4364
4365static int __init msmsdcc_init(void)
4366{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004367#if defined(CONFIG_DEBUG_FS)
4368 int ret = 0;
4369 ret = msmsdcc_dbg_init();
4370 if (ret) {
4371 pr_err("Failed to create debug fs dir \n");
4372 return ret;
4373 }
4374#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004375 return platform_driver_register(&msmsdcc_driver);
4376}
4377
4378static void __exit msmsdcc_exit(void)
4379{
4380 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004381
4382#if defined(CONFIG_DEBUG_FS)
4383 debugfs_remove(debugfs_file);
4384 debugfs_remove(debugfs_dir);
4385#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004386}
4387
4388module_init(msmsdcc_init);
4389module_exit(msmsdcc_exit);
4390
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004391MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07004392MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004393
4394#if defined(CONFIG_DEBUG_FS)
4395
4396static int
4397msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
4398{
4399 file->private_data = inode->i_private;
4400 return 0;
4401}
4402
4403static ssize_t
4404msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
4405 size_t count, loff_t *ppos)
4406{
4407 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
4408 char buf[1024];
4409 int max, i;
4410
4411 i = 0;
4412 max = sizeof(buf) - 1;
4413
4414 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
4415 host->curr.cmd, host->curr.data);
4416 if (host->curr.cmd) {
4417 struct mmc_command *cmd = host->curr.cmd;
4418
4419 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
4420 cmd->opcode, cmd->arg, cmd->flags);
4421 }
4422 if (host->curr.data) {
4423 struct mmc_data *data = host->curr.data;
4424 i += scnprintf(buf + i, max - i,
4425 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
4426 data->timeout_ns, data->timeout_clks,
4427 data->blksz, data->blocks, data->error,
4428 data->flags);
4429 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
4430 host->curr.xfer_size, host->curr.xfer_remain,
4431 host->curr.data_xfered, host->dma.sg);
4432 }
4433
4434 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
4435}
4436
4437static const struct file_operations msmsdcc_dbg_state_ops = {
4438 .read = msmsdcc_dbg_state_read,
4439 .open = msmsdcc_dbg_state_open,
4440};
4441
4442static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
4443{
4444 if (debugfs_dir) {
4445 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
4446 0644, debugfs_dir, host,
4447 &msmsdcc_dbg_state_ops);
4448 }
4449}
4450
4451static int __init msmsdcc_dbg_init(void)
4452{
4453 int err;
4454
4455 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
4456 if (IS_ERR(debugfs_dir)) {
4457 err = PTR_ERR(debugfs_dir);
4458 debugfs_dir = NULL;
4459 return err;
4460 }
4461
4462 return 0;
4463}
4464#endif