blob: 6181758b2c7930b7c7b95ca1070996c3b4f31550 [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
Krishna Kondafea60182011-11-01 16:01:34 -07001685 /* regulators that do not support regulator_set_voltage also
1686 do not support regulator_set_optimum_mode */
1687 if (vreg->set_voltage_sup) {
1688 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1689 if (rc < 0)
1690 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
1691 "uA_load=%d) failed. rc=%d\n", __func__,
1692 vreg->name, uA_load, rc);
1693 else
1694 /* regulator_set_optimum_mode() can return non zero
1695 * value even for success case.
1696 */
1697 rc = 0;
1698 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001699
1700 return rc;
1701}
1702
1703static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1704 struct device *dev)
1705{
1706 int rc = 0;
1707
1708 /* check if regulator is already initialized? */
1709 if (vreg->reg)
1710 goto out;
1711
1712 /* Get the regulator handle */
1713 vreg->reg = regulator_get(dev, vreg->name);
1714 if (IS_ERR(vreg->reg)) {
1715 rc = PTR_ERR(vreg->reg);
1716 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
1717 __func__, vreg->name, rc);
1718 }
1719out:
1720 return rc;
1721}
1722
1723static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
1724{
1725 if (vreg->reg)
1726 regulator_put(vreg->reg);
1727}
1728
1729/* This init function should be called only once for each SDCC slot */
1730static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
1731{
1732 int rc = 0;
1733 struct msm_mmc_slot_reg_data *curr_slot;
1734 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1735 struct device *dev = mmc_dev(host->mmc);
1736
1737 curr_slot = host->plat->vreg_data;
1738 if (!curr_slot)
1739 goto out;
1740
1741 curr_vdd_reg = curr_slot->vdd_data;
1742 curr_vccq_reg = curr_slot->vccq_data;
1743 curr_vddp_reg = curr_slot->vddp_data;
1744
1745 if (is_init) {
1746 /*
1747 * Get the regulator handle from voltage regulator framework
1748 * and then try to set the voltage level for the regulator
1749 */
1750 if (curr_vdd_reg) {
1751 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
1752 if (rc)
1753 goto out;
1754 }
1755 if (curr_vccq_reg) {
1756 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
1757 if (rc)
1758 goto vdd_reg_deinit;
1759 }
1760 if (curr_vddp_reg) {
1761 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
1762 if (rc)
1763 goto vccq_reg_deinit;
1764 }
1765 goto out;
1766 } else {
1767 /* Deregister all regulators from regulator framework */
1768 goto vddp_reg_deinit;
1769 }
1770vddp_reg_deinit:
1771 if (curr_vddp_reg)
1772 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
1773vccq_reg_deinit:
1774 if (curr_vccq_reg)
1775 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
1776vdd_reg_deinit:
1777 if (curr_vdd_reg)
1778 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
1779out:
1780 return rc;
1781}
1782
1783static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
1784{
1785 int rc = 0;
1786
Subhash Jadavanicc922692011-08-01 23:05:01 +05301787 /* Put regulator in HPM (high power mode) */
1788 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
1789 if (rc < 0)
1790 goto out;
1791
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001792 if (!vreg->is_enabled) {
1793 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301794 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
1795 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001796 if (rc)
1797 goto out;
1798
1799 rc = regulator_enable(vreg->reg);
1800 if (rc) {
1801 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
1802 __func__, vreg->name, rc);
1803 goto out;
1804 }
1805 vreg->is_enabled = true;
1806 }
1807
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001808out:
1809 return rc;
1810}
1811
1812static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
1813{
1814 int rc = 0;
1815
1816 /* Never disable regulator marked as always_on */
1817 if (vreg->is_enabled && !vreg->always_on) {
1818 rc = regulator_disable(vreg->reg);
1819 if (rc) {
1820 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
1821 __func__, vreg->name, rc);
1822 goto out;
1823 }
1824 vreg->is_enabled = false;
1825
1826 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
1827 if (rc < 0)
1828 goto out;
1829
1830 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301831 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001832 if (rc)
1833 goto out;
1834 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
1835 /* Put always_on regulator in LPM (low power mode) */
1836 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
1837 if (rc < 0)
1838 goto out;
1839 }
1840out:
1841 return rc;
1842}
1843
1844static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
1845{
1846 int rc = 0, i;
1847 struct msm_mmc_slot_reg_data *curr_slot;
1848 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1849 struct msm_mmc_reg_data *vreg_table[3];
1850
1851 curr_slot = host->plat->vreg_data;
1852 if (!curr_slot)
1853 goto out;
1854
1855 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
1856 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
1857 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
1858
1859 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
1860 if (vreg_table[i]) {
1861 if (enable)
1862 rc = msmsdcc_vreg_enable(vreg_table[i]);
1863 else
1864 rc = msmsdcc_vreg_disable(vreg_table[i]);
1865 if (rc)
1866 goto out;
1867 }
1868 }
1869out:
1870 return rc;
1871}
1872
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301873static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001874{
1875 int rc = 0;
1876
1877 if (host->plat->vreg_data) {
1878 struct msm_mmc_reg_data *vddp_reg =
1879 host->plat->vreg_data->vddp_data;
1880
1881 if (vddp_reg && vddp_reg->is_enabled)
1882 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
1883 }
1884
1885 return rc;
1886}
1887
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301888static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
1889{
1890 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1891 int rc = 0;
1892
1893 if (curr_slot && curr_slot->vddp_data) {
1894 rc = msmsdcc_set_vddp_level(host,
1895 curr_slot->vddp_data->low_vol_level);
1896
1897 if (rc)
1898 pr_err("%s: %s: failed to change vddp level to %d",
1899 mmc_hostname(host->mmc), __func__,
1900 curr_slot->vddp_data->low_vol_level);
1901 }
1902
1903 return rc;
1904}
1905
1906static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
1907{
1908 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1909 int rc = 0;
1910
1911 if (curr_slot && curr_slot->vddp_data) {
1912 rc = msmsdcc_set_vddp_level(host,
1913 curr_slot->vddp_data->high_vol_level);
1914
1915 if (rc)
1916 pr_err("%s: %s: failed to change vddp level to %d",
1917 mmc_hostname(host->mmc), __func__,
1918 curr_slot->vddp_data->high_vol_level);
1919 }
1920
1921 return rc;
1922}
1923
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001924static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
1925{
1926 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
1927 return 1;
1928 return 0;
1929}
1930
1931static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
1932{
1933 if (enable) {
1934 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1935 clk_enable(host->dfab_pclk);
1936 if (!IS_ERR(host->pclk))
1937 clk_enable(host->pclk);
1938 clk_enable(host->clk);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301939 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001940 } else {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301941 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001942 clk_disable(host->clk);
1943 if (!IS_ERR(host->pclk))
1944 clk_disable(host->pclk);
1945 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1946 clk_disable(host->dfab_pclk);
1947 }
1948}
1949
1950static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
1951 unsigned int req_clk)
1952{
1953 unsigned int sel_clk = -1;
1954
1955 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
1956 unsigned char cnt;
1957
1958 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
1959 if (host->plat->sup_clk_table[cnt] > req_clk)
1960 break;
1961 else if (host->plat->sup_clk_table[cnt] == req_clk) {
1962 sel_clk = host->plat->sup_clk_table[cnt];
1963 break;
1964 } else
1965 sel_clk = host->plat->sup_clk_table[cnt];
1966 }
1967 } else {
1968 if ((req_clk < host->plat->msmsdcc_fmax) &&
1969 (req_clk > host->plat->msmsdcc_fmid))
1970 sel_clk = host->plat->msmsdcc_fmid;
1971 else
1972 sel_clk = req_clk;
1973 }
1974
1975 return sel_clk;
1976}
1977
1978static inline unsigned int msmsdcc_get_min_sup_clk_rate(
1979 struct msmsdcc_host *host)
1980{
1981 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
1982 return host->plat->sup_clk_table[0];
1983 else
1984 return host->plat->msmsdcc_fmin;
1985}
1986
1987static inline unsigned int msmsdcc_get_max_sup_clk_rate(
1988 struct msmsdcc_host *host)
1989{
1990 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
1991 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
1992 else
1993 return host->plat->msmsdcc_fmax;
1994}
1995
1996static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05301997{
1998 struct msm_mmc_gpio_data *curr;
1999 int i, rc = 0;
2000
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002001 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302002 for (i = 0; i < curr->size; i++) {
2003 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002004 if (curr->gpio[i].is_always_on &&
2005 curr->gpio[i].is_enabled)
2006 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302007 rc = gpio_request(curr->gpio[i].no,
2008 curr->gpio[i].name);
2009 if (rc) {
2010 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2011 mmc_hostname(host->mmc),
2012 curr->gpio[i].no,
2013 curr->gpio[i].name, rc);
2014 goto free_gpios;
2015 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002016 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302017 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002018 if (curr->gpio[i].is_always_on)
2019 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302020 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002021 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302022 }
2023 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002024 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302025
2026free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002027 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302028 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002029 curr->gpio[i].is_enabled = false;
2030 }
2031out:
2032 return rc;
2033}
2034
2035static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2036{
2037 struct msm_mmc_pad_data *curr;
2038 int i;
2039
2040 curr = host->plat->pin_data->pad_data;
2041 for (i = 0; i < curr->drv->size; i++) {
2042 if (enable)
2043 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2044 curr->drv->on[i].val);
2045 else
2046 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2047 curr->drv->off[i].val);
2048 }
2049
2050 for (i = 0; i < curr->pull->size; i++) {
2051 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002052 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002053 curr->pull->on[i].val);
2054 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002055 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002056 curr->pull->off[i].val);
2057 }
2058
2059 return 0;
2060}
2061
2062static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2063{
2064 int rc = 0;
2065
2066 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2067 return 0;
2068
2069 if (host->plat->pin_data->is_gpio)
2070 rc = msmsdcc_setup_gpio(host, enable);
2071 else
2072 rc = msmsdcc_setup_pad(host, enable);
2073
2074 if (!rc)
2075 host->plat->pin_data->cfg_sts = enable;
2076
2077 return rc;
2078}
2079
2080static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2081{
2082 unsigned int wakeup_irq;
2083
2084 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2085 host->plat->sdiowakeup_irq :
2086 host->core_irqres->start;
2087
2088 if (!host->irq_wake_enabled) {
2089 enable_irq_wake(wakeup_irq);
2090 host->irq_wake_enabled = true;
2091 }
2092}
2093
2094static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2095{
2096 unsigned int wakeup_irq;
2097
2098 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2099 host->plat->sdiowakeup_irq :
2100 host->core_irqres->start;
2101
2102 if (host->irq_wake_enabled) {
2103 disable_irq_wake(wakeup_irq);
2104 host->irq_wake_enabled = false;
2105 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302106}
2107
San Mehat9d2bd732009-09-22 16:44:22 -07002108static void
2109msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2110{
2111 struct msmsdcc_host *host = mmc_priv(mmc);
2112 u32 clk = 0, pwr = 0;
2113 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002114 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002115 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002116
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002117 DBG(host, "ios->clock = %u\n", ios->clock);
Sahitya Tummala7a892482011-01-18 11:22:49 +05302118
San Mehat9d2bd732009-09-22 16:44:22 -07002119 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002120 spin_lock_irqsave(&host->lock, flags);
2121 if (!host->clks_on) {
2122 msmsdcc_setup_clocks(host, true);
2123 host->clks_on = 1;
2124 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2125 if (!host->plat->sdiowakeup_irq) {
2126 writel_relaxed(host->mci_irqenable,
2127 host->base + MMCIMASK0);
2128 mb();
2129 if (host->plat->cfg_mpm_sdiowakeup &&
2130 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2131 host->plat->cfg_mpm_sdiowakeup(
2132 mmc_dev(mmc), SDC_DAT1_DISWAKE);
2133 msmsdcc_disable_irq_wake(host);
2134 } else if (!(mmc->pm_flags &
2135 MMC_PM_WAKE_SDIO_IRQ)) {
2136 writel_relaxed(host->mci_irqenable,
2137 host->base + MMCIMASK0);
2138 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05302139 } else {
2140 writel_relaxed(host->mci_irqenable,
2141 host->base + MMCIMASK0);
2142 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002143 }
San Mehat9d2bd732009-09-22 16:44:22 -07002144 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002145 spin_unlock_irqrestore(&host->lock, flags);
2146
2147 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2148 /*
2149 * For DDR50 mode, controller needs clock rate to be
2150 * double than what is required on the SD card CLK pin.
2151 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302152 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002153 /*
2154 * Make sure that we don't double the clock if
2155 * doubled clock rate is already set
2156 */
2157 if (!host->ddr_doubled_clk_rate ||
2158 (host->ddr_doubled_clk_rate &&
2159 (host->ddr_doubled_clk_rate != ios->clock))) {
2160 host->ddr_doubled_clk_rate =
2161 msmsdcc_get_sup_clk_rate(
2162 host, (ios->clock * 2));
2163 clock = host->ddr_doubled_clk_rate;
2164 }
2165 } else {
2166 host->ddr_doubled_clk_rate = 0;
2167 }
2168
2169 if (clock != host->clk_rate) {
2170 rc = clk_set_rate(host->clk, clock);
2171 if (rc < 0)
2172 pr_debug("%s: failed to set clk rate %u\n",
2173 mmc_hostname(mmc), clock);
2174 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302175 host->reg_write_delay =
2176 (1 + ((3 * USEC_PER_SEC) /
2177 (host->clk_rate ? host->clk_rate :
2178 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002179 }
2180 /*
2181 * give atleast 2 MCLK cycles delay for clocks
2182 * and SDCC core to stabilize
2183 */
2184 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002185 clk |= MCI_CLK_ENABLE;
2186 }
2187
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002188 if (ios->bus_width == MMC_BUS_WIDTH_8)
2189 clk |= MCI_CLK_WIDEBUS_8;
2190 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2191 clk |= MCI_CLK_WIDEBUS_4;
2192 else
2193 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002194
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002195 if (msmsdcc_is_pwrsave(host))
2196 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002197
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002198 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002199
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002200 host->tuning_needed = 0;
2201 /*
2202 * Select the controller timing mode according
2203 * to current bus speed mode
2204 */
2205 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2206 (ios->timing == MMC_TIMING_UHS_SDR50)) {
2207 clk |= (4 << 14);
2208 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302209 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002210 clk |= (3 << 14);
2211 } else {
2212 clk |= (2 << 14); /* feedback clock */
2213 }
2214
2215 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2216 clk |= (2 << 23);
2217
2218 if (host->io_pad_pwr_switch)
2219 clk |= IO_PAD_PWR_SWITCH;
2220
2221 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
San Mehat9d2bd732009-09-22 16:44:22 -07002222 pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002223 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2224 pwr |= msmsdcc_setup_vreg(host, !!ios->vdd);
San Mehat9d2bd732009-09-22 16:44:22 -07002225
2226 switch (ios->power_mode) {
2227 case MMC_POWER_OFF:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002228 htc_pwrsink_set(PWRSINK_SDCARD, 0);
2229 if (!host->sdcc_irq_disabled) {
2230 if (host->plat->cfg_mpm_sdiowakeup)
2231 host->plat->cfg_mpm_sdiowakeup(
2232 mmc_dev(mmc), SDC_DAT1_DISABLE);
2233 disable_irq(host->core_irqres->start);
2234 host->sdcc_irq_disabled = 1;
2235 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302236 /*
2237 * As VDD pad rail is always on, set low voltage for VDD
2238 * pad rail when slot is unused (when card is not present
2239 * or during system suspend).
2240 */
2241 msmsdcc_set_vddp_low_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002242 msmsdcc_setup_pins(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002243 break;
2244 case MMC_POWER_UP:
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302245 /* writing PWR_UP bit is redundant */
San Mehat9d2bd732009-09-22 16:44:22 -07002246 pwr |= MCI_PWR_UP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002247 if (host->sdcc_irq_disabled) {
2248 if (host->plat->cfg_mpm_sdiowakeup)
2249 host->plat->cfg_mpm_sdiowakeup(
2250 mmc_dev(mmc), SDC_DAT1_ENABLE);
2251 enable_irq(host->core_irqres->start);
2252 host->sdcc_irq_disabled = 0;
2253 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302254 msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002255 msmsdcc_setup_pins(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07002256 break;
2257 case MMC_POWER_ON:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002258 htc_pwrsink_set(PWRSINK_SDCARD, 100);
San Mehat9d2bd732009-09-22 16:44:22 -07002259 pwr |= MCI_PWR_ON;
2260 break;
2261 }
2262
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002263 spin_lock_irqsave(&host->lock, flags);
2264 if (!host->clks_on) {
2265 /* force the clocks to be on */
2266 msmsdcc_setup_clocks(host, true);
2267 /*
2268 * give atleast 2 MCLK cycles delay for clocks
2269 * and SDCC core to stabilize
2270 */
2271 msmsdcc_delay(host);
2272 }
2273 writel_relaxed(clk, host->base + MMCICLOCK);
2274 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002275
2276 if (host->pwr != pwr) {
2277 host->pwr = pwr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002278 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302279 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002280 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002281 if (!host->clks_on) {
2282 /* force the clocks to be off */
2283 msmsdcc_setup_clocks(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002284 }
2285
2286 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
2287 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2288 if (!host->plat->sdiowakeup_irq) {
2289 writel_relaxed(MCI_SDIOINTMASK,
2290 host->base + MMCIMASK0);
2291 mb();
2292 if (host->plat->cfg_mpm_sdiowakeup &&
2293 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2294 host->plat->cfg_mpm_sdiowakeup(
2295 mmc_dev(mmc), SDC_DAT1_ENWAKE);
2296 msmsdcc_enable_irq_wake(host);
2297 } else if (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2298 writel_relaxed(0, host->base + MMCIMASK0);
2299 } else {
2300 writel_relaxed(MCI_SDIOINTMASK,
2301 host->base + MMCIMASK0);
2302 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302303 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002304 }
2305 msmsdcc_setup_clocks(host, false);
2306 host->clks_on = 0;
2307 }
San Mehat4adbbcc2009-11-08 13:00:37 -08002308 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002309}
2310
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002311int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2312{
2313 struct msmsdcc_host *host = mmc_priv(mmc);
2314 u32 clk;
2315
2316 clk = readl_relaxed(host->base + MMCICLOCK);
2317 pr_debug("Changing to pwr_save=%d", pwrsave);
2318 if (pwrsave && msmsdcc_is_pwrsave(host))
2319 clk |= MCI_CLK_PWRSAVE;
2320 else
2321 clk &= ~MCI_CLK_PWRSAVE;
2322 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302323 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002324
2325 return 0;
2326}
2327
2328static int msmsdcc_get_ro(struct mmc_host *mmc)
2329{
2330 int status = -ENOSYS;
2331 struct msmsdcc_host *host = mmc_priv(mmc);
2332
2333 if (host->plat->wpswitch) {
2334 status = host->plat->wpswitch(mmc_dev(mmc));
2335 } else if (host->plat->wpswitch_gpio) {
2336 status = gpio_request(host->plat->wpswitch_gpio,
2337 "SD_WP_Switch");
2338 if (status) {
2339 pr_err("%s: %s: Failed to request GPIO %d\n",
2340 mmc_hostname(mmc), __func__,
2341 host->plat->wpswitch_gpio);
2342 } else {
2343 status = gpio_direction_input(
2344 host->plat->wpswitch_gpio);
2345 if (!status) {
2346 /*
2347 * Wait for atleast 300ms as debounce
2348 * time for GPIO input to stabilize.
2349 */
2350 msleep(300);
2351 status = gpio_get_value_cansleep(
2352 host->plat->wpswitch_gpio);
2353 status ^= !host->plat->wpswitch_polarity;
2354 }
2355 gpio_free(host->plat->wpswitch_gpio);
2356 }
2357 }
2358
2359 if (status < 0)
2360 status = -ENOSYS;
2361 pr_debug("%s: Card read-only status %d\n", __func__, status);
2362
2363 return status;
2364}
2365
2366#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002367static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2368{
2369 struct msmsdcc_host *host = mmc_priv(mmc);
2370 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002371
2372 if (enable) {
2373 spin_lock_irqsave(&host->lock, flags);
2374 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
2375 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
2376 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2377 spin_unlock_irqrestore(&host->lock, flags);
2378 } else {
2379 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
2380 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
2381 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2382 }
2383 mb();
2384}
2385#endif /* CONFIG_MMC_MSM_SDIO_SUPPORT */
2386
2387#ifdef CONFIG_PM_RUNTIME
2388static int msmsdcc_enable(struct mmc_host *mmc)
2389{
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302390 int rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002391 struct device *dev = mmc->parent;
2392
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302393 if (dev->power.runtime_status == RPM_SUSPENDING) {
2394 if (mmc->suspend_task == current) {
2395 pm_runtime_get_noresume(dev);
2396 goto out;
2397 }
2398 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002399
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302400 rc = pm_runtime_get_sync(dev);
2401
2402 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002403 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2404 __func__, rc);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302405 return rc;
2406 }
2407out:
2408 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002409}
2410
2411static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2412{
2413 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302414 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002415
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302416 if (host->plat->disable_runtime_pm)
2417 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002418 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO)
2419 return -ENOTSUPP;
2420
2421 rc = pm_runtime_put_sync(mmc->parent);
2422
2423 if (rc < 0)
2424 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2425 __func__, rc);
2426 return rc;
2427}
2428#else
2429#define msmsdcc_enable NULL
2430#define msmsdcc_disable NULL
2431#endif
2432
2433static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2434 struct mmc_ios *ios)
2435{
2436 struct msmsdcc_host *host = mmc_priv(mmc);
2437 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302438 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002439
2440 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2441 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302442 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002443 goto out;
2444 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2445 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302446 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002447 goto out;
2448 }
San Mehat9d2bd732009-09-22 16:44:22 -07002449
2450 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002451 /*
2452 * If we are here means voltage switch from high voltage to
2453 * low voltage is required
2454 */
2455
2456 /*
2457 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2458 * register until they become all zeros.
2459 */
2460 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302461 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002462 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2463 mmc_hostname(mmc), __func__);
2464 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002465 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002466
2467 /* Stop SD CLK output. */
2468 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2469 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302470 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002471 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002472
2473 /*
2474 * Switch VDDPX from high voltage to low voltage
2475 * to change the VDD of the SD IO pads.
2476 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302477 rc = msmsdcc_set_vddp_low_vol(host);
2478 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002479 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002480
2481 spin_lock_irqsave(&host->lock, flags);
2482 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2483 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302484 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002485 host->io_pad_pwr_switch = 1;
2486 spin_unlock_irqrestore(&host->lock, flags);
2487
2488 /* Wait 5 ms for the voltage regulater in the card to become stable. */
2489 usleep_range(5000, 5500);
2490
2491 spin_lock_irqsave(&host->lock, flags);
2492 /* Start SD CLK output. */
2493 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2494 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302495 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002496 spin_unlock_irqrestore(&host->lock, flags);
2497
2498 /*
2499 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
2500 * don't become all ones within 1 ms then a Voltage Switch
2501 * sequence has failed and a power cycle to the card is required.
2502 * Otherwise Voltage Switch sequence is completed successfully.
2503 */
2504 usleep_range(1000, 1500);
2505
2506 spin_lock_irqsave(&host->lock, flags);
2507 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
2508 != (0xF << 1)) {
2509 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
2510 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302511 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002512 goto out_unlock;
2513 }
2514
2515out_unlock:
2516 spin_unlock_irqrestore(&host->lock, flags);
2517out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302518 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002519}
2520
2521static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2522 u8 phase);
2523/* Initialize the DLL (Programmable Delay Line ) */
2524static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
2525{
2526 int rc = 0;
2527 u32 wait_timeout;
2528
2529 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
2530 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2531 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2532
2533 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
2534 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2535 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2536
2537 msmsdcc_delay(host);
2538
2539 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
2540 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2541 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2542
2543 /* Initialize the phase to 0 */
2544 rc = msmsdcc_config_cm_sdc4_dll_phase(host, 0);
2545 if (rc)
2546 goto out;
2547
2548 wait_timeout = 1000;
2549 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
2550 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
2551 /* max. wait for 1 sec for LOCK bit to be set */
2552 if (--wait_timeout == 0) {
2553 pr_err("%s: %s: DLL failed to lock at phase: %d",
2554 mmc_hostname(host->mmc), __func__, 0);
2555 rc = -1;
2556 goto out;
2557 }
2558 /* wait for 1ms */
2559 usleep_range(1000, 1500);
2560 }
2561out:
2562 return rc;
2563}
2564
2565/*
2566 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
2567 * calibration sequence. This function should be called before
2568 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
2569 * commands (CMD17/CMD18).
2570 */
2571static void msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
2572{
2573 /* Set CDR_EN bit to 1. */
2574 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) |
2575 MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2576
2577 /* Set CDR_EXT_EN bit to 0. */
2578 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2579 & ~MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2580
2581 /* Set CK_OUT_EN bit to 0. */
2582 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2583 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2584
2585 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2586 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)
2587 ;
2588
2589 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2590 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2591 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2592
2593 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register is 1. */
2594 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN))
2595 ;
2596}
2597
2598static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2599 u8 phase)
2600{
2601 int rc = 0;
2602 u32 mclk_freq = 0;
2603 u32 wait_timeout;
2604
2605 /* Set CDR_EN bit to 0. */
2606 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2607 & ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2608
2609 /* Set CDR_EXT_EN bit to 1. */
2610 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2611 | MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2612
2613 /* Program the MCLK value to MCLK_FREQ bit field */
2614 if (host->clk_rate <= 112000000)
2615 mclk_freq = 0;
2616 else if (host->clk_rate <= 125000000)
2617 mclk_freq = 1;
2618 else if (host->clk_rate <= 137000000)
2619 mclk_freq = 2;
2620 else if (host->clk_rate <= 150000000)
2621 mclk_freq = 3;
2622 else if (host->clk_rate <= 162000000)
2623 mclk_freq = 4;
2624 else if (host->clk_rate <= 175000000)
2625 mclk_freq = 5;
2626 else if (host->clk_rate <= 187000000)
2627 mclk_freq = 6;
2628 else if (host->clk_rate <= 200000000)
2629 mclk_freq = 7;
2630
2631 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2632 & ~(7 << 24)) | (mclk_freq << 24)),
2633 host->base + MCI_DLL_CONFIG);
2634
2635 /* Set CK_OUT_EN bit to 0. */
2636 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2637 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2638
2639 /* Set DLL_EN bit to 1. */
2640 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2641 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
2642
2643 wait_timeout = 1000;
2644 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2645 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN) {
2646 /* max. wait for 1 sec for LOCK bit for be set */
2647 if (--wait_timeout == 0) {
2648 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 0",
2649 mmc_hostname(host->mmc), __func__, phase);
2650 rc = -1;
2651 goto out;
2652 }
2653 /* wait for 1ms */
2654 usleep_range(1000, 1500);
2655 }
2656
2657 /*
2658 * Write the selected DLL clock output phase (0 ... 15)
2659 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
2660 */
2661 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2662 & ~(0xF << 20)) | (phase << 20)),
2663 host->base + MCI_DLL_CONFIG);
2664
2665 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2666 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2667 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2668
2669 wait_timeout = 1000;
2670 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
2671 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)) {
2672 /* max. wait for 1 sec for LOCK bit for be set */
2673 if (--wait_timeout == 0) {
2674 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 1",
2675 mmc_hostname(host->mmc), __func__, phase);
2676 rc = -1;
2677 goto out;
2678 }
2679 /* wait for 1ms */
2680 usleep_range(1000, 1500);
2681 }
2682out:
2683 return rc;
2684}
2685
2686static int msmsdcc_execute_tuning(struct mmc_host *mmc)
2687{
2688 struct msmsdcc_host *host = mmc_priv(mmc);
2689 u8 phase;
2690 u8 *data_buf;
2691 u8 tuned_phases[16], tuned_phase_cnt = 0;
2692 int rc = 0;
2693
2694 /* Tuning is only required for SDR50 & SDR104 modes */
2695 if (!host->tuning_needed) {
2696 rc = 0;
2697 goto out;
2698 }
2699
2700 host->cmd19_tuning_in_progress = 1;
2701 /*
2702 * Make sure that clock is always enabled when DLL
2703 * tuning is in progress. Keeping PWRSAVE ON may
2704 * turn off the clock. So let's disable the PWRSAVE
2705 * here and re-enable it once tuning is completed.
2706 */
2707 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2708 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302709 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002710 /* first of all reset the tuning block */
2711 rc = msmsdcc_init_cm_sdc4_dll(host);
2712 if (rc)
2713 goto out;
2714
2715 data_buf = kmalloc(64, GFP_KERNEL);
2716 if (!data_buf) {
2717 rc = -ENOMEM;
2718 goto out;
2719 }
2720
2721 phase = 0;
2722 do {
2723 struct mmc_command cmd = {0};
2724 struct mmc_data data = {0};
2725 struct mmc_request mrq = {
2726 .cmd = &cmd,
2727 .data = &data
2728 };
2729 struct scatterlist sg;
2730
2731 /* set the phase in delay line hw block */
2732 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2733 if (rc)
2734 goto kfree;
2735
2736 cmd.opcode = MMC_SEND_TUNING_BLOCK;
2737 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
2738
2739 data.blksz = 64;
2740 data.blocks = 1;
2741 data.flags = MMC_DATA_READ;
2742 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
2743
2744 data.sg = &sg;
2745 data.sg_len = 1;
2746 sg_init_one(&sg, data_buf, 64);
2747 memset(data_buf, 0, 64);
2748 mmc_wait_for_req(mmc, &mrq);
2749
2750 if (!cmd.error && !data.error &&
2751 !memcmp(data_buf, cmd19_tuning_block, 64)) {
2752 /* tuning is successful with this tuning point */
2753 tuned_phases[tuned_phase_cnt++] = phase;
2754 }
2755 } while (++phase < 16);
2756
2757 kfree(data_buf);
2758
2759 if (tuned_phase_cnt) {
2760 tuned_phase_cnt--;
2761 tuned_phase_cnt = (tuned_phase_cnt * 3) / 4;
2762 phase = tuned_phases[tuned_phase_cnt];
2763 /*
2764 * Finally set the selected phase in delay
2765 * line hw block.
2766 */
2767 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2768 if (rc)
2769 goto out;
2770 } else {
2771 /* tuning failed */
2772 rc = -EAGAIN;
2773 pr_err("%s: %s: no tuning point found",
2774 mmc_hostname(mmc), __func__);
2775 }
2776 goto out;
2777
2778kfree:
2779 kfree(data_buf);
2780out:
2781 /* re-enable PWESAVE */
2782 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2783 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302784 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002785 host->cmd19_tuning_in_progress = 0;
2786 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07002787}
2788
2789static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002790 .enable = msmsdcc_enable,
2791 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07002792 .request = msmsdcc_request,
2793 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002794 .get_ro = msmsdcc_get_ro,
2795#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002796 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002797#endif
2798 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
2799 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07002800};
2801
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002802static unsigned int
2803msmsdcc_slot_status(struct msmsdcc_host *host)
2804{
2805 int status;
2806 unsigned int gpio_no = host->plat->status_gpio;
2807
2808 status = gpio_request(gpio_no, "SD_HW_Detect");
2809 if (status) {
2810 pr_err("%s: %s: Failed to request GPIO %d\n",
2811 mmc_hostname(host->mmc), __func__, gpio_no);
2812 } else {
2813 status = gpio_direction_input(gpio_no);
2814 if (!status)
2815 status = !gpio_get_value_cansleep(gpio_no);
2816 gpio_free(gpio_no);
2817 }
2818 return status;
2819}
2820
San Mehat9d2bd732009-09-22 16:44:22 -07002821static void
2822msmsdcc_check_status(unsigned long data)
2823{
2824 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
2825 unsigned int status;
2826
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002827 if (host->plat->status || host->plat->status_gpio) {
2828 if (host->plat->status)
2829 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07002830 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002831 status = msmsdcc_slot_status(host);
2832
2833 host->eject = !status;
2834 if (status ^ host->oldstat) {
2835 pr_info("%s: Slot status change detected (%d -> %d)\n",
2836 mmc_hostname(host->mmc), host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07002837 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002838 }
2839 host->oldstat = status;
2840 } else {
2841 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07002842 }
San Mehat9d2bd732009-09-22 16:44:22 -07002843}
2844
2845static irqreturn_t
2846msmsdcc_platform_status_irq(int irq, void *dev_id)
2847{
2848 struct msmsdcc_host *host = dev_id;
2849
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002850 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07002851 msmsdcc_check_status((unsigned long) host);
2852 return IRQ_HANDLED;
2853}
2854
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002855static irqreturn_t
2856msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
2857{
2858 struct msmsdcc_host *host = dev_id;
2859
2860 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
2861 spin_lock(&host->lock);
2862 if (!host->sdio_irq_disabled) {
2863 disable_irq_nosync(irq);
2864 if (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2865 wake_lock(&host->sdio_wlock);
2866 msmsdcc_disable_irq_wake(host);
2867 }
2868 host->sdio_irq_disabled = 1;
2869 }
2870 if (host->plat->is_sdio_al_client) {
2871 if (!host->clks_on) {
2872 msmsdcc_setup_clocks(host, true);
2873 host->clks_on = 1;
2874 }
2875 if (host->sdcc_irq_disabled) {
2876 writel_relaxed(host->mci_irqenable,
2877 host->base + MMCIMASK0);
2878 mb();
2879 enable_irq(host->core_irqres->start);
2880 host->sdcc_irq_disabled = 0;
2881 }
2882 wake_lock(&host->sdio_wlock);
2883 }
2884 spin_unlock(&host->lock);
2885
2886 return IRQ_HANDLED;
2887}
2888
San Mehat9d2bd732009-09-22 16:44:22 -07002889static void
2890msmsdcc_status_notify_cb(int card_present, void *dev_id)
2891{
2892 struct msmsdcc_host *host = dev_id;
2893
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002894 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07002895 card_present);
2896 msmsdcc_check_status((unsigned long) host);
2897}
2898
San Mehat9d2bd732009-09-22 16:44:22 -07002899static int
2900msmsdcc_init_dma(struct msmsdcc_host *host)
2901{
2902 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
2903 host->dma.host = host;
2904 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07002905 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07002906
2907 if (!host->dmares)
2908 return -ENODEV;
2909
2910 host->dma.nc = dma_alloc_coherent(NULL,
2911 sizeof(struct msmsdcc_nc_dmadata),
2912 &host->dma.nc_busaddr,
2913 GFP_KERNEL);
2914 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07002915 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07002916 return -ENOMEM;
2917 }
2918 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
2919 host->dma.cmd_busaddr = host->dma.nc_busaddr;
2920 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
2921 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
2922 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07002923 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07002924
2925 return 0;
2926}
2927
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002928#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
2929/**
2930 * Allocate and Connect a SDCC peripheral's SPS endpoint
2931 *
2932 * This function allocates endpoint context and
2933 * connect it with memory endpoint by calling
2934 * appropriate SPS driver APIs.
2935 *
2936 * Also registers a SPS callback function with
2937 * SPS driver
2938 *
2939 * This function should only be called once typically
2940 * during driver probe.
2941 *
2942 * @host - Pointer to sdcc host structure
2943 * @ep - Pointer to sps endpoint data structure
2944 * @is_produce - 1 means Producer endpoint
2945 * 0 means Consumer endpoint
2946 *
2947 * @return - 0 if successful else negative value.
2948 *
2949 */
2950static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
2951 struct msmsdcc_sps_ep_conn_data *ep,
2952 bool is_producer)
2953{
2954 int rc = 0;
2955 struct sps_pipe *sps_pipe_handle;
2956 struct sps_connect *sps_config = &ep->config;
2957 struct sps_register_event *sps_event = &ep->event;
2958
2959 /* Allocate endpoint context */
2960 sps_pipe_handle = sps_alloc_endpoint();
2961 if (!sps_pipe_handle) {
2962 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
2963 mmc_hostname(host->mmc), is_producer);
2964 rc = -ENOMEM;
2965 goto out;
2966 }
2967
2968 /* Get default connection configuration for an endpoint */
2969 rc = sps_get_config(sps_pipe_handle, sps_config);
2970 if (rc) {
2971 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
2972 " rc=%d", mmc_hostname(host->mmc),
2973 (u32)sps_pipe_handle, rc);
2974 goto get_config_err;
2975 }
2976
2977 /* Modify the default connection configuration */
2978 if (is_producer) {
2979 /*
2980 * For SDCC producer transfer, source should be
2981 * SDCC peripheral where as destination should
2982 * be system memory.
2983 */
2984 sps_config->source = host->sps.bam_handle;
2985 sps_config->destination = SPS_DEV_HANDLE_MEM;
2986 /* Producer pipe will handle this connection */
2987 sps_config->mode = SPS_MODE_SRC;
2988 sps_config->options =
2989 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
2990 } else {
2991 /*
2992 * For SDCC consumer transfer, source should be
2993 * system memory where as destination should
2994 * SDCC peripheral
2995 */
2996 sps_config->source = SPS_DEV_HANDLE_MEM;
2997 sps_config->destination = host->sps.bam_handle;
2998 sps_config->mode = SPS_MODE_DEST;
2999 sps_config->options =
3000 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3001 }
3002
3003 /* Producer pipe index */
3004 sps_config->src_pipe_index = host->sps.src_pipe_index;
3005 /* Consumer pipe index */
3006 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
3007 /*
3008 * This event thresold value is only significant for BAM-to-BAM
3009 * transfer. It's ignored for BAM-to-System mode transfer.
3010 */
3011 sps_config->event_thresh = 0x10;
3012 /*
3013 * Max. no of scatter/gather buffers that can
3014 * be passed by block layer = 32 (NR_SG).
3015 * Each BAM descritor needs 64 bits (8 bytes).
3016 * One BAM descriptor is required per buffer transfer.
3017 * So we would require total 256 (32 * 8) bytes of descriptor FIFO.
3018 * But due to HW limitation we need to allocate atleast one extra
3019 * descriptor memory (256 bytes + 8 bytes). But in order to be
3020 * in power of 2, we are allocating 512 bytes of memory.
3021 */
3022 sps_config->desc.size = 512;
3023 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
3024 sps_config->desc.size,
3025 &sps_config->desc.phys_base,
3026 GFP_KERNEL);
3027
Pratibhasagar V00b94332011-10-18 14:57:27 +05303028 if (!sps_config->desc.base) {
3029 rc = -ENOMEM;
3030 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3031 , mmc_hostname(host->mmc));
3032 goto get_config_err;
3033 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003034 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3035
3036 /* Establish connection between peripheral and memory endpoint */
3037 rc = sps_connect(sps_pipe_handle, sps_config);
3038 if (rc) {
3039 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3040 " rc=%d", mmc_hostname(host->mmc),
3041 (u32)sps_pipe_handle, rc);
3042 goto sps_connect_err;
3043 }
3044
3045 sps_event->mode = SPS_TRIGGER_CALLBACK;
3046 sps_event->options = SPS_O_EOT;
3047 sps_event->callback = msmsdcc_sps_complete_cb;
3048 sps_event->xfer_done = NULL;
3049 sps_event->user = (void *)host;
3050
3051 /* Register callback event for EOT (End of transfer) event. */
3052 rc = sps_register_event(sps_pipe_handle, sps_event);
3053 if (rc) {
3054 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3055 " rc=%d", mmc_hostname(host->mmc),
3056 (u32)sps_pipe_handle, rc);
3057 goto reg_event_err;
3058 }
3059 /* Now save the sps pipe handle */
3060 ep->pipe_handle = sps_pipe_handle;
3061 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3062 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3063 __func__, is_producer ? "READ" : "WRITE",
3064 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3065 goto out;
3066
3067reg_event_err:
3068 sps_disconnect(sps_pipe_handle);
3069sps_connect_err:
3070 dma_free_coherent(mmc_dev(host->mmc),
3071 sps_config->desc.size,
3072 sps_config->desc.base,
3073 sps_config->desc.phys_base);
3074get_config_err:
3075 sps_free_endpoint(sps_pipe_handle);
3076out:
3077 return rc;
3078}
3079
3080/**
3081 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3082 *
3083 * This function disconnect endpoint and deallocates
3084 * endpoint context.
3085 *
3086 * This function should only be called once typically
3087 * during driver remove.
3088 *
3089 * @host - Pointer to sdcc host structure
3090 * @ep - Pointer to sps endpoint data structure
3091 *
3092 */
3093static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3094 struct msmsdcc_sps_ep_conn_data *ep)
3095{
3096 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3097 struct sps_connect *sps_config = &ep->config;
3098 struct sps_register_event *sps_event = &ep->event;
3099
3100 sps_event->xfer_done = NULL;
3101 sps_event->callback = NULL;
3102 sps_register_event(sps_pipe_handle, sps_event);
3103 sps_disconnect(sps_pipe_handle);
3104 dma_free_coherent(mmc_dev(host->mmc),
3105 sps_config->desc.size,
3106 sps_config->desc.base,
3107 sps_config->desc.phys_base);
3108 sps_free_endpoint(sps_pipe_handle);
3109}
3110
3111/**
3112 * Reset SDCC peripheral's SPS endpoint
3113 *
3114 * This function disconnects an endpoint.
3115 *
3116 * This function should be called for reseting
3117 * SPS endpoint when data transfer error is
3118 * encountered during data transfer. This
3119 * can be considered as soft reset to endpoint.
3120 *
3121 * This function should only be called if
3122 * msmsdcc_sps_init() is already called.
3123 *
3124 * @host - Pointer to sdcc host structure
3125 * @ep - Pointer to sps endpoint data structure
3126 *
3127 * @return - 0 if successful else negative value.
3128 */
3129static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3130 struct msmsdcc_sps_ep_conn_data *ep)
3131{
3132 int rc = 0;
3133 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3134
3135 rc = sps_disconnect(sps_pipe_handle);
3136 if (rc) {
3137 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3138 " rc=%d", mmc_hostname(host->mmc), __func__,
3139 (u32)sps_pipe_handle, rc);
3140 goto out;
3141 }
3142 out:
3143 return rc;
3144}
3145
3146/**
3147 * Restore SDCC peripheral's SPS endpoint
3148 *
3149 * This function connects an endpoint.
3150 *
3151 * This function should be called for restoring
3152 * SPS endpoint after data transfer error is
3153 * encountered during data transfer. This
3154 * can be considered as soft reset to endpoint.
3155 *
3156 * This function should only be called if
3157 * msmsdcc_sps_reset_ep() is called before.
3158 *
3159 * @host - Pointer to sdcc host structure
3160 * @ep - Pointer to sps endpoint data structure
3161 *
3162 * @return - 0 if successful else negative value.
3163 */
3164static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3165 struct msmsdcc_sps_ep_conn_data *ep)
3166{
3167 int rc = 0;
3168 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3169 struct sps_connect *sps_config = &ep->config;
3170 struct sps_register_event *sps_event = &ep->event;
3171
3172 /* Establish connection between peripheral and memory endpoint */
3173 rc = sps_connect(sps_pipe_handle, sps_config);
3174 if (rc) {
3175 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3176 " rc=%d", mmc_hostname(host->mmc), __func__,
3177 (u32)sps_pipe_handle, rc);
3178 goto out;
3179 }
3180
3181 /* Register callback event for EOT (End of transfer) event. */
3182 rc = sps_register_event(sps_pipe_handle, sps_event);
3183 if (rc) {
3184 pr_err("%s: %s: sps_register_event() failed!!!"
3185 " pipe_handle=0x%x, rc=%d",
3186 mmc_hostname(host->mmc), __func__,
3187 (u32)sps_pipe_handle, rc);
3188 goto reg_event_err;
3189 }
3190 goto out;
3191
3192reg_event_err:
3193 sps_disconnect(sps_pipe_handle);
3194out:
3195 return rc;
3196}
3197
3198/**
3199 * Initialize SPS HW connected with SDCC core
3200 *
3201 * This function register BAM HW resources with
3202 * SPS driver and then initialize 2 SPS endpoints
3203 *
3204 * This function should only be called once typically
3205 * during driver probe.
3206 *
3207 * @host - Pointer to sdcc host structure
3208 *
3209 * @return - 0 if successful else negative value.
3210 *
3211 */
3212static int msmsdcc_sps_init(struct msmsdcc_host *host)
3213{
3214 int rc = 0;
3215 struct sps_bam_props bam = {0};
3216
3217 host->bam_base = ioremap(host->bam_memres->start,
3218 resource_size(host->bam_memres));
3219 if (!host->bam_base) {
3220 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3221 " size=0x%x", mmc_hostname(host->mmc),
3222 host->bam_memres->start,
3223 (host->bam_memres->end -
3224 host->bam_memres->start));
3225 rc = -ENOMEM;
3226 goto out;
3227 }
3228
3229 bam.phys_addr = host->bam_memres->start;
3230 bam.virt_addr = host->bam_base;
3231 /*
3232 * This event thresold value is only significant for BAM-to-BAM
3233 * transfer. It's ignored for BAM-to-System mode transfer.
3234 */
3235 bam.event_threshold = 0x10; /* Pipe event threshold */
3236 /*
3237 * This threshold controls when the BAM publish
3238 * the descriptor size on the sideband interface.
3239 * SPS HW will only be used when
3240 * data transfer size > MCI_FIFOSIZE (64 bytes).
3241 * PIO mode will be used when
3242 * data transfer size < MCI_FIFOSIZE (64 bytes).
3243 * So set this thresold value to 64 bytes.
3244 */
3245 bam.summing_threshold = 64;
3246 /* SPS driver wll handle the SDCC BAM IRQ */
3247 bam.irq = (u32)host->bam_irqres->start;
3248 bam.manage = SPS_BAM_MGR_LOCAL;
3249
3250 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3251 (u32)bam.phys_addr);
3252 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3253 (u32)bam.virt_addr);
3254
3255 /* Register SDCC Peripheral BAM device to SPS driver */
3256 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3257 if (rc) {
3258 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3259 mmc_hostname(host->mmc), rc);
3260 goto reg_bam_err;
3261 }
3262 pr_info("%s: BAM device registered. bam_handle=0x%x",
3263 mmc_hostname(host->mmc), host->sps.bam_handle);
3264
3265 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3266 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3267
3268 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3269 SPS_PROD_PERIPHERAL);
3270 if (rc)
3271 goto sps_reset_err;
3272 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3273 SPS_CONS_PERIPHERAL);
3274 if (rc)
3275 goto cons_conn_err;
3276
3277 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3278 mmc_hostname(host->mmc),
3279 (unsigned long long)host->bam_memres->start,
3280 (unsigned int)host->bam_irqres->start);
3281 goto out;
3282
3283cons_conn_err:
3284 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3285sps_reset_err:
3286 sps_deregister_bam_device(host->sps.bam_handle);
3287reg_bam_err:
3288 iounmap(host->bam_base);
3289out:
3290 return rc;
3291}
3292
3293/**
3294 * De-initialize SPS HW connected with SDCC core
3295 *
3296 * This function deinitialize SPS endpoints and then
3297 * deregisters BAM resources from SPS driver.
3298 *
3299 * This function should only be called once typically
3300 * during driver remove.
3301 *
3302 * @host - Pointer to sdcc host structure
3303 *
3304 */
3305static void msmsdcc_sps_exit(struct msmsdcc_host *host)
3306{
3307 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
3308 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3309 sps_deregister_bam_device(host->sps.bam_handle);
3310 iounmap(host->bam_base);
3311}
3312#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
3313
3314static ssize_t
3315show_polling(struct device *dev, struct device_attribute *attr, char *buf)
3316{
3317 struct mmc_host *mmc = dev_get_drvdata(dev);
3318 struct msmsdcc_host *host = mmc_priv(mmc);
3319 int poll;
3320 unsigned long flags;
3321
3322 spin_lock_irqsave(&host->lock, flags);
3323 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
3324 spin_unlock_irqrestore(&host->lock, flags);
3325
3326 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
3327}
3328
3329static ssize_t
3330set_polling(struct device *dev, struct device_attribute *attr,
3331 const char *buf, size_t count)
3332{
3333 struct mmc_host *mmc = dev_get_drvdata(dev);
3334 struct msmsdcc_host *host = mmc_priv(mmc);
3335 int value;
3336 unsigned long flags;
3337
3338 sscanf(buf, "%d", &value);
3339
3340 spin_lock_irqsave(&host->lock, flags);
3341 if (value) {
3342 mmc->caps |= MMC_CAP_NEEDS_POLL;
3343 mmc_detect_change(host->mmc, 0);
3344 } else {
3345 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3346 }
3347#ifdef CONFIG_HAS_EARLYSUSPEND
3348 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
3349#endif
3350 spin_unlock_irqrestore(&host->lock, flags);
3351 return count;
3352}
3353
3354static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
3355 show_polling, set_polling);
3356static struct attribute *dev_attrs[] = {
3357 &dev_attr_polling.attr,
3358 NULL,
3359};
3360static struct attribute_group dev_attr_grp = {
3361 .attrs = dev_attrs,
3362};
3363
3364#ifdef CONFIG_HAS_EARLYSUSPEND
3365static void msmsdcc_early_suspend(struct early_suspend *h)
3366{
3367 struct msmsdcc_host *host =
3368 container_of(h, struct msmsdcc_host, early_suspend);
3369 unsigned long flags;
3370
3371 spin_lock_irqsave(&host->lock, flags);
3372 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
3373 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3374 spin_unlock_irqrestore(&host->lock, flags);
3375};
3376static void msmsdcc_late_resume(struct early_suspend *h)
3377{
3378 struct msmsdcc_host *host =
3379 container_of(h, struct msmsdcc_host, early_suspend);
3380 unsigned long flags;
3381
3382 if (host->polling_enabled) {
3383 spin_lock_irqsave(&host->lock, flags);
3384 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
3385 mmc_detect_change(host->mmc, 0);
3386 spin_unlock_irqrestore(&host->lock, flags);
3387 }
3388};
3389#endif
3390
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303391void msmsdcc_print_regs(const char *name, void __iomem *base,
3392 unsigned int no_of_regs)
3393{
3394 unsigned int i;
3395
3396 if (!base)
3397 return;
3398 pr_info("===== %s: Register Dumps @base=0x%x =====\n",
3399 name, (u32)base);
3400 for (i = 0; i < no_of_regs; i = i + 4) {
3401 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x.\n", i*4,
3402 (u32)readl_relaxed(base + i*4),
3403 (u32)readl_relaxed(base + ((i+1)*4)),
3404 (u32)readl_relaxed(base + ((i+2)*4)),
3405 (u32)readl_relaxed(base + ((i+3)*4)));
3406 }
3407}
3408
3409static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
3410{
3411 /* Dump current state of SDCC clocks, power and irq */
3412 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
3413 (host->pwr ? "ON" : "OFF"));
3414 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
3415 mmc_hostname(host->mmc),
3416 (host->clks_on ? "ON" : "OFF"),
3417 (u32)clk_get_rate(host->clk));
3418 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
3419 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
3420
3421 /* Now dump SDCC registers. Don't print FIFO registers */
3422 if (host->clks_on)
3423 msmsdcc_print_regs("SDCC-CORE", host->base, 28);
3424
3425 if (host->curr.data) {
3426 if (msmsdcc_check_dma_op_req(host->curr.data))
3427 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
3428 else if (host->is_dma_mode)
3429 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
3430 mmc_hostname(host->mmc), host->dma.busy,
3431 host->dma.channel, host->dma.crci);
3432 else if (host->is_sps_mode)
3433 pr_info("%s: SPS mode: busy=%d\n",
3434 mmc_hostname(host->mmc), host->sps.busy);
3435
3436 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
3437 mmc_hostname(host->mmc), host->curr.xfer_size,
3438 host->curr.data_xfered, host->curr.xfer_remain);
3439 pr_info("%s: got_dataend=%d, prog_enable=%d,"
3440 " wait_for_auto_prog_done=%d,"
3441 " got_auto_prog_done=%d\n",
3442 mmc_hostname(host->mmc), host->curr.got_dataend,
3443 host->prog_enable, host->curr.wait_for_auto_prog_done,
3444 host->curr.got_auto_prog_done);
3445 }
3446
3447}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003448static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
3449{
3450 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3451 struct mmc_request *mrq;
3452 unsigned long flags;
3453
3454 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003455 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003456 pr_info("%s: %s: dummy CMD52 timeout\n",
3457 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003458 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003459 }
3460
3461 mrq = host->curr.mrq;
3462
3463 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303464 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
3465 mrq->cmd->opcode);
3466 msmsdcc_dump_sdcc_state(host);
3467
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003468 if (!mrq->cmd->error)
3469 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303470 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003471 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003472 if (mrq->data && !mrq->data->error)
3473 mrq->data->error = -ETIMEDOUT;
3474 host->curr.data_xfered = 0;
3475 if (host->dma.sg && host->is_dma_mode) {
3476 msm_dmov_stop_cmd(host->dma.channel,
3477 &host->dma.hdr, 0);
3478 } else if (host->sps.sg && host->is_sps_mode) {
3479 /* Stop current SPS transfer */
3480 msmsdcc_sps_exit_curr_xfer(host);
3481 } else {
3482 msmsdcc_reset_and_restore(host);
3483 msmsdcc_stop_data(host);
3484 if (mrq->data && mrq->data->stop)
3485 msmsdcc_start_command(host,
3486 mrq->data->stop, 0);
3487 else
3488 msmsdcc_request_end(host, mrq);
3489 }
3490 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05303491 host->prog_enable = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003492 msmsdcc_reset_and_restore(host);
3493 msmsdcc_request_end(host, mrq);
3494 }
3495 }
3496 spin_unlock_irqrestore(&host->lock, flags);
3497}
3498
San Mehat9d2bd732009-09-22 16:44:22 -07003499static int
3500msmsdcc_probe(struct platform_device *pdev)
3501{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003502 struct mmc_platform_data *plat = pdev->dev.platform_data;
San Mehat9d2bd732009-09-22 16:44:22 -07003503 struct msmsdcc_host *host;
3504 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003505 unsigned long flags;
3506 struct resource *core_irqres = NULL;
3507 struct resource *bam_irqres = NULL;
3508 struct resource *core_memres = NULL;
3509 struct resource *dml_memres = NULL;
3510 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07003511 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07003512 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05303513 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003514 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07003515
3516 /* must have platform data */
3517 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003518 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003519 ret = -EINVAL;
3520 goto out;
3521 }
3522
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003523 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07003524 return -EINVAL;
3525
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003526 if (plat->is_sdio_al_client)
3527 if (!plat->sdio_lpm_gpio_setup || !plat->sdiowakeup_irq)
3528 return -EINVAL;
3529
San Mehat9d2bd732009-09-22 16:44:22 -07003530 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003531 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003532 return -ENXIO;
3533 }
3534
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003535 for (i = 0; i < pdev->num_resources; i++) {
3536 if (pdev->resource[i].flags & IORESOURCE_MEM) {
3537 if (!strcmp(pdev->resource[i].name,
3538 "sdcc_dml_addr"))
3539 dml_memres = &pdev->resource[i];
3540 else if (!strcmp(pdev->resource[i].name,
3541 "sdcc_bam_addr"))
3542 bam_memres = &pdev->resource[i];
3543 else
3544 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07003545
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003546 }
3547 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
3548 if (!strcmp(pdev->resource[i].name,
3549 "sdcc_bam_irq"))
3550 bam_irqres = &pdev->resource[i];
3551 else
3552 core_irqres = &pdev->resource[i];
3553 }
Krishna Konda25786ec2011-07-25 16:21:36 -07003554 if (pdev->resource[i].flags & IORESOURCE_DMA) {
3555 if (!strncmp(pdev->resource[i].name,
3556 "sdcc_dma_chnl",
3557 sizeof("sdcc_dma_chnl")))
3558 dmares = &pdev->resource[i];
3559 else if (!strncmp(pdev->resource[i].name,
3560 "sdcc_dma_crci",
3561 sizeof("sdcc_dma_crci")))
3562 dma_crci_res = &pdev->resource[i];
3563 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003564 }
3565
3566 if (!core_irqres || !core_memres) {
3567 pr_err("%s: Invalid sdcc core resource\n", __func__);
3568 return -ENXIO;
3569 }
3570
3571 /*
3572 * Both BAM and DML memory resource should be preset.
3573 * BAM IRQ resource should also be present.
3574 */
3575 if ((bam_memres && !dml_memres) ||
3576 (!bam_memres && dml_memres) ||
3577 ((bam_memres && dml_memres) && !bam_irqres)) {
3578 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003579 return -ENXIO;
3580 }
3581
3582 /*
3583 * Setup our host structure
3584 */
San Mehat9d2bd732009-09-22 16:44:22 -07003585 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
3586 if (!mmc) {
3587 ret = -ENOMEM;
3588 goto out;
3589 }
3590
3591 host = mmc_priv(mmc);
3592 host->pdev_id = pdev->id;
3593 host->plat = plat;
3594 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08003595 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05303596
3597 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003598 host->is_sps_mode = 1;
3599 else if (dmares)
3600 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07003601
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003602 host->base = ioremap(core_memres->start,
3603 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07003604 if (!host->base) {
3605 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003606 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003607 }
3608
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003609 host->core_irqres = core_irqres;
3610 host->bam_irqres = bam_irqres;
3611 host->core_memres = core_memres;
3612 host->dml_memres = dml_memres;
3613 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07003614 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07003615 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07003616 spin_lock_init(&host->lock);
3617
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003618#ifdef CONFIG_MMC_EMBEDDED_SDIO
3619 if (plat->embedded_sdio)
3620 mmc_set_embedded_sdio_data(mmc,
3621 &plat->embedded_sdio->cis,
3622 &plat->embedded_sdio->cccr,
3623 plat->embedded_sdio->funcs,
3624 plat->embedded_sdio->num_funcs);
3625#endif
3626
Sahitya Tummala62612cf2010-12-08 15:03:03 +05303627 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
3628 (unsigned long)host);
3629
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003630 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
3631 (unsigned long)host);
3632 if (host->is_dma_mode) {
3633 /* Setup DMA */
3634 ret = msmsdcc_init_dma(host);
3635 if (ret)
3636 goto ioremap_free;
3637 } else {
3638 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003639 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003640 }
3641
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003642 /*
3643 * Setup SDCC clock if derived from Dayatona
3644 * fabric core clock.
3645 */
3646 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07003647 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003648 if (!IS_ERR(host->dfab_pclk)) {
3649 /* Set the clock rate to 64MHz for max. performance */
3650 ret = clk_set_rate(host->dfab_pclk, 64000000);
3651 if (ret)
3652 goto dfab_pclk_put;
3653 ret = clk_enable(host->dfab_pclk);
3654 if (ret)
3655 goto dfab_pclk_put;
3656 } else
3657 goto dma_free;
3658 }
3659
3660 /*
3661 * Setup main peripheral bus clock
3662 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003663 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003664 if (!IS_ERR(host->pclk)) {
3665 ret = clk_enable(host->pclk);
3666 if (ret)
3667 goto pclk_put;
3668
3669 host->pclk_rate = clk_get_rate(host->pclk);
3670 }
3671
3672 /*
3673 * Setup SDC MMC clock
3674 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003675 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07003676 if (IS_ERR(host->clk)) {
3677 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003678 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07003679 }
3680
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003681 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
3682 if (ret) {
3683 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
3684 goto clk_put;
3685 }
3686
3687 ret = clk_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003688 if (ret)
3689 goto clk_put;
3690
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003691 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303692 if (!host->clk_rate)
3693 dev_err(&pdev->dev, "Failed to read MCLK\n");
3694 /*
3695 * Set the register write delay according to min. clock frequency
3696 * supported and update later when the host->clk_rate changes.
3697 */
3698 host->reg_write_delay =
3699 (1 + ((3 * USEC_PER_SEC) /
3700 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003701
3702 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05303703 /* Apply Hard reset to SDCC to put it in power on default state */
3704 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003705
3706 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07003707 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003708 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07003709 goto clk_disable;
3710 }
3711
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003712
3713 /* Clocks has to be running before accessing SPS/DML HW blocks */
3714 if (host->is_sps_mode) {
3715 /* Initialize SPS */
3716 ret = msmsdcc_sps_init(host);
3717 if (ret)
3718 goto vreg_deinit;
3719 /* Initialize DML */
3720 ret = msmsdcc_dml_init(host);
3721 if (ret)
3722 goto sps_exit;
3723 }
San Mehat9d2bd732009-09-22 16:44:22 -07003724
San Mehat9d2bd732009-09-22 16:44:22 -07003725 /*
3726 * Setup MMC host structure
3727 */
3728 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003729 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
3730 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003731 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003732 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
3733 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07003734
San Mehat9d2bd732009-09-22 16:44:22 -07003735 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05303736 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05303737
3738 /*
3739 * If we send the CMD23 before multi block write/read command
3740 * then we need not to send CMD12 at the end of the transfer.
3741 * If we don't send the CMD12 then only way to detect the PROG_DONE
3742 * status is to use the AUTO_PROG_DONE status provided by SDCC4
3743 * controller. So let's enable the CMD23 for SDCC4 only.
3744 */
Sahitya Tummala85fa0702011-09-15 09:39:37 +05303745 if (!plat->disable_cmd23 && host->plat->sdcc_v4_sup)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05303746 mmc->caps |= MMC_CAP_CMD23;
3747
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003748 mmc->caps |= plat->uhs_caps;
3749 /*
3750 * XPC controls the maximum current in the default speed mode of SDXC
3751 * card. XPC=0 means 100mA (max.) but speed class is not supported.
3752 * XPC=1 means 150mA (max.) and speed class is supported.
3753 */
3754 if (plat->xpc_cap)
3755 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
3756 MMC_CAP_SET_XPC_180);
3757
3758 if (plat->nonremovable)
3759 mmc->caps |= MMC_CAP_NONREMOVABLE;
3760#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
3761 mmc->caps |= MMC_CAP_SDIO_IRQ;
3762#endif
3763
3764 if (plat->is_sdio_al_client)
3765 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07003766
Martin K. Petersena36274e2010-09-10 01:33:59 -04003767 mmc->max_segs = NR_SG;
San Mehat9d2bd732009-09-22 16:44:22 -07003768 mmc->max_blk_size = 4096; /* MCI_DATA_CTL BLOCKSIZE up to 4096 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003769 mmc->max_blk_count = 65535;
San Mehat9d2bd732009-09-22 16:44:22 -07003770
3771 mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */
3772 mmc->max_seg_size = mmc->max_req_size;
3773
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003774 writel_relaxed(0, host->base + MMCIMASK0);
3775 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -07003776
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003777 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
3778 mb();
3779 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07003780
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003781 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
3782 DRIVER_NAME " (cmd)", host);
3783 if (ret)
3784 goto dml_exit;
3785
3786 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
3787 DRIVER_NAME " (pio)", host);
3788 if (ret)
3789 goto irq_free;
3790
3791 /*
3792 * Enable SDCC IRQ only when host is powered on. Otherwise, this
3793 * IRQ is un-necessarily being monitored by MPM (Modem power
3794 * management block) during idle-power collapse. The MPM will be
3795 * configured to monitor the DATA1 GPIO line with level-low trigger
3796 * and thus depending on the GPIO status, it prevents TCXO shutdown
3797 * during idle-power collapse.
3798 */
3799 disable_irq(core_irqres->start);
3800 host->sdcc_irq_disabled = 1;
3801
3802 if (plat->sdiowakeup_irq) {
3803 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3804 mmc_hostname(mmc));
3805 ret = request_irq(plat->sdiowakeup_irq,
3806 msmsdcc_platform_sdiowakeup_irq,
3807 IRQF_SHARED | IRQF_TRIGGER_LOW,
3808 DRIVER_NAME "sdiowakeup", host);
3809 if (ret) {
3810 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
3811 plat->sdiowakeup_irq, ret);
3812 goto pio_irq_free;
3813 } else {
3814 spin_lock_irqsave(&host->lock, flags);
3815 if (!host->sdio_irq_disabled) {
3816 disable_irq_nosync(plat->sdiowakeup_irq);
3817 host->sdio_irq_disabled = 1;
3818 }
3819 spin_unlock_irqrestore(&host->lock, flags);
3820 }
3821 }
3822
3823 if (plat->cfg_mpm_sdiowakeup) {
3824 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3825 mmc_hostname(mmc));
3826 }
3827
3828 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
3829 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003830 /*
3831 * Setup card detect change
3832 */
3833
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003834 if (plat->status || plat->status_gpio) {
3835 if (plat->status)
3836 host->oldstat = plat->status(mmc_dev(host->mmc));
3837 else
3838 host->oldstat = msmsdcc_slot_status(host);
3839 host->eject = !host->oldstat;
3840 }
San Mehat9d2bd732009-09-22 16:44:22 -07003841
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003842 if (plat->status_irq) {
3843 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07003844 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003845 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07003846 DRIVER_NAME " (slot)",
3847 host);
3848 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003849 pr_err("Unable to get slot IRQ %d (%d)\n",
3850 plat->status_irq, ret);
3851 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003852 }
3853 } else if (plat->register_status_notify) {
3854 plat->register_status_notify(msmsdcc_status_notify_cb, host);
3855 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003856 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07003857 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003858
3859 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003860
3861 ret = pm_runtime_set_active(&(pdev)->dev);
3862 if (ret < 0)
3863 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3864 __func__, ret);
3865 /*
3866 * There is no notion of suspend/resume for SD/MMC/SDIO
3867 * cards. So host can be suspended/resumed with out
3868 * worrying about its children.
3869 */
3870 pm_suspend_ignore_children(&(pdev)->dev, true);
3871
3872 /*
3873 * MMC/SD/SDIO bus suspend/resume operations are defined
3874 * only for the slots that will be used for non-removable
3875 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
3876 * defined. Otherwise, they simply become card removal and
3877 * insertion events during suspend and resume respectively.
3878 * Hence, enable run-time PM only for slots for which bus
3879 * suspend/resume operations are defined.
3880 */
3881#ifdef CONFIG_MMC_UNSAFE_RESUME
3882 /*
3883 * If this capability is set, MMC core will enable/disable host
3884 * for every claim/release operation on a host. We use this
3885 * notification to increment/decrement runtime pm usage count.
3886 */
3887 mmc->caps |= MMC_CAP_DISABLE;
3888 pm_runtime_enable(&(pdev)->dev);
3889#else
3890 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
3891 mmc->caps |= MMC_CAP_DISABLE;
3892 pm_runtime_enable(&(pdev)->dev);
3893 }
3894#endif
3895 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
3896 (unsigned long)host);
3897
San Mehat9d2bd732009-09-22 16:44:22 -07003898 mmc_add_host(mmc);
3899
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003900#ifdef CONFIG_HAS_EARLYSUSPEND
3901 host->early_suspend.suspend = msmsdcc_early_suspend;
3902 host->early_suspend.resume = msmsdcc_late_resume;
3903 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
3904 register_early_suspend(&host->early_suspend);
3905#endif
San Mehat9d2bd732009-09-22 16:44:22 -07003906
Krishna Konda25786ec2011-07-25 16:21:36 -07003907 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
3908 " dmacrcri %d\n", mmc_hostname(mmc),
3909 (unsigned long long)core_memres->start,
3910 (unsigned int) core_irqres->start,
3911 (unsigned int) plat->status_irq, host->dma.channel,
3912 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003913
3914 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
3915 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
3916 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
3917 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
3918 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
3919 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
3920 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
3921 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
3922 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
3923 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
3924 host->eject);
3925 pr_info("%s: Power save feature enable = %d\n",
3926 mmc_hostname(mmc), msmsdcc_pwrsave);
3927
Krishna Konda25786ec2011-07-25 16:21:36 -07003928 if (host->is_dma_mode && host->dma.channel != -1
3929 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003930 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003931 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003932 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003933 mmc_hostname(mmc), host->dma.cmd_busaddr,
3934 host->dma.cmdptr_busaddr);
3935 } else if (host->is_sps_mode) {
3936 pr_info("%s: SPS-BAM data transfer mode available\n",
3937 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003938 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003939 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003940
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003941#if defined(CONFIG_DEBUG_FS)
3942 msmsdcc_dbg_createhost(host);
3943#endif
3944 if (!plat->status_irq) {
3945 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
3946 if (ret)
3947 goto platform_irq_free;
3948 }
San Mehat9d2bd732009-09-22 16:44:22 -07003949 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003950
3951 platform_irq_free:
3952 del_timer_sync(&host->req_tout_timer);
3953 pm_runtime_disable(&(pdev)->dev);
3954 pm_runtime_set_suspended(&(pdev)->dev);
3955
3956 if (plat->status_irq)
3957 free_irq(plat->status_irq, host);
3958 sdiowakeup_irq_free:
3959 wake_lock_destroy(&host->sdio_suspend_wlock);
3960 if (plat->sdiowakeup_irq)
3961 free_irq(plat->sdiowakeup_irq, host);
3962 pio_irq_free:
3963 if (plat->sdiowakeup_irq)
3964 wake_lock_destroy(&host->sdio_wlock);
3965 free_irq(core_irqres->start, host);
3966 irq_free:
3967 free_irq(core_irqres->start, host);
3968 dml_exit:
3969 if (host->is_sps_mode)
3970 msmsdcc_dml_exit(host);
3971 sps_exit:
3972 if (host->is_sps_mode)
3973 msmsdcc_sps_exit(host);
3974 vreg_deinit:
3975 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07003976 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003977 clk_disable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003978 clk_put:
3979 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003980 pclk_disable:
3981 if (!IS_ERR(host->pclk))
3982 clk_disable(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07003983 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003984 if (!IS_ERR(host->pclk))
3985 clk_put(host->pclk);
3986 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3987 clk_disable(host->dfab_pclk);
3988 dfab_pclk_put:
3989 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3990 clk_put(host->dfab_pclk);
3991 dma_free:
3992 if (host->is_dma_mode) {
3993 if (host->dmares)
3994 dma_free_coherent(NULL,
3995 sizeof(struct msmsdcc_nc_dmadata),
3996 host->dma.nc, host->dma.nc_busaddr);
3997 }
3998 ioremap_free:
3999 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07004000 host_free:
4001 mmc_free_host(mmc);
4002 out:
4003 return ret;
4004}
4005
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004006static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07004007{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004008 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4009 struct mmc_platform_data *plat;
4010 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004011
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004012 if (!mmc)
4013 return -ENXIO;
4014
4015 if (pm_runtime_suspended(&(pdev)->dev))
4016 pm_runtime_resume(&(pdev)->dev);
4017
4018 host = mmc_priv(mmc);
4019
4020 DBG(host, "Removing SDCC device = %d\n", pdev->id);
4021 plat = host->plat;
4022
4023 if (!plat->status_irq)
4024 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
4025
4026 del_timer_sync(&host->req_tout_timer);
4027 tasklet_kill(&host->dma_tlet);
4028 tasklet_kill(&host->sps.tlet);
4029 mmc_remove_host(mmc);
4030
4031 if (plat->status_irq)
4032 free_irq(plat->status_irq, host);
4033
4034 wake_lock_destroy(&host->sdio_suspend_wlock);
4035 if (plat->sdiowakeup_irq) {
4036 wake_lock_destroy(&host->sdio_wlock);
4037 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
4038 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07004039 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004040
4041 free_irq(host->core_irqres->start, host);
4042 free_irq(host->core_irqres->start, host);
4043
4044 clk_put(host->clk);
4045 if (!IS_ERR(host->pclk))
4046 clk_put(host->pclk);
4047 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4048 clk_put(host->dfab_pclk);
4049
4050 msmsdcc_vreg_init(host, false);
4051
4052 if (host->is_dma_mode) {
4053 if (host->dmares)
4054 dma_free_coherent(NULL,
4055 sizeof(struct msmsdcc_nc_dmadata),
4056 host->dma.nc, host->dma.nc_busaddr);
4057 }
4058
4059 if (host->is_sps_mode) {
4060 msmsdcc_dml_exit(host);
4061 msmsdcc_sps_exit(host);
4062 }
4063
4064 iounmap(host->base);
4065 mmc_free_host(mmc);
4066
4067#ifdef CONFIG_HAS_EARLYSUSPEND
4068 unregister_early_suspend(&host->early_suspend);
4069#endif
4070 pm_runtime_disable(&(pdev)->dev);
4071 pm_runtime_set_suspended(&(pdev)->dev);
4072
4073 return 0;
4074}
4075
4076#ifdef CONFIG_MSM_SDIO_AL
4077int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4078{
4079 struct msmsdcc_host *host = mmc_priv(mmc);
4080 unsigned long flags;
4081
4082 spin_lock_irqsave(&host->lock, flags);
4083 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
4084 enable ? "En" : "Dis");
4085
4086 if (enable) {
4087 if (!host->sdcc_irq_disabled) {
4088 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05304089 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004090 host->sdcc_irq_disabled = 1;
4091 }
4092
4093 if (host->clks_on) {
4094 msmsdcc_setup_clocks(host, false);
4095 host->clks_on = 0;
4096 }
4097
4098 if (!host->sdio_gpio_lpm) {
4099 spin_unlock_irqrestore(&host->lock, flags);
4100 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
4101 spin_lock_irqsave(&host->lock, flags);
4102 host->sdio_gpio_lpm = 1;
4103 }
4104
4105 if (host->sdio_irq_disabled) {
4106 msmsdcc_enable_irq_wake(host);
4107 enable_irq(host->plat->sdiowakeup_irq);
4108 host->sdio_irq_disabled = 0;
4109 }
4110 } else {
4111 if (!host->sdio_irq_disabled) {
4112 disable_irq_nosync(host->plat->sdiowakeup_irq);
4113 host->sdio_irq_disabled = 1;
4114 msmsdcc_disable_irq_wake(host);
4115 }
4116
4117 if (host->sdio_gpio_lpm) {
4118 spin_unlock_irqrestore(&host->lock, flags);
4119 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
4120 spin_lock_irqsave(&host->lock, flags);
4121 host->sdio_gpio_lpm = 0;
4122 }
4123
4124 if (!host->clks_on) {
4125 msmsdcc_setup_clocks(host, true);
4126 host->clks_on = 1;
4127 }
4128
4129 if (host->sdcc_irq_disabled) {
4130 writel_relaxed(host->mci_irqenable,
4131 host->base + MMCIMASK0);
4132 mb();
4133 enable_irq(host->core_irqres->start);
4134 host->sdcc_irq_disabled = 0;
4135 }
4136 wake_lock_timeout(&host->sdio_wlock, 1);
4137 }
4138 spin_unlock_irqrestore(&host->lock, flags);
4139 return 0;
4140}
4141#else
4142int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4143{
4144 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004145}
4146#endif
4147
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004148#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07004149static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004150msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004151{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004152 struct mmc_host *mmc = dev_get_drvdata(dev);
4153 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07004154 int rc = 0;
4155
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004156 if (host->plat->is_sdio_al_client)
4157 return 0;
4158
Sahitya Tummala7661a452011-07-18 13:28:35 +05304159 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004160 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004161 host->sdcc_suspending = 1;
4162 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07004163
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004164 /*
4165 * If the clocks are already turned off by SDIO clients (as
4166 * part of LPM), then clocks should be turned on before
4167 * calling mmc_suspend_host() because mmc_suspend_host might
4168 * send some commands to the card. The clocks will be turned
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304169 * off again after mmc_suspend_host. Thus for SDIO
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004170 * cards, clocks will be turned on before mmc_suspend_host
4171 * and turned off after mmc_suspend_host.
4172 */
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304173 if (mmc->card && mmc_card_sdio(mmc->card)) {
4174 mmc->ios.clock = host->clk_rate;
4175 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4176 }
San Mehat9d2bd732009-09-22 16:44:22 -07004177
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004178 /*
4179 * MMC core thinks that host is disabled by now since
4180 * runtime suspend is scheduled after msmsdcc_disable()
4181 * is called. Thus, MMC core will try to enable the host
4182 * while suspending it. This results in a synchronous
4183 * runtime resume request while in runtime suspending
4184 * context and hence inorder to complete this resume
4185 * requet, it will wait for suspend to be complete,
4186 * but runtime suspend also can not proceed further
4187 * until the host is resumed. Thus, it leads to a hang.
4188 * Hence, increase the pm usage count before suspending
4189 * the host so that any resume requests after this will
4190 * simple become pm usage counter increment operations.
4191 */
4192 pm_runtime_get_noresume(dev);
4193 rc = mmc_suspend_host(mmc);
4194 pm_runtime_put_noidle(dev);
4195
4196 if (!rc) {
4197 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
4198 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ)) {
4199 disable_irq(host->core_irqres->start);
4200 host->sdcc_irq_disabled = 1;
4201
4202 /*
4203 * If MMC core level suspend is not supported,
4204 * turn off clocks to allow deep sleep (TCXO
4205 * shutdown).
4206 */
4207 mmc->ios.clock = 0;
4208 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4209 enable_irq(host->core_irqres->start);
4210 host->sdcc_irq_disabled = 0;
4211
4212 if (host->plat->sdiowakeup_irq) {
4213 host->sdio_irq_disabled = 0;
4214 msmsdcc_enable_irq_wake(host);
4215 enable_irq(host->plat->sdiowakeup_irq);
4216 }
4217 }
4218 }
4219 host->sdcc_suspending = 0;
4220 mmc->suspend_task = NULL;
4221 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
4222 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004223 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304224 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004225 return rc;
4226}
4227
4228static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004229msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004230{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004231 struct mmc_host *mmc = dev_get_drvdata(dev);
4232 struct msmsdcc_host *host = mmc_priv(mmc);
4233 unsigned long flags;
4234
4235 if (host->plat->is_sdio_al_client)
4236 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07004237
Sahitya Tummala7661a452011-07-18 13:28:35 +05304238 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004239 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004240 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
4241 if (host->sdcc_irq_disabled) {
4242 enable_irq(host->core_irqres->start);
4243 host->sdcc_irq_disabled = 0;
4244 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304245 mmc->ios.clock = host->clk_rate;
4246 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07004247
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304248 spin_lock_irqsave(&host->lock, flags);
4249 writel_relaxed(host->mci_irqenable,
4250 host->base + MMCIMASK0);
4251 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07004252
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304253 if ((mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) &&
4254 !host->sdio_irq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004255 if (host->plat->sdiowakeup_irq) {
4256 disable_irq_nosync(
4257 host->plat->sdiowakeup_irq);
4258 msmsdcc_disable_irq_wake(host);
4259 host->sdio_irq_disabled = 1;
4260 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304261 }
San Mehat9d2bd732009-09-22 16:44:22 -07004262
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304263 spin_unlock_irqrestore(&host->lock, flags);
4264 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004265
4266 mmc_resume_host(mmc);
4267
4268 /*
4269 * FIXME: Clearing of flags must be handled in clients
4270 * resume handler.
4271 */
4272 spin_lock_irqsave(&host->lock, flags);
4273 mmc->pm_flags = 0;
4274 spin_unlock_irqrestore(&host->lock, flags);
4275
4276 /*
4277 * After resuming the host wait for sometime so that
4278 * the SDIO work will be processed.
4279 */
4280 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO)) {
4281 if ((host->plat->cfg_mpm_sdiowakeup ||
4282 host->plat->sdiowakeup_irq) &&
4283 wake_lock_active(&host->sdio_wlock))
4284 wake_lock_timeout(&host->sdio_wlock, 1);
4285 }
4286
4287 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004288 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304289 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004290 return 0;
4291}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004292
4293static int msmsdcc_runtime_idle(struct device *dev)
4294{
4295 struct mmc_host *mmc = dev_get_drvdata(dev);
4296 struct msmsdcc_host *host = mmc_priv(mmc);
4297
4298 if (host->plat->is_sdio_al_client)
4299 return 0;
4300
4301 /* Idle timeout is not configurable for now */
4302 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
4303
4304 return -EAGAIN;
4305}
4306
4307static int msmsdcc_pm_suspend(struct device *dev)
4308{
4309 struct mmc_host *mmc = dev_get_drvdata(dev);
4310 struct msmsdcc_host *host = mmc_priv(mmc);
4311 int rc = 0;
4312
4313 if (host->plat->is_sdio_al_client)
4314 return 0;
4315
4316
4317 if (host->plat->status_irq)
4318 disable_irq(host->plat->status_irq);
4319
4320 if (!pm_runtime_suspended(dev))
4321 rc = msmsdcc_runtime_suspend(dev);
4322
4323 return rc;
4324}
4325
4326static int msmsdcc_pm_resume(struct device *dev)
4327{
4328 struct mmc_host *mmc = dev_get_drvdata(dev);
4329 struct msmsdcc_host *host = mmc_priv(mmc);
4330 int rc = 0;
4331
4332 if (host->plat->is_sdio_al_client)
4333 return 0;
4334
Sahitya Tummalafb486372011-09-02 19:01:49 +05304335 if (!pm_runtime_suspended(dev))
4336 rc = msmsdcc_runtime_resume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004337 if (host->plat->status_irq) {
4338 msmsdcc_check_status((unsigned long)host);
4339 enable_irq(host->plat->status_irq);
4340 }
4341
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004342 return rc;
4343}
4344
Daniel Walker08ecfde2010-06-23 12:32:20 -07004345#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004346#define msmsdcc_runtime_suspend NULL
4347#define msmsdcc_runtime_resume NULL
4348#define msmsdcc_runtime_idle NULL
4349#define msmsdcc_pm_suspend NULL
4350#define msmsdcc_pm_resume NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07004351#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004352
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004353static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
4354 .runtime_suspend = msmsdcc_runtime_suspend,
4355 .runtime_resume = msmsdcc_runtime_resume,
4356 .runtime_idle = msmsdcc_runtime_idle,
4357 .suspend = msmsdcc_pm_suspend,
4358 .resume = msmsdcc_pm_resume,
4359};
4360
San Mehat9d2bd732009-09-22 16:44:22 -07004361static struct platform_driver msmsdcc_driver = {
4362 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004363 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07004364 .driver = {
4365 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004366 .pm = &msmsdcc_dev_pm_ops,
San Mehat9d2bd732009-09-22 16:44:22 -07004367 },
4368};
4369
4370static int __init msmsdcc_init(void)
4371{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004372#if defined(CONFIG_DEBUG_FS)
4373 int ret = 0;
4374 ret = msmsdcc_dbg_init();
4375 if (ret) {
4376 pr_err("Failed to create debug fs dir \n");
4377 return ret;
4378 }
4379#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004380 return platform_driver_register(&msmsdcc_driver);
4381}
4382
4383static void __exit msmsdcc_exit(void)
4384{
4385 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004386
4387#if defined(CONFIG_DEBUG_FS)
4388 debugfs_remove(debugfs_file);
4389 debugfs_remove(debugfs_dir);
4390#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004391}
4392
4393module_init(msmsdcc_init);
4394module_exit(msmsdcc_exit);
4395
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004396MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07004397MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004398
4399#if defined(CONFIG_DEBUG_FS)
4400
4401static int
4402msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
4403{
4404 file->private_data = inode->i_private;
4405 return 0;
4406}
4407
4408static ssize_t
4409msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
4410 size_t count, loff_t *ppos)
4411{
4412 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
4413 char buf[1024];
4414 int max, i;
4415
4416 i = 0;
4417 max = sizeof(buf) - 1;
4418
4419 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
4420 host->curr.cmd, host->curr.data);
4421 if (host->curr.cmd) {
4422 struct mmc_command *cmd = host->curr.cmd;
4423
4424 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
4425 cmd->opcode, cmd->arg, cmd->flags);
4426 }
4427 if (host->curr.data) {
4428 struct mmc_data *data = host->curr.data;
4429 i += scnprintf(buf + i, max - i,
4430 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
4431 data->timeout_ns, data->timeout_clks,
4432 data->blksz, data->blocks, data->error,
4433 data->flags);
4434 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
4435 host->curr.xfer_size, host->curr.xfer_remain,
4436 host->curr.data_xfered, host->dma.sg);
4437 }
4438
4439 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
4440}
4441
4442static const struct file_operations msmsdcc_dbg_state_ops = {
4443 .read = msmsdcc_dbg_state_read,
4444 .open = msmsdcc_dbg_state_open,
4445};
4446
4447static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
4448{
4449 if (debugfs_dir) {
4450 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
4451 0644, debugfs_dir, host,
4452 &msmsdcc_dbg_state_ops);
4453 }
4454}
4455
4456static int __init msmsdcc_dbg_init(void)
4457{
4458 int err;
4459
4460 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
4461 if (IS_ERR(debugfs_dir)) {
4462 err = PTR_ERR(debugfs_dir);
4463 debugfs_dir = NULL;
4464 return err;
4465 }
4466
4467 return 0;
4468}
4469#endif