blob: 31c41722f1d7e89ffb1b38c88b9aa01fdfee5a88 [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);
Subhash Jadavanibbf38a32011-10-12 16:47:52 +05301027 else if (data->flags & MMC_DATA_WRITE)
1028 datactrl |= MCI_DATA_PEND;
San Mehat9d2bd732009-09-22 16:44:22 -07001029
San Mehat56a8b5b2009-11-21 12:29:46 -08001030 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001031 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001032 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -07001033
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001034 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
1035 /* Use ADM (Application Data Mover) HW for Data transfer */
1036 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001037 host->cmd_timeout = timeout;
1038 host->cmd_pio_irqmask = pio_irqmask;
1039 host->cmd_datactrl = datactrl;
1040 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001041
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001042 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1043 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001044 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001045
1046 if (cmd) {
1047 msmsdcc_start_command_deferred(host, cmd, &c);
1048 host->cmd_c = c;
1049 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001050 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1051 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1052 host->base + MMCIMASK0);
1053 mb();
1054 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001055 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001056 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001057 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001058
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001059 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001060
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001061 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1062 (~(MCI_IRQ_PIO))) | pio_irqmask,
1063 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001064 writel_relaxed(datactrl, base + MMCIDATACTRL);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301065 /*
1066 * We don't need delay after writing to DATA_CTRL register
1067 * if we are not writing to CMD register immediately after
1068 * this. As we already have delay before sending the
1069 * command, we just need mb() here.
1070 */
1071 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001072
1073 if (cmd) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001074 msmsdcc_delay(host); /* Delay between data/command */
San Mehat56a8b5b2009-11-21 12:29:46 -08001075 /* Daisy-chain the command if requested */
1076 msmsdcc_start_command(host, cmd, c);
1077 }
San Mehat9d2bd732009-09-22 16:44:22 -07001078 }
1079}
1080
1081static void
1082msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1083{
San Mehat56a8b5b2009-11-21 12:29:46 -08001084 msmsdcc_start_command_deferred(host, cmd, &c);
1085 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001086}
1087
1088static void
1089msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1090 unsigned int status)
1091{
1092 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001093 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1094 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1095 pr_err("%s: Data CRC error\n",
1096 mmc_hostname(host->mmc));
1097 pr_err("%s: opcode 0x%.8x\n", __func__,
1098 data->mrq->cmd->opcode);
1099 pr_err("%s: blksz %d, blocks %d\n", __func__,
1100 data->blksz, data->blocks);
1101 data->error = -EILSEQ;
1102 }
San Mehat9d2bd732009-09-22 16:44:22 -07001103 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001104 /* CRC is optional for the bus test commands, not all
1105 * cards respond back with CRC. However controller
1106 * waits for the CRC and times out. Hence ignore the
1107 * data timeouts during the Bustest.
1108 */
1109 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1110 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1111 pr_err("%s: Data timeout\n",
1112 mmc_hostname(host->mmc));
1113 data->error = -ETIMEDOUT;
1114 }
San Mehat9d2bd732009-09-22 16:44:22 -07001115 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001116 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001117 data->error = -EIO;
1118 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001119 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001120 data->error = -EIO;
1121 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001122 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001123 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001124 data->error = -EIO;
1125 }
San Mehat9d2bd732009-09-22 16:44:22 -07001126
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001127 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001128 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001129 host->dummy_52_needed = 0;
1130}
San Mehat9d2bd732009-09-22 16:44:22 -07001131
1132static int
1133msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1134{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001135 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001136 uint32_t *ptr = (uint32_t *) buffer;
1137 int count = 0;
1138
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301139 if (remain % 4)
1140 remain = ((remain >> 2) + 1) << 2;
1141
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001142 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1143
1144 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001145 ptr++;
1146 count += sizeof(uint32_t);
1147
1148 remain -= sizeof(uint32_t);
1149 if (remain == 0)
1150 break;
1151 }
1152 return count;
1153}
1154
1155static int
1156msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001157 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001158{
1159 void __iomem *base = host->base;
1160 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001161 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001162
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001163 while (readl_relaxed(base + MMCISTATUS) &
1164 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1165 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001166
San Mehat9d2bd732009-09-22 16:44:22 -07001167 count = min(remain, maxcnt);
1168
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301169 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1170 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001171 ptr += count;
1172 remain -= count;
1173
1174 if (remain == 0)
1175 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001176 }
1177 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001178
1179 return ptr - buffer;
1180}
1181
San Mehat1cd22962010-02-03 12:59:29 -08001182static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001183msmsdcc_pio_irq(int irq, void *dev_id)
1184{
1185 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001186 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001187 uint32_t status;
1188
Murali Palnati36448a42011-09-02 15:06:18 +05301189 spin_lock(&host->lock);
1190
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001191 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001192
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001193 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301194 (MCI_IRQ_PIO)) == 0) {
1195 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001196 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301197 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001198
1199#if IRQ_DEBUG
1200 msmsdcc_print_status(host, "irq1-r", status);
1201#endif
1202
San Mehat9d2bd732009-09-22 16:44:22 -07001203 do {
1204 unsigned long flags;
1205 unsigned int remain, len;
1206 char *buffer;
1207
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001208 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1209 | MCI_RXDATAAVLBL)))
1210 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001211
1212 /* Map the current scatter buffer */
1213 local_irq_save(flags);
1214 buffer = kmap_atomic(sg_page(host->pio.sg),
1215 KM_BIO_SRC_IRQ) + host->pio.sg->offset;
1216 buffer += host->pio.sg_off;
1217 remain = host->pio.sg->length - host->pio.sg_off;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001218
San Mehat9d2bd732009-09-22 16:44:22 -07001219 len = 0;
1220 if (status & MCI_RXACTIVE)
1221 len = msmsdcc_pio_read(host, buffer, remain);
1222 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001223 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001224
1225 /* Unmap the buffer */
1226 kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
1227 local_irq_restore(flags);
1228
1229 host->pio.sg_off += len;
1230 host->curr.xfer_remain -= len;
1231 host->curr.data_xfered += len;
1232 remain -= len;
1233
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001234 if (remain) /* Done with this page? */
1235 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001236
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001237 if (status & MCI_RXACTIVE && host->curr.user_pages)
1238 flush_dcache_page(sg_page(host->pio.sg));
San Mehat9d2bd732009-09-22 16:44:22 -07001239
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001240 if (!--host->pio.sg_len) {
1241 memset(&host->pio, 0, sizeof(host->pio));
1242 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001243 }
1244
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001245 /* Advance to next sg */
1246 host->pio.sg++;
1247 host->pio.sg_off = 0;
1248
1249 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001250 } while (1);
1251
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001252 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1253 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1254 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1255 host->base + MMCIMASK0);
1256 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301257 /*
1258 * back to back write to MASK0 register don't need
1259 * synchronization delay.
1260 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001261 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1262 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1263 }
1264 mb();
1265 } else if (!host->curr.xfer_remain) {
1266 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1267 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1268 mb();
1269 }
San Mehat9d2bd732009-09-22 16:44:22 -07001270
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001271 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001272
1273 return IRQ_HANDLED;
1274}
1275
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001276static void
1277msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1278
1279static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1280 struct mmc_data *data)
1281{
1282 u32 loop_cnt = 0;
1283
1284 /*
1285 * For read commands with data less than fifo size, it is possible to
1286 * get DATAEND first and RXDATA_AVAIL might be set later because of
1287 * synchronization delay through the asynchronous RX FIFO. Thus, for
1288 * such cases, even after DATAEND interrupt is received software
1289 * should poll for RXDATA_AVAIL until the requested data is read out
1290 * of FIFO. This change is needed to get around this abnormal but
1291 * sometimes expected behavior of SDCC3 controller.
1292 *
1293 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1294 * after the data is loaded into RX FIFO. This would amount to less
1295 * than a microsecond and thus looping for 1000 times is good enough
1296 * for that delay.
1297 */
1298 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1299 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1300 spin_unlock(&host->lock);
1301 msmsdcc_pio_irq(1, host);
1302 spin_lock(&host->lock);
1303 }
1304 }
1305 if (loop_cnt == 1000) {
1306 pr_info("%s: Timed out while polling for Rx Data\n",
1307 mmc_hostname(host->mmc));
1308 data->error = -ETIMEDOUT;
1309 msmsdcc_reset_and_restore(host);
1310 }
1311}
1312
San Mehat9d2bd732009-09-22 16:44:22 -07001313static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1314{
1315 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001316
1317 host->curr.cmd = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001318 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1319 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1320 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1321 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -07001322
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001323 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Sahitya Tummala5a0ae912011-07-18 13:34:01 +05301324 pr_debug("%s: Command timeout\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001325 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001326 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
1327 !host->cmd19_tuning_in_progress) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001328 pr_err("%s: Command CRC error\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001329 cmd->error = -EILSEQ;
1330 }
1331
1332 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001333 if (host->curr.data && host->dma.sg &&
1334 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001335 msm_dmov_stop_cmd(host->dma.channel,
1336 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001337 else if (host->curr.data && host->sps.sg &&
1338 host->is_sps_mode){
1339 /* Stop current SPS transfer */
1340 msmsdcc_sps_exit_curr_xfer(host);
1341 }
San Mehat9d2bd732009-09-22 16:44:22 -07001342 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301343 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001344 msmsdcc_stop_data(host);
1345 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301346 } else { /* host->data == NULL */
1347 if (!cmd->error && host->prog_enable) {
1348 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001349 host->prog_enable = 0;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301350 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001351 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301352 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301353 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301354 host->prog_enable = 0;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001355 if (host->dummy_52_needed)
1356 host->dummy_52_needed = 0;
1357 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001358 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301359 msmsdcc_request_end(host, cmd->mrq);
1360 }
1361 }
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301362 } else if ((cmd == host->curr.mrq->sbc) && cmd->data) {
1363 if (cmd->data->flags & MMC_DATA_READ)
1364 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1365 else
1366 msmsdcc_request_start(host, host->curr.mrq);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001367 }
1368}
1369
San Mehat9d2bd732009-09-22 16:44:22 -07001370static irqreturn_t
1371msmsdcc_irq(int irq, void *dev_id)
1372{
1373 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001374 u32 status;
1375 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001376 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001377
1378 spin_lock(&host->lock);
1379
1380 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001381 struct mmc_command *cmd;
1382 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001383
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001384 if (timer) {
1385 timer = 0;
1386 msmsdcc_delay(host);
1387 }
San Mehat865c8062009-11-13 13:42:06 -08001388
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001389 if (!host->clks_on) {
1390 pr_debug("%s: %s: SDIO async irq received\n",
1391 mmc_hostname(host->mmc), __func__);
1392 host->mmc->ios.clock = host->clk_rate;
1393 spin_unlock(&host->lock);
1394 host->mmc->ops->set_ios(host->mmc, &host->mmc->ios);
1395 spin_lock(&host->lock);
1396 if (host->plat->cfg_mpm_sdiowakeup &&
1397 (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
1398 wake_lock(&host->sdio_wlock);
1399 /* only ansyc interrupt can come when clocks are off */
1400 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301401 if (host->clk_rate <=
1402 msmsdcc_get_min_sup_clk_rate(host))
1403 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001404 }
1405
1406 status = readl_relaxed(host->base + MMCISTATUS);
1407
1408 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1409 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001410 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001411
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001412#if IRQ_DEBUG
1413 msmsdcc_print_status(host, "irq0-r", status);
1414#endif
1415 status &= readl_relaxed(host->base + MMCIMASK0);
1416 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301417 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301418 if (host->clk_rate <=
1419 msmsdcc_get_min_sup_clk_rate(host))
1420 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001421#if IRQ_DEBUG
1422 msmsdcc_print_status(host, "irq0-p", status);
1423#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001424
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001425#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
1426 if (status & MCI_SDIOINTROPE) {
1427 if (host->sdcc_suspending)
1428 wake_lock(&host->sdio_suspend_wlock);
1429 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001430 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001431#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001432 data = host->curr.data;
1433
1434 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001435 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1436 MCI_CMDTIMEOUT)) {
1437 if (status & MCI_CMDTIMEOUT)
1438 pr_debug("%s: dummy CMD52 timeout\n",
1439 mmc_hostname(host->mmc));
1440 if (status & MCI_CMDCRCFAIL)
1441 pr_debug("%s: dummy CMD52 CRC failed\n",
1442 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001443 host->dummy_52_sent = 0;
1444 host->dummy_52_needed = 0;
1445 if (data) {
1446 msmsdcc_stop_data(host);
1447 msmsdcc_request_end(host, data->mrq);
1448 }
1449 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001450 spin_unlock(&host->lock);
1451 return IRQ_HANDLED;
1452 }
1453 break;
1454 }
1455
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001456 /*
1457 * Check for proper command response
1458 */
1459 cmd = host->curr.cmd;
1460 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1461 MCI_CMDTIMEOUT | MCI_PROGDONE |
1462 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1463 msmsdcc_do_cmdirq(host, status);
1464 }
1465
1466 if (data) {
1467 /* Check for data errors */
1468 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1469 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1470 msmsdcc_data_err(host, data, status);
1471 host->curr.data_xfered = 0;
1472 if (host->dma.sg && host->is_dma_mode)
1473 msm_dmov_stop_cmd(host->dma.channel,
1474 &host->dma.hdr, 0);
1475 else if (host->sps.sg && host->is_sps_mode) {
1476 /* Stop current SPS transfer */
1477 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301478 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001479 msmsdcc_reset_and_restore(host);
1480 if (host->curr.data)
1481 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301482 if (!data->stop || (host->curr.mrq->sbc
1483 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001484 timer |=
1485 msmsdcc_request_end(host,
1486 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301487 else if ((host->curr.mrq->sbc
1488 && data->error) ||
1489 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001490 msmsdcc_start_command(host,
1491 data->stop,
1492 0);
1493 timer = 1;
1494 }
1495 }
1496 }
1497
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301498 /* Check for prog done */
1499 if (host->curr.wait_for_auto_prog_done &&
1500 (status & MCI_PROGDONE))
1501 host->curr.got_auto_prog_done = 1;
1502
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001503 /* Check for data done */
1504 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1505 host->curr.got_dataend = 1;
1506
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301507 if (host->curr.got_dataend &&
1508 (!host->curr.wait_for_auto_prog_done ||
1509 (host->curr.wait_for_auto_prog_done &&
1510 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001511 /*
1512 * If DMA is still in progress, we complete
1513 * via the completion handler
1514 */
1515 if (!host->dma.busy && !host->sps.busy) {
1516 /*
1517 * There appears to be an issue in the
1518 * controller where if you request a
1519 * small block transfer (< fifo size),
1520 * you may get your DATAEND/DATABLKEND
1521 * irq without the PIO data irq.
1522 *
1523 * Check to see if theres still data
1524 * to be read, and simulate a PIO irq.
1525 */
1526 if (data->flags & MMC_DATA_READ)
1527 msmsdcc_wait_for_rxdata(host,
1528 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001529 if (!data->error) {
1530 host->curr.data_xfered =
1531 host->curr.xfer_size;
1532 host->curr.xfer_remain -=
1533 host->curr.xfer_size;
1534 }
1535
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001536 if (!host->dummy_52_needed) {
1537 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301538 if (!data->stop ||
1539 (host->curr.mrq->sbc
1540 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001541 msmsdcc_request_end(
1542 host,
1543 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301544 else if ((host->curr.mrq->sbc
1545 && data->error) ||
1546 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001547 msmsdcc_start_command(
1548 host,
1549 data->stop, 0);
1550 timer = 1;
1551 }
1552 } else {
1553 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001554 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001555 &dummy52cmd,
1556 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001557 }
1558 }
1559 }
1560 }
1561
San Mehat9d2bd732009-09-22 16:44:22 -07001562 ret = 1;
1563 } while (status);
1564
1565 spin_unlock(&host->lock);
1566
San Mehat9d2bd732009-09-22 16:44:22 -07001567 return IRQ_RETVAL(ret);
1568}
1569
1570static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001571msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1572{
Subhash Jadavanibbf38a32011-10-12 16:47:52 +05301573 if (mrq->data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001574 /* Queue/read data, daisy-chain command when data starts */
Subhash Jadavanibbf38a32011-10-12 16:47:52 +05301575 if (mrq->sbc && (mrq->data->flags & MMC_DATA_READ))
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301576 msmsdcc_start_data(host, mrq->data, mrq->sbc, 0);
1577 else
1578 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001579 } else {
1580 msmsdcc_start_command(host, mrq->cmd, 0);
1581 }
1582}
1583
1584static void
San Mehat9d2bd732009-09-22 16:44:22 -07001585msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1586{
1587 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001588 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001589
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001590 /*
1591 * Get the SDIO AL client out of LPM.
1592 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001593 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001594 if (host->plat->is_sdio_al_client)
1595 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001596
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301597 /* check if sps pipe reset is pending? */
1598 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1599 msmsdcc_sps_pipes_reset_and_restore(host);
1600 host->sps.pipe_reset_pending = false;
1601 }
1602
San Mehat9d2bd732009-09-22 16:44:22 -07001603 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001604 WARN(host->curr.mrq, "Request in progress\n");
1605 WARN(!host->pwr, "SDCC power is turned off\n");
1606 WARN(!host->clks_on, "SDCC clocks are turned off\n");
1607 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
San Mehat9d2bd732009-09-22 16:44:22 -07001608
1609 if (host->eject) {
1610 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1611 mrq->cmd->error = 0;
1612 mrq->data->bytes_xfered = mrq->data->blksz *
1613 mrq->data->blocks;
1614 } else
1615 mrq->cmd->error = -ENOMEDIUM;
1616
1617 spin_unlock_irqrestore(&host->lock, flags);
1618 mmc_request_done(mmc, mrq);
1619 return;
1620 }
1621
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301622 /*
1623 * Kick the software command timeout timer here.
1624 * Timer expires in 10 secs.
1625 */
1626 mod_timer(&host->req_tout_timer,
1627 (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
San Mehat9d2bd732009-09-22 16:44:22 -07001628
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301629 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301630 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301631 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
1632 mrq->cmd->opcode == 54) {
1633 if (!host->plat->sdcc_v4_sup)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001634 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301635 else
1636 /*
1637 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
1638 * write operations using CMD53 and CMD54.
1639 * Setting this bit with CMD53 would
1640 * automatically triggers PROG_DONE interrupt
1641 * without the need of sending dummy CMD52.
1642 */
1643 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001644 }
San Mehat9d2bd732009-09-22 16:44:22 -07001645 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301646
Pratibhasagar V00b94332011-10-18 14:57:27 +05301647 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301648 mrq->sbc->mrq = mrq;
1649 mrq->sbc->data = mrq->data;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301650 if (mrq->data->flags & MMC_DATA_WRITE) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301651 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301652 msmsdcc_start_command(host, mrq->sbc, 0);
1653 } else {
1654 msmsdcc_request_start(host, mrq);
1655 }
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301656 } else {
1657 msmsdcc_request_start(host, mrq);
1658 }
1659
San Mehat9d2bd732009-09-22 16:44:22 -07001660 spin_unlock_irqrestore(&host->lock, flags);
1661}
1662
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001663static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1664 int min_uV, int max_uV)
1665{
1666 int rc = 0;
1667
1668 if (vreg->set_voltage_sup) {
1669 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1670 if (rc) {
1671 pr_err("%s: regulator_set_voltage(%s) failed."
1672 " min_uV=%d, max_uV=%d, rc=%d\n",
1673 __func__, vreg->name, min_uV, max_uV, rc);
1674 }
1675 }
1676
1677 return rc;
1678}
1679
1680static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1681 int uA_load)
1682{
1683 int rc = 0;
1684
1685 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1686 if (rc < 0)
1687 pr_err("%s: regulator_set_optimum_mode(reg=%s, uA_load=%d)"
1688 " failed. rc=%d\n", __func__, vreg->name,
1689 uA_load, rc);
1690 else
1691 /* regulator_set_optimum_mode() can return non zero value
1692 * even for success case.
1693 */
1694 rc = 0;
1695
1696 return rc;
1697}
1698
1699static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1700 struct device *dev)
1701{
1702 int rc = 0;
1703
1704 /* check if regulator is already initialized? */
1705 if (vreg->reg)
1706 goto out;
1707
1708 /* Get the regulator handle */
1709 vreg->reg = regulator_get(dev, vreg->name);
1710 if (IS_ERR(vreg->reg)) {
1711 rc = PTR_ERR(vreg->reg);
1712 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
1713 __func__, vreg->name, rc);
1714 }
1715out:
1716 return rc;
1717}
1718
1719static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
1720{
1721 if (vreg->reg)
1722 regulator_put(vreg->reg);
1723}
1724
1725/* This init function should be called only once for each SDCC slot */
1726static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
1727{
1728 int rc = 0;
1729 struct msm_mmc_slot_reg_data *curr_slot;
1730 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1731 struct device *dev = mmc_dev(host->mmc);
1732
1733 curr_slot = host->plat->vreg_data;
1734 if (!curr_slot)
1735 goto out;
1736
1737 curr_vdd_reg = curr_slot->vdd_data;
1738 curr_vccq_reg = curr_slot->vccq_data;
1739 curr_vddp_reg = curr_slot->vddp_data;
1740
1741 if (is_init) {
1742 /*
1743 * Get the regulator handle from voltage regulator framework
1744 * and then try to set the voltage level for the regulator
1745 */
1746 if (curr_vdd_reg) {
1747 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
1748 if (rc)
1749 goto out;
1750 }
1751 if (curr_vccq_reg) {
1752 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
1753 if (rc)
1754 goto vdd_reg_deinit;
1755 }
1756 if (curr_vddp_reg) {
1757 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
1758 if (rc)
1759 goto vccq_reg_deinit;
1760 }
1761 goto out;
1762 } else {
1763 /* Deregister all regulators from regulator framework */
1764 goto vddp_reg_deinit;
1765 }
1766vddp_reg_deinit:
1767 if (curr_vddp_reg)
1768 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
1769vccq_reg_deinit:
1770 if (curr_vccq_reg)
1771 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
1772vdd_reg_deinit:
1773 if (curr_vdd_reg)
1774 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
1775out:
1776 return rc;
1777}
1778
1779static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
1780{
1781 int rc = 0;
1782
Subhash Jadavanicc922692011-08-01 23:05:01 +05301783 /* Put regulator in HPM (high power mode) */
1784 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
1785 if (rc < 0)
1786 goto out;
1787
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001788 if (!vreg->is_enabled) {
1789 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301790 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
1791 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001792 if (rc)
1793 goto out;
1794
1795 rc = regulator_enable(vreg->reg);
1796 if (rc) {
1797 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
1798 __func__, vreg->name, rc);
1799 goto out;
1800 }
1801 vreg->is_enabled = true;
1802 }
1803
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001804out:
1805 return rc;
1806}
1807
1808static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
1809{
1810 int rc = 0;
1811
1812 /* Never disable regulator marked as always_on */
1813 if (vreg->is_enabled && !vreg->always_on) {
1814 rc = regulator_disable(vreg->reg);
1815 if (rc) {
1816 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
1817 __func__, vreg->name, rc);
1818 goto out;
1819 }
1820 vreg->is_enabled = false;
1821
1822 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
1823 if (rc < 0)
1824 goto out;
1825
1826 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301827 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001828 if (rc)
1829 goto out;
1830 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
1831 /* Put always_on regulator in LPM (low power mode) */
1832 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
1833 if (rc < 0)
1834 goto out;
1835 }
1836out:
1837 return rc;
1838}
1839
1840static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
1841{
1842 int rc = 0, i;
1843 struct msm_mmc_slot_reg_data *curr_slot;
1844 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1845 struct msm_mmc_reg_data *vreg_table[3];
1846
1847 curr_slot = host->plat->vreg_data;
1848 if (!curr_slot)
1849 goto out;
1850
1851 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
1852 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
1853 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
1854
1855 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
1856 if (vreg_table[i]) {
1857 if (enable)
1858 rc = msmsdcc_vreg_enable(vreg_table[i]);
1859 else
1860 rc = msmsdcc_vreg_disable(vreg_table[i]);
1861 if (rc)
1862 goto out;
1863 }
1864 }
1865out:
1866 return rc;
1867}
1868
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301869static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001870{
1871 int rc = 0;
1872
1873 if (host->plat->vreg_data) {
1874 struct msm_mmc_reg_data *vddp_reg =
1875 host->plat->vreg_data->vddp_data;
1876
1877 if (vddp_reg && vddp_reg->is_enabled)
1878 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
1879 }
1880
1881 return rc;
1882}
1883
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301884static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
1885{
1886 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1887 int rc = 0;
1888
1889 if (curr_slot && curr_slot->vddp_data) {
1890 rc = msmsdcc_set_vddp_level(host,
1891 curr_slot->vddp_data->low_vol_level);
1892
1893 if (rc)
1894 pr_err("%s: %s: failed to change vddp level to %d",
1895 mmc_hostname(host->mmc), __func__,
1896 curr_slot->vddp_data->low_vol_level);
1897 }
1898
1899 return rc;
1900}
1901
1902static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
1903{
1904 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1905 int rc = 0;
1906
1907 if (curr_slot && curr_slot->vddp_data) {
1908 rc = msmsdcc_set_vddp_level(host,
1909 curr_slot->vddp_data->high_vol_level);
1910
1911 if (rc)
1912 pr_err("%s: %s: failed to change vddp level to %d",
1913 mmc_hostname(host->mmc), __func__,
1914 curr_slot->vddp_data->high_vol_level);
1915 }
1916
1917 return rc;
1918}
1919
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001920static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
1921{
1922 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
1923 return 1;
1924 return 0;
1925}
1926
1927static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
1928{
1929 if (enable) {
1930 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1931 clk_enable(host->dfab_pclk);
1932 if (!IS_ERR(host->pclk))
1933 clk_enable(host->pclk);
1934 clk_enable(host->clk);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301935 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001936 } else {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301937 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001938 clk_disable(host->clk);
1939 if (!IS_ERR(host->pclk))
1940 clk_disable(host->pclk);
1941 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1942 clk_disable(host->dfab_pclk);
1943 }
1944}
1945
1946static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
1947 unsigned int req_clk)
1948{
1949 unsigned int sel_clk = -1;
1950
1951 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
1952 unsigned char cnt;
1953
1954 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
1955 if (host->plat->sup_clk_table[cnt] > req_clk)
1956 break;
1957 else if (host->plat->sup_clk_table[cnt] == req_clk) {
1958 sel_clk = host->plat->sup_clk_table[cnt];
1959 break;
1960 } else
1961 sel_clk = host->plat->sup_clk_table[cnt];
1962 }
1963 } else {
1964 if ((req_clk < host->plat->msmsdcc_fmax) &&
1965 (req_clk > host->plat->msmsdcc_fmid))
1966 sel_clk = host->plat->msmsdcc_fmid;
1967 else
1968 sel_clk = req_clk;
1969 }
1970
1971 return sel_clk;
1972}
1973
1974static inline unsigned int msmsdcc_get_min_sup_clk_rate(
1975 struct msmsdcc_host *host)
1976{
1977 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
1978 return host->plat->sup_clk_table[0];
1979 else
1980 return host->plat->msmsdcc_fmin;
1981}
1982
1983static inline unsigned int msmsdcc_get_max_sup_clk_rate(
1984 struct msmsdcc_host *host)
1985{
1986 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
1987 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
1988 else
1989 return host->plat->msmsdcc_fmax;
1990}
1991
1992static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05301993{
1994 struct msm_mmc_gpio_data *curr;
1995 int i, rc = 0;
1996
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001997 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05301998 for (i = 0; i < curr->size; i++) {
1999 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002000 if (curr->gpio[i].is_always_on &&
2001 curr->gpio[i].is_enabled)
2002 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302003 rc = gpio_request(curr->gpio[i].no,
2004 curr->gpio[i].name);
2005 if (rc) {
2006 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2007 mmc_hostname(host->mmc),
2008 curr->gpio[i].no,
2009 curr->gpio[i].name, rc);
2010 goto free_gpios;
2011 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002012 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302013 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002014 if (curr->gpio[i].is_always_on)
2015 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302016 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002017 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302018 }
2019 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002020 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302021
2022free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002023 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302024 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002025 curr->gpio[i].is_enabled = false;
2026 }
2027out:
2028 return rc;
2029}
2030
2031static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2032{
2033 struct msm_mmc_pad_data *curr;
2034 int i;
2035
2036 curr = host->plat->pin_data->pad_data;
2037 for (i = 0; i < curr->drv->size; i++) {
2038 if (enable)
2039 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2040 curr->drv->on[i].val);
2041 else
2042 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2043 curr->drv->off[i].val);
2044 }
2045
2046 for (i = 0; i < curr->pull->size; i++) {
2047 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002048 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002049 curr->pull->on[i].val);
2050 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002051 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002052 curr->pull->off[i].val);
2053 }
2054
2055 return 0;
2056}
2057
2058static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2059{
2060 int rc = 0;
2061
2062 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2063 return 0;
2064
2065 if (host->plat->pin_data->is_gpio)
2066 rc = msmsdcc_setup_gpio(host, enable);
2067 else
2068 rc = msmsdcc_setup_pad(host, enable);
2069
2070 if (!rc)
2071 host->plat->pin_data->cfg_sts = enable;
2072
2073 return rc;
2074}
2075
2076static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2077{
2078 unsigned int wakeup_irq;
2079
2080 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2081 host->plat->sdiowakeup_irq :
2082 host->core_irqres->start;
2083
2084 if (!host->irq_wake_enabled) {
2085 enable_irq_wake(wakeup_irq);
2086 host->irq_wake_enabled = true;
2087 }
2088}
2089
2090static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2091{
2092 unsigned int wakeup_irq;
2093
2094 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2095 host->plat->sdiowakeup_irq :
2096 host->core_irqres->start;
2097
2098 if (host->irq_wake_enabled) {
2099 disable_irq_wake(wakeup_irq);
2100 host->irq_wake_enabled = false;
2101 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302102}
2103
San Mehat9d2bd732009-09-22 16:44:22 -07002104static void
2105msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2106{
2107 struct msmsdcc_host *host = mmc_priv(mmc);
2108 u32 clk = 0, pwr = 0;
2109 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002110 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002111 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002112
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002113 DBG(host, "ios->clock = %u\n", ios->clock);
Sahitya Tummala7a892482011-01-18 11:22:49 +05302114
San Mehat9d2bd732009-09-22 16:44:22 -07002115 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002116 spin_lock_irqsave(&host->lock, flags);
2117 if (!host->clks_on) {
2118 msmsdcc_setup_clocks(host, true);
2119 host->clks_on = 1;
2120 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2121 if (!host->plat->sdiowakeup_irq) {
2122 writel_relaxed(host->mci_irqenable,
2123 host->base + MMCIMASK0);
2124 mb();
2125 if (host->plat->cfg_mpm_sdiowakeup &&
2126 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2127 host->plat->cfg_mpm_sdiowakeup(
2128 mmc_dev(mmc), SDC_DAT1_DISWAKE);
2129 msmsdcc_disable_irq_wake(host);
2130 } else if (!(mmc->pm_flags &
2131 MMC_PM_WAKE_SDIO_IRQ)) {
2132 writel_relaxed(host->mci_irqenable,
2133 host->base + MMCIMASK0);
2134 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05302135 } else {
2136 writel_relaxed(host->mci_irqenable,
2137 host->base + MMCIMASK0);
2138 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002139 }
San Mehat9d2bd732009-09-22 16:44:22 -07002140 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002141 spin_unlock_irqrestore(&host->lock, flags);
2142
2143 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2144 /*
2145 * For DDR50 mode, controller needs clock rate to be
2146 * double than what is required on the SD card CLK pin.
2147 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302148 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002149 /*
2150 * Make sure that we don't double the clock if
2151 * doubled clock rate is already set
2152 */
2153 if (!host->ddr_doubled_clk_rate ||
2154 (host->ddr_doubled_clk_rate &&
2155 (host->ddr_doubled_clk_rate != ios->clock))) {
2156 host->ddr_doubled_clk_rate =
2157 msmsdcc_get_sup_clk_rate(
2158 host, (ios->clock * 2));
2159 clock = host->ddr_doubled_clk_rate;
2160 }
2161 } else {
2162 host->ddr_doubled_clk_rate = 0;
2163 }
2164
2165 if (clock != host->clk_rate) {
2166 rc = clk_set_rate(host->clk, clock);
2167 if (rc < 0)
2168 pr_debug("%s: failed to set clk rate %u\n",
2169 mmc_hostname(mmc), clock);
2170 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302171 host->reg_write_delay =
2172 (1 + ((3 * USEC_PER_SEC) /
2173 (host->clk_rate ? host->clk_rate :
2174 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002175 }
2176 /*
2177 * give atleast 2 MCLK cycles delay for clocks
2178 * and SDCC core to stabilize
2179 */
2180 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002181 clk |= MCI_CLK_ENABLE;
2182 }
2183
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002184 if (ios->bus_width == MMC_BUS_WIDTH_8)
2185 clk |= MCI_CLK_WIDEBUS_8;
2186 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2187 clk |= MCI_CLK_WIDEBUS_4;
2188 else
2189 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002190
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002191 if (msmsdcc_is_pwrsave(host))
2192 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002193
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002194 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002195
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002196 host->tuning_needed = 0;
2197 /*
2198 * Select the controller timing mode according
2199 * to current bus speed mode
2200 */
2201 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2202 (ios->timing == MMC_TIMING_UHS_SDR50)) {
2203 clk |= (4 << 14);
2204 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302205 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002206 clk |= (3 << 14);
2207 } else {
2208 clk |= (2 << 14); /* feedback clock */
2209 }
2210
2211 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2212 clk |= (2 << 23);
2213
2214 if (host->io_pad_pwr_switch)
2215 clk |= IO_PAD_PWR_SWITCH;
2216
2217 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
San Mehat9d2bd732009-09-22 16:44:22 -07002218 pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002219 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2220 pwr |= msmsdcc_setup_vreg(host, !!ios->vdd);
San Mehat9d2bd732009-09-22 16:44:22 -07002221
2222 switch (ios->power_mode) {
2223 case MMC_POWER_OFF:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002224 htc_pwrsink_set(PWRSINK_SDCARD, 0);
2225 if (!host->sdcc_irq_disabled) {
2226 if (host->plat->cfg_mpm_sdiowakeup)
2227 host->plat->cfg_mpm_sdiowakeup(
2228 mmc_dev(mmc), SDC_DAT1_DISABLE);
2229 disable_irq(host->core_irqres->start);
2230 host->sdcc_irq_disabled = 1;
2231 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302232 /*
2233 * As VDD pad rail is always on, set low voltage for VDD
2234 * pad rail when slot is unused (when card is not present
2235 * or during system suspend).
2236 */
2237 msmsdcc_set_vddp_low_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002238 msmsdcc_setup_pins(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002239 break;
2240 case MMC_POWER_UP:
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302241 /* writing PWR_UP bit is redundant */
San Mehat9d2bd732009-09-22 16:44:22 -07002242 pwr |= MCI_PWR_UP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002243 if (host->sdcc_irq_disabled) {
2244 if (host->plat->cfg_mpm_sdiowakeup)
2245 host->plat->cfg_mpm_sdiowakeup(
2246 mmc_dev(mmc), SDC_DAT1_ENABLE);
2247 enable_irq(host->core_irqres->start);
2248 host->sdcc_irq_disabled = 0;
2249 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302250 msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002251 msmsdcc_setup_pins(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07002252 break;
2253 case MMC_POWER_ON:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002254 htc_pwrsink_set(PWRSINK_SDCARD, 100);
San Mehat9d2bd732009-09-22 16:44:22 -07002255 pwr |= MCI_PWR_ON;
2256 break;
2257 }
2258
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002259 spin_lock_irqsave(&host->lock, flags);
2260 if (!host->clks_on) {
2261 /* force the clocks to be on */
2262 msmsdcc_setup_clocks(host, true);
2263 /*
2264 * give atleast 2 MCLK cycles delay for clocks
2265 * and SDCC core to stabilize
2266 */
2267 msmsdcc_delay(host);
2268 }
2269 writel_relaxed(clk, host->base + MMCICLOCK);
2270 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002271
2272 if (host->pwr != pwr) {
2273 host->pwr = pwr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002274 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302275 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002276 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002277 if (!host->clks_on) {
2278 /* force the clocks to be off */
2279 msmsdcc_setup_clocks(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002280 }
2281
2282 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
2283 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2284 if (!host->plat->sdiowakeup_irq) {
2285 writel_relaxed(MCI_SDIOINTMASK,
2286 host->base + MMCIMASK0);
2287 mb();
2288 if (host->plat->cfg_mpm_sdiowakeup &&
2289 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2290 host->plat->cfg_mpm_sdiowakeup(
2291 mmc_dev(mmc), SDC_DAT1_ENWAKE);
2292 msmsdcc_enable_irq_wake(host);
2293 } else if (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2294 writel_relaxed(0, host->base + MMCIMASK0);
2295 } else {
2296 writel_relaxed(MCI_SDIOINTMASK,
2297 host->base + MMCIMASK0);
2298 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302299 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002300 }
2301 msmsdcc_setup_clocks(host, false);
2302 host->clks_on = 0;
2303 }
San Mehat4adbbcc2009-11-08 13:00:37 -08002304 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002305}
2306
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002307int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2308{
2309 struct msmsdcc_host *host = mmc_priv(mmc);
2310 u32 clk;
2311
2312 clk = readl_relaxed(host->base + MMCICLOCK);
2313 pr_debug("Changing to pwr_save=%d", pwrsave);
2314 if (pwrsave && msmsdcc_is_pwrsave(host))
2315 clk |= MCI_CLK_PWRSAVE;
2316 else
2317 clk &= ~MCI_CLK_PWRSAVE;
2318 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302319 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002320
2321 return 0;
2322}
2323
2324static int msmsdcc_get_ro(struct mmc_host *mmc)
2325{
2326 int status = -ENOSYS;
2327 struct msmsdcc_host *host = mmc_priv(mmc);
2328
2329 if (host->plat->wpswitch) {
2330 status = host->plat->wpswitch(mmc_dev(mmc));
2331 } else if (host->plat->wpswitch_gpio) {
2332 status = gpio_request(host->plat->wpswitch_gpio,
2333 "SD_WP_Switch");
2334 if (status) {
2335 pr_err("%s: %s: Failed to request GPIO %d\n",
2336 mmc_hostname(mmc), __func__,
2337 host->plat->wpswitch_gpio);
2338 } else {
2339 status = gpio_direction_input(
2340 host->plat->wpswitch_gpio);
2341 if (!status) {
2342 /*
2343 * Wait for atleast 300ms as debounce
2344 * time for GPIO input to stabilize.
2345 */
2346 msleep(300);
2347 status = gpio_get_value_cansleep(
2348 host->plat->wpswitch_gpio);
2349 status ^= !host->plat->wpswitch_polarity;
2350 }
2351 gpio_free(host->plat->wpswitch_gpio);
2352 }
2353 }
2354
2355 if (status < 0)
2356 status = -ENOSYS;
2357 pr_debug("%s: Card read-only status %d\n", __func__, status);
2358
2359 return status;
2360}
2361
2362#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002363static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2364{
2365 struct msmsdcc_host *host = mmc_priv(mmc);
2366 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002367
2368 if (enable) {
2369 spin_lock_irqsave(&host->lock, flags);
2370 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
2371 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
2372 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2373 spin_unlock_irqrestore(&host->lock, flags);
2374 } else {
2375 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
2376 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
2377 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2378 }
2379 mb();
2380}
2381#endif /* CONFIG_MMC_MSM_SDIO_SUPPORT */
2382
2383#ifdef CONFIG_PM_RUNTIME
2384static int msmsdcc_enable(struct mmc_host *mmc)
2385{
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302386 int rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002387 struct device *dev = mmc->parent;
2388
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302389 if (dev->power.runtime_status == RPM_SUSPENDING) {
2390 if (mmc->suspend_task == current) {
2391 pm_runtime_get_noresume(dev);
2392 goto out;
2393 }
2394 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002395
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302396 rc = pm_runtime_get_sync(dev);
2397
2398 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002399 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2400 __func__, rc);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302401 return rc;
2402 }
2403out:
2404 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002405}
2406
2407static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2408{
2409 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302410 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002411
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302412 if (host->plat->disable_runtime_pm)
2413 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002414 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO)
2415 return -ENOTSUPP;
2416
2417 rc = pm_runtime_put_sync(mmc->parent);
2418
2419 if (rc < 0)
2420 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2421 __func__, rc);
2422 return rc;
2423}
2424#else
2425#define msmsdcc_enable NULL
2426#define msmsdcc_disable NULL
2427#endif
2428
2429static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2430 struct mmc_ios *ios)
2431{
2432 struct msmsdcc_host *host = mmc_priv(mmc);
2433 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302434 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002435
2436 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2437 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302438 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002439 goto out;
2440 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2441 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302442 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002443 goto out;
2444 }
San Mehat9d2bd732009-09-22 16:44:22 -07002445
2446 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002447 /*
2448 * If we are here means voltage switch from high voltage to
2449 * low voltage is required
2450 */
2451
2452 /*
2453 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2454 * register until they become all zeros.
2455 */
2456 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302457 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002458 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2459 mmc_hostname(mmc), __func__);
2460 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002461 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002462
2463 /* Stop SD CLK output. */
2464 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2465 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302466 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002467 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002468
2469 /*
2470 * Switch VDDPX from high voltage to low voltage
2471 * to change the VDD of the SD IO pads.
2472 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302473 rc = msmsdcc_set_vddp_low_vol(host);
2474 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002475 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002476
2477 spin_lock_irqsave(&host->lock, flags);
2478 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2479 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302480 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002481 host->io_pad_pwr_switch = 1;
2482 spin_unlock_irqrestore(&host->lock, flags);
2483
2484 /* Wait 5 ms for the voltage regulater in the card to become stable. */
2485 usleep_range(5000, 5500);
2486
2487 spin_lock_irqsave(&host->lock, flags);
2488 /* Start SD CLK output. */
2489 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2490 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302491 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002492 spin_unlock_irqrestore(&host->lock, flags);
2493
2494 /*
2495 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
2496 * don't become all ones within 1 ms then a Voltage Switch
2497 * sequence has failed and a power cycle to the card is required.
2498 * Otherwise Voltage Switch sequence is completed successfully.
2499 */
2500 usleep_range(1000, 1500);
2501
2502 spin_lock_irqsave(&host->lock, flags);
2503 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
2504 != (0xF << 1)) {
2505 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
2506 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302507 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002508 goto out_unlock;
2509 }
2510
2511out_unlock:
2512 spin_unlock_irqrestore(&host->lock, flags);
2513out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302514 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002515}
2516
2517static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2518 u8 phase);
2519/* Initialize the DLL (Programmable Delay Line ) */
2520static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
2521{
2522 int rc = 0;
2523 u32 wait_timeout;
2524
2525 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
2526 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2527 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2528
2529 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
2530 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2531 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2532
2533 msmsdcc_delay(host);
2534
2535 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
2536 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2537 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2538
2539 /* Initialize the phase to 0 */
2540 rc = msmsdcc_config_cm_sdc4_dll_phase(host, 0);
2541 if (rc)
2542 goto out;
2543
2544 wait_timeout = 1000;
2545 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
2546 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
2547 /* max. wait for 1 sec for LOCK bit to be set */
2548 if (--wait_timeout == 0) {
2549 pr_err("%s: %s: DLL failed to lock at phase: %d",
2550 mmc_hostname(host->mmc), __func__, 0);
2551 rc = -1;
2552 goto out;
2553 }
2554 /* wait for 1ms */
2555 usleep_range(1000, 1500);
2556 }
2557out:
2558 return rc;
2559}
2560
2561/*
2562 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
2563 * calibration sequence. This function should be called before
2564 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
2565 * commands (CMD17/CMD18).
2566 */
2567static void msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
2568{
2569 /* Set CDR_EN bit to 1. */
2570 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) |
2571 MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2572
2573 /* Set CDR_EXT_EN bit to 0. */
2574 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2575 & ~MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2576
2577 /* Set CK_OUT_EN bit to 0. */
2578 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2579 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2580
2581 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2582 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)
2583 ;
2584
2585 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2586 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2587 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2588
2589 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register is 1. */
2590 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN))
2591 ;
2592}
2593
2594static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2595 u8 phase)
2596{
2597 int rc = 0;
2598 u32 mclk_freq = 0;
2599 u32 wait_timeout;
2600
2601 /* Set CDR_EN bit to 0. */
2602 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2603 & ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2604
2605 /* Set CDR_EXT_EN bit to 1. */
2606 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2607 | MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2608
2609 /* Program the MCLK value to MCLK_FREQ bit field */
2610 if (host->clk_rate <= 112000000)
2611 mclk_freq = 0;
2612 else if (host->clk_rate <= 125000000)
2613 mclk_freq = 1;
2614 else if (host->clk_rate <= 137000000)
2615 mclk_freq = 2;
2616 else if (host->clk_rate <= 150000000)
2617 mclk_freq = 3;
2618 else if (host->clk_rate <= 162000000)
2619 mclk_freq = 4;
2620 else if (host->clk_rate <= 175000000)
2621 mclk_freq = 5;
2622 else if (host->clk_rate <= 187000000)
2623 mclk_freq = 6;
2624 else if (host->clk_rate <= 200000000)
2625 mclk_freq = 7;
2626
2627 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2628 & ~(7 << 24)) | (mclk_freq << 24)),
2629 host->base + MCI_DLL_CONFIG);
2630
2631 /* Set CK_OUT_EN bit to 0. */
2632 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2633 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2634
2635 /* Set DLL_EN bit to 1. */
2636 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2637 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
2638
2639 wait_timeout = 1000;
2640 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2641 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN) {
2642 /* max. wait for 1 sec for LOCK bit for be set */
2643 if (--wait_timeout == 0) {
2644 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 0",
2645 mmc_hostname(host->mmc), __func__, phase);
2646 rc = -1;
2647 goto out;
2648 }
2649 /* wait for 1ms */
2650 usleep_range(1000, 1500);
2651 }
2652
2653 /*
2654 * Write the selected DLL clock output phase (0 ... 15)
2655 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
2656 */
2657 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2658 & ~(0xF << 20)) | (phase << 20)),
2659 host->base + MCI_DLL_CONFIG);
2660
2661 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2662 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2663 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2664
2665 wait_timeout = 1000;
2666 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
2667 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)) {
2668 /* max. wait for 1 sec for LOCK bit for be set */
2669 if (--wait_timeout == 0) {
2670 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 1",
2671 mmc_hostname(host->mmc), __func__, phase);
2672 rc = -1;
2673 goto out;
2674 }
2675 /* wait for 1ms */
2676 usleep_range(1000, 1500);
2677 }
2678out:
2679 return rc;
2680}
2681
2682static int msmsdcc_execute_tuning(struct mmc_host *mmc)
2683{
2684 struct msmsdcc_host *host = mmc_priv(mmc);
2685 u8 phase;
2686 u8 *data_buf;
2687 u8 tuned_phases[16], tuned_phase_cnt = 0;
2688 int rc = 0;
2689
2690 /* Tuning is only required for SDR50 & SDR104 modes */
2691 if (!host->tuning_needed) {
2692 rc = 0;
2693 goto out;
2694 }
2695
2696 host->cmd19_tuning_in_progress = 1;
2697 /*
2698 * Make sure that clock is always enabled when DLL
2699 * tuning is in progress. Keeping PWRSAVE ON may
2700 * turn off the clock. So let's disable the PWRSAVE
2701 * here and re-enable it once tuning is completed.
2702 */
2703 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2704 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302705 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002706 /* first of all reset the tuning block */
2707 rc = msmsdcc_init_cm_sdc4_dll(host);
2708 if (rc)
2709 goto out;
2710
2711 data_buf = kmalloc(64, GFP_KERNEL);
2712 if (!data_buf) {
2713 rc = -ENOMEM;
2714 goto out;
2715 }
2716
2717 phase = 0;
2718 do {
2719 struct mmc_command cmd = {0};
2720 struct mmc_data data = {0};
2721 struct mmc_request mrq = {
2722 .cmd = &cmd,
2723 .data = &data
2724 };
2725 struct scatterlist sg;
2726
2727 /* set the phase in delay line hw block */
2728 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2729 if (rc)
2730 goto kfree;
2731
2732 cmd.opcode = MMC_SEND_TUNING_BLOCK;
2733 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
2734
2735 data.blksz = 64;
2736 data.blocks = 1;
2737 data.flags = MMC_DATA_READ;
2738 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
2739
2740 data.sg = &sg;
2741 data.sg_len = 1;
2742 sg_init_one(&sg, data_buf, 64);
2743 memset(data_buf, 0, 64);
2744 mmc_wait_for_req(mmc, &mrq);
2745
2746 if (!cmd.error && !data.error &&
2747 !memcmp(data_buf, cmd19_tuning_block, 64)) {
2748 /* tuning is successful with this tuning point */
2749 tuned_phases[tuned_phase_cnt++] = phase;
2750 }
2751 } while (++phase < 16);
2752
2753 kfree(data_buf);
2754
2755 if (tuned_phase_cnt) {
2756 tuned_phase_cnt--;
2757 tuned_phase_cnt = (tuned_phase_cnt * 3) / 4;
2758 phase = tuned_phases[tuned_phase_cnt];
2759 /*
2760 * Finally set the selected phase in delay
2761 * line hw block.
2762 */
2763 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2764 if (rc)
2765 goto out;
2766 } else {
2767 /* tuning failed */
2768 rc = -EAGAIN;
2769 pr_err("%s: %s: no tuning point found",
2770 mmc_hostname(mmc), __func__);
2771 }
2772 goto out;
2773
2774kfree:
2775 kfree(data_buf);
2776out:
2777 /* re-enable PWESAVE */
2778 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2779 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302780 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002781 host->cmd19_tuning_in_progress = 0;
2782 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07002783}
2784
2785static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002786 .enable = msmsdcc_enable,
2787 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07002788 .request = msmsdcc_request,
2789 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002790 .get_ro = msmsdcc_get_ro,
2791#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002792 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002793#endif
2794 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
2795 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07002796};
2797
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002798static unsigned int
2799msmsdcc_slot_status(struct msmsdcc_host *host)
2800{
2801 int status;
2802 unsigned int gpio_no = host->plat->status_gpio;
2803
2804 status = gpio_request(gpio_no, "SD_HW_Detect");
2805 if (status) {
2806 pr_err("%s: %s: Failed to request GPIO %d\n",
2807 mmc_hostname(host->mmc), __func__, gpio_no);
2808 } else {
2809 status = gpio_direction_input(gpio_no);
2810 if (!status)
2811 status = !gpio_get_value_cansleep(gpio_no);
2812 gpio_free(gpio_no);
2813 }
2814 return status;
2815}
2816
San Mehat9d2bd732009-09-22 16:44:22 -07002817static void
2818msmsdcc_check_status(unsigned long data)
2819{
2820 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
2821 unsigned int status;
2822
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002823 if (host->plat->status || host->plat->status_gpio) {
2824 if (host->plat->status)
2825 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07002826 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002827 status = msmsdcc_slot_status(host);
2828
2829 host->eject = !status;
2830 if (status ^ host->oldstat) {
2831 pr_info("%s: Slot status change detected (%d -> %d)\n",
2832 mmc_hostname(host->mmc), host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07002833 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002834 }
2835 host->oldstat = status;
2836 } else {
2837 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07002838 }
San Mehat9d2bd732009-09-22 16:44:22 -07002839}
2840
2841static irqreturn_t
2842msmsdcc_platform_status_irq(int irq, void *dev_id)
2843{
2844 struct msmsdcc_host *host = dev_id;
2845
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002846 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07002847 msmsdcc_check_status((unsigned long) host);
2848 return IRQ_HANDLED;
2849}
2850
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002851static irqreturn_t
2852msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
2853{
2854 struct msmsdcc_host *host = dev_id;
2855
2856 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
2857 spin_lock(&host->lock);
2858 if (!host->sdio_irq_disabled) {
2859 disable_irq_nosync(irq);
2860 if (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2861 wake_lock(&host->sdio_wlock);
2862 msmsdcc_disable_irq_wake(host);
2863 }
2864 host->sdio_irq_disabled = 1;
2865 }
2866 if (host->plat->is_sdio_al_client) {
2867 if (!host->clks_on) {
2868 msmsdcc_setup_clocks(host, true);
2869 host->clks_on = 1;
2870 }
2871 if (host->sdcc_irq_disabled) {
2872 writel_relaxed(host->mci_irqenable,
2873 host->base + MMCIMASK0);
2874 mb();
2875 enable_irq(host->core_irqres->start);
2876 host->sdcc_irq_disabled = 0;
2877 }
2878 wake_lock(&host->sdio_wlock);
2879 }
2880 spin_unlock(&host->lock);
2881
2882 return IRQ_HANDLED;
2883}
2884
San Mehat9d2bd732009-09-22 16:44:22 -07002885static void
2886msmsdcc_status_notify_cb(int card_present, void *dev_id)
2887{
2888 struct msmsdcc_host *host = dev_id;
2889
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002890 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07002891 card_present);
2892 msmsdcc_check_status((unsigned long) host);
2893}
2894
San Mehat9d2bd732009-09-22 16:44:22 -07002895static int
2896msmsdcc_init_dma(struct msmsdcc_host *host)
2897{
2898 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
2899 host->dma.host = host;
2900 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07002901 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07002902
2903 if (!host->dmares)
2904 return -ENODEV;
2905
2906 host->dma.nc = dma_alloc_coherent(NULL,
2907 sizeof(struct msmsdcc_nc_dmadata),
2908 &host->dma.nc_busaddr,
2909 GFP_KERNEL);
2910 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07002911 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07002912 return -ENOMEM;
2913 }
2914 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
2915 host->dma.cmd_busaddr = host->dma.nc_busaddr;
2916 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
2917 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
2918 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07002919 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07002920
2921 return 0;
2922}
2923
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002924#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
2925/**
2926 * Allocate and Connect a SDCC peripheral's SPS endpoint
2927 *
2928 * This function allocates endpoint context and
2929 * connect it with memory endpoint by calling
2930 * appropriate SPS driver APIs.
2931 *
2932 * Also registers a SPS callback function with
2933 * SPS driver
2934 *
2935 * This function should only be called once typically
2936 * during driver probe.
2937 *
2938 * @host - Pointer to sdcc host structure
2939 * @ep - Pointer to sps endpoint data structure
2940 * @is_produce - 1 means Producer endpoint
2941 * 0 means Consumer endpoint
2942 *
2943 * @return - 0 if successful else negative value.
2944 *
2945 */
2946static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
2947 struct msmsdcc_sps_ep_conn_data *ep,
2948 bool is_producer)
2949{
2950 int rc = 0;
2951 struct sps_pipe *sps_pipe_handle;
2952 struct sps_connect *sps_config = &ep->config;
2953 struct sps_register_event *sps_event = &ep->event;
2954
2955 /* Allocate endpoint context */
2956 sps_pipe_handle = sps_alloc_endpoint();
2957 if (!sps_pipe_handle) {
2958 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
2959 mmc_hostname(host->mmc), is_producer);
2960 rc = -ENOMEM;
2961 goto out;
2962 }
2963
2964 /* Get default connection configuration for an endpoint */
2965 rc = sps_get_config(sps_pipe_handle, sps_config);
2966 if (rc) {
2967 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
2968 " rc=%d", mmc_hostname(host->mmc),
2969 (u32)sps_pipe_handle, rc);
2970 goto get_config_err;
2971 }
2972
2973 /* Modify the default connection configuration */
2974 if (is_producer) {
2975 /*
2976 * For SDCC producer transfer, source should be
2977 * SDCC peripheral where as destination should
2978 * be system memory.
2979 */
2980 sps_config->source = host->sps.bam_handle;
2981 sps_config->destination = SPS_DEV_HANDLE_MEM;
2982 /* Producer pipe will handle this connection */
2983 sps_config->mode = SPS_MODE_SRC;
2984 sps_config->options =
2985 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
2986 } else {
2987 /*
2988 * For SDCC consumer transfer, source should be
2989 * system memory where as destination should
2990 * SDCC peripheral
2991 */
2992 sps_config->source = SPS_DEV_HANDLE_MEM;
2993 sps_config->destination = host->sps.bam_handle;
2994 sps_config->mode = SPS_MODE_DEST;
2995 sps_config->options =
2996 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
2997 }
2998
2999 /* Producer pipe index */
3000 sps_config->src_pipe_index = host->sps.src_pipe_index;
3001 /* Consumer pipe index */
3002 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
3003 /*
3004 * This event thresold value is only significant for BAM-to-BAM
3005 * transfer. It's ignored for BAM-to-System mode transfer.
3006 */
3007 sps_config->event_thresh = 0x10;
3008 /*
3009 * Max. no of scatter/gather buffers that can
3010 * be passed by block layer = 32 (NR_SG).
3011 * Each BAM descritor needs 64 bits (8 bytes).
3012 * One BAM descriptor is required per buffer transfer.
3013 * So we would require total 256 (32 * 8) bytes of descriptor FIFO.
3014 * But due to HW limitation we need to allocate atleast one extra
3015 * descriptor memory (256 bytes + 8 bytes). But in order to be
3016 * in power of 2, we are allocating 512 bytes of memory.
3017 */
3018 sps_config->desc.size = 512;
3019 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
3020 sps_config->desc.size,
3021 &sps_config->desc.phys_base,
3022 GFP_KERNEL);
3023
Pratibhasagar V00b94332011-10-18 14:57:27 +05303024 if (!sps_config->desc.base) {
3025 rc = -ENOMEM;
3026 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3027 , mmc_hostname(host->mmc));
3028 goto get_config_err;
3029 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003030 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3031
3032 /* Establish connection between peripheral and memory endpoint */
3033 rc = sps_connect(sps_pipe_handle, sps_config);
3034 if (rc) {
3035 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3036 " rc=%d", mmc_hostname(host->mmc),
3037 (u32)sps_pipe_handle, rc);
3038 goto sps_connect_err;
3039 }
3040
3041 sps_event->mode = SPS_TRIGGER_CALLBACK;
3042 sps_event->options = SPS_O_EOT;
3043 sps_event->callback = msmsdcc_sps_complete_cb;
3044 sps_event->xfer_done = NULL;
3045 sps_event->user = (void *)host;
3046
3047 /* Register callback event for EOT (End of transfer) event. */
3048 rc = sps_register_event(sps_pipe_handle, sps_event);
3049 if (rc) {
3050 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3051 " rc=%d", mmc_hostname(host->mmc),
3052 (u32)sps_pipe_handle, rc);
3053 goto reg_event_err;
3054 }
3055 /* Now save the sps pipe handle */
3056 ep->pipe_handle = sps_pipe_handle;
3057 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3058 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3059 __func__, is_producer ? "READ" : "WRITE",
3060 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3061 goto out;
3062
3063reg_event_err:
3064 sps_disconnect(sps_pipe_handle);
3065sps_connect_err:
3066 dma_free_coherent(mmc_dev(host->mmc),
3067 sps_config->desc.size,
3068 sps_config->desc.base,
3069 sps_config->desc.phys_base);
3070get_config_err:
3071 sps_free_endpoint(sps_pipe_handle);
3072out:
3073 return rc;
3074}
3075
3076/**
3077 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3078 *
3079 * This function disconnect endpoint and deallocates
3080 * endpoint context.
3081 *
3082 * This function should only be called once typically
3083 * during driver remove.
3084 *
3085 * @host - Pointer to sdcc host structure
3086 * @ep - Pointer to sps endpoint data structure
3087 *
3088 */
3089static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3090 struct msmsdcc_sps_ep_conn_data *ep)
3091{
3092 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3093 struct sps_connect *sps_config = &ep->config;
3094 struct sps_register_event *sps_event = &ep->event;
3095
3096 sps_event->xfer_done = NULL;
3097 sps_event->callback = NULL;
3098 sps_register_event(sps_pipe_handle, sps_event);
3099 sps_disconnect(sps_pipe_handle);
3100 dma_free_coherent(mmc_dev(host->mmc),
3101 sps_config->desc.size,
3102 sps_config->desc.base,
3103 sps_config->desc.phys_base);
3104 sps_free_endpoint(sps_pipe_handle);
3105}
3106
3107/**
3108 * Reset SDCC peripheral's SPS endpoint
3109 *
3110 * This function disconnects an endpoint.
3111 *
3112 * This function should be called for reseting
3113 * SPS endpoint when data transfer error is
3114 * encountered during data transfer. This
3115 * can be considered as soft reset to endpoint.
3116 *
3117 * This function should only be called if
3118 * msmsdcc_sps_init() is already called.
3119 *
3120 * @host - Pointer to sdcc host structure
3121 * @ep - Pointer to sps endpoint data structure
3122 *
3123 * @return - 0 if successful else negative value.
3124 */
3125static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3126 struct msmsdcc_sps_ep_conn_data *ep)
3127{
3128 int rc = 0;
3129 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3130
3131 rc = sps_disconnect(sps_pipe_handle);
3132 if (rc) {
3133 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3134 " rc=%d", mmc_hostname(host->mmc), __func__,
3135 (u32)sps_pipe_handle, rc);
3136 goto out;
3137 }
3138 out:
3139 return rc;
3140}
3141
3142/**
3143 * Restore SDCC peripheral's SPS endpoint
3144 *
3145 * This function connects an endpoint.
3146 *
3147 * This function should be called for restoring
3148 * SPS endpoint after data transfer error is
3149 * encountered during data transfer. This
3150 * can be considered as soft reset to endpoint.
3151 *
3152 * This function should only be called if
3153 * msmsdcc_sps_reset_ep() is called before.
3154 *
3155 * @host - Pointer to sdcc host structure
3156 * @ep - Pointer to sps endpoint data structure
3157 *
3158 * @return - 0 if successful else negative value.
3159 */
3160static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3161 struct msmsdcc_sps_ep_conn_data *ep)
3162{
3163 int rc = 0;
3164 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3165 struct sps_connect *sps_config = &ep->config;
3166 struct sps_register_event *sps_event = &ep->event;
3167
3168 /* Establish connection between peripheral and memory endpoint */
3169 rc = sps_connect(sps_pipe_handle, sps_config);
3170 if (rc) {
3171 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3172 " rc=%d", mmc_hostname(host->mmc), __func__,
3173 (u32)sps_pipe_handle, rc);
3174 goto out;
3175 }
3176
3177 /* Register callback event for EOT (End of transfer) event. */
3178 rc = sps_register_event(sps_pipe_handle, sps_event);
3179 if (rc) {
3180 pr_err("%s: %s: sps_register_event() failed!!!"
3181 " pipe_handle=0x%x, rc=%d",
3182 mmc_hostname(host->mmc), __func__,
3183 (u32)sps_pipe_handle, rc);
3184 goto reg_event_err;
3185 }
3186 goto out;
3187
3188reg_event_err:
3189 sps_disconnect(sps_pipe_handle);
3190out:
3191 return rc;
3192}
3193
3194/**
3195 * Initialize SPS HW connected with SDCC core
3196 *
3197 * This function register BAM HW resources with
3198 * SPS driver and then initialize 2 SPS endpoints
3199 *
3200 * This function should only be called once typically
3201 * during driver probe.
3202 *
3203 * @host - Pointer to sdcc host structure
3204 *
3205 * @return - 0 if successful else negative value.
3206 *
3207 */
3208static int msmsdcc_sps_init(struct msmsdcc_host *host)
3209{
3210 int rc = 0;
3211 struct sps_bam_props bam = {0};
3212
3213 host->bam_base = ioremap(host->bam_memres->start,
3214 resource_size(host->bam_memres));
3215 if (!host->bam_base) {
3216 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3217 " size=0x%x", mmc_hostname(host->mmc),
3218 host->bam_memres->start,
3219 (host->bam_memres->end -
3220 host->bam_memres->start));
3221 rc = -ENOMEM;
3222 goto out;
3223 }
3224
3225 bam.phys_addr = host->bam_memres->start;
3226 bam.virt_addr = host->bam_base;
3227 /*
3228 * This event thresold value is only significant for BAM-to-BAM
3229 * transfer. It's ignored for BAM-to-System mode transfer.
3230 */
3231 bam.event_threshold = 0x10; /* Pipe event threshold */
3232 /*
3233 * This threshold controls when the BAM publish
3234 * the descriptor size on the sideband interface.
3235 * SPS HW will only be used when
3236 * data transfer size > MCI_FIFOSIZE (64 bytes).
3237 * PIO mode will be used when
3238 * data transfer size < MCI_FIFOSIZE (64 bytes).
3239 * So set this thresold value to 64 bytes.
3240 */
3241 bam.summing_threshold = 64;
3242 /* SPS driver wll handle the SDCC BAM IRQ */
3243 bam.irq = (u32)host->bam_irqres->start;
3244 bam.manage = SPS_BAM_MGR_LOCAL;
3245
3246 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3247 (u32)bam.phys_addr);
3248 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3249 (u32)bam.virt_addr);
3250
3251 /* Register SDCC Peripheral BAM device to SPS driver */
3252 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3253 if (rc) {
3254 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3255 mmc_hostname(host->mmc), rc);
3256 goto reg_bam_err;
3257 }
3258 pr_info("%s: BAM device registered. bam_handle=0x%x",
3259 mmc_hostname(host->mmc), host->sps.bam_handle);
3260
3261 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3262 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3263
3264 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3265 SPS_PROD_PERIPHERAL);
3266 if (rc)
3267 goto sps_reset_err;
3268 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3269 SPS_CONS_PERIPHERAL);
3270 if (rc)
3271 goto cons_conn_err;
3272
3273 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3274 mmc_hostname(host->mmc),
3275 (unsigned long long)host->bam_memres->start,
3276 (unsigned int)host->bam_irqres->start);
3277 goto out;
3278
3279cons_conn_err:
3280 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3281sps_reset_err:
3282 sps_deregister_bam_device(host->sps.bam_handle);
3283reg_bam_err:
3284 iounmap(host->bam_base);
3285out:
3286 return rc;
3287}
3288
3289/**
3290 * De-initialize SPS HW connected with SDCC core
3291 *
3292 * This function deinitialize SPS endpoints and then
3293 * deregisters BAM resources from SPS driver.
3294 *
3295 * This function should only be called once typically
3296 * during driver remove.
3297 *
3298 * @host - Pointer to sdcc host structure
3299 *
3300 */
3301static void msmsdcc_sps_exit(struct msmsdcc_host *host)
3302{
3303 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
3304 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3305 sps_deregister_bam_device(host->sps.bam_handle);
3306 iounmap(host->bam_base);
3307}
3308#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
3309
3310static ssize_t
3311show_polling(struct device *dev, struct device_attribute *attr, char *buf)
3312{
3313 struct mmc_host *mmc = dev_get_drvdata(dev);
3314 struct msmsdcc_host *host = mmc_priv(mmc);
3315 int poll;
3316 unsigned long flags;
3317
3318 spin_lock_irqsave(&host->lock, flags);
3319 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
3320 spin_unlock_irqrestore(&host->lock, flags);
3321
3322 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
3323}
3324
3325static ssize_t
3326set_polling(struct device *dev, struct device_attribute *attr,
3327 const char *buf, size_t count)
3328{
3329 struct mmc_host *mmc = dev_get_drvdata(dev);
3330 struct msmsdcc_host *host = mmc_priv(mmc);
3331 int value;
3332 unsigned long flags;
3333
3334 sscanf(buf, "%d", &value);
3335
3336 spin_lock_irqsave(&host->lock, flags);
3337 if (value) {
3338 mmc->caps |= MMC_CAP_NEEDS_POLL;
3339 mmc_detect_change(host->mmc, 0);
3340 } else {
3341 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3342 }
3343#ifdef CONFIG_HAS_EARLYSUSPEND
3344 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
3345#endif
3346 spin_unlock_irqrestore(&host->lock, flags);
3347 return count;
3348}
3349
3350static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
3351 show_polling, set_polling);
3352static struct attribute *dev_attrs[] = {
3353 &dev_attr_polling.attr,
3354 NULL,
3355};
3356static struct attribute_group dev_attr_grp = {
3357 .attrs = dev_attrs,
3358};
3359
3360#ifdef CONFIG_HAS_EARLYSUSPEND
3361static void msmsdcc_early_suspend(struct early_suspend *h)
3362{
3363 struct msmsdcc_host *host =
3364 container_of(h, struct msmsdcc_host, early_suspend);
3365 unsigned long flags;
3366
3367 spin_lock_irqsave(&host->lock, flags);
3368 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
3369 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3370 spin_unlock_irqrestore(&host->lock, flags);
3371};
3372static void msmsdcc_late_resume(struct early_suspend *h)
3373{
3374 struct msmsdcc_host *host =
3375 container_of(h, struct msmsdcc_host, early_suspend);
3376 unsigned long flags;
3377
3378 if (host->polling_enabled) {
3379 spin_lock_irqsave(&host->lock, flags);
3380 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
3381 mmc_detect_change(host->mmc, 0);
3382 spin_unlock_irqrestore(&host->lock, flags);
3383 }
3384};
3385#endif
3386
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303387void msmsdcc_print_regs(const char *name, void __iomem *base,
3388 unsigned int no_of_regs)
3389{
3390 unsigned int i;
3391
3392 if (!base)
3393 return;
3394 pr_info("===== %s: Register Dumps @base=0x%x =====\n",
3395 name, (u32)base);
3396 for (i = 0; i < no_of_regs; i = i + 4) {
3397 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x.\n", i*4,
3398 (u32)readl_relaxed(base + i*4),
3399 (u32)readl_relaxed(base + ((i+1)*4)),
3400 (u32)readl_relaxed(base + ((i+2)*4)),
3401 (u32)readl_relaxed(base + ((i+3)*4)));
3402 }
3403}
3404
3405static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
3406{
3407 /* Dump current state of SDCC clocks, power and irq */
3408 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
3409 (host->pwr ? "ON" : "OFF"));
3410 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
3411 mmc_hostname(host->mmc),
3412 (host->clks_on ? "ON" : "OFF"),
3413 (u32)clk_get_rate(host->clk));
3414 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
3415 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
3416
3417 /* Now dump SDCC registers. Don't print FIFO registers */
3418 if (host->clks_on)
3419 msmsdcc_print_regs("SDCC-CORE", host->base, 28);
3420
3421 if (host->curr.data) {
3422 if (msmsdcc_check_dma_op_req(host->curr.data))
3423 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
3424 else if (host->is_dma_mode)
3425 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
3426 mmc_hostname(host->mmc), host->dma.busy,
3427 host->dma.channel, host->dma.crci);
3428 else if (host->is_sps_mode)
3429 pr_info("%s: SPS mode: busy=%d\n",
3430 mmc_hostname(host->mmc), host->sps.busy);
3431
3432 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
3433 mmc_hostname(host->mmc), host->curr.xfer_size,
3434 host->curr.data_xfered, host->curr.xfer_remain);
3435 pr_info("%s: got_dataend=%d, prog_enable=%d,"
3436 " wait_for_auto_prog_done=%d,"
3437 " got_auto_prog_done=%d\n",
3438 mmc_hostname(host->mmc), host->curr.got_dataend,
3439 host->prog_enable, host->curr.wait_for_auto_prog_done,
3440 host->curr.got_auto_prog_done);
3441 }
3442
3443}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003444static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
3445{
3446 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3447 struct mmc_request *mrq;
3448 unsigned long flags;
3449
3450 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003451 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003452 pr_info("%s: %s: dummy CMD52 timeout\n",
3453 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003454 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003455 }
3456
3457 mrq = host->curr.mrq;
3458
3459 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303460 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
3461 mrq->cmd->opcode);
3462 msmsdcc_dump_sdcc_state(host);
3463
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003464 if (!mrq->cmd->error)
3465 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303466 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003467 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003468 if (mrq->data && !mrq->data->error)
3469 mrq->data->error = -ETIMEDOUT;
3470 host->curr.data_xfered = 0;
3471 if (host->dma.sg && host->is_dma_mode) {
3472 msm_dmov_stop_cmd(host->dma.channel,
3473 &host->dma.hdr, 0);
3474 } else if (host->sps.sg && host->is_sps_mode) {
3475 /* Stop current SPS transfer */
3476 msmsdcc_sps_exit_curr_xfer(host);
3477 } else {
3478 msmsdcc_reset_and_restore(host);
3479 msmsdcc_stop_data(host);
3480 if (mrq->data && mrq->data->stop)
3481 msmsdcc_start_command(host,
3482 mrq->data->stop, 0);
3483 else
3484 msmsdcc_request_end(host, mrq);
3485 }
3486 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05303487 host->prog_enable = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003488 msmsdcc_reset_and_restore(host);
3489 msmsdcc_request_end(host, mrq);
3490 }
3491 }
3492 spin_unlock_irqrestore(&host->lock, flags);
3493}
3494
San Mehat9d2bd732009-09-22 16:44:22 -07003495static int
3496msmsdcc_probe(struct platform_device *pdev)
3497{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003498 struct mmc_platform_data *plat = pdev->dev.platform_data;
San Mehat9d2bd732009-09-22 16:44:22 -07003499 struct msmsdcc_host *host;
3500 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003501 unsigned long flags;
3502 struct resource *core_irqres = NULL;
3503 struct resource *bam_irqres = NULL;
3504 struct resource *core_memres = NULL;
3505 struct resource *dml_memres = NULL;
3506 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07003507 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07003508 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05303509 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003510 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07003511
3512 /* must have platform data */
3513 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003514 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003515 ret = -EINVAL;
3516 goto out;
3517 }
3518
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003519 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07003520 return -EINVAL;
3521
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003522 if (plat->is_sdio_al_client)
3523 if (!plat->sdio_lpm_gpio_setup || !plat->sdiowakeup_irq)
3524 return -EINVAL;
3525
San Mehat9d2bd732009-09-22 16:44:22 -07003526 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003527 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003528 return -ENXIO;
3529 }
3530
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003531 for (i = 0; i < pdev->num_resources; i++) {
3532 if (pdev->resource[i].flags & IORESOURCE_MEM) {
3533 if (!strcmp(pdev->resource[i].name,
3534 "sdcc_dml_addr"))
3535 dml_memres = &pdev->resource[i];
3536 else if (!strcmp(pdev->resource[i].name,
3537 "sdcc_bam_addr"))
3538 bam_memres = &pdev->resource[i];
3539 else
3540 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07003541
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003542 }
3543 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
3544 if (!strcmp(pdev->resource[i].name,
3545 "sdcc_bam_irq"))
3546 bam_irqres = &pdev->resource[i];
3547 else
3548 core_irqres = &pdev->resource[i];
3549 }
Krishna Konda25786ec2011-07-25 16:21:36 -07003550 if (pdev->resource[i].flags & IORESOURCE_DMA) {
3551 if (!strncmp(pdev->resource[i].name,
3552 "sdcc_dma_chnl",
3553 sizeof("sdcc_dma_chnl")))
3554 dmares = &pdev->resource[i];
3555 else if (!strncmp(pdev->resource[i].name,
3556 "sdcc_dma_crci",
3557 sizeof("sdcc_dma_crci")))
3558 dma_crci_res = &pdev->resource[i];
3559 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003560 }
3561
3562 if (!core_irqres || !core_memres) {
3563 pr_err("%s: Invalid sdcc core resource\n", __func__);
3564 return -ENXIO;
3565 }
3566
3567 /*
3568 * Both BAM and DML memory resource should be preset.
3569 * BAM IRQ resource should also be present.
3570 */
3571 if ((bam_memres && !dml_memres) ||
3572 (!bam_memres && dml_memres) ||
3573 ((bam_memres && dml_memres) && !bam_irqres)) {
3574 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003575 return -ENXIO;
3576 }
3577
3578 /*
3579 * Setup our host structure
3580 */
San Mehat9d2bd732009-09-22 16:44:22 -07003581 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
3582 if (!mmc) {
3583 ret = -ENOMEM;
3584 goto out;
3585 }
3586
3587 host = mmc_priv(mmc);
3588 host->pdev_id = pdev->id;
3589 host->plat = plat;
3590 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08003591 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05303592
3593 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003594 host->is_sps_mode = 1;
3595 else if (dmares)
3596 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07003597
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003598 host->base = ioremap(core_memres->start,
3599 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07003600 if (!host->base) {
3601 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003602 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003603 }
3604
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003605 host->core_irqres = core_irqres;
3606 host->bam_irqres = bam_irqres;
3607 host->core_memres = core_memres;
3608 host->dml_memres = dml_memres;
3609 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07003610 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07003611 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07003612 spin_lock_init(&host->lock);
3613
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003614#ifdef CONFIG_MMC_EMBEDDED_SDIO
3615 if (plat->embedded_sdio)
3616 mmc_set_embedded_sdio_data(mmc,
3617 &plat->embedded_sdio->cis,
3618 &plat->embedded_sdio->cccr,
3619 plat->embedded_sdio->funcs,
3620 plat->embedded_sdio->num_funcs);
3621#endif
3622
Sahitya Tummala62612cf2010-12-08 15:03:03 +05303623 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
3624 (unsigned long)host);
3625
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003626 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
3627 (unsigned long)host);
3628 if (host->is_dma_mode) {
3629 /* Setup DMA */
3630 ret = msmsdcc_init_dma(host);
3631 if (ret)
3632 goto ioremap_free;
3633 } else {
3634 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003635 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003636 }
3637
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003638 /*
3639 * Setup SDCC clock if derived from Dayatona
3640 * fabric core clock.
3641 */
3642 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07003643 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003644 if (!IS_ERR(host->dfab_pclk)) {
3645 /* Set the clock rate to 64MHz for max. performance */
3646 ret = clk_set_rate(host->dfab_pclk, 64000000);
3647 if (ret)
3648 goto dfab_pclk_put;
3649 ret = clk_enable(host->dfab_pclk);
3650 if (ret)
3651 goto dfab_pclk_put;
3652 } else
3653 goto dma_free;
3654 }
3655
3656 /*
3657 * Setup main peripheral bus clock
3658 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003659 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003660 if (!IS_ERR(host->pclk)) {
3661 ret = clk_enable(host->pclk);
3662 if (ret)
3663 goto pclk_put;
3664
3665 host->pclk_rate = clk_get_rate(host->pclk);
3666 }
3667
3668 /*
3669 * Setup SDC MMC clock
3670 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003671 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07003672 if (IS_ERR(host->clk)) {
3673 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003674 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07003675 }
3676
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003677 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
3678 if (ret) {
3679 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
3680 goto clk_put;
3681 }
3682
3683 ret = clk_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003684 if (ret)
3685 goto clk_put;
3686
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003687 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303688 if (!host->clk_rate)
3689 dev_err(&pdev->dev, "Failed to read MCLK\n");
3690 /*
3691 * Set the register write delay according to min. clock frequency
3692 * supported and update later when the host->clk_rate changes.
3693 */
3694 host->reg_write_delay =
3695 (1 + ((3 * USEC_PER_SEC) /
3696 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003697
3698 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05303699 /* Apply Hard reset to SDCC to put it in power on default state */
3700 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003701
3702 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07003703 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003704 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07003705 goto clk_disable;
3706 }
3707
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003708
3709 /* Clocks has to be running before accessing SPS/DML HW blocks */
3710 if (host->is_sps_mode) {
3711 /* Initialize SPS */
3712 ret = msmsdcc_sps_init(host);
3713 if (ret)
3714 goto vreg_deinit;
3715 /* Initialize DML */
3716 ret = msmsdcc_dml_init(host);
3717 if (ret)
3718 goto sps_exit;
3719 }
San Mehat9d2bd732009-09-22 16:44:22 -07003720
San Mehat9d2bd732009-09-22 16:44:22 -07003721 /*
3722 * Setup MMC host structure
3723 */
3724 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003725 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
3726 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003727 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003728 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
3729 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07003730
San Mehat9d2bd732009-09-22 16:44:22 -07003731 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05303732 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05303733
3734 /*
3735 * If we send the CMD23 before multi block write/read command
3736 * then we need not to send CMD12 at the end of the transfer.
3737 * If we don't send the CMD12 then only way to detect the PROG_DONE
3738 * status is to use the AUTO_PROG_DONE status provided by SDCC4
3739 * controller. So let's enable the CMD23 for SDCC4 only.
3740 */
Sahitya Tummala85fa0702011-09-15 09:39:37 +05303741 if (!plat->disable_cmd23 && host->plat->sdcc_v4_sup)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05303742 mmc->caps |= MMC_CAP_CMD23;
3743
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003744 mmc->caps |= plat->uhs_caps;
3745 /*
3746 * XPC controls the maximum current in the default speed mode of SDXC
3747 * card. XPC=0 means 100mA (max.) but speed class is not supported.
3748 * XPC=1 means 150mA (max.) and speed class is supported.
3749 */
3750 if (plat->xpc_cap)
3751 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
3752 MMC_CAP_SET_XPC_180);
3753
3754 if (plat->nonremovable)
3755 mmc->caps |= MMC_CAP_NONREMOVABLE;
3756#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
3757 mmc->caps |= MMC_CAP_SDIO_IRQ;
3758#endif
3759
3760 if (plat->is_sdio_al_client)
3761 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07003762
Martin K. Petersena36274e2010-09-10 01:33:59 -04003763 mmc->max_segs = NR_SG;
San Mehat9d2bd732009-09-22 16:44:22 -07003764 mmc->max_blk_size = 4096; /* MCI_DATA_CTL BLOCKSIZE up to 4096 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003765 mmc->max_blk_count = 65535;
San Mehat9d2bd732009-09-22 16:44:22 -07003766
3767 mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */
3768 mmc->max_seg_size = mmc->max_req_size;
3769
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003770 writel_relaxed(0, host->base + MMCIMASK0);
3771 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -07003772
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003773 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
3774 mb();
3775 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07003776
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003777 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
3778 DRIVER_NAME " (cmd)", host);
3779 if (ret)
3780 goto dml_exit;
3781
3782 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
3783 DRIVER_NAME " (pio)", host);
3784 if (ret)
3785 goto irq_free;
3786
3787 /*
3788 * Enable SDCC IRQ only when host is powered on. Otherwise, this
3789 * IRQ is un-necessarily being monitored by MPM (Modem power
3790 * management block) during idle-power collapse. The MPM will be
3791 * configured to monitor the DATA1 GPIO line with level-low trigger
3792 * and thus depending on the GPIO status, it prevents TCXO shutdown
3793 * during idle-power collapse.
3794 */
3795 disable_irq(core_irqres->start);
3796 host->sdcc_irq_disabled = 1;
3797
3798 if (plat->sdiowakeup_irq) {
3799 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3800 mmc_hostname(mmc));
3801 ret = request_irq(plat->sdiowakeup_irq,
3802 msmsdcc_platform_sdiowakeup_irq,
3803 IRQF_SHARED | IRQF_TRIGGER_LOW,
3804 DRIVER_NAME "sdiowakeup", host);
3805 if (ret) {
3806 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
3807 plat->sdiowakeup_irq, ret);
3808 goto pio_irq_free;
3809 } else {
3810 spin_lock_irqsave(&host->lock, flags);
3811 if (!host->sdio_irq_disabled) {
3812 disable_irq_nosync(plat->sdiowakeup_irq);
3813 host->sdio_irq_disabled = 1;
3814 }
3815 spin_unlock_irqrestore(&host->lock, flags);
3816 }
3817 }
3818
3819 if (plat->cfg_mpm_sdiowakeup) {
3820 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3821 mmc_hostname(mmc));
3822 }
3823
3824 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
3825 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003826 /*
3827 * Setup card detect change
3828 */
3829
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003830 if (plat->status || plat->status_gpio) {
3831 if (plat->status)
3832 host->oldstat = plat->status(mmc_dev(host->mmc));
3833 else
3834 host->oldstat = msmsdcc_slot_status(host);
3835 host->eject = !host->oldstat;
3836 }
San Mehat9d2bd732009-09-22 16:44:22 -07003837
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003838 if (plat->status_irq) {
3839 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07003840 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003841 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07003842 DRIVER_NAME " (slot)",
3843 host);
3844 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003845 pr_err("Unable to get slot IRQ %d (%d)\n",
3846 plat->status_irq, ret);
3847 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003848 }
3849 } else if (plat->register_status_notify) {
3850 plat->register_status_notify(msmsdcc_status_notify_cb, host);
3851 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003852 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07003853 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003854
3855 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003856
3857 ret = pm_runtime_set_active(&(pdev)->dev);
3858 if (ret < 0)
3859 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3860 __func__, ret);
3861 /*
3862 * There is no notion of suspend/resume for SD/MMC/SDIO
3863 * cards. So host can be suspended/resumed with out
3864 * worrying about its children.
3865 */
3866 pm_suspend_ignore_children(&(pdev)->dev, true);
3867
3868 /*
3869 * MMC/SD/SDIO bus suspend/resume operations are defined
3870 * only for the slots that will be used for non-removable
3871 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
3872 * defined. Otherwise, they simply become card removal and
3873 * insertion events during suspend and resume respectively.
3874 * Hence, enable run-time PM only for slots for which bus
3875 * suspend/resume operations are defined.
3876 */
3877#ifdef CONFIG_MMC_UNSAFE_RESUME
3878 /*
3879 * If this capability is set, MMC core will enable/disable host
3880 * for every claim/release operation on a host. We use this
3881 * notification to increment/decrement runtime pm usage count.
3882 */
3883 mmc->caps |= MMC_CAP_DISABLE;
3884 pm_runtime_enable(&(pdev)->dev);
3885#else
3886 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
3887 mmc->caps |= MMC_CAP_DISABLE;
3888 pm_runtime_enable(&(pdev)->dev);
3889 }
3890#endif
3891 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
3892 (unsigned long)host);
3893
San Mehat9d2bd732009-09-22 16:44:22 -07003894 mmc_add_host(mmc);
3895
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003896#ifdef CONFIG_HAS_EARLYSUSPEND
3897 host->early_suspend.suspend = msmsdcc_early_suspend;
3898 host->early_suspend.resume = msmsdcc_late_resume;
3899 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
3900 register_early_suspend(&host->early_suspend);
3901#endif
San Mehat9d2bd732009-09-22 16:44:22 -07003902
Krishna Konda25786ec2011-07-25 16:21:36 -07003903 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
3904 " dmacrcri %d\n", mmc_hostname(mmc),
3905 (unsigned long long)core_memres->start,
3906 (unsigned int) core_irqres->start,
3907 (unsigned int) plat->status_irq, host->dma.channel,
3908 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003909
3910 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
3911 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
3912 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
3913 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
3914 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
3915 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
3916 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
3917 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
3918 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
3919 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
3920 host->eject);
3921 pr_info("%s: Power save feature enable = %d\n",
3922 mmc_hostname(mmc), msmsdcc_pwrsave);
3923
Krishna Konda25786ec2011-07-25 16:21:36 -07003924 if (host->is_dma_mode && host->dma.channel != -1
3925 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003926 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003927 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003928 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003929 mmc_hostname(mmc), host->dma.cmd_busaddr,
3930 host->dma.cmdptr_busaddr);
3931 } else if (host->is_sps_mode) {
3932 pr_info("%s: SPS-BAM data transfer mode available\n",
3933 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003934 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003935 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003936
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003937#if defined(CONFIG_DEBUG_FS)
3938 msmsdcc_dbg_createhost(host);
3939#endif
3940 if (!plat->status_irq) {
3941 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
3942 if (ret)
3943 goto platform_irq_free;
3944 }
San Mehat9d2bd732009-09-22 16:44:22 -07003945 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003946
3947 platform_irq_free:
3948 del_timer_sync(&host->req_tout_timer);
3949 pm_runtime_disable(&(pdev)->dev);
3950 pm_runtime_set_suspended(&(pdev)->dev);
3951
3952 if (plat->status_irq)
3953 free_irq(plat->status_irq, host);
3954 sdiowakeup_irq_free:
3955 wake_lock_destroy(&host->sdio_suspend_wlock);
3956 if (plat->sdiowakeup_irq)
3957 free_irq(plat->sdiowakeup_irq, host);
3958 pio_irq_free:
3959 if (plat->sdiowakeup_irq)
3960 wake_lock_destroy(&host->sdio_wlock);
3961 free_irq(core_irqres->start, host);
3962 irq_free:
3963 free_irq(core_irqres->start, host);
3964 dml_exit:
3965 if (host->is_sps_mode)
3966 msmsdcc_dml_exit(host);
3967 sps_exit:
3968 if (host->is_sps_mode)
3969 msmsdcc_sps_exit(host);
3970 vreg_deinit:
3971 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07003972 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003973 clk_disable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003974 clk_put:
3975 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003976 pclk_disable:
3977 if (!IS_ERR(host->pclk))
3978 clk_disable(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07003979 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003980 if (!IS_ERR(host->pclk))
3981 clk_put(host->pclk);
3982 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3983 clk_disable(host->dfab_pclk);
3984 dfab_pclk_put:
3985 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3986 clk_put(host->dfab_pclk);
3987 dma_free:
3988 if (host->is_dma_mode) {
3989 if (host->dmares)
3990 dma_free_coherent(NULL,
3991 sizeof(struct msmsdcc_nc_dmadata),
3992 host->dma.nc, host->dma.nc_busaddr);
3993 }
3994 ioremap_free:
3995 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07003996 host_free:
3997 mmc_free_host(mmc);
3998 out:
3999 return ret;
4000}
4001
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004002static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07004003{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004004 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4005 struct mmc_platform_data *plat;
4006 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004007
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004008 if (!mmc)
4009 return -ENXIO;
4010
4011 if (pm_runtime_suspended(&(pdev)->dev))
4012 pm_runtime_resume(&(pdev)->dev);
4013
4014 host = mmc_priv(mmc);
4015
4016 DBG(host, "Removing SDCC device = %d\n", pdev->id);
4017 plat = host->plat;
4018
4019 if (!plat->status_irq)
4020 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
4021
4022 del_timer_sync(&host->req_tout_timer);
4023 tasklet_kill(&host->dma_tlet);
4024 tasklet_kill(&host->sps.tlet);
4025 mmc_remove_host(mmc);
4026
4027 if (plat->status_irq)
4028 free_irq(plat->status_irq, host);
4029
4030 wake_lock_destroy(&host->sdio_suspend_wlock);
4031 if (plat->sdiowakeup_irq) {
4032 wake_lock_destroy(&host->sdio_wlock);
4033 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
4034 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07004035 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004036
4037 free_irq(host->core_irqres->start, host);
4038 free_irq(host->core_irqres->start, host);
4039
4040 clk_put(host->clk);
4041 if (!IS_ERR(host->pclk))
4042 clk_put(host->pclk);
4043 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4044 clk_put(host->dfab_pclk);
4045
4046 msmsdcc_vreg_init(host, false);
4047
4048 if (host->is_dma_mode) {
4049 if (host->dmares)
4050 dma_free_coherent(NULL,
4051 sizeof(struct msmsdcc_nc_dmadata),
4052 host->dma.nc, host->dma.nc_busaddr);
4053 }
4054
4055 if (host->is_sps_mode) {
4056 msmsdcc_dml_exit(host);
4057 msmsdcc_sps_exit(host);
4058 }
4059
4060 iounmap(host->base);
4061 mmc_free_host(mmc);
4062
4063#ifdef CONFIG_HAS_EARLYSUSPEND
4064 unregister_early_suspend(&host->early_suspend);
4065#endif
4066 pm_runtime_disable(&(pdev)->dev);
4067 pm_runtime_set_suspended(&(pdev)->dev);
4068
4069 return 0;
4070}
4071
4072#ifdef CONFIG_MSM_SDIO_AL
4073int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4074{
4075 struct msmsdcc_host *host = mmc_priv(mmc);
4076 unsigned long flags;
4077
4078 spin_lock_irqsave(&host->lock, flags);
4079 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
4080 enable ? "En" : "Dis");
4081
4082 if (enable) {
4083 if (!host->sdcc_irq_disabled) {
4084 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05304085 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004086 host->sdcc_irq_disabled = 1;
4087 }
4088
4089 if (host->clks_on) {
4090 msmsdcc_setup_clocks(host, false);
4091 host->clks_on = 0;
4092 }
4093
4094 if (!host->sdio_gpio_lpm) {
4095 spin_unlock_irqrestore(&host->lock, flags);
4096 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
4097 spin_lock_irqsave(&host->lock, flags);
4098 host->sdio_gpio_lpm = 1;
4099 }
4100
4101 if (host->sdio_irq_disabled) {
4102 msmsdcc_enable_irq_wake(host);
4103 enable_irq(host->plat->sdiowakeup_irq);
4104 host->sdio_irq_disabled = 0;
4105 }
4106 } else {
4107 if (!host->sdio_irq_disabled) {
4108 disable_irq_nosync(host->plat->sdiowakeup_irq);
4109 host->sdio_irq_disabled = 1;
4110 msmsdcc_disable_irq_wake(host);
4111 }
4112
4113 if (host->sdio_gpio_lpm) {
4114 spin_unlock_irqrestore(&host->lock, flags);
4115 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
4116 spin_lock_irqsave(&host->lock, flags);
4117 host->sdio_gpio_lpm = 0;
4118 }
4119
4120 if (!host->clks_on) {
4121 msmsdcc_setup_clocks(host, true);
4122 host->clks_on = 1;
4123 }
4124
4125 if (host->sdcc_irq_disabled) {
4126 writel_relaxed(host->mci_irqenable,
4127 host->base + MMCIMASK0);
4128 mb();
4129 enable_irq(host->core_irqres->start);
4130 host->sdcc_irq_disabled = 0;
4131 }
4132 wake_lock_timeout(&host->sdio_wlock, 1);
4133 }
4134 spin_unlock_irqrestore(&host->lock, flags);
4135 return 0;
4136}
4137#else
4138int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4139{
4140 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004141}
4142#endif
4143
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004144#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07004145static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004146msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004147{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004148 struct mmc_host *mmc = dev_get_drvdata(dev);
4149 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07004150 int rc = 0;
4151
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004152 if (host->plat->is_sdio_al_client)
4153 return 0;
4154
Sahitya Tummala7661a452011-07-18 13:28:35 +05304155 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004156 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004157 host->sdcc_suspending = 1;
4158 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07004159
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004160 /*
4161 * If the clocks are already turned off by SDIO clients (as
4162 * part of LPM), then clocks should be turned on before
4163 * calling mmc_suspend_host() because mmc_suspend_host might
4164 * send some commands to the card. The clocks will be turned
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304165 * off again after mmc_suspend_host. Thus for SDIO
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004166 * cards, clocks will be turned on before mmc_suspend_host
4167 * and turned off after mmc_suspend_host.
4168 */
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304169 if (mmc->card && mmc_card_sdio(mmc->card)) {
4170 mmc->ios.clock = host->clk_rate;
4171 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4172 }
San Mehat9d2bd732009-09-22 16:44:22 -07004173
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004174 /*
4175 * MMC core thinks that host is disabled by now since
4176 * runtime suspend is scheduled after msmsdcc_disable()
4177 * is called. Thus, MMC core will try to enable the host
4178 * while suspending it. This results in a synchronous
4179 * runtime resume request while in runtime suspending
4180 * context and hence inorder to complete this resume
4181 * requet, it will wait for suspend to be complete,
4182 * but runtime suspend also can not proceed further
4183 * until the host is resumed. Thus, it leads to a hang.
4184 * Hence, increase the pm usage count before suspending
4185 * the host so that any resume requests after this will
4186 * simple become pm usage counter increment operations.
4187 */
4188 pm_runtime_get_noresume(dev);
4189 rc = mmc_suspend_host(mmc);
4190 pm_runtime_put_noidle(dev);
4191
4192 if (!rc) {
4193 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
4194 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ)) {
4195 disable_irq(host->core_irqres->start);
4196 host->sdcc_irq_disabled = 1;
4197
4198 /*
4199 * If MMC core level suspend is not supported,
4200 * turn off clocks to allow deep sleep (TCXO
4201 * shutdown).
4202 */
4203 mmc->ios.clock = 0;
4204 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4205 enable_irq(host->core_irqres->start);
4206 host->sdcc_irq_disabled = 0;
4207
4208 if (host->plat->sdiowakeup_irq) {
4209 host->sdio_irq_disabled = 0;
4210 msmsdcc_enable_irq_wake(host);
4211 enable_irq(host->plat->sdiowakeup_irq);
4212 }
4213 }
4214 }
4215 host->sdcc_suspending = 0;
4216 mmc->suspend_task = NULL;
4217 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
4218 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004219 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304220 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004221 return rc;
4222}
4223
4224static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004225msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004226{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004227 struct mmc_host *mmc = dev_get_drvdata(dev);
4228 struct msmsdcc_host *host = mmc_priv(mmc);
4229 unsigned long flags;
4230
4231 if (host->plat->is_sdio_al_client)
4232 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07004233
Sahitya Tummala7661a452011-07-18 13:28:35 +05304234 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004235 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004236 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
4237 if (host->sdcc_irq_disabled) {
4238 enable_irq(host->core_irqres->start);
4239 host->sdcc_irq_disabled = 0;
4240 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304241 mmc->ios.clock = host->clk_rate;
4242 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07004243
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304244 spin_lock_irqsave(&host->lock, flags);
4245 writel_relaxed(host->mci_irqenable,
4246 host->base + MMCIMASK0);
4247 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07004248
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304249 if ((mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) &&
4250 !host->sdio_irq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004251 if (host->plat->sdiowakeup_irq) {
4252 disable_irq_nosync(
4253 host->plat->sdiowakeup_irq);
4254 msmsdcc_disable_irq_wake(host);
4255 host->sdio_irq_disabled = 1;
4256 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304257 }
San Mehat9d2bd732009-09-22 16:44:22 -07004258
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304259 spin_unlock_irqrestore(&host->lock, flags);
4260 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004261
4262 mmc_resume_host(mmc);
4263
4264 /*
4265 * FIXME: Clearing of flags must be handled in clients
4266 * resume handler.
4267 */
4268 spin_lock_irqsave(&host->lock, flags);
4269 mmc->pm_flags = 0;
4270 spin_unlock_irqrestore(&host->lock, flags);
4271
4272 /*
4273 * After resuming the host wait for sometime so that
4274 * the SDIO work will be processed.
4275 */
4276 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO)) {
4277 if ((host->plat->cfg_mpm_sdiowakeup ||
4278 host->plat->sdiowakeup_irq) &&
4279 wake_lock_active(&host->sdio_wlock))
4280 wake_lock_timeout(&host->sdio_wlock, 1);
4281 }
4282
4283 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004284 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304285 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004286 return 0;
4287}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004288
4289static int msmsdcc_runtime_idle(struct device *dev)
4290{
4291 struct mmc_host *mmc = dev_get_drvdata(dev);
4292 struct msmsdcc_host *host = mmc_priv(mmc);
4293
4294 if (host->plat->is_sdio_al_client)
4295 return 0;
4296
4297 /* Idle timeout is not configurable for now */
4298 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
4299
4300 return -EAGAIN;
4301}
4302
4303static int msmsdcc_pm_suspend(struct device *dev)
4304{
4305 struct mmc_host *mmc = dev_get_drvdata(dev);
4306 struct msmsdcc_host *host = mmc_priv(mmc);
4307 int rc = 0;
4308
4309 if (host->plat->is_sdio_al_client)
4310 return 0;
4311
4312
4313 if (host->plat->status_irq)
4314 disable_irq(host->plat->status_irq);
4315
4316 if (!pm_runtime_suspended(dev))
4317 rc = msmsdcc_runtime_suspend(dev);
4318
4319 return rc;
4320}
4321
4322static int msmsdcc_pm_resume(struct device *dev)
4323{
4324 struct mmc_host *mmc = dev_get_drvdata(dev);
4325 struct msmsdcc_host *host = mmc_priv(mmc);
4326 int rc = 0;
4327
4328 if (host->plat->is_sdio_al_client)
4329 return 0;
4330
Sahitya Tummalafb486372011-09-02 19:01:49 +05304331 if (!pm_runtime_suspended(dev))
4332 rc = msmsdcc_runtime_resume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004333 if (host->plat->status_irq) {
4334 msmsdcc_check_status((unsigned long)host);
4335 enable_irq(host->plat->status_irq);
4336 }
4337
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004338 return rc;
4339}
4340
Daniel Walker08ecfde2010-06-23 12:32:20 -07004341#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004342#define msmsdcc_runtime_suspend NULL
4343#define msmsdcc_runtime_resume NULL
4344#define msmsdcc_runtime_idle NULL
4345#define msmsdcc_pm_suspend NULL
4346#define msmsdcc_pm_resume NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07004347#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004348
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004349static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
4350 .runtime_suspend = msmsdcc_runtime_suspend,
4351 .runtime_resume = msmsdcc_runtime_resume,
4352 .runtime_idle = msmsdcc_runtime_idle,
4353 .suspend = msmsdcc_pm_suspend,
4354 .resume = msmsdcc_pm_resume,
4355};
4356
San Mehat9d2bd732009-09-22 16:44:22 -07004357static struct platform_driver msmsdcc_driver = {
4358 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004359 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07004360 .driver = {
4361 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004362 .pm = &msmsdcc_dev_pm_ops,
San Mehat9d2bd732009-09-22 16:44:22 -07004363 },
4364};
4365
4366static int __init msmsdcc_init(void)
4367{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004368#if defined(CONFIG_DEBUG_FS)
4369 int ret = 0;
4370 ret = msmsdcc_dbg_init();
4371 if (ret) {
4372 pr_err("Failed to create debug fs dir \n");
4373 return ret;
4374 }
4375#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004376 return platform_driver_register(&msmsdcc_driver);
4377}
4378
4379static void __exit msmsdcc_exit(void)
4380{
4381 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004382
4383#if defined(CONFIG_DEBUG_FS)
4384 debugfs_remove(debugfs_file);
4385 debugfs_remove(debugfs_dir);
4386#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004387}
4388
4389module_init(msmsdcc_init);
4390module_exit(msmsdcc_exit);
4391
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004392MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07004393MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004394
4395#if defined(CONFIG_DEBUG_FS)
4396
4397static int
4398msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
4399{
4400 file->private_data = inode->i_private;
4401 return 0;
4402}
4403
4404static ssize_t
4405msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
4406 size_t count, loff_t *ppos)
4407{
4408 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
4409 char buf[1024];
4410 int max, i;
4411
4412 i = 0;
4413 max = sizeof(buf) - 1;
4414
4415 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
4416 host->curr.cmd, host->curr.data);
4417 if (host->curr.cmd) {
4418 struct mmc_command *cmd = host->curr.cmd;
4419
4420 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
4421 cmd->opcode, cmd->arg, cmd->flags);
4422 }
4423 if (host->curr.data) {
4424 struct mmc_data *data = host->curr.data;
4425 i += scnprintf(buf + i, max - i,
4426 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
4427 data->timeout_ns, data->timeout_clks,
4428 data->blksz, data->blocks, data->error,
4429 data->flags);
4430 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
4431 host->curr.xfer_size, host->curr.xfer_remain,
4432 host->curr.data_xfered, host->dma.sg);
4433 }
4434
4435 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
4436}
4437
4438static const struct file_operations msmsdcc_dbg_state_ops = {
4439 .read = msmsdcc_dbg_state_read,
4440 .open = msmsdcc_dbg_state_open,
4441};
4442
4443static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
4444{
4445 if (debugfs_dir) {
4446 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
4447 0644, debugfs_dir, host,
4448 &msmsdcc_dbg_state_ops);
4449 }
4450}
4451
4452static int __init msmsdcc_dbg_init(void)
4453{
4454 int err;
4455
4456 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
4457 if (IS_ERR(debugfs_dir)) {
4458 err = PTR_ERR(debugfs_dir);
4459 debugfs_dir = NULL;
4460 return err;
4461 }
4462
4463 return 0;
4464}
4465#endif