blob: ce13d276419b14c14f7a83dbc17cb0691aa26551 [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);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700620 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700621 return;
622 }
623 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530624 if (!mrq->data->stop || mrq->cmd->error ||
625 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700626 host->curr.mrq = NULL;
627 host->curr.cmd = NULL;
628 mrq->data->bytes_xfered = host->curr.data_xfered;
629 del_timer(&host->req_tout_timer);
630 spin_unlock_irqrestore(&host->lock, flags);
631
632 mmc_request_done(host->mmc, mrq);
633 return;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530634 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
635 || !mrq->sbc)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700636 msmsdcc_start_command(host, mrq->data->stop, 0);
637 }
638 }
639 spin_unlock_irqrestore(&host->lock, flags);
640}
641
642/**
643 * Exit from current SPS data transfer
644 *
645 * This function exits from current SPS data transfer.
646 *
647 * This function should be called when error condition
648 * is encountered during data transfer.
649 *
650 * @host - Pointer to sdcc host structure
651 *
652 */
653static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
654{
655 struct mmc_request *mrq;
656
657 mrq = host->curr.mrq;
658 BUG_ON(!mrq);
659
660 msmsdcc_reset_and_restore(host);
661 if (!mrq->data->error)
662 mrq->data->error = -EIO;
663
664 /* Unmap sg buffers */
665 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
666 host->sps.dir);
667
668 host->sps.sg = NULL;
669 host->sps.busy = 0;
670 if (host->curr.data)
671 msmsdcc_stop_data(host);
672
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530673 if (!mrq->data->stop || mrq->cmd->error ||
674 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700675 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530676 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
677 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700678 msmsdcc_start_command(host, mrq->data->stop, 0);
679
680}
681#else
682static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
683static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
684static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
685#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
686
687static void msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
688
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530689static void
690msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
691 unsigned int result,
692 struct msm_dmov_errdata *err)
693{
694 struct msmsdcc_dma_data *dma_data =
695 container_of(cmd, struct msmsdcc_dma_data, hdr);
696 struct msmsdcc_host *host = dma_data->host;
697
698 dma_data->result = result;
699 if (err)
700 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
701
702 tasklet_schedule(&host->dma_tlet);
703}
704
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700705static int msmsdcc_check_dma_op_req(struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700706{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700707 if (((data->blksz * data->blocks) < MCI_FIFOSIZE) ||
708 ((data->blksz * data->blocks) % MCI_FIFOSIZE))
San Mehat9d2bd732009-09-22 16:44:22 -0700709 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700710 else
711 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700712}
713
714static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
715{
716 struct msmsdcc_nc_dmadata *nc;
717 dmov_box *box;
718 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700719 unsigned int n;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700720 int i;
San Mehat9d2bd732009-09-22 16:44:22 -0700721 struct scatterlist *sg = data->sg;
722
Krishna Konda25786ec2011-07-25 16:21:36 -0700723 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700724 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700725
Krishna Konda25786ec2011-07-25 16:21:36 -0700726 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
727
San Mehat9d2bd732009-09-22 16:44:22 -0700728 host->dma.sg = data->sg;
729 host->dma.num_ents = data->sg_len;
730
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700731 BUG_ON(host->dma.num_ents > NR_SG); /* Prevent memory corruption */
San Mehat56a8b5b2009-11-21 12:29:46 -0800732
San Mehat9d2bd732009-09-22 16:44:22 -0700733 nc = host->dma.nc;
734
San Mehat9d2bd732009-09-22 16:44:22 -0700735 if (data->flags & MMC_DATA_READ)
736 host->dma.dir = DMA_FROM_DEVICE;
737 else
738 host->dma.dir = DMA_TO_DEVICE;
739
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700740 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
San Mehat9d2bd732009-09-22 16:44:22 -0700741 host->curr.user_pages = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700742 box = &nc->cmd[0];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700743 for (i = 0; i < host->dma.num_ents; i++) {
San Mehat9d2bd732009-09-22 16:44:22 -0700744 box->cmd = CMD_MODE_BOX;
745
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700746 /* Initialize sg dma address */
747 sg->dma_address = pfn_to_dma(mmc_dev(host->mmc),
748 page_to_pfn(sg_page(sg)))
749 + sg->offset;
750
751 if (i == (host->dma.num_ents - 1))
San Mehat9d2bd732009-09-22 16:44:22 -0700752 box->cmd |= CMD_LC;
753 rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ?
754 (sg_dma_len(sg) / MCI_FIFOSIZE) + 1 :
755 (sg_dma_len(sg) / MCI_FIFOSIZE) ;
756
757 if (data->flags & MMC_DATA_READ) {
758 box->src_row_addr = msmsdcc_fifo_addr(host);
759 box->dst_row_addr = sg_dma_address(sg);
760
761 box->src_dst_len = (MCI_FIFOSIZE << 16) |
762 (MCI_FIFOSIZE);
763 box->row_offset = MCI_FIFOSIZE;
764
765 box->num_rows = rows * ((1 << 16) + 1);
Krishna Konda25786ec2011-07-25 16:21:36 -0700766 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
San Mehat9d2bd732009-09-22 16:44:22 -0700767 } else {
768 box->src_row_addr = sg_dma_address(sg);
769 box->dst_row_addr = msmsdcc_fifo_addr(host);
770
771 box->src_dst_len = (MCI_FIFOSIZE << 16) |
772 (MCI_FIFOSIZE);
773 box->row_offset = (MCI_FIFOSIZE << 16);
774
775 box->num_rows = rows * ((1 << 16) + 1);
Krishna Konda25786ec2011-07-25 16:21:36 -0700776 box->cmd |= CMD_DST_CRCI(host->dma.crci);
San Mehat9d2bd732009-09-22 16:44:22 -0700777 }
778 box++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700779 sg++;
780 }
781
782 /* location of command block must be 64 bit aligned */
783 BUG_ON(host->dma.cmd_busaddr & 0x07);
784
785 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
786 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
787 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
788 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700789
790 n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
791 host->dma.num_ents, host->dma.dir);
792 /* dsb inside dma_map_sg will write nc out to mem as well */
793
794 if (n != host->dma.num_ents) {
795 pr_err("%s: Unable to map in all sg elements\n",
796 mmc_hostname(host->mmc));
797 host->dma.sg = NULL;
798 host->dma.num_ents = 0;
799 return -ENOMEM;
San Mehat56a8b5b2009-11-21 12:29:46 -0800800 }
San Mehat9d2bd732009-09-22 16:44:22 -0700801
802 return 0;
803}
804
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700805#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
806/**
807 * Submits data transfer request to SPS driver
808 *
809 * This function make sg (scatter gather) data buffers
810 * DMA ready and then submits them to SPS driver for
811 * transfer.
812 *
813 * @host - Pointer to sdcc host structure
814 * @data - Pointer to mmc_data structure
815 *
816 * @return 0 if success else negative value
817 */
818static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
819 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -0800820{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700821 int rc = 0;
822 u32 flags;
823 int i;
824 u32 addr, len, data_cnt;
825 struct scatterlist *sg = data->sg;
826 struct sps_pipe *sps_pipe_handle;
827
828 BUG_ON(data->sg_len > NR_SG); /* Prevent memory corruption */
829
830 host->sps.sg = data->sg;
831 host->sps.num_ents = data->sg_len;
832 host->sps.xfer_req_cnt = 0;
833 if (data->flags & MMC_DATA_READ) {
834 host->sps.dir = DMA_FROM_DEVICE;
835 sps_pipe_handle = host->sps.prod.pipe_handle;
836 } else {
837 host->sps.dir = DMA_TO_DEVICE;
838 sps_pipe_handle = host->sps.cons.pipe_handle;
839 }
840
841 /* Make sg buffers DMA ready */
842 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
843 host->sps.dir);
844
845 if (rc != data->sg_len) {
846 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
847 mmc_hostname(host->mmc), rc);
848 host->sps.sg = NULL;
849 host->sps.num_ents = 0;
850 rc = -ENOMEM;
851 goto dma_map_err;
852 }
853
854 pr_debug("%s: %s: %s: pipe=0x%x, total_xfer=0x%x, sg_len=%d\n",
855 mmc_hostname(host->mmc), __func__,
856 host->sps.dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
857 (u32)sps_pipe_handle, host->curr.xfer_size, data->sg_len);
858
859 for (i = 0; i < data->sg_len; i++) {
860 /*
861 * Check if this is the last buffer to transfer?
862 * If yes then set the INT and EOT flags.
863 */
864 len = sg_dma_len(sg);
865 addr = sg_dma_address(sg);
866 flags = 0;
867 while (len > 0) {
868 if (len > SPS_MAX_DESC_SIZE) {
869 data_cnt = SPS_MAX_DESC_SIZE;
870 } else {
871 data_cnt = len;
872 if (i == data->sg_len - 1)
873 flags = SPS_IOVEC_FLAG_INT |
874 SPS_IOVEC_FLAG_EOT;
875 }
876 rc = sps_transfer_one(sps_pipe_handle, addr,
877 data_cnt, host, flags);
878 if (rc) {
879 pr_err("%s: sps_transfer_one() error! rc=%d,"
880 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
881 mmc_hostname(host->mmc), rc,
882 (u32)sps_pipe_handle, (u32)sg, i);
883 goto dma_map_err;
884 }
885 addr += data_cnt;
886 len -= data_cnt;
887 host->sps.xfer_req_cnt++;
888 }
889 sg++;
890 }
891 goto out;
892
893dma_map_err:
894 /* unmap sg buffers */
895 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
896 host->sps.dir);
897out:
898 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -0700899}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700900#else
901static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
902 struct mmc_data *data) { return 0; }
903#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -0700904
905static void
San Mehat56a8b5b2009-11-21 12:29:46 -0800906msmsdcc_start_command_deferred(struct msmsdcc_host *host,
907 struct mmc_command *cmd, u32 *c)
908{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700909 DBG(host, "op %02x arg %08x flags %08x\n",
910 cmd->opcode, cmd->arg, cmd->flags);
911
San Mehat56a8b5b2009-11-21 12:29:46 -0800912 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
913
914 if (cmd->flags & MMC_RSP_PRESENT) {
915 if (cmd->flags & MMC_RSP_136)
916 *c |= MCI_CPSM_LONGRSP;
917 *c |= MCI_CPSM_RESPONSE;
918 }
919
920 if (/*interrupt*/0)
921 *c |= MCI_CPSM_INTERRUPT;
922
923 if ((((cmd->opcode == 17) || (cmd->opcode == 18)) ||
924 ((cmd->opcode == 24) || (cmd->opcode == 25))) ||
925 (cmd->opcode == 53))
926 *c |= MCI_CSPM_DATCMD;
927
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700928 /* Check if AUTO CMD19 is required or not? */
Subhash Jadavani1d6ba602011-09-21 18:10:54 +0530929 if (host->tuning_needed) {
930 /*
931 * For open ended block read operation (without CMD23),
932 * AUTO_CMD19 bit should be set while sending the READ command.
933 * For close ended block read operation (with CMD23),
934 * AUTO_CMD19 bit should be set while sending CMD23.
935 */
936 if ((cmd->opcode == 23 && (host->curr.mrq->cmd->opcode == 17 ||
937 host->curr.mrq->cmd->opcode == 18)) ||
938 (!host->curr.mrq->sbc &&
939 (cmd->opcode == 17 || cmd->opcode == 18))) {
940 msmsdcc_enable_cdr_cm_sdc4_dll(host);
941 *c |= MCI_CSPM_AUTO_CMD19;
942 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700943 }
944
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +0530945 if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +0530946 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700947 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +0530948 }
949
San Mehat56a8b5b2009-11-21 12:29:46 -0800950 if (cmd == cmd->mrq->stop)
951 *c |= MCI_CSPM_MCIABORT;
952
San Mehat56a8b5b2009-11-21 12:29:46 -0800953 if (host->curr.cmd != NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700954 pr_err("%s: Overlapping command requests\n",
955 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -0800956 }
957 host->curr.cmd = cmd;
958}
959
960static void
961msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
962 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -0700963{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +0530964 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -0700965 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700966 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -0700967 unsigned int pio_irqmask = 0;
968
969 host->curr.data = data;
970 host->curr.xfer_size = data->blksz * data->blocks;
971 host->curr.xfer_remain = host->curr.xfer_size;
972 host->curr.data_xfered = 0;
973 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530974 host->curr.got_auto_prog_done = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700975
976 memset(&host->pio, 0, sizeof(host->pio));
977
San Mehat9d2bd732009-09-22 16:44:22 -0700978 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
979
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530980 if (host->curr.wait_for_auto_prog_done)
981 datactrl |= MCI_AUTO_PROG_DONE;
982
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700983 if (!msmsdcc_check_dma_op_req(data)) {
984 if (host->is_dma_mode && !msmsdcc_config_dma(host, data)) {
985 datactrl |= MCI_DPSM_DMAENABLE;
986 } else if (host->is_sps_mode) {
987 if (!msmsdcc_is_dml_busy(host)) {
988 if (!msmsdcc_sps_start_xfer(host, data)) {
989 /* Now kick start DML transfer */
990 mb();
991 msmsdcc_dml_start_xfer(host, data);
992 datactrl |= MCI_DPSM_DMAENABLE;
993 host->sps.busy = 1;
994 }
995 } else {
996 /*
997 * Can't proceed with new transfer as
998 * previous trasnfer is already in progress.
999 * There is no point of going into PIO mode
1000 * as well. Is this a time to do kernel panic?
1001 */
1002 pr_err("%s: %s: DML HW is busy!!!"
1003 " Can't perform new SPS transfers"
1004 " now\n", mmc_hostname(host->mmc),
1005 __func__);
1006 }
1007 }
1008 }
1009
1010 /* Is data transfer in PIO mode required? */
1011 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001012 host->pio.sg = data->sg;
1013 host->pio.sg_len = data->sg_len;
1014 host->pio.sg_off = 0;
1015
1016 if (data->flags & MMC_DATA_READ) {
1017 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1018 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1019 pio_irqmask |= MCI_RXDATAAVLBLMASK;
1020 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001021 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1022 MCI_TXFIFOEMPTYMASK;
San Mehat9d2bd732009-09-22 16:44:22 -07001023 }
1024
1025 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301026 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
San Mehat9d2bd732009-09-22 16:44:22 -07001027
San Mehat56a8b5b2009-11-21 12:29:46 -08001028 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001029 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001030 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -07001031
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001032 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
1033 /* Use ADM (Application Data Mover) HW for Data transfer */
1034 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001035 host->cmd_timeout = timeout;
1036 host->cmd_pio_irqmask = pio_irqmask;
1037 host->cmd_datactrl = datactrl;
1038 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001039
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001040 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1041 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001042 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001043
1044 if (cmd) {
1045 msmsdcc_start_command_deferred(host, cmd, &c);
1046 host->cmd_c = c;
1047 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001048 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1049 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1050 host->base + MMCIMASK0);
1051 mb();
1052 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001053 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001054 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001055 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001056
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001057 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001058
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001059 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1060 (~(MCI_IRQ_PIO))) | pio_irqmask,
1061 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001062 writel_relaxed(datactrl, base + MMCIDATACTRL);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301063 /*
1064 * We don't need delay after writing to DATA_CTRL register
1065 * if we are not writing to CMD register immediately after
1066 * this. As we already have delay before sending the
1067 * command, we just need mb() here.
1068 */
1069 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001070
1071 if (cmd) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001072 msmsdcc_delay(host); /* Delay between data/command */
San Mehat56a8b5b2009-11-21 12:29:46 -08001073 /* Daisy-chain the command if requested */
1074 msmsdcc_start_command(host, cmd, c);
1075 }
San Mehat9d2bd732009-09-22 16:44:22 -07001076 }
1077}
1078
1079static void
1080msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1081{
San Mehat56a8b5b2009-11-21 12:29:46 -08001082 msmsdcc_start_command_deferred(host, cmd, &c);
1083 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001084}
1085
1086static void
1087msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1088 unsigned int status)
1089{
1090 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001091 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1092 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1093 pr_err("%s: Data CRC error\n",
1094 mmc_hostname(host->mmc));
1095 pr_err("%s: opcode 0x%.8x\n", __func__,
1096 data->mrq->cmd->opcode);
1097 pr_err("%s: blksz %d, blocks %d\n", __func__,
1098 data->blksz, data->blocks);
1099 data->error = -EILSEQ;
1100 }
San Mehat9d2bd732009-09-22 16:44:22 -07001101 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001102 /* CRC is optional for the bus test commands, not all
1103 * cards respond back with CRC. However controller
1104 * waits for the CRC and times out. Hence ignore the
1105 * data timeouts during the Bustest.
1106 */
1107 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1108 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1109 pr_err("%s: Data timeout\n",
1110 mmc_hostname(host->mmc));
1111 data->error = -ETIMEDOUT;
1112 }
San Mehat9d2bd732009-09-22 16:44:22 -07001113 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001114 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001115 data->error = -EIO;
1116 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001117 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001118 data->error = -EIO;
1119 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001120 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001121 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001122 data->error = -EIO;
1123 }
San Mehat9d2bd732009-09-22 16:44:22 -07001124
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001125 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001126 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001127 host->dummy_52_needed = 0;
1128}
San Mehat9d2bd732009-09-22 16:44:22 -07001129
1130static int
1131msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1132{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001133 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001134 uint32_t *ptr = (uint32_t *) buffer;
1135 int count = 0;
1136
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301137 if (remain % 4)
1138 remain = ((remain >> 2) + 1) << 2;
1139
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001140 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1141
1142 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001143 ptr++;
1144 count += sizeof(uint32_t);
1145
1146 remain -= sizeof(uint32_t);
1147 if (remain == 0)
1148 break;
1149 }
1150 return count;
1151}
1152
1153static int
1154msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001155 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001156{
1157 void __iomem *base = host->base;
1158 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001159 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001160
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001161 while (readl_relaxed(base + MMCISTATUS) &
1162 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1163 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001164
San Mehat9d2bd732009-09-22 16:44:22 -07001165 count = min(remain, maxcnt);
1166
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301167 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1168 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001169 ptr += count;
1170 remain -= count;
1171
1172 if (remain == 0)
1173 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001174 }
1175 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001176
1177 return ptr - buffer;
1178}
1179
San Mehat1cd22962010-02-03 12:59:29 -08001180static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001181msmsdcc_pio_irq(int irq, void *dev_id)
1182{
1183 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001184 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001185 uint32_t status;
1186
Murali Palnati36448a42011-09-02 15:06:18 +05301187 spin_lock(&host->lock);
1188
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001189 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001190
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001191 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301192 (MCI_IRQ_PIO)) == 0) {
1193 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001194 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301195 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001196
1197#if IRQ_DEBUG
1198 msmsdcc_print_status(host, "irq1-r", status);
1199#endif
1200
San Mehat9d2bd732009-09-22 16:44:22 -07001201 do {
1202 unsigned long flags;
1203 unsigned int remain, len;
1204 char *buffer;
1205
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001206 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1207 | MCI_RXDATAAVLBL)))
1208 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001209
1210 /* Map the current scatter buffer */
1211 local_irq_save(flags);
1212 buffer = kmap_atomic(sg_page(host->pio.sg),
1213 KM_BIO_SRC_IRQ) + host->pio.sg->offset;
1214 buffer += host->pio.sg_off;
1215 remain = host->pio.sg->length - host->pio.sg_off;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001216
San Mehat9d2bd732009-09-22 16:44:22 -07001217 len = 0;
1218 if (status & MCI_RXACTIVE)
1219 len = msmsdcc_pio_read(host, buffer, remain);
1220 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001221 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001222
1223 /* Unmap the buffer */
1224 kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
1225 local_irq_restore(flags);
1226
1227 host->pio.sg_off += len;
1228 host->curr.xfer_remain -= len;
1229 host->curr.data_xfered += len;
1230 remain -= len;
1231
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001232 if (remain) /* Done with this page? */
1233 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001234
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001235 if (status & MCI_RXACTIVE && host->curr.user_pages)
1236 flush_dcache_page(sg_page(host->pio.sg));
San Mehat9d2bd732009-09-22 16:44:22 -07001237
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001238 if (!--host->pio.sg_len) {
1239 memset(&host->pio, 0, sizeof(host->pio));
1240 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001241 }
1242
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001243 /* Advance to next sg */
1244 host->pio.sg++;
1245 host->pio.sg_off = 0;
1246
1247 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001248 } while (1);
1249
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001250 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1251 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1252 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1253 host->base + MMCIMASK0);
1254 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301255 /*
1256 * back to back write to MASK0 register don't need
1257 * synchronization delay.
1258 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001259 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1260 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1261 }
1262 mb();
1263 } else if (!host->curr.xfer_remain) {
1264 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1265 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1266 mb();
1267 }
San Mehat9d2bd732009-09-22 16:44:22 -07001268
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001269 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001270
1271 return IRQ_HANDLED;
1272}
1273
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001274static void
1275msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1276
1277static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1278 struct mmc_data *data)
1279{
1280 u32 loop_cnt = 0;
1281
1282 /*
1283 * For read commands with data less than fifo size, it is possible to
1284 * get DATAEND first and RXDATA_AVAIL might be set later because of
1285 * synchronization delay through the asynchronous RX FIFO. Thus, for
1286 * such cases, even after DATAEND interrupt is received software
1287 * should poll for RXDATA_AVAIL until the requested data is read out
1288 * of FIFO. This change is needed to get around this abnormal but
1289 * sometimes expected behavior of SDCC3 controller.
1290 *
1291 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1292 * after the data is loaded into RX FIFO. This would amount to less
1293 * than a microsecond and thus looping for 1000 times is good enough
1294 * for that delay.
1295 */
1296 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1297 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1298 spin_unlock(&host->lock);
1299 msmsdcc_pio_irq(1, host);
1300 spin_lock(&host->lock);
1301 }
1302 }
1303 if (loop_cnt == 1000) {
1304 pr_info("%s: Timed out while polling for Rx Data\n",
1305 mmc_hostname(host->mmc));
1306 data->error = -ETIMEDOUT;
1307 msmsdcc_reset_and_restore(host);
1308 }
1309}
1310
San Mehat9d2bd732009-09-22 16:44:22 -07001311static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1312{
1313 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001314
1315 host->curr.cmd = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001316 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1317 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1318 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1319 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -07001320
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001321 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Sahitya Tummala5a0ae912011-07-18 13:34:01 +05301322 pr_debug("%s: Command timeout\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001323 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001324 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
1325 !host->cmd19_tuning_in_progress) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001326 pr_err("%s: Command CRC error\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001327 cmd->error = -EILSEQ;
1328 }
1329
1330 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001331 if (host->curr.data && host->dma.sg &&
1332 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001333 msm_dmov_stop_cmd(host->dma.channel,
1334 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001335 else if (host->curr.data && host->sps.sg &&
1336 host->is_sps_mode){
1337 /* Stop current SPS transfer */
1338 msmsdcc_sps_exit_curr_xfer(host);
1339 }
San Mehat9d2bd732009-09-22 16:44:22 -07001340 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301341 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001342 msmsdcc_stop_data(host);
1343 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301344 } else { /* host->data == NULL */
1345 if (!cmd->error && host->prog_enable) {
1346 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001347 host->prog_enable = 0;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301348 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001349 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301350 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301351 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301352 host->prog_enable = 0;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001353 if (host->dummy_52_needed)
1354 host->dummy_52_needed = 0;
1355 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001356 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301357 msmsdcc_request_end(host, cmd->mrq);
1358 }
1359 }
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301360 } else if ((cmd == host->curr.mrq->sbc) && cmd->data) {
1361 if (cmd->data->flags & MMC_DATA_READ)
1362 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1363 else
1364 msmsdcc_request_start(host, host->curr.mrq);
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301365 } else if (cmd->data) {
1366 if (!(cmd->data->flags & MMC_DATA_READ))
1367 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001368 }
1369}
1370
San Mehat9d2bd732009-09-22 16:44:22 -07001371static irqreturn_t
1372msmsdcc_irq(int irq, void *dev_id)
1373{
1374 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001375 u32 status;
1376 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001377 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001378
1379 spin_lock(&host->lock);
1380
1381 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001382 struct mmc_command *cmd;
1383 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001384
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001385 if (timer) {
1386 timer = 0;
1387 msmsdcc_delay(host);
1388 }
San Mehat865c8062009-11-13 13:42:06 -08001389
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001390 if (!host->clks_on) {
1391 pr_debug("%s: %s: SDIO async irq received\n",
1392 mmc_hostname(host->mmc), __func__);
1393 host->mmc->ios.clock = host->clk_rate;
1394 spin_unlock(&host->lock);
1395 host->mmc->ops->set_ios(host->mmc, &host->mmc->ios);
1396 spin_lock(&host->lock);
1397 if (host->plat->cfg_mpm_sdiowakeup &&
1398 (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
1399 wake_lock(&host->sdio_wlock);
1400 /* only ansyc interrupt can come when clocks are off */
1401 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301402 if (host->clk_rate <=
1403 msmsdcc_get_min_sup_clk_rate(host))
1404 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001405 }
1406
1407 status = readl_relaxed(host->base + MMCISTATUS);
1408
1409 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1410 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001411 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001412
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001413#if IRQ_DEBUG
1414 msmsdcc_print_status(host, "irq0-r", status);
1415#endif
1416 status &= readl_relaxed(host->base + MMCIMASK0);
1417 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301418 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301419 if (host->clk_rate <=
1420 msmsdcc_get_min_sup_clk_rate(host))
1421 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001422#if IRQ_DEBUG
1423 msmsdcc_print_status(host, "irq0-p", status);
1424#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001425
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001426#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
1427 if (status & MCI_SDIOINTROPE) {
1428 if (host->sdcc_suspending)
1429 wake_lock(&host->sdio_suspend_wlock);
1430 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001431 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001432#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001433 data = host->curr.data;
1434
1435 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001436 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1437 MCI_CMDTIMEOUT)) {
1438 if (status & MCI_CMDTIMEOUT)
1439 pr_debug("%s: dummy CMD52 timeout\n",
1440 mmc_hostname(host->mmc));
1441 if (status & MCI_CMDCRCFAIL)
1442 pr_debug("%s: dummy CMD52 CRC failed\n",
1443 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001444 host->dummy_52_sent = 0;
1445 host->dummy_52_needed = 0;
1446 if (data) {
1447 msmsdcc_stop_data(host);
1448 msmsdcc_request_end(host, data->mrq);
1449 }
1450 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001451 spin_unlock(&host->lock);
1452 return IRQ_HANDLED;
1453 }
1454 break;
1455 }
1456
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001457 /*
1458 * Check for proper command response
1459 */
1460 cmd = host->curr.cmd;
1461 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1462 MCI_CMDTIMEOUT | MCI_PROGDONE |
1463 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1464 msmsdcc_do_cmdirq(host, status);
1465 }
1466
1467 if (data) {
1468 /* Check for data errors */
1469 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1470 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1471 msmsdcc_data_err(host, data, status);
1472 host->curr.data_xfered = 0;
1473 if (host->dma.sg && host->is_dma_mode)
1474 msm_dmov_stop_cmd(host->dma.channel,
1475 &host->dma.hdr, 0);
1476 else if (host->sps.sg && host->is_sps_mode) {
1477 /* Stop current SPS transfer */
1478 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301479 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001480 msmsdcc_reset_and_restore(host);
1481 if (host->curr.data)
1482 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301483 if (!data->stop || (host->curr.mrq->sbc
1484 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001485 timer |=
1486 msmsdcc_request_end(host,
1487 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301488 else if ((host->curr.mrq->sbc
1489 && data->error) ||
1490 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001491 msmsdcc_start_command(host,
1492 data->stop,
1493 0);
1494 timer = 1;
1495 }
1496 }
1497 }
1498
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301499 /* Check for prog done */
1500 if (host->curr.wait_for_auto_prog_done &&
1501 (status & MCI_PROGDONE))
1502 host->curr.got_auto_prog_done = 1;
1503
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001504 /* Check for data done */
1505 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1506 host->curr.got_dataend = 1;
1507
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301508 if (host->curr.got_dataend &&
1509 (!host->curr.wait_for_auto_prog_done ||
1510 (host->curr.wait_for_auto_prog_done &&
1511 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001512 /*
1513 * If DMA is still in progress, we complete
1514 * via the completion handler
1515 */
1516 if (!host->dma.busy && !host->sps.busy) {
1517 /*
1518 * There appears to be an issue in the
1519 * controller where if you request a
1520 * small block transfer (< fifo size),
1521 * you may get your DATAEND/DATABLKEND
1522 * irq without the PIO data irq.
1523 *
1524 * Check to see if theres still data
1525 * to be read, and simulate a PIO irq.
1526 */
1527 if (data->flags & MMC_DATA_READ)
1528 msmsdcc_wait_for_rxdata(host,
1529 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001530 if (!data->error) {
1531 host->curr.data_xfered =
1532 host->curr.xfer_size;
1533 host->curr.xfer_remain -=
1534 host->curr.xfer_size;
1535 }
1536
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001537 if (!host->dummy_52_needed) {
1538 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301539 if (!data->stop ||
1540 (host->curr.mrq->sbc
1541 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001542 msmsdcc_request_end(
1543 host,
1544 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301545 else if ((host->curr.mrq->sbc
1546 && data->error) ||
1547 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001548 msmsdcc_start_command(
1549 host,
1550 data->stop, 0);
1551 timer = 1;
1552 }
1553 } else {
1554 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001555 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001556 &dummy52cmd,
1557 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001558 }
1559 }
1560 }
1561 }
1562
San Mehat9d2bd732009-09-22 16:44:22 -07001563 ret = 1;
1564 } while (status);
1565
1566 spin_unlock(&host->lock);
1567
San Mehat9d2bd732009-09-22 16:44:22 -07001568 return IRQ_RETVAL(ret);
1569}
1570
1571static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001572msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1573{
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301574 if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001575 /* Queue/read data, daisy-chain command when data starts */
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301576 if (mrq->sbc)
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301577 msmsdcc_start_data(host, mrq->data, mrq->sbc, 0);
1578 else
1579 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001580 } else {
1581 msmsdcc_start_command(host, mrq->cmd, 0);
1582 }
1583}
1584
1585static void
San Mehat9d2bd732009-09-22 16:44:22 -07001586msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1587{
1588 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001589 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001590
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001591 /*
1592 * Get the SDIO AL client out of LPM.
1593 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001594 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001595 if (host->plat->is_sdio_al_client)
1596 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001597
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301598 /* check if sps pipe reset is pending? */
1599 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1600 msmsdcc_sps_pipes_reset_and_restore(host);
1601 host->sps.pipe_reset_pending = false;
1602 }
1603
San Mehat9d2bd732009-09-22 16:44:22 -07001604 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001605 WARN(host->curr.mrq, "Request in progress\n");
1606 WARN(!host->pwr, "SDCC power is turned off\n");
1607 WARN(!host->clks_on, "SDCC clocks are turned off\n");
1608 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
San Mehat9d2bd732009-09-22 16:44:22 -07001609
1610 if (host->eject) {
1611 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1612 mrq->cmd->error = 0;
1613 mrq->data->bytes_xfered = mrq->data->blksz *
1614 mrq->data->blocks;
1615 } else
1616 mrq->cmd->error = -ENOMEDIUM;
1617
1618 spin_unlock_irqrestore(&host->lock, flags);
1619 mmc_request_done(mmc, mrq);
1620 return;
1621 }
1622
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301623 /*
1624 * Kick the software command timeout timer here.
1625 * Timer expires in 10 secs.
1626 */
1627 mod_timer(&host->req_tout_timer,
1628 (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
San Mehat9d2bd732009-09-22 16:44:22 -07001629
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301630 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301631 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301632 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
1633 mrq->cmd->opcode == 54) {
1634 if (!host->plat->sdcc_v4_sup)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001635 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301636 else
1637 /*
1638 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
1639 * write operations using CMD53 and CMD54.
1640 * Setting this bit with CMD53 would
1641 * automatically triggers PROG_DONE interrupt
1642 * without the need of sending dummy CMD52.
1643 */
1644 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001645 }
San Mehat9d2bd732009-09-22 16:44:22 -07001646 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301647
Pratibhasagar V00b94332011-10-18 14:57:27 +05301648 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301649 mrq->sbc->mrq = mrq;
1650 mrq->sbc->data = mrq->data;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301651 if (mrq->data->flags & MMC_DATA_WRITE) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301652 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301653 msmsdcc_start_command(host, mrq->sbc, 0);
1654 } else {
1655 msmsdcc_request_start(host, mrq);
1656 }
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301657 } else {
1658 msmsdcc_request_start(host, mrq);
1659 }
1660
San Mehat9d2bd732009-09-22 16:44:22 -07001661 spin_unlock_irqrestore(&host->lock, flags);
1662}
1663
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001664static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1665 int min_uV, int max_uV)
1666{
1667 int rc = 0;
1668
1669 if (vreg->set_voltage_sup) {
1670 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1671 if (rc) {
1672 pr_err("%s: regulator_set_voltage(%s) failed."
1673 " min_uV=%d, max_uV=%d, rc=%d\n",
1674 __func__, vreg->name, min_uV, max_uV, rc);
1675 }
1676 }
1677
1678 return rc;
1679}
1680
1681static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1682 int uA_load)
1683{
1684 int rc = 0;
1685
Krishna Kondafea60182011-11-01 16:01:34 -07001686 /* regulators that do not support regulator_set_voltage also
1687 do not support regulator_set_optimum_mode */
1688 if (vreg->set_voltage_sup) {
1689 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1690 if (rc < 0)
1691 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
1692 "uA_load=%d) failed. rc=%d\n", __func__,
1693 vreg->name, uA_load, rc);
1694 else
1695 /* regulator_set_optimum_mode() can return non zero
1696 * value even for success case.
1697 */
1698 rc = 0;
1699 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001700
1701 return rc;
1702}
1703
1704static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1705 struct device *dev)
1706{
1707 int rc = 0;
1708
1709 /* check if regulator is already initialized? */
1710 if (vreg->reg)
1711 goto out;
1712
1713 /* Get the regulator handle */
1714 vreg->reg = regulator_get(dev, vreg->name);
1715 if (IS_ERR(vreg->reg)) {
1716 rc = PTR_ERR(vreg->reg);
1717 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
1718 __func__, vreg->name, rc);
1719 }
1720out:
1721 return rc;
1722}
1723
1724static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
1725{
1726 if (vreg->reg)
1727 regulator_put(vreg->reg);
1728}
1729
1730/* This init function should be called only once for each SDCC slot */
1731static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
1732{
1733 int rc = 0;
1734 struct msm_mmc_slot_reg_data *curr_slot;
1735 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1736 struct device *dev = mmc_dev(host->mmc);
1737
1738 curr_slot = host->plat->vreg_data;
1739 if (!curr_slot)
1740 goto out;
1741
1742 curr_vdd_reg = curr_slot->vdd_data;
1743 curr_vccq_reg = curr_slot->vccq_data;
1744 curr_vddp_reg = curr_slot->vddp_data;
1745
1746 if (is_init) {
1747 /*
1748 * Get the regulator handle from voltage regulator framework
1749 * and then try to set the voltage level for the regulator
1750 */
1751 if (curr_vdd_reg) {
1752 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
1753 if (rc)
1754 goto out;
1755 }
1756 if (curr_vccq_reg) {
1757 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
1758 if (rc)
1759 goto vdd_reg_deinit;
1760 }
1761 if (curr_vddp_reg) {
1762 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
1763 if (rc)
1764 goto vccq_reg_deinit;
1765 }
1766 goto out;
1767 } else {
1768 /* Deregister all regulators from regulator framework */
1769 goto vddp_reg_deinit;
1770 }
1771vddp_reg_deinit:
1772 if (curr_vddp_reg)
1773 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
1774vccq_reg_deinit:
1775 if (curr_vccq_reg)
1776 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
1777vdd_reg_deinit:
1778 if (curr_vdd_reg)
1779 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
1780out:
1781 return rc;
1782}
1783
1784static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
1785{
1786 int rc = 0;
1787
Subhash Jadavanicc922692011-08-01 23:05:01 +05301788 /* Put regulator in HPM (high power mode) */
1789 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
1790 if (rc < 0)
1791 goto out;
1792
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001793 if (!vreg->is_enabled) {
1794 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301795 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
1796 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001797 if (rc)
1798 goto out;
1799
1800 rc = regulator_enable(vreg->reg);
1801 if (rc) {
1802 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
1803 __func__, vreg->name, rc);
1804 goto out;
1805 }
1806 vreg->is_enabled = true;
1807 }
1808
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001809out:
1810 return rc;
1811}
1812
1813static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
1814{
1815 int rc = 0;
1816
1817 /* Never disable regulator marked as always_on */
1818 if (vreg->is_enabled && !vreg->always_on) {
1819 rc = regulator_disable(vreg->reg);
1820 if (rc) {
1821 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
1822 __func__, vreg->name, rc);
1823 goto out;
1824 }
1825 vreg->is_enabled = false;
1826
1827 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
1828 if (rc < 0)
1829 goto out;
1830
1831 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301832 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001833 if (rc)
1834 goto out;
1835 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
1836 /* Put always_on regulator in LPM (low power mode) */
1837 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
1838 if (rc < 0)
1839 goto out;
1840 }
1841out:
1842 return rc;
1843}
1844
1845static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
1846{
1847 int rc = 0, i;
1848 struct msm_mmc_slot_reg_data *curr_slot;
1849 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1850 struct msm_mmc_reg_data *vreg_table[3];
1851
1852 curr_slot = host->plat->vreg_data;
1853 if (!curr_slot)
1854 goto out;
1855
1856 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
1857 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
1858 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
1859
1860 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
1861 if (vreg_table[i]) {
1862 if (enable)
1863 rc = msmsdcc_vreg_enable(vreg_table[i]);
1864 else
1865 rc = msmsdcc_vreg_disable(vreg_table[i]);
1866 if (rc)
1867 goto out;
1868 }
1869 }
1870out:
1871 return rc;
1872}
1873
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301874static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001875{
1876 int rc = 0;
1877
1878 if (host->plat->vreg_data) {
1879 struct msm_mmc_reg_data *vddp_reg =
1880 host->plat->vreg_data->vddp_data;
1881
1882 if (vddp_reg && vddp_reg->is_enabled)
1883 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
1884 }
1885
1886 return rc;
1887}
1888
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301889static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
1890{
1891 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1892 int rc = 0;
1893
1894 if (curr_slot && curr_slot->vddp_data) {
1895 rc = msmsdcc_set_vddp_level(host,
1896 curr_slot->vddp_data->low_vol_level);
1897
1898 if (rc)
1899 pr_err("%s: %s: failed to change vddp level to %d",
1900 mmc_hostname(host->mmc), __func__,
1901 curr_slot->vddp_data->low_vol_level);
1902 }
1903
1904 return rc;
1905}
1906
1907static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
1908{
1909 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1910 int rc = 0;
1911
1912 if (curr_slot && curr_slot->vddp_data) {
1913 rc = msmsdcc_set_vddp_level(host,
1914 curr_slot->vddp_data->high_vol_level);
1915
1916 if (rc)
1917 pr_err("%s: %s: failed to change vddp level to %d",
1918 mmc_hostname(host->mmc), __func__,
1919 curr_slot->vddp_data->high_vol_level);
1920 }
1921
1922 return rc;
1923}
1924
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001925static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
1926{
1927 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
1928 return 1;
1929 return 0;
1930}
1931
1932static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
1933{
1934 if (enable) {
1935 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1936 clk_enable(host->dfab_pclk);
1937 if (!IS_ERR(host->pclk))
1938 clk_enable(host->pclk);
1939 clk_enable(host->clk);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301940 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001941 } else {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301942 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001943 clk_disable(host->clk);
1944 if (!IS_ERR(host->pclk))
1945 clk_disable(host->pclk);
1946 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1947 clk_disable(host->dfab_pclk);
1948 }
1949}
1950
1951static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
1952 unsigned int req_clk)
1953{
1954 unsigned int sel_clk = -1;
1955
1956 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
1957 unsigned char cnt;
1958
1959 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
1960 if (host->plat->sup_clk_table[cnt] > req_clk)
1961 break;
1962 else if (host->plat->sup_clk_table[cnt] == req_clk) {
1963 sel_clk = host->plat->sup_clk_table[cnt];
1964 break;
1965 } else
1966 sel_clk = host->plat->sup_clk_table[cnt];
1967 }
1968 } else {
1969 if ((req_clk < host->plat->msmsdcc_fmax) &&
1970 (req_clk > host->plat->msmsdcc_fmid))
1971 sel_clk = host->plat->msmsdcc_fmid;
1972 else
1973 sel_clk = req_clk;
1974 }
1975
1976 return sel_clk;
1977}
1978
1979static inline unsigned int msmsdcc_get_min_sup_clk_rate(
1980 struct msmsdcc_host *host)
1981{
1982 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
1983 return host->plat->sup_clk_table[0];
1984 else
1985 return host->plat->msmsdcc_fmin;
1986}
1987
1988static inline unsigned int msmsdcc_get_max_sup_clk_rate(
1989 struct msmsdcc_host *host)
1990{
1991 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
1992 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
1993 else
1994 return host->plat->msmsdcc_fmax;
1995}
1996
1997static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05301998{
1999 struct msm_mmc_gpio_data *curr;
2000 int i, rc = 0;
2001
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002002 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302003 for (i = 0; i < curr->size; i++) {
2004 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002005 if (curr->gpio[i].is_always_on &&
2006 curr->gpio[i].is_enabled)
2007 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302008 rc = gpio_request(curr->gpio[i].no,
2009 curr->gpio[i].name);
2010 if (rc) {
2011 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2012 mmc_hostname(host->mmc),
2013 curr->gpio[i].no,
2014 curr->gpio[i].name, rc);
2015 goto free_gpios;
2016 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002017 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302018 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002019 if (curr->gpio[i].is_always_on)
2020 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302021 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002022 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302023 }
2024 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002025 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302026
2027free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002028 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302029 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002030 curr->gpio[i].is_enabled = false;
2031 }
2032out:
2033 return rc;
2034}
2035
2036static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2037{
2038 struct msm_mmc_pad_data *curr;
2039 int i;
2040
2041 curr = host->plat->pin_data->pad_data;
2042 for (i = 0; i < curr->drv->size; i++) {
2043 if (enable)
2044 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2045 curr->drv->on[i].val);
2046 else
2047 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2048 curr->drv->off[i].val);
2049 }
2050
2051 for (i = 0; i < curr->pull->size; i++) {
2052 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002053 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002054 curr->pull->on[i].val);
2055 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002056 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002057 curr->pull->off[i].val);
2058 }
2059
2060 return 0;
2061}
2062
2063static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2064{
2065 int rc = 0;
2066
2067 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2068 return 0;
2069
2070 if (host->plat->pin_data->is_gpio)
2071 rc = msmsdcc_setup_gpio(host, enable);
2072 else
2073 rc = msmsdcc_setup_pad(host, enable);
2074
2075 if (!rc)
2076 host->plat->pin_data->cfg_sts = enable;
2077
2078 return rc;
2079}
2080
2081static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2082{
2083 unsigned int wakeup_irq;
2084
2085 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2086 host->plat->sdiowakeup_irq :
2087 host->core_irqres->start;
2088
2089 if (!host->irq_wake_enabled) {
2090 enable_irq_wake(wakeup_irq);
2091 host->irq_wake_enabled = true;
2092 }
2093}
2094
2095static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2096{
2097 unsigned int wakeup_irq;
2098
2099 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2100 host->plat->sdiowakeup_irq :
2101 host->core_irqres->start;
2102
2103 if (host->irq_wake_enabled) {
2104 disable_irq_wake(wakeup_irq);
2105 host->irq_wake_enabled = false;
2106 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302107}
2108
San Mehat9d2bd732009-09-22 16:44:22 -07002109static void
2110msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2111{
2112 struct msmsdcc_host *host = mmc_priv(mmc);
2113 u32 clk = 0, pwr = 0;
2114 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002115 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002116 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002117
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002118 DBG(host, "ios->clock = %u\n", ios->clock);
Sahitya Tummala7a892482011-01-18 11:22:49 +05302119
San Mehat9d2bd732009-09-22 16:44:22 -07002120 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002121 spin_lock_irqsave(&host->lock, flags);
2122 if (!host->clks_on) {
2123 msmsdcc_setup_clocks(host, true);
2124 host->clks_on = 1;
2125 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2126 if (!host->plat->sdiowakeup_irq) {
2127 writel_relaxed(host->mci_irqenable,
2128 host->base + MMCIMASK0);
2129 mb();
2130 if (host->plat->cfg_mpm_sdiowakeup &&
2131 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2132 host->plat->cfg_mpm_sdiowakeup(
2133 mmc_dev(mmc), SDC_DAT1_DISWAKE);
2134 msmsdcc_disable_irq_wake(host);
2135 } else if (!(mmc->pm_flags &
2136 MMC_PM_WAKE_SDIO_IRQ)) {
2137 writel_relaxed(host->mci_irqenable,
2138 host->base + MMCIMASK0);
2139 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05302140 } else {
2141 writel_relaxed(host->mci_irqenable,
2142 host->base + MMCIMASK0);
2143 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002144 }
San Mehat9d2bd732009-09-22 16:44:22 -07002145 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002146 spin_unlock_irqrestore(&host->lock, flags);
2147
2148 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2149 /*
2150 * For DDR50 mode, controller needs clock rate to be
2151 * double than what is required on the SD card CLK pin.
2152 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302153 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002154 /*
2155 * Make sure that we don't double the clock if
2156 * doubled clock rate is already set
2157 */
2158 if (!host->ddr_doubled_clk_rate ||
2159 (host->ddr_doubled_clk_rate &&
2160 (host->ddr_doubled_clk_rate != ios->clock))) {
2161 host->ddr_doubled_clk_rate =
2162 msmsdcc_get_sup_clk_rate(
2163 host, (ios->clock * 2));
2164 clock = host->ddr_doubled_clk_rate;
2165 }
2166 } else {
2167 host->ddr_doubled_clk_rate = 0;
2168 }
2169
2170 if (clock != host->clk_rate) {
2171 rc = clk_set_rate(host->clk, clock);
2172 if (rc < 0)
2173 pr_debug("%s: failed to set clk rate %u\n",
2174 mmc_hostname(mmc), clock);
2175 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302176 host->reg_write_delay =
2177 (1 + ((3 * USEC_PER_SEC) /
2178 (host->clk_rate ? host->clk_rate :
2179 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002180 }
2181 /*
2182 * give atleast 2 MCLK cycles delay for clocks
2183 * and SDCC core to stabilize
2184 */
2185 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002186 clk |= MCI_CLK_ENABLE;
2187 }
2188
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002189 if (ios->bus_width == MMC_BUS_WIDTH_8)
2190 clk |= MCI_CLK_WIDEBUS_8;
2191 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2192 clk |= MCI_CLK_WIDEBUS_4;
2193 else
2194 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002195
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002196 if (msmsdcc_is_pwrsave(host))
2197 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002198
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002199 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002201 host->tuning_needed = 0;
2202 /*
2203 * Select the controller timing mode according
2204 * to current bus speed mode
2205 */
2206 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2207 (ios->timing == MMC_TIMING_UHS_SDR50)) {
2208 clk |= (4 << 14);
2209 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302210 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002211 clk |= (3 << 14);
2212 } else {
2213 clk |= (2 << 14); /* feedback clock */
2214 }
2215
2216 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2217 clk |= (2 << 23);
2218
2219 if (host->io_pad_pwr_switch)
2220 clk |= IO_PAD_PWR_SWITCH;
2221
2222 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
San Mehat9d2bd732009-09-22 16:44:22 -07002223 pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002224 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2225 pwr |= msmsdcc_setup_vreg(host, !!ios->vdd);
San Mehat9d2bd732009-09-22 16:44:22 -07002226
2227 switch (ios->power_mode) {
2228 case MMC_POWER_OFF:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002229 htc_pwrsink_set(PWRSINK_SDCARD, 0);
2230 if (!host->sdcc_irq_disabled) {
2231 if (host->plat->cfg_mpm_sdiowakeup)
2232 host->plat->cfg_mpm_sdiowakeup(
2233 mmc_dev(mmc), SDC_DAT1_DISABLE);
2234 disable_irq(host->core_irqres->start);
2235 host->sdcc_irq_disabled = 1;
2236 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302237 /*
2238 * As VDD pad rail is always on, set low voltage for VDD
2239 * pad rail when slot is unused (when card is not present
2240 * or during system suspend).
2241 */
2242 msmsdcc_set_vddp_low_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002243 msmsdcc_setup_pins(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002244 break;
2245 case MMC_POWER_UP:
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302246 /* writing PWR_UP bit is redundant */
San Mehat9d2bd732009-09-22 16:44:22 -07002247 pwr |= MCI_PWR_UP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002248 if (host->sdcc_irq_disabled) {
2249 if (host->plat->cfg_mpm_sdiowakeup)
2250 host->plat->cfg_mpm_sdiowakeup(
2251 mmc_dev(mmc), SDC_DAT1_ENABLE);
2252 enable_irq(host->core_irqres->start);
2253 host->sdcc_irq_disabled = 0;
2254 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302255 msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002256 msmsdcc_setup_pins(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07002257 break;
2258 case MMC_POWER_ON:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002259 htc_pwrsink_set(PWRSINK_SDCARD, 100);
San Mehat9d2bd732009-09-22 16:44:22 -07002260 pwr |= MCI_PWR_ON;
2261 break;
2262 }
2263
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002264 spin_lock_irqsave(&host->lock, flags);
2265 if (!host->clks_on) {
2266 /* force the clocks to be on */
2267 msmsdcc_setup_clocks(host, true);
2268 /*
2269 * give atleast 2 MCLK cycles delay for clocks
2270 * and SDCC core to stabilize
2271 */
2272 msmsdcc_delay(host);
2273 }
2274 writel_relaxed(clk, host->base + MMCICLOCK);
2275 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002276
2277 if (host->pwr != pwr) {
2278 host->pwr = pwr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002279 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302280 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002281 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002282 if (!host->clks_on) {
2283 /* force the clocks to be off */
2284 msmsdcc_setup_clocks(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002285 }
2286
2287 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
2288 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2289 if (!host->plat->sdiowakeup_irq) {
2290 writel_relaxed(MCI_SDIOINTMASK,
2291 host->base + MMCIMASK0);
2292 mb();
2293 if (host->plat->cfg_mpm_sdiowakeup &&
2294 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2295 host->plat->cfg_mpm_sdiowakeup(
2296 mmc_dev(mmc), SDC_DAT1_ENWAKE);
2297 msmsdcc_enable_irq_wake(host);
2298 } else if (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2299 writel_relaxed(0, host->base + MMCIMASK0);
2300 } else {
2301 writel_relaxed(MCI_SDIOINTMASK,
2302 host->base + MMCIMASK0);
2303 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302304 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002305 }
2306 msmsdcc_setup_clocks(host, false);
2307 host->clks_on = 0;
2308 }
San Mehat4adbbcc2009-11-08 13:00:37 -08002309 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002310}
2311
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002312int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2313{
2314 struct msmsdcc_host *host = mmc_priv(mmc);
2315 u32 clk;
2316
2317 clk = readl_relaxed(host->base + MMCICLOCK);
2318 pr_debug("Changing to pwr_save=%d", pwrsave);
2319 if (pwrsave && msmsdcc_is_pwrsave(host))
2320 clk |= MCI_CLK_PWRSAVE;
2321 else
2322 clk &= ~MCI_CLK_PWRSAVE;
2323 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302324 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002325
2326 return 0;
2327}
2328
2329static int msmsdcc_get_ro(struct mmc_host *mmc)
2330{
2331 int status = -ENOSYS;
2332 struct msmsdcc_host *host = mmc_priv(mmc);
2333
2334 if (host->plat->wpswitch) {
2335 status = host->plat->wpswitch(mmc_dev(mmc));
2336 } else if (host->plat->wpswitch_gpio) {
2337 status = gpio_request(host->plat->wpswitch_gpio,
2338 "SD_WP_Switch");
2339 if (status) {
2340 pr_err("%s: %s: Failed to request GPIO %d\n",
2341 mmc_hostname(mmc), __func__,
2342 host->plat->wpswitch_gpio);
2343 } else {
2344 status = gpio_direction_input(
2345 host->plat->wpswitch_gpio);
2346 if (!status) {
2347 /*
2348 * Wait for atleast 300ms as debounce
2349 * time for GPIO input to stabilize.
2350 */
2351 msleep(300);
2352 status = gpio_get_value_cansleep(
2353 host->plat->wpswitch_gpio);
2354 status ^= !host->plat->wpswitch_polarity;
2355 }
2356 gpio_free(host->plat->wpswitch_gpio);
2357 }
2358 }
2359
2360 if (status < 0)
2361 status = -ENOSYS;
2362 pr_debug("%s: Card read-only status %d\n", __func__, status);
2363
2364 return status;
2365}
2366
2367#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002368static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2369{
2370 struct msmsdcc_host *host = mmc_priv(mmc);
2371 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002372
2373 if (enable) {
2374 spin_lock_irqsave(&host->lock, flags);
2375 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
2376 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
2377 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2378 spin_unlock_irqrestore(&host->lock, flags);
2379 } else {
2380 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
2381 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
2382 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2383 }
2384 mb();
2385}
2386#endif /* CONFIG_MMC_MSM_SDIO_SUPPORT */
2387
2388#ifdef CONFIG_PM_RUNTIME
2389static int msmsdcc_enable(struct mmc_host *mmc)
2390{
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302391 int rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002392 struct device *dev = mmc->parent;
2393
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302394 if (dev->power.runtime_status == RPM_SUSPENDING) {
2395 if (mmc->suspend_task == current) {
2396 pm_runtime_get_noresume(dev);
2397 goto out;
2398 }
2399 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002400
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302401 rc = pm_runtime_get_sync(dev);
2402
2403 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002404 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2405 __func__, rc);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302406 return rc;
2407 }
2408out:
2409 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002410}
2411
2412static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2413{
2414 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302415 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002416
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302417 if (host->plat->disable_runtime_pm)
2418 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002419 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO)
2420 return -ENOTSUPP;
2421
2422 rc = pm_runtime_put_sync(mmc->parent);
2423
2424 if (rc < 0)
2425 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2426 __func__, rc);
2427 return rc;
2428}
2429#else
2430#define msmsdcc_enable NULL
2431#define msmsdcc_disable NULL
2432#endif
2433
2434static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2435 struct mmc_ios *ios)
2436{
2437 struct msmsdcc_host *host = mmc_priv(mmc);
2438 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302439 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002440
2441 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2442 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302443 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002444 goto out;
2445 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2446 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302447 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002448 goto out;
2449 }
San Mehat9d2bd732009-09-22 16:44:22 -07002450
2451 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002452 /*
2453 * If we are here means voltage switch from high voltage to
2454 * low voltage is required
2455 */
2456
2457 /*
2458 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2459 * register until they become all zeros.
2460 */
2461 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302462 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002463 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2464 mmc_hostname(mmc), __func__);
2465 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002466 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002467
2468 /* Stop SD CLK output. */
2469 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2470 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302471 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002472 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002473
2474 /*
2475 * Switch VDDPX from high voltage to low voltage
2476 * to change the VDD of the SD IO pads.
2477 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302478 rc = msmsdcc_set_vddp_low_vol(host);
2479 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002480 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002481
2482 spin_lock_irqsave(&host->lock, flags);
2483 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2484 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302485 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002486 host->io_pad_pwr_switch = 1;
2487 spin_unlock_irqrestore(&host->lock, flags);
2488
2489 /* Wait 5 ms for the voltage regulater in the card to become stable. */
2490 usleep_range(5000, 5500);
2491
2492 spin_lock_irqsave(&host->lock, flags);
2493 /* Start SD CLK output. */
2494 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2495 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302496 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002497 spin_unlock_irqrestore(&host->lock, flags);
2498
2499 /*
2500 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
2501 * don't become all ones within 1 ms then a Voltage Switch
2502 * sequence has failed and a power cycle to the card is required.
2503 * Otherwise Voltage Switch sequence is completed successfully.
2504 */
2505 usleep_range(1000, 1500);
2506
2507 spin_lock_irqsave(&host->lock, flags);
2508 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
2509 != (0xF << 1)) {
2510 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
2511 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302512 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002513 goto out_unlock;
2514 }
2515
2516out_unlock:
2517 spin_unlock_irqrestore(&host->lock, flags);
2518out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302519 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002520}
2521
2522static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2523 u8 phase);
2524/* Initialize the DLL (Programmable Delay Line ) */
2525static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
2526{
2527 int rc = 0;
2528 u32 wait_timeout;
2529
2530 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
2531 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2532 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2533
2534 /* Write 1 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 msmsdcc_delay(host);
2539
2540 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
2541 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2542 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2543
2544 /* Initialize the phase to 0 */
2545 rc = msmsdcc_config_cm_sdc4_dll_phase(host, 0);
2546 if (rc)
2547 goto out;
2548
2549 wait_timeout = 1000;
2550 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
2551 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
2552 /* max. wait for 1 sec for LOCK bit to be set */
2553 if (--wait_timeout == 0) {
2554 pr_err("%s: %s: DLL failed to lock at phase: %d",
2555 mmc_hostname(host->mmc), __func__, 0);
2556 rc = -1;
2557 goto out;
2558 }
2559 /* wait for 1ms */
2560 usleep_range(1000, 1500);
2561 }
2562out:
2563 return rc;
2564}
2565
2566/*
2567 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
2568 * calibration sequence. This function should be called before
2569 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
2570 * commands (CMD17/CMD18).
2571 */
2572static void msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
2573{
2574 /* Set CDR_EN bit to 1. */
2575 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) |
2576 MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2577
2578 /* Set CDR_EXT_EN bit to 0. */
2579 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2580 & ~MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2581
2582 /* Set CK_OUT_EN bit to 0. */
2583 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2584 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2585
2586 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2587 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)
2588 ;
2589
2590 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2591 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2592 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2593
2594 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register is 1. */
2595 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN))
2596 ;
2597}
2598
2599static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2600 u8 phase)
2601{
2602 int rc = 0;
2603 u32 mclk_freq = 0;
2604 u32 wait_timeout;
2605
2606 /* Set CDR_EN bit to 0. */
2607 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2608 & ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2609
2610 /* Set CDR_EXT_EN bit to 1. */
2611 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2612 | MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2613
2614 /* Program the MCLK value to MCLK_FREQ bit field */
2615 if (host->clk_rate <= 112000000)
2616 mclk_freq = 0;
2617 else if (host->clk_rate <= 125000000)
2618 mclk_freq = 1;
2619 else if (host->clk_rate <= 137000000)
2620 mclk_freq = 2;
2621 else if (host->clk_rate <= 150000000)
2622 mclk_freq = 3;
2623 else if (host->clk_rate <= 162000000)
2624 mclk_freq = 4;
2625 else if (host->clk_rate <= 175000000)
2626 mclk_freq = 5;
2627 else if (host->clk_rate <= 187000000)
2628 mclk_freq = 6;
2629 else if (host->clk_rate <= 200000000)
2630 mclk_freq = 7;
2631
2632 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2633 & ~(7 << 24)) | (mclk_freq << 24)),
2634 host->base + MCI_DLL_CONFIG);
2635
2636 /* Set CK_OUT_EN bit to 0. */
2637 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2638 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2639
2640 /* Set DLL_EN bit to 1. */
2641 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2642 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
2643
2644 wait_timeout = 1000;
2645 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2646 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN) {
2647 /* max. wait for 1 sec for LOCK bit for be set */
2648 if (--wait_timeout == 0) {
2649 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 0",
2650 mmc_hostname(host->mmc), __func__, phase);
2651 rc = -1;
2652 goto out;
2653 }
2654 /* wait for 1ms */
2655 usleep_range(1000, 1500);
2656 }
2657
2658 /*
2659 * Write the selected DLL clock output phase (0 ... 15)
2660 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
2661 */
2662 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2663 & ~(0xF << 20)) | (phase << 20)),
2664 host->base + MCI_DLL_CONFIG);
2665
2666 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2667 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2668 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2669
2670 wait_timeout = 1000;
2671 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
2672 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)) {
2673 /* max. wait for 1 sec for LOCK bit for be set */
2674 if (--wait_timeout == 0) {
2675 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 1",
2676 mmc_hostname(host->mmc), __func__, phase);
2677 rc = -1;
2678 goto out;
2679 }
2680 /* wait for 1ms */
2681 usleep_range(1000, 1500);
2682 }
2683out:
2684 return rc;
2685}
2686
2687static int msmsdcc_execute_tuning(struct mmc_host *mmc)
2688{
2689 struct msmsdcc_host *host = mmc_priv(mmc);
2690 u8 phase;
2691 u8 *data_buf;
2692 u8 tuned_phases[16], tuned_phase_cnt = 0;
2693 int rc = 0;
2694
2695 /* Tuning is only required for SDR50 & SDR104 modes */
2696 if (!host->tuning_needed) {
2697 rc = 0;
2698 goto out;
2699 }
2700
2701 host->cmd19_tuning_in_progress = 1;
2702 /*
2703 * Make sure that clock is always enabled when DLL
2704 * tuning is in progress. Keeping PWRSAVE ON may
2705 * turn off the clock. So let's disable the PWRSAVE
2706 * here and re-enable it once tuning is completed.
2707 */
2708 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2709 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302710 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002711 /* first of all reset the tuning block */
2712 rc = msmsdcc_init_cm_sdc4_dll(host);
2713 if (rc)
2714 goto out;
2715
2716 data_buf = kmalloc(64, GFP_KERNEL);
2717 if (!data_buf) {
2718 rc = -ENOMEM;
2719 goto out;
2720 }
2721
2722 phase = 0;
2723 do {
2724 struct mmc_command cmd = {0};
2725 struct mmc_data data = {0};
2726 struct mmc_request mrq = {
2727 .cmd = &cmd,
2728 .data = &data
2729 };
2730 struct scatterlist sg;
2731
2732 /* set the phase in delay line hw block */
2733 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2734 if (rc)
2735 goto kfree;
2736
2737 cmd.opcode = MMC_SEND_TUNING_BLOCK;
2738 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
2739
2740 data.blksz = 64;
2741 data.blocks = 1;
2742 data.flags = MMC_DATA_READ;
2743 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
2744
2745 data.sg = &sg;
2746 data.sg_len = 1;
2747 sg_init_one(&sg, data_buf, 64);
2748 memset(data_buf, 0, 64);
2749 mmc_wait_for_req(mmc, &mrq);
2750
2751 if (!cmd.error && !data.error &&
2752 !memcmp(data_buf, cmd19_tuning_block, 64)) {
2753 /* tuning is successful with this tuning point */
2754 tuned_phases[tuned_phase_cnt++] = phase;
2755 }
2756 } while (++phase < 16);
2757
2758 kfree(data_buf);
2759
2760 if (tuned_phase_cnt) {
2761 tuned_phase_cnt--;
2762 tuned_phase_cnt = (tuned_phase_cnt * 3) / 4;
2763 phase = tuned_phases[tuned_phase_cnt];
2764 /*
2765 * Finally set the selected phase in delay
2766 * line hw block.
2767 */
2768 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2769 if (rc)
2770 goto out;
2771 } else {
2772 /* tuning failed */
2773 rc = -EAGAIN;
2774 pr_err("%s: %s: no tuning point found",
2775 mmc_hostname(mmc), __func__);
2776 }
2777 goto out;
2778
2779kfree:
2780 kfree(data_buf);
2781out:
2782 /* re-enable PWESAVE */
2783 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2784 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302785 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002786 host->cmd19_tuning_in_progress = 0;
2787 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07002788}
2789
2790static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002791 .enable = msmsdcc_enable,
2792 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07002793 .request = msmsdcc_request,
2794 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002795 .get_ro = msmsdcc_get_ro,
2796#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002797 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002798#endif
2799 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
2800 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07002801};
2802
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002803static unsigned int
2804msmsdcc_slot_status(struct msmsdcc_host *host)
2805{
2806 int status;
2807 unsigned int gpio_no = host->plat->status_gpio;
2808
2809 status = gpio_request(gpio_no, "SD_HW_Detect");
2810 if (status) {
2811 pr_err("%s: %s: Failed to request GPIO %d\n",
2812 mmc_hostname(host->mmc), __func__, gpio_no);
2813 } else {
2814 status = gpio_direction_input(gpio_no);
2815 if (!status)
2816 status = !gpio_get_value_cansleep(gpio_no);
2817 gpio_free(gpio_no);
2818 }
2819 return status;
2820}
2821
San Mehat9d2bd732009-09-22 16:44:22 -07002822static void
2823msmsdcc_check_status(unsigned long data)
2824{
2825 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
2826 unsigned int status;
2827
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002828 if (host->plat->status || host->plat->status_gpio) {
2829 if (host->plat->status)
2830 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07002831 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002832 status = msmsdcc_slot_status(host);
2833
2834 host->eject = !status;
2835 if (status ^ host->oldstat) {
2836 pr_info("%s: Slot status change detected (%d -> %d)\n",
2837 mmc_hostname(host->mmc), host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07002838 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002839 }
2840 host->oldstat = status;
2841 } else {
2842 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07002843 }
San Mehat9d2bd732009-09-22 16:44:22 -07002844}
2845
2846static irqreturn_t
2847msmsdcc_platform_status_irq(int irq, void *dev_id)
2848{
2849 struct msmsdcc_host *host = dev_id;
2850
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002851 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07002852 msmsdcc_check_status((unsigned long) host);
2853 return IRQ_HANDLED;
2854}
2855
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002856static irqreturn_t
2857msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
2858{
2859 struct msmsdcc_host *host = dev_id;
2860
2861 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
2862 spin_lock(&host->lock);
2863 if (!host->sdio_irq_disabled) {
2864 disable_irq_nosync(irq);
2865 if (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2866 wake_lock(&host->sdio_wlock);
2867 msmsdcc_disable_irq_wake(host);
2868 }
2869 host->sdio_irq_disabled = 1;
2870 }
2871 if (host->plat->is_sdio_al_client) {
2872 if (!host->clks_on) {
2873 msmsdcc_setup_clocks(host, true);
2874 host->clks_on = 1;
2875 }
2876 if (host->sdcc_irq_disabled) {
2877 writel_relaxed(host->mci_irqenable,
2878 host->base + MMCIMASK0);
2879 mb();
2880 enable_irq(host->core_irqres->start);
2881 host->sdcc_irq_disabled = 0;
2882 }
2883 wake_lock(&host->sdio_wlock);
2884 }
2885 spin_unlock(&host->lock);
2886
2887 return IRQ_HANDLED;
2888}
2889
San Mehat9d2bd732009-09-22 16:44:22 -07002890static void
2891msmsdcc_status_notify_cb(int card_present, void *dev_id)
2892{
2893 struct msmsdcc_host *host = dev_id;
2894
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002895 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07002896 card_present);
2897 msmsdcc_check_status((unsigned long) host);
2898}
2899
San Mehat9d2bd732009-09-22 16:44:22 -07002900static int
2901msmsdcc_init_dma(struct msmsdcc_host *host)
2902{
2903 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
2904 host->dma.host = host;
2905 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07002906 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07002907
2908 if (!host->dmares)
2909 return -ENODEV;
2910
2911 host->dma.nc = dma_alloc_coherent(NULL,
2912 sizeof(struct msmsdcc_nc_dmadata),
2913 &host->dma.nc_busaddr,
2914 GFP_KERNEL);
2915 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07002916 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07002917 return -ENOMEM;
2918 }
2919 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
2920 host->dma.cmd_busaddr = host->dma.nc_busaddr;
2921 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
2922 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
2923 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07002924 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07002925
2926 return 0;
2927}
2928
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002929#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
2930/**
2931 * Allocate and Connect a SDCC peripheral's SPS endpoint
2932 *
2933 * This function allocates endpoint context and
2934 * connect it with memory endpoint by calling
2935 * appropriate SPS driver APIs.
2936 *
2937 * Also registers a SPS callback function with
2938 * SPS driver
2939 *
2940 * This function should only be called once typically
2941 * during driver probe.
2942 *
2943 * @host - Pointer to sdcc host structure
2944 * @ep - Pointer to sps endpoint data structure
2945 * @is_produce - 1 means Producer endpoint
2946 * 0 means Consumer endpoint
2947 *
2948 * @return - 0 if successful else negative value.
2949 *
2950 */
2951static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
2952 struct msmsdcc_sps_ep_conn_data *ep,
2953 bool is_producer)
2954{
2955 int rc = 0;
2956 struct sps_pipe *sps_pipe_handle;
2957 struct sps_connect *sps_config = &ep->config;
2958 struct sps_register_event *sps_event = &ep->event;
2959
2960 /* Allocate endpoint context */
2961 sps_pipe_handle = sps_alloc_endpoint();
2962 if (!sps_pipe_handle) {
2963 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
2964 mmc_hostname(host->mmc), is_producer);
2965 rc = -ENOMEM;
2966 goto out;
2967 }
2968
2969 /* Get default connection configuration for an endpoint */
2970 rc = sps_get_config(sps_pipe_handle, sps_config);
2971 if (rc) {
2972 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
2973 " rc=%d", mmc_hostname(host->mmc),
2974 (u32)sps_pipe_handle, rc);
2975 goto get_config_err;
2976 }
2977
2978 /* Modify the default connection configuration */
2979 if (is_producer) {
2980 /*
2981 * For SDCC producer transfer, source should be
2982 * SDCC peripheral where as destination should
2983 * be system memory.
2984 */
2985 sps_config->source = host->sps.bam_handle;
2986 sps_config->destination = SPS_DEV_HANDLE_MEM;
2987 /* Producer pipe will handle this connection */
2988 sps_config->mode = SPS_MODE_SRC;
2989 sps_config->options =
2990 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
2991 } else {
2992 /*
2993 * For SDCC consumer transfer, source should be
2994 * system memory where as destination should
2995 * SDCC peripheral
2996 */
2997 sps_config->source = SPS_DEV_HANDLE_MEM;
2998 sps_config->destination = host->sps.bam_handle;
2999 sps_config->mode = SPS_MODE_DEST;
3000 sps_config->options =
3001 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3002 }
3003
3004 /* Producer pipe index */
3005 sps_config->src_pipe_index = host->sps.src_pipe_index;
3006 /* Consumer pipe index */
3007 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
3008 /*
3009 * This event thresold value is only significant for BAM-to-BAM
3010 * transfer. It's ignored for BAM-to-System mode transfer.
3011 */
3012 sps_config->event_thresh = 0x10;
3013 /*
3014 * Max. no of scatter/gather buffers that can
3015 * be passed by block layer = 32 (NR_SG).
3016 * Each BAM descritor needs 64 bits (8 bytes).
3017 * One BAM descriptor is required per buffer transfer.
3018 * So we would require total 256 (32 * 8) bytes of descriptor FIFO.
3019 * But due to HW limitation we need to allocate atleast one extra
3020 * descriptor memory (256 bytes + 8 bytes). But in order to be
3021 * in power of 2, we are allocating 512 bytes of memory.
3022 */
3023 sps_config->desc.size = 512;
3024 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
3025 sps_config->desc.size,
3026 &sps_config->desc.phys_base,
3027 GFP_KERNEL);
3028
Pratibhasagar V00b94332011-10-18 14:57:27 +05303029 if (!sps_config->desc.base) {
3030 rc = -ENOMEM;
3031 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3032 , mmc_hostname(host->mmc));
3033 goto get_config_err;
3034 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003035 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3036
3037 /* Establish connection between peripheral and memory endpoint */
3038 rc = sps_connect(sps_pipe_handle, sps_config);
3039 if (rc) {
3040 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3041 " rc=%d", mmc_hostname(host->mmc),
3042 (u32)sps_pipe_handle, rc);
3043 goto sps_connect_err;
3044 }
3045
3046 sps_event->mode = SPS_TRIGGER_CALLBACK;
3047 sps_event->options = SPS_O_EOT;
3048 sps_event->callback = msmsdcc_sps_complete_cb;
3049 sps_event->xfer_done = NULL;
3050 sps_event->user = (void *)host;
3051
3052 /* Register callback event for EOT (End of transfer) event. */
3053 rc = sps_register_event(sps_pipe_handle, sps_event);
3054 if (rc) {
3055 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3056 " rc=%d", mmc_hostname(host->mmc),
3057 (u32)sps_pipe_handle, rc);
3058 goto reg_event_err;
3059 }
3060 /* Now save the sps pipe handle */
3061 ep->pipe_handle = sps_pipe_handle;
3062 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3063 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3064 __func__, is_producer ? "READ" : "WRITE",
3065 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3066 goto out;
3067
3068reg_event_err:
3069 sps_disconnect(sps_pipe_handle);
3070sps_connect_err:
3071 dma_free_coherent(mmc_dev(host->mmc),
3072 sps_config->desc.size,
3073 sps_config->desc.base,
3074 sps_config->desc.phys_base);
3075get_config_err:
3076 sps_free_endpoint(sps_pipe_handle);
3077out:
3078 return rc;
3079}
3080
3081/**
3082 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3083 *
3084 * This function disconnect endpoint and deallocates
3085 * endpoint context.
3086 *
3087 * This function should only be called once typically
3088 * during driver remove.
3089 *
3090 * @host - Pointer to sdcc host structure
3091 * @ep - Pointer to sps endpoint data structure
3092 *
3093 */
3094static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3095 struct msmsdcc_sps_ep_conn_data *ep)
3096{
3097 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3098 struct sps_connect *sps_config = &ep->config;
3099 struct sps_register_event *sps_event = &ep->event;
3100
3101 sps_event->xfer_done = NULL;
3102 sps_event->callback = NULL;
3103 sps_register_event(sps_pipe_handle, sps_event);
3104 sps_disconnect(sps_pipe_handle);
3105 dma_free_coherent(mmc_dev(host->mmc),
3106 sps_config->desc.size,
3107 sps_config->desc.base,
3108 sps_config->desc.phys_base);
3109 sps_free_endpoint(sps_pipe_handle);
3110}
3111
3112/**
3113 * Reset SDCC peripheral's SPS endpoint
3114 *
3115 * This function disconnects an endpoint.
3116 *
3117 * This function should be called for reseting
3118 * SPS endpoint when data transfer error is
3119 * encountered during data transfer. This
3120 * can be considered as soft reset to endpoint.
3121 *
3122 * This function should only be called if
3123 * msmsdcc_sps_init() is already called.
3124 *
3125 * @host - Pointer to sdcc host structure
3126 * @ep - Pointer to sps endpoint data structure
3127 *
3128 * @return - 0 if successful else negative value.
3129 */
3130static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3131 struct msmsdcc_sps_ep_conn_data *ep)
3132{
3133 int rc = 0;
3134 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3135
3136 rc = sps_disconnect(sps_pipe_handle);
3137 if (rc) {
3138 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3139 " rc=%d", mmc_hostname(host->mmc), __func__,
3140 (u32)sps_pipe_handle, rc);
3141 goto out;
3142 }
3143 out:
3144 return rc;
3145}
3146
3147/**
3148 * Restore SDCC peripheral's SPS endpoint
3149 *
3150 * This function connects an endpoint.
3151 *
3152 * This function should be called for restoring
3153 * SPS endpoint after data transfer error is
3154 * encountered during data transfer. This
3155 * can be considered as soft reset to endpoint.
3156 *
3157 * This function should only be called if
3158 * msmsdcc_sps_reset_ep() is called before.
3159 *
3160 * @host - Pointer to sdcc host structure
3161 * @ep - Pointer to sps endpoint data structure
3162 *
3163 * @return - 0 if successful else negative value.
3164 */
3165static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3166 struct msmsdcc_sps_ep_conn_data *ep)
3167{
3168 int rc = 0;
3169 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3170 struct sps_connect *sps_config = &ep->config;
3171 struct sps_register_event *sps_event = &ep->event;
3172
3173 /* Establish connection between peripheral and memory endpoint */
3174 rc = sps_connect(sps_pipe_handle, sps_config);
3175 if (rc) {
3176 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3177 " rc=%d", mmc_hostname(host->mmc), __func__,
3178 (u32)sps_pipe_handle, rc);
3179 goto out;
3180 }
3181
3182 /* Register callback event for EOT (End of transfer) event. */
3183 rc = sps_register_event(sps_pipe_handle, sps_event);
3184 if (rc) {
3185 pr_err("%s: %s: sps_register_event() failed!!!"
3186 " pipe_handle=0x%x, rc=%d",
3187 mmc_hostname(host->mmc), __func__,
3188 (u32)sps_pipe_handle, rc);
3189 goto reg_event_err;
3190 }
3191 goto out;
3192
3193reg_event_err:
3194 sps_disconnect(sps_pipe_handle);
3195out:
3196 return rc;
3197}
3198
3199/**
3200 * Initialize SPS HW connected with SDCC core
3201 *
3202 * This function register BAM HW resources with
3203 * SPS driver and then initialize 2 SPS endpoints
3204 *
3205 * This function should only be called once typically
3206 * during driver probe.
3207 *
3208 * @host - Pointer to sdcc host structure
3209 *
3210 * @return - 0 if successful else negative value.
3211 *
3212 */
3213static int msmsdcc_sps_init(struct msmsdcc_host *host)
3214{
3215 int rc = 0;
3216 struct sps_bam_props bam = {0};
3217
3218 host->bam_base = ioremap(host->bam_memres->start,
3219 resource_size(host->bam_memres));
3220 if (!host->bam_base) {
3221 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3222 " size=0x%x", mmc_hostname(host->mmc),
3223 host->bam_memres->start,
3224 (host->bam_memres->end -
3225 host->bam_memres->start));
3226 rc = -ENOMEM;
3227 goto out;
3228 }
3229
3230 bam.phys_addr = host->bam_memres->start;
3231 bam.virt_addr = host->bam_base;
3232 /*
3233 * This event thresold value is only significant for BAM-to-BAM
3234 * transfer. It's ignored for BAM-to-System mode transfer.
3235 */
3236 bam.event_threshold = 0x10; /* Pipe event threshold */
3237 /*
3238 * This threshold controls when the BAM publish
3239 * the descriptor size on the sideband interface.
3240 * SPS HW will only be used when
3241 * data transfer size > MCI_FIFOSIZE (64 bytes).
3242 * PIO mode will be used when
3243 * data transfer size < MCI_FIFOSIZE (64 bytes).
3244 * So set this thresold value to 64 bytes.
3245 */
3246 bam.summing_threshold = 64;
3247 /* SPS driver wll handle the SDCC BAM IRQ */
3248 bam.irq = (u32)host->bam_irqres->start;
3249 bam.manage = SPS_BAM_MGR_LOCAL;
3250
3251 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3252 (u32)bam.phys_addr);
3253 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3254 (u32)bam.virt_addr);
3255
3256 /* Register SDCC Peripheral BAM device to SPS driver */
3257 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3258 if (rc) {
3259 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3260 mmc_hostname(host->mmc), rc);
3261 goto reg_bam_err;
3262 }
3263 pr_info("%s: BAM device registered. bam_handle=0x%x",
3264 mmc_hostname(host->mmc), host->sps.bam_handle);
3265
3266 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3267 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3268
3269 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3270 SPS_PROD_PERIPHERAL);
3271 if (rc)
3272 goto sps_reset_err;
3273 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3274 SPS_CONS_PERIPHERAL);
3275 if (rc)
3276 goto cons_conn_err;
3277
3278 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3279 mmc_hostname(host->mmc),
3280 (unsigned long long)host->bam_memres->start,
3281 (unsigned int)host->bam_irqres->start);
3282 goto out;
3283
3284cons_conn_err:
3285 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3286sps_reset_err:
3287 sps_deregister_bam_device(host->sps.bam_handle);
3288reg_bam_err:
3289 iounmap(host->bam_base);
3290out:
3291 return rc;
3292}
3293
3294/**
3295 * De-initialize SPS HW connected with SDCC core
3296 *
3297 * This function deinitialize SPS endpoints and then
3298 * deregisters BAM resources from SPS driver.
3299 *
3300 * This function should only be called once typically
3301 * during driver remove.
3302 *
3303 * @host - Pointer to sdcc host structure
3304 *
3305 */
3306static void msmsdcc_sps_exit(struct msmsdcc_host *host)
3307{
3308 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
3309 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3310 sps_deregister_bam_device(host->sps.bam_handle);
3311 iounmap(host->bam_base);
3312}
3313#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
3314
3315static ssize_t
3316show_polling(struct device *dev, struct device_attribute *attr, char *buf)
3317{
3318 struct mmc_host *mmc = dev_get_drvdata(dev);
3319 struct msmsdcc_host *host = mmc_priv(mmc);
3320 int poll;
3321 unsigned long flags;
3322
3323 spin_lock_irqsave(&host->lock, flags);
3324 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
3325 spin_unlock_irqrestore(&host->lock, flags);
3326
3327 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
3328}
3329
3330static ssize_t
3331set_polling(struct device *dev, struct device_attribute *attr,
3332 const char *buf, size_t count)
3333{
3334 struct mmc_host *mmc = dev_get_drvdata(dev);
3335 struct msmsdcc_host *host = mmc_priv(mmc);
3336 int value;
3337 unsigned long flags;
3338
3339 sscanf(buf, "%d", &value);
3340
3341 spin_lock_irqsave(&host->lock, flags);
3342 if (value) {
3343 mmc->caps |= MMC_CAP_NEEDS_POLL;
3344 mmc_detect_change(host->mmc, 0);
3345 } else {
3346 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3347 }
3348#ifdef CONFIG_HAS_EARLYSUSPEND
3349 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
3350#endif
3351 spin_unlock_irqrestore(&host->lock, flags);
3352 return count;
3353}
3354
3355static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
3356 show_polling, set_polling);
3357static struct attribute *dev_attrs[] = {
3358 &dev_attr_polling.attr,
3359 NULL,
3360};
3361static struct attribute_group dev_attr_grp = {
3362 .attrs = dev_attrs,
3363};
3364
3365#ifdef CONFIG_HAS_EARLYSUSPEND
3366static void msmsdcc_early_suspend(struct early_suspend *h)
3367{
3368 struct msmsdcc_host *host =
3369 container_of(h, struct msmsdcc_host, early_suspend);
3370 unsigned long flags;
3371
3372 spin_lock_irqsave(&host->lock, flags);
3373 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
3374 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3375 spin_unlock_irqrestore(&host->lock, flags);
3376};
3377static void msmsdcc_late_resume(struct early_suspend *h)
3378{
3379 struct msmsdcc_host *host =
3380 container_of(h, struct msmsdcc_host, early_suspend);
3381 unsigned long flags;
3382
3383 if (host->polling_enabled) {
3384 spin_lock_irqsave(&host->lock, flags);
3385 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
3386 mmc_detect_change(host->mmc, 0);
3387 spin_unlock_irqrestore(&host->lock, flags);
3388 }
3389};
3390#endif
3391
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303392void msmsdcc_print_regs(const char *name, void __iomem *base,
3393 unsigned int no_of_regs)
3394{
3395 unsigned int i;
3396
3397 if (!base)
3398 return;
3399 pr_info("===== %s: Register Dumps @base=0x%x =====\n",
3400 name, (u32)base);
3401 for (i = 0; i < no_of_regs; i = i + 4) {
3402 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x.\n", i*4,
3403 (u32)readl_relaxed(base + i*4),
3404 (u32)readl_relaxed(base + ((i+1)*4)),
3405 (u32)readl_relaxed(base + ((i+2)*4)),
3406 (u32)readl_relaxed(base + ((i+3)*4)));
3407 }
3408}
3409
3410static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
3411{
3412 /* Dump current state of SDCC clocks, power and irq */
3413 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
3414 (host->pwr ? "ON" : "OFF"));
3415 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
3416 mmc_hostname(host->mmc),
3417 (host->clks_on ? "ON" : "OFF"),
3418 (u32)clk_get_rate(host->clk));
3419 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
3420 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
3421
3422 /* Now dump SDCC registers. Don't print FIFO registers */
3423 if (host->clks_on)
3424 msmsdcc_print_regs("SDCC-CORE", host->base, 28);
3425
3426 if (host->curr.data) {
3427 if (msmsdcc_check_dma_op_req(host->curr.data))
3428 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
3429 else if (host->is_dma_mode)
3430 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
3431 mmc_hostname(host->mmc), host->dma.busy,
3432 host->dma.channel, host->dma.crci);
3433 else if (host->is_sps_mode)
3434 pr_info("%s: SPS mode: busy=%d\n",
3435 mmc_hostname(host->mmc), host->sps.busy);
3436
3437 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
3438 mmc_hostname(host->mmc), host->curr.xfer_size,
3439 host->curr.data_xfered, host->curr.xfer_remain);
3440 pr_info("%s: got_dataend=%d, prog_enable=%d,"
3441 " wait_for_auto_prog_done=%d,"
3442 " got_auto_prog_done=%d\n",
3443 mmc_hostname(host->mmc), host->curr.got_dataend,
3444 host->prog_enable, host->curr.wait_for_auto_prog_done,
3445 host->curr.got_auto_prog_done);
3446 }
3447
3448}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003449static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
3450{
3451 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3452 struct mmc_request *mrq;
3453 unsigned long flags;
3454
3455 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003456 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003457 pr_info("%s: %s: dummy CMD52 timeout\n",
3458 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003459 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003460 }
3461
3462 mrq = host->curr.mrq;
3463
3464 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303465 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
3466 mrq->cmd->opcode);
3467 msmsdcc_dump_sdcc_state(host);
3468
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003469 if (!mrq->cmd->error)
3470 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303471 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003472 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003473 if (mrq->data && !mrq->data->error)
3474 mrq->data->error = -ETIMEDOUT;
3475 host->curr.data_xfered = 0;
3476 if (host->dma.sg && host->is_dma_mode) {
3477 msm_dmov_stop_cmd(host->dma.channel,
3478 &host->dma.hdr, 0);
3479 } else if (host->sps.sg && host->is_sps_mode) {
3480 /* Stop current SPS transfer */
3481 msmsdcc_sps_exit_curr_xfer(host);
3482 } else {
3483 msmsdcc_reset_and_restore(host);
3484 msmsdcc_stop_data(host);
3485 if (mrq->data && mrq->data->stop)
3486 msmsdcc_start_command(host,
3487 mrq->data->stop, 0);
3488 else
3489 msmsdcc_request_end(host, mrq);
3490 }
3491 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05303492 host->prog_enable = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003493 msmsdcc_reset_and_restore(host);
3494 msmsdcc_request_end(host, mrq);
3495 }
3496 }
3497 spin_unlock_irqrestore(&host->lock, flags);
3498}
3499
San Mehat9d2bd732009-09-22 16:44:22 -07003500static int
3501msmsdcc_probe(struct platform_device *pdev)
3502{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003503 struct mmc_platform_data *plat = pdev->dev.platform_data;
San Mehat9d2bd732009-09-22 16:44:22 -07003504 struct msmsdcc_host *host;
3505 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003506 unsigned long flags;
3507 struct resource *core_irqres = NULL;
3508 struct resource *bam_irqres = NULL;
3509 struct resource *core_memres = NULL;
3510 struct resource *dml_memres = NULL;
3511 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07003512 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07003513 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05303514 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003515 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07003516
3517 /* must have platform data */
3518 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003519 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003520 ret = -EINVAL;
3521 goto out;
3522 }
3523
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003524 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07003525 return -EINVAL;
3526
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003527 if (plat->is_sdio_al_client)
3528 if (!plat->sdio_lpm_gpio_setup || !plat->sdiowakeup_irq)
3529 return -EINVAL;
3530
San Mehat9d2bd732009-09-22 16:44:22 -07003531 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003532 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003533 return -ENXIO;
3534 }
3535
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003536 for (i = 0; i < pdev->num_resources; i++) {
3537 if (pdev->resource[i].flags & IORESOURCE_MEM) {
3538 if (!strcmp(pdev->resource[i].name,
3539 "sdcc_dml_addr"))
3540 dml_memres = &pdev->resource[i];
3541 else if (!strcmp(pdev->resource[i].name,
3542 "sdcc_bam_addr"))
3543 bam_memres = &pdev->resource[i];
3544 else
3545 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07003546
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003547 }
3548 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
3549 if (!strcmp(pdev->resource[i].name,
3550 "sdcc_bam_irq"))
3551 bam_irqres = &pdev->resource[i];
3552 else
3553 core_irqres = &pdev->resource[i];
3554 }
Krishna Konda25786ec2011-07-25 16:21:36 -07003555 if (pdev->resource[i].flags & IORESOURCE_DMA) {
3556 if (!strncmp(pdev->resource[i].name,
3557 "sdcc_dma_chnl",
3558 sizeof("sdcc_dma_chnl")))
3559 dmares = &pdev->resource[i];
3560 else if (!strncmp(pdev->resource[i].name,
3561 "sdcc_dma_crci",
3562 sizeof("sdcc_dma_crci")))
3563 dma_crci_res = &pdev->resource[i];
3564 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003565 }
3566
3567 if (!core_irqres || !core_memres) {
3568 pr_err("%s: Invalid sdcc core resource\n", __func__);
3569 return -ENXIO;
3570 }
3571
3572 /*
3573 * Both BAM and DML memory resource should be preset.
3574 * BAM IRQ resource should also be present.
3575 */
3576 if ((bam_memres && !dml_memres) ||
3577 (!bam_memres && dml_memres) ||
3578 ((bam_memres && dml_memres) && !bam_irqres)) {
3579 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003580 return -ENXIO;
3581 }
3582
3583 /*
3584 * Setup our host structure
3585 */
San Mehat9d2bd732009-09-22 16:44:22 -07003586 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
3587 if (!mmc) {
3588 ret = -ENOMEM;
3589 goto out;
3590 }
3591
3592 host = mmc_priv(mmc);
3593 host->pdev_id = pdev->id;
3594 host->plat = plat;
3595 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08003596 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05303597
3598 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003599 host->is_sps_mode = 1;
3600 else if (dmares)
3601 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07003602
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003603 host->base = ioremap(core_memres->start,
3604 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07003605 if (!host->base) {
3606 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003607 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003608 }
3609
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003610 host->core_irqres = core_irqres;
3611 host->bam_irqres = bam_irqres;
3612 host->core_memres = core_memres;
3613 host->dml_memres = dml_memres;
3614 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07003615 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07003616 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07003617 spin_lock_init(&host->lock);
3618
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003619#ifdef CONFIG_MMC_EMBEDDED_SDIO
3620 if (plat->embedded_sdio)
3621 mmc_set_embedded_sdio_data(mmc,
3622 &plat->embedded_sdio->cis,
3623 &plat->embedded_sdio->cccr,
3624 plat->embedded_sdio->funcs,
3625 plat->embedded_sdio->num_funcs);
3626#endif
3627
Sahitya Tummala62612cf2010-12-08 15:03:03 +05303628 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
3629 (unsigned long)host);
3630
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003631 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
3632 (unsigned long)host);
3633 if (host->is_dma_mode) {
3634 /* Setup DMA */
3635 ret = msmsdcc_init_dma(host);
3636 if (ret)
3637 goto ioremap_free;
3638 } else {
3639 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003640 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003641 }
3642
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003643 /*
3644 * Setup SDCC clock if derived from Dayatona
3645 * fabric core clock.
3646 */
3647 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07003648 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003649 if (!IS_ERR(host->dfab_pclk)) {
3650 /* Set the clock rate to 64MHz for max. performance */
3651 ret = clk_set_rate(host->dfab_pclk, 64000000);
3652 if (ret)
3653 goto dfab_pclk_put;
3654 ret = clk_enable(host->dfab_pclk);
3655 if (ret)
3656 goto dfab_pclk_put;
3657 } else
3658 goto dma_free;
3659 }
3660
3661 /*
3662 * Setup main peripheral bus clock
3663 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003664 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003665 if (!IS_ERR(host->pclk)) {
3666 ret = clk_enable(host->pclk);
3667 if (ret)
3668 goto pclk_put;
3669
3670 host->pclk_rate = clk_get_rate(host->pclk);
3671 }
3672
3673 /*
3674 * Setup SDC MMC clock
3675 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003676 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07003677 if (IS_ERR(host->clk)) {
3678 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003679 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07003680 }
3681
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003682 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
3683 if (ret) {
3684 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
3685 goto clk_put;
3686 }
3687
3688 ret = clk_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003689 if (ret)
3690 goto clk_put;
3691
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003692 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303693 if (!host->clk_rate)
3694 dev_err(&pdev->dev, "Failed to read MCLK\n");
3695 /*
3696 * Set the register write delay according to min. clock frequency
3697 * supported and update later when the host->clk_rate changes.
3698 */
3699 host->reg_write_delay =
3700 (1 + ((3 * USEC_PER_SEC) /
3701 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003702
3703 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05303704 /* Apply Hard reset to SDCC to put it in power on default state */
3705 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003706
3707 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07003708 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003709 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07003710 goto clk_disable;
3711 }
3712
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003713
3714 /* Clocks has to be running before accessing SPS/DML HW blocks */
3715 if (host->is_sps_mode) {
3716 /* Initialize SPS */
3717 ret = msmsdcc_sps_init(host);
3718 if (ret)
3719 goto vreg_deinit;
3720 /* Initialize DML */
3721 ret = msmsdcc_dml_init(host);
3722 if (ret)
3723 goto sps_exit;
3724 }
San Mehat9d2bd732009-09-22 16:44:22 -07003725
San Mehat9d2bd732009-09-22 16:44:22 -07003726 /*
3727 * Setup MMC host structure
3728 */
3729 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003730 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
3731 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003732 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003733 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
3734 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07003735
San Mehat9d2bd732009-09-22 16:44:22 -07003736 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05303737 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05303738
3739 /*
3740 * If we send the CMD23 before multi block write/read command
3741 * then we need not to send CMD12 at the end of the transfer.
3742 * If we don't send the CMD12 then only way to detect the PROG_DONE
3743 * status is to use the AUTO_PROG_DONE status provided by SDCC4
3744 * controller. So let's enable the CMD23 for SDCC4 only.
3745 */
Sahitya Tummala85fa0702011-09-15 09:39:37 +05303746 if (!plat->disable_cmd23 && host->plat->sdcc_v4_sup)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05303747 mmc->caps |= MMC_CAP_CMD23;
3748
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003749 mmc->caps |= plat->uhs_caps;
3750 /*
3751 * XPC controls the maximum current in the default speed mode of SDXC
3752 * card. XPC=0 means 100mA (max.) but speed class is not supported.
3753 * XPC=1 means 150mA (max.) and speed class is supported.
3754 */
3755 if (plat->xpc_cap)
3756 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
3757 MMC_CAP_SET_XPC_180);
3758
3759 if (plat->nonremovable)
3760 mmc->caps |= MMC_CAP_NONREMOVABLE;
3761#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
3762 mmc->caps |= MMC_CAP_SDIO_IRQ;
3763#endif
3764
3765 if (plat->is_sdio_al_client)
3766 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07003767
Martin K. Petersena36274e2010-09-10 01:33:59 -04003768 mmc->max_segs = NR_SG;
San Mehat9d2bd732009-09-22 16:44:22 -07003769 mmc->max_blk_size = 4096; /* MCI_DATA_CTL BLOCKSIZE up to 4096 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003770 mmc->max_blk_count = 65535;
San Mehat9d2bd732009-09-22 16:44:22 -07003771
3772 mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */
3773 mmc->max_seg_size = mmc->max_req_size;
3774
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003775 writel_relaxed(0, host->base + MMCIMASK0);
3776 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -07003777
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003778 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
3779 mb();
3780 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07003781
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003782 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
3783 DRIVER_NAME " (cmd)", host);
3784 if (ret)
3785 goto dml_exit;
3786
3787 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
3788 DRIVER_NAME " (pio)", host);
3789 if (ret)
3790 goto irq_free;
3791
3792 /*
3793 * Enable SDCC IRQ only when host is powered on. Otherwise, this
3794 * IRQ is un-necessarily being monitored by MPM (Modem power
3795 * management block) during idle-power collapse. The MPM will be
3796 * configured to monitor the DATA1 GPIO line with level-low trigger
3797 * and thus depending on the GPIO status, it prevents TCXO shutdown
3798 * during idle-power collapse.
3799 */
3800 disable_irq(core_irqres->start);
3801 host->sdcc_irq_disabled = 1;
3802
3803 if (plat->sdiowakeup_irq) {
3804 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3805 mmc_hostname(mmc));
3806 ret = request_irq(plat->sdiowakeup_irq,
3807 msmsdcc_platform_sdiowakeup_irq,
3808 IRQF_SHARED | IRQF_TRIGGER_LOW,
3809 DRIVER_NAME "sdiowakeup", host);
3810 if (ret) {
3811 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
3812 plat->sdiowakeup_irq, ret);
3813 goto pio_irq_free;
3814 } else {
3815 spin_lock_irqsave(&host->lock, flags);
3816 if (!host->sdio_irq_disabled) {
3817 disable_irq_nosync(plat->sdiowakeup_irq);
3818 host->sdio_irq_disabled = 1;
3819 }
3820 spin_unlock_irqrestore(&host->lock, flags);
3821 }
3822 }
3823
3824 if (plat->cfg_mpm_sdiowakeup) {
3825 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3826 mmc_hostname(mmc));
3827 }
3828
3829 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
3830 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003831 /*
3832 * Setup card detect change
3833 */
3834
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003835 if (plat->status || plat->status_gpio) {
3836 if (plat->status)
3837 host->oldstat = plat->status(mmc_dev(host->mmc));
3838 else
3839 host->oldstat = msmsdcc_slot_status(host);
3840 host->eject = !host->oldstat;
3841 }
San Mehat9d2bd732009-09-22 16:44:22 -07003842
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003843 if (plat->status_irq) {
3844 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07003845 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003846 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07003847 DRIVER_NAME " (slot)",
3848 host);
3849 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003850 pr_err("Unable to get slot IRQ %d (%d)\n",
3851 plat->status_irq, ret);
3852 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003853 }
3854 } else if (plat->register_status_notify) {
3855 plat->register_status_notify(msmsdcc_status_notify_cb, host);
3856 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003857 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07003858 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003859
3860 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003861
3862 ret = pm_runtime_set_active(&(pdev)->dev);
3863 if (ret < 0)
3864 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3865 __func__, ret);
3866 /*
3867 * There is no notion of suspend/resume for SD/MMC/SDIO
3868 * cards. So host can be suspended/resumed with out
3869 * worrying about its children.
3870 */
3871 pm_suspend_ignore_children(&(pdev)->dev, true);
3872
3873 /*
3874 * MMC/SD/SDIO bus suspend/resume operations are defined
3875 * only for the slots that will be used for non-removable
3876 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
3877 * defined. Otherwise, they simply become card removal and
3878 * insertion events during suspend and resume respectively.
3879 * Hence, enable run-time PM only for slots for which bus
3880 * suspend/resume operations are defined.
3881 */
3882#ifdef CONFIG_MMC_UNSAFE_RESUME
3883 /*
3884 * If this capability is set, MMC core will enable/disable host
3885 * for every claim/release operation on a host. We use this
3886 * notification to increment/decrement runtime pm usage count.
3887 */
3888 mmc->caps |= MMC_CAP_DISABLE;
3889 pm_runtime_enable(&(pdev)->dev);
3890#else
3891 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
3892 mmc->caps |= MMC_CAP_DISABLE;
3893 pm_runtime_enable(&(pdev)->dev);
3894 }
3895#endif
3896 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
3897 (unsigned long)host);
3898
San Mehat9d2bd732009-09-22 16:44:22 -07003899 mmc_add_host(mmc);
3900
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003901#ifdef CONFIG_HAS_EARLYSUSPEND
3902 host->early_suspend.suspend = msmsdcc_early_suspend;
3903 host->early_suspend.resume = msmsdcc_late_resume;
3904 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
3905 register_early_suspend(&host->early_suspend);
3906#endif
San Mehat9d2bd732009-09-22 16:44:22 -07003907
Krishna Konda25786ec2011-07-25 16:21:36 -07003908 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
3909 " dmacrcri %d\n", mmc_hostname(mmc),
3910 (unsigned long long)core_memres->start,
3911 (unsigned int) core_irqres->start,
3912 (unsigned int) plat->status_irq, host->dma.channel,
3913 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003914
3915 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
3916 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
3917 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
3918 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
3919 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
3920 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
3921 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
3922 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
3923 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
3924 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
3925 host->eject);
3926 pr_info("%s: Power save feature enable = %d\n",
3927 mmc_hostname(mmc), msmsdcc_pwrsave);
3928
Krishna Konda25786ec2011-07-25 16:21:36 -07003929 if (host->is_dma_mode && host->dma.channel != -1
3930 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003931 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003932 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003933 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003934 mmc_hostname(mmc), host->dma.cmd_busaddr,
3935 host->dma.cmdptr_busaddr);
3936 } else if (host->is_sps_mode) {
3937 pr_info("%s: SPS-BAM data transfer mode available\n",
3938 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003939 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003940 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003941
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003942#if defined(CONFIG_DEBUG_FS)
3943 msmsdcc_dbg_createhost(host);
3944#endif
3945 if (!plat->status_irq) {
3946 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
3947 if (ret)
3948 goto platform_irq_free;
3949 }
San Mehat9d2bd732009-09-22 16:44:22 -07003950 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003951
3952 platform_irq_free:
3953 del_timer_sync(&host->req_tout_timer);
3954 pm_runtime_disable(&(pdev)->dev);
3955 pm_runtime_set_suspended(&(pdev)->dev);
3956
3957 if (plat->status_irq)
3958 free_irq(plat->status_irq, host);
3959 sdiowakeup_irq_free:
3960 wake_lock_destroy(&host->sdio_suspend_wlock);
3961 if (plat->sdiowakeup_irq)
3962 free_irq(plat->sdiowakeup_irq, host);
3963 pio_irq_free:
3964 if (plat->sdiowakeup_irq)
3965 wake_lock_destroy(&host->sdio_wlock);
3966 free_irq(core_irqres->start, host);
3967 irq_free:
3968 free_irq(core_irqres->start, host);
3969 dml_exit:
3970 if (host->is_sps_mode)
3971 msmsdcc_dml_exit(host);
3972 sps_exit:
3973 if (host->is_sps_mode)
3974 msmsdcc_sps_exit(host);
3975 vreg_deinit:
3976 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07003977 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003978 clk_disable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003979 clk_put:
3980 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003981 pclk_disable:
3982 if (!IS_ERR(host->pclk))
3983 clk_disable(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07003984 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003985 if (!IS_ERR(host->pclk))
3986 clk_put(host->pclk);
3987 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3988 clk_disable(host->dfab_pclk);
3989 dfab_pclk_put:
3990 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3991 clk_put(host->dfab_pclk);
3992 dma_free:
3993 if (host->is_dma_mode) {
3994 if (host->dmares)
3995 dma_free_coherent(NULL,
3996 sizeof(struct msmsdcc_nc_dmadata),
3997 host->dma.nc, host->dma.nc_busaddr);
3998 }
3999 ioremap_free:
4000 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07004001 host_free:
4002 mmc_free_host(mmc);
4003 out:
4004 return ret;
4005}
4006
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004007static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07004008{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004009 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4010 struct mmc_platform_data *plat;
4011 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004012
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004013 if (!mmc)
4014 return -ENXIO;
4015
4016 if (pm_runtime_suspended(&(pdev)->dev))
4017 pm_runtime_resume(&(pdev)->dev);
4018
4019 host = mmc_priv(mmc);
4020
4021 DBG(host, "Removing SDCC device = %d\n", pdev->id);
4022 plat = host->plat;
4023
4024 if (!plat->status_irq)
4025 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
4026
4027 del_timer_sync(&host->req_tout_timer);
4028 tasklet_kill(&host->dma_tlet);
4029 tasklet_kill(&host->sps.tlet);
4030 mmc_remove_host(mmc);
4031
4032 if (plat->status_irq)
4033 free_irq(plat->status_irq, host);
4034
4035 wake_lock_destroy(&host->sdio_suspend_wlock);
4036 if (plat->sdiowakeup_irq) {
4037 wake_lock_destroy(&host->sdio_wlock);
4038 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
4039 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07004040 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004041
4042 free_irq(host->core_irqres->start, host);
4043 free_irq(host->core_irqres->start, host);
4044
4045 clk_put(host->clk);
4046 if (!IS_ERR(host->pclk))
4047 clk_put(host->pclk);
4048 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4049 clk_put(host->dfab_pclk);
4050
4051 msmsdcc_vreg_init(host, false);
4052
4053 if (host->is_dma_mode) {
4054 if (host->dmares)
4055 dma_free_coherent(NULL,
4056 sizeof(struct msmsdcc_nc_dmadata),
4057 host->dma.nc, host->dma.nc_busaddr);
4058 }
4059
4060 if (host->is_sps_mode) {
4061 msmsdcc_dml_exit(host);
4062 msmsdcc_sps_exit(host);
4063 }
4064
4065 iounmap(host->base);
4066 mmc_free_host(mmc);
4067
4068#ifdef CONFIG_HAS_EARLYSUSPEND
4069 unregister_early_suspend(&host->early_suspend);
4070#endif
4071 pm_runtime_disable(&(pdev)->dev);
4072 pm_runtime_set_suspended(&(pdev)->dev);
4073
4074 return 0;
4075}
4076
4077#ifdef CONFIG_MSM_SDIO_AL
4078int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4079{
4080 struct msmsdcc_host *host = mmc_priv(mmc);
4081 unsigned long flags;
4082
4083 spin_lock_irqsave(&host->lock, flags);
4084 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
4085 enable ? "En" : "Dis");
4086
4087 if (enable) {
4088 if (!host->sdcc_irq_disabled) {
4089 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05304090 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004091 host->sdcc_irq_disabled = 1;
4092 }
4093
4094 if (host->clks_on) {
4095 msmsdcc_setup_clocks(host, false);
4096 host->clks_on = 0;
4097 }
4098
4099 if (!host->sdio_gpio_lpm) {
4100 spin_unlock_irqrestore(&host->lock, flags);
4101 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
4102 spin_lock_irqsave(&host->lock, flags);
4103 host->sdio_gpio_lpm = 1;
4104 }
4105
4106 if (host->sdio_irq_disabled) {
4107 msmsdcc_enable_irq_wake(host);
4108 enable_irq(host->plat->sdiowakeup_irq);
4109 host->sdio_irq_disabled = 0;
4110 }
4111 } else {
4112 if (!host->sdio_irq_disabled) {
4113 disable_irq_nosync(host->plat->sdiowakeup_irq);
4114 host->sdio_irq_disabled = 1;
4115 msmsdcc_disable_irq_wake(host);
4116 }
4117
4118 if (host->sdio_gpio_lpm) {
4119 spin_unlock_irqrestore(&host->lock, flags);
4120 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
4121 spin_lock_irqsave(&host->lock, flags);
4122 host->sdio_gpio_lpm = 0;
4123 }
4124
4125 if (!host->clks_on) {
4126 msmsdcc_setup_clocks(host, true);
4127 host->clks_on = 1;
4128 }
4129
4130 if (host->sdcc_irq_disabled) {
4131 writel_relaxed(host->mci_irqenable,
4132 host->base + MMCIMASK0);
4133 mb();
4134 enable_irq(host->core_irqres->start);
4135 host->sdcc_irq_disabled = 0;
4136 }
4137 wake_lock_timeout(&host->sdio_wlock, 1);
4138 }
4139 spin_unlock_irqrestore(&host->lock, flags);
4140 return 0;
4141}
4142#else
4143int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4144{
4145 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004146}
4147#endif
4148
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004149#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07004150static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004151msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004152{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004153 struct mmc_host *mmc = dev_get_drvdata(dev);
4154 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07004155 int rc = 0;
4156
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004157 if (host->plat->is_sdio_al_client)
4158 return 0;
4159
Sahitya Tummala7661a452011-07-18 13:28:35 +05304160 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004161 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004162 host->sdcc_suspending = 1;
4163 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07004164
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004165 /*
4166 * If the clocks are already turned off by SDIO clients (as
4167 * part of LPM), then clocks should be turned on before
4168 * calling mmc_suspend_host() because mmc_suspend_host might
4169 * send some commands to the card. The clocks will be turned
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304170 * off again after mmc_suspend_host. Thus for SDIO
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004171 * cards, clocks will be turned on before mmc_suspend_host
4172 * and turned off after mmc_suspend_host.
4173 */
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304174 if (mmc->card && mmc_card_sdio(mmc->card)) {
4175 mmc->ios.clock = host->clk_rate;
4176 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4177 }
San Mehat9d2bd732009-09-22 16:44:22 -07004178
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004179 /*
4180 * MMC core thinks that host is disabled by now since
4181 * runtime suspend is scheduled after msmsdcc_disable()
4182 * is called. Thus, MMC core will try to enable the host
4183 * while suspending it. This results in a synchronous
4184 * runtime resume request while in runtime suspending
4185 * context and hence inorder to complete this resume
4186 * requet, it will wait for suspend to be complete,
4187 * but runtime suspend also can not proceed further
4188 * until the host is resumed. Thus, it leads to a hang.
4189 * Hence, increase the pm usage count before suspending
4190 * the host so that any resume requests after this will
4191 * simple become pm usage counter increment operations.
4192 */
4193 pm_runtime_get_noresume(dev);
4194 rc = mmc_suspend_host(mmc);
4195 pm_runtime_put_noidle(dev);
4196
4197 if (!rc) {
4198 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
4199 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ)) {
4200 disable_irq(host->core_irqres->start);
4201 host->sdcc_irq_disabled = 1;
4202
4203 /*
4204 * If MMC core level suspend is not supported,
4205 * turn off clocks to allow deep sleep (TCXO
4206 * shutdown).
4207 */
4208 mmc->ios.clock = 0;
4209 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4210 enable_irq(host->core_irqres->start);
4211 host->sdcc_irq_disabled = 0;
4212
4213 if (host->plat->sdiowakeup_irq) {
4214 host->sdio_irq_disabled = 0;
4215 msmsdcc_enable_irq_wake(host);
4216 enable_irq(host->plat->sdiowakeup_irq);
4217 }
4218 }
4219 }
4220 host->sdcc_suspending = 0;
4221 mmc->suspend_task = NULL;
4222 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
4223 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004224 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304225 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004226 return rc;
4227}
4228
4229static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004230msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004231{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004232 struct mmc_host *mmc = dev_get_drvdata(dev);
4233 struct msmsdcc_host *host = mmc_priv(mmc);
4234 unsigned long flags;
4235
4236 if (host->plat->is_sdio_al_client)
4237 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07004238
Sahitya Tummala7661a452011-07-18 13:28:35 +05304239 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004240 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004241 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
4242 if (host->sdcc_irq_disabled) {
4243 enable_irq(host->core_irqres->start);
4244 host->sdcc_irq_disabled = 0;
4245 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304246 mmc->ios.clock = host->clk_rate;
4247 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07004248
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304249 spin_lock_irqsave(&host->lock, flags);
4250 writel_relaxed(host->mci_irqenable,
4251 host->base + MMCIMASK0);
4252 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07004253
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304254 if ((mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) &&
4255 !host->sdio_irq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004256 if (host->plat->sdiowakeup_irq) {
4257 disable_irq_nosync(
4258 host->plat->sdiowakeup_irq);
4259 msmsdcc_disable_irq_wake(host);
4260 host->sdio_irq_disabled = 1;
4261 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304262 }
San Mehat9d2bd732009-09-22 16:44:22 -07004263
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304264 spin_unlock_irqrestore(&host->lock, flags);
4265 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004266
4267 mmc_resume_host(mmc);
4268
4269 /*
4270 * FIXME: Clearing of flags must be handled in clients
4271 * resume handler.
4272 */
4273 spin_lock_irqsave(&host->lock, flags);
4274 mmc->pm_flags = 0;
4275 spin_unlock_irqrestore(&host->lock, flags);
4276
4277 /*
4278 * After resuming the host wait for sometime so that
4279 * the SDIO work will be processed.
4280 */
4281 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO)) {
4282 if ((host->plat->cfg_mpm_sdiowakeup ||
4283 host->plat->sdiowakeup_irq) &&
4284 wake_lock_active(&host->sdio_wlock))
4285 wake_lock_timeout(&host->sdio_wlock, 1);
4286 }
4287
4288 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004289 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304290 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004291 return 0;
4292}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004293
4294static int msmsdcc_runtime_idle(struct device *dev)
4295{
4296 struct mmc_host *mmc = dev_get_drvdata(dev);
4297 struct msmsdcc_host *host = mmc_priv(mmc);
4298
4299 if (host->plat->is_sdio_al_client)
4300 return 0;
4301
4302 /* Idle timeout is not configurable for now */
4303 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
4304
4305 return -EAGAIN;
4306}
4307
4308static int msmsdcc_pm_suspend(struct device *dev)
4309{
4310 struct mmc_host *mmc = dev_get_drvdata(dev);
4311 struct msmsdcc_host *host = mmc_priv(mmc);
4312 int rc = 0;
4313
4314 if (host->plat->is_sdio_al_client)
4315 return 0;
4316
4317
4318 if (host->plat->status_irq)
4319 disable_irq(host->plat->status_irq);
4320
4321 if (!pm_runtime_suspended(dev))
4322 rc = msmsdcc_runtime_suspend(dev);
4323
4324 return rc;
4325}
4326
4327static int msmsdcc_pm_resume(struct device *dev)
4328{
4329 struct mmc_host *mmc = dev_get_drvdata(dev);
4330 struct msmsdcc_host *host = mmc_priv(mmc);
4331 int rc = 0;
4332
4333 if (host->plat->is_sdio_al_client)
4334 return 0;
4335
Sahitya Tummalafb486372011-09-02 19:01:49 +05304336 if (!pm_runtime_suspended(dev))
4337 rc = msmsdcc_runtime_resume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004338 if (host->plat->status_irq) {
4339 msmsdcc_check_status((unsigned long)host);
4340 enable_irq(host->plat->status_irq);
4341 }
4342
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004343 return rc;
4344}
4345
Daniel Walker08ecfde2010-06-23 12:32:20 -07004346#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004347#define msmsdcc_runtime_suspend NULL
4348#define msmsdcc_runtime_resume NULL
4349#define msmsdcc_runtime_idle NULL
4350#define msmsdcc_pm_suspend NULL
4351#define msmsdcc_pm_resume NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07004352#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004353
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004354static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
4355 .runtime_suspend = msmsdcc_runtime_suspend,
4356 .runtime_resume = msmsdcc_runtime_resume,
4357 .runtime_idle = msmsdcc_runtime_idle,
4358 .suspend = msmsdcc_pm_suspend,
4359 .resume = msmsdcc_pm_resume,
4360};
4361
San Mehat9d2bd732009-09-22 16:44:22 -07004362static struct platform_driver msmsdcc_driver = {
4363 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004364 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07004365 .driver = {
4366 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004367 .pm = &msmsdcc_dev_pm_ops,
San Mehat9d2bd732009-09-22 16:44:22 -07004368 },
4369};
4370
4371static int __init msmsdcc_init(void)
4372{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004373#if defined(CONFIG_DEBUG_FS)
4374 int ret = 0;
4375 ret = msmsdcc_dbg_init();
4376 if (ret) {
4377 pr_err("Failed to create debug fs dir \n");
4378 return ret;
4379 }
4380#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004381 return platform_driver_register(&msmsdcc_driver);
4382}
4383
4384static void __exit msmsdcc_exit(void)
4385{
4386 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004387
4388#if defined(CONFIG_DEBUG_FS)
4389 debugfs_remove(debugfs_file);
4390 debugfs_remove(debugfs_dir);
4391#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004392}
4393
4394module_init(msmsdcc_init);
4395module_exit(msmsdcc_exit);
4396
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004397MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07004398MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004399
4400#if defined(CONFIG_DEBUG_FS)
4401
4402static int
4403msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
4404{
4405 file->private_data = inode->i_private;
4406 return 0;
4407}
4408
4409static ssize_t
4410msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
4411 size_t count, loff_t *ppos)
4412{
4413 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
4414 char buf[1024];
4415 int max, i;
4416
4417 i = 0;
4418 max = sizeof(buf) - 1;
4419
4420 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
4421 host->curr.cmd, host->curr.data);
4422 if (host->curr.cmd) {
4423 struct mmc_command *cmd = host->curr.cmd;
4424
4425 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
4426 cmd->opcode, cmd->arg, cmd->flags);
4427 }
4428 if (host->curr.data) {
4429 struct mmc_data *data = host->curr.data;
4430 i += scnprintf(buf + i, max - i,
4431 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
4432 data->timeout_ns, data->timeout_clks,
4433 data->blksz, data->blocks, data->error,
4434 data->flags);
4435 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
4436 host->curr.xfer_size, host->curr.xfer_remain,
4437 host->curr.data_xfered, host->dma.sg);
4438 }
4439
4440 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
4441}
4442
4443static const struct file_operations msmsdcc_dbg_state_ops = {
4444 .read = msmsdcc_dbg_state_read,
4445 .open = msmsdcc_dbg_state_open,
4446};
4447
4448static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
4449{
4450 if (debugfs_dir) {
4451 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
4452 0644, debugfs_dir, host,
4453 &msmsdcc_dbg_state_ops);
4454 }
4455}
4456
4457static int __init msmsdcc_dbg_init(void)
4458{
4459 int err;
4460
4461 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
4462 if (IS_ERR(debugfs_dir)) {
4463 err = PTR_ERR(debugfs_dir);
4464 debugfs_dir = NULL;
4465 return err;
4466 }
4467
4468 return 0;
4469}
4470#endif