blob: 0bb8ac74f278b12b93c910e82a41eca5a59bcfb5 [file] [log] [blame]
San Mehat9d2bd732009-09-22 16:44:22 -07001/*
2 * linux/drivers/mmc/host/msm_sdcc.c - Qualcomm MSM 7X00A SDCC Driver
3 *
4 * Copyright (C) 2007 Google Inc,
5 * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006 * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
San Mehat9d2bd732009-09-22 16:44:22 -07007 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * Based on mmci.c
13 *
14 * Author: San Mehat (san@android.com)
15 *
16 */
17
18#include <linux/module.h>
19#include <linux/moduleparam.h>
20#include <linux/init.h>
21#include <linux/ioport.h>
22#include <linux/device.h>
23#include <linux/interrupt.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070024#include <linux/irq.h>
San Mehat9d2bd732009-09-22 16:44:22 -070025#include <linux/delay.h>
26#include <linux/err.h>
27#include <linux/highmem.h>
28#include <linux/log2.h>
29#include <linux/mmc/host.h>
30#include <linux/mmc/card.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070031#include <linux/mmc/mmc.h>
San Mehatb3fa5792009-11-02 18:46:09 -080032#include <linux/mmc/sdio.h>
San Mehat9d2bd732009-09-22 16:44:22 -070033#include <linux/clk.h>
34#include <linux/scatterlist.h>
35#include <linux/platform_device.h>
36#include <linux/dma-mapping.h>
37#include <linux/debugfs.h>
38#include <linux/io.h>
39#include <linux/memory.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070040#include <linux/pm_runtime.h>
41#include <linux/wakelock.h>
Sahitya Tummala7a892482011-01-18 11:22:49 +053042#include <linux/gpio.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070043#include <linux/regulator/consumer.h>
44#include <linux/slab.h>
45#include <linux/mmc/mmc.h>
San Mehat9d2bd732009-09-22 16:44:22 -070046
47#include <asm/cacheflush.h>
48#include <asm/div64.h>
49#include <asm/sizes.h>
50
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070051#include <asm/mach/mmc.h>
San Mehat9d2bd732009-09-22 16:44:22 -070052#include <mach/msm_iomap.h>
Sahitya Tummalab08bb352010-12-08 15:03:05 +053053#include <mach/clk.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070054#include <mach/dma.h>
55#include <mach/htc_pwrsink.h>
56#include <mach/sdio_al.h>
San Mehat9d2bd732009-09-22 16:44:22 -070057
San Mehat9d2bd732009-09-22 16:44:22 -070058#include "msm_sdcc.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070059#include "msm_sdcc_dml.h"
San Mehat9d2bd732009-09-22 16:44:22 -070060
61#define DRIVER_NAME "msm-sdcc"
62
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070063#define DBG(host, fmt, args...) \
64 pr_debug("%s: %s: " fmt "\n", mmc_hostname(host->mmc), __func__ , args)
65
66#define IRQ_DEBUG 0
67#define SPS_SDCC_PRODUCER_PIPE_INDEX 1
68#define SPS_SDCC_CONSUMER_PIPE_INDEX 2
69#define SPS_CONS_PERIPHERAL 0
70#define SPS_PROD_PERIPHERAL 1
71/* 16 KB */
72#define SPS_MAX_DESC_SIZE (16 * 1024)
73
74#if defined(CONFIG_DEBUG_FS)
75static void msmsdcc_dbg_createhost(struct msmsdcc_host *);
76static struct dentry *debugfs_dir;
77static struct dentry *debugfs_file;
78static int msmsdcc_dbg_init(void);
79#endif
80
San Mehat9d2bd732009-09-22 16:44:22 -070081static unsigned int msmsdcc_pwrsave = 1;
San Mehat9d2bd732009-09-22 16:44:22 -070082
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070083static struct mmc_command dummy52cmd;
84static struct mmc_request dummy52mrq = {
85 .cmd = &dummy52cmd,
86 .data = NULL,
87 .stop = NULL,
88};
89static struct mmc_command dummy52cmd = {
90 .opcode = SD_IO_RW_DIRECT,
91 .flags = MMC_RSP_PRESENT,
92 .data = NULL,
93 .mrq = &dummy52mrq,
94};
95/*
96 * An array holding the Tuning pattern to compare with when
97 * executing a tuning cycle.
98 */
99static const u32 cmd19_tuning_block[16] = {
100 0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
101 0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
102 0xF0FFF0FF, 0x3CCCFC0F, 0xCFCC33CC, 0xEEFFEFFF,
103 0xFDFFFDFF, 0xFFBFFFDF, 0xFFF7FFBB, 0xDE7B7FF7
104};
San Mehat865c8062009-11-13 13:42:06 -0800105
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700106#if IRQ_DEBUG == 1
107static char *irq_status_bits[] = { "cmdcrcfail", "datcrcfail", "cmdtimeout",
108 "dattimeout", "txunderrun", "rxoverrun",
109 "cmdrespend", "cmdsent", "dataend", NULL,
110 "datablkend", "cmdactive", "txactive",
111 "rxactive", "txhalfempty", "rxhalffull",
112 "txfifofull", "rxfifofull", "txfifoempty",
113 "rxfifoempty", "txdataavlbl", "rxdataavlbl",
114 "sdiointr", "progdone", "atacmdcompl",
115 "sdiointrope", "ccstimeout", NULL, NULL,
116 NULL, NULL, NULL };
117
118static void
119msmsdcc_print_status(struct msmsdcc_host *host, char *hdr, uint32_t status)
San Mehat865c8062009-11-13 13:42:06 -0800120{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700121 int i;
San Mehat8b1c2ba2009-11-16 10:17:30 -0800122
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700123 pr_debug("%s-%s ", mmc_hostname(host->mmc), hdr);
124 for (i = 0; i < 32; i++) {
125 if (status & (1 << i))
126 pr_debug("%s ", irq_status_bits[i]);
San Mehat865c8062009-11-13 13:42:06 -0800127 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700128 pr_debug("\n");
San Mehatc7fc9372009-11-22 17:19:07 -0800129}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700130#endif
San Mehat865c8062009-11-13 13:42:06 -0800131
San Mehat9d2bd732009-09-22 16:44:22 -0700132static void
133msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
134 u32 c);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530135static inline void msmsdcc_delay(struct msmsdcc_host *host);
136
San Mehat9d2bd732009-09-22 16:44:22 -0700137
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700138#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
139static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
140 struct msmsdcc_sps_ep_conn_data *ep);
141static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
142 struct msmsdcc_sps_ep_conn_data *ep);
143#else
144static inline int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
145 struct msmsdcc_sps_ep_conn_data *ep,
146 bool is_producer) { return 0; }
147static inline void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
148 struct msmsdcc_sps_ep_conn_data *ep) { }
149static inline int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
150 struct msmsdcc_sps_ep_conn_data *ep)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530151{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700152 return 0;
153}
154static inline int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
155 struct msmsdcc_sps_ep_conn_data *ep)
156{
157 return 0;
158}
159static inline int msmsdcc_sps_init(struct msmsdcc_host *host) { return 0; }
160static inline void msmsdcc_sps_exit(struct msmsdcc_host *host) {}
161#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530162
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700163/**
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530164 * Apply soft reset to all SDCC BAM pipes
165 *
166 * This function applies soft reset to SDCC BAM pipe.
167 *
168 * This function should be called to recover from error
169 * conditions encountered during CMD/DATA tranfsers with card.
170 *
171 * @host - Pointer to driver's host structure
172 *
173 */
174static void msmsdcc_sps_pipes_reset_and_restore(struct msmsdcc_host *host)
175{
176 int rc;
177
178 /* Reset all SDCC BAM pipes */
179 rc = msmsdcc_sps_reset_ep(host, &host->sps.prod);
180 if (rc)
181 pr_err("%s:msmsdcc_sps_reset_ep(prod) error=%d\n",
182 mmc_hostname(host->mmc), rc);
183 rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
184 if (rc)
185 pr_err("%s:msmsdcc_sps_reset_ep(cons) error=%d\n",
186 mmc_hostname(host->mmc), rc);
187
188 /* Restore all BAM pipes connections */
189 rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
190 if (rc)
191 pr_err("%s:msmsdcc_sps_restore_ep(prod) error=%d\n",
192 mmc_hostname(host->mmc), rc);
193 rc = msmsdcc_sps_restore_ep(host, &host->sps.cons);
194 if (rc)
195 pr_err("%s:msmsdcc_sps_restore_ep(cons) error=%d\n",
196 mmc_hostname(host->mmc), rc);
197}
198
199/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700200 * Apply soft reset
201 *
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530202 * This function applies soft reset to SDCC core and DML core.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700203 *
204 * This function should be called to recover from error
205 * conditions encountered with CMD/DATA tranfsers with card.
206 *
207 * Soft reset should only be used with SDCC controller v4.
208 *
209 * @host - Pointer to driver's host structure
210 *
211 */
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530212static void msmsdcc_soft_reset(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700213{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700214 /*
215 * Reset SDCC controller's DPSM (data path state machine
216 * and CPSM (command path state machine).
217 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700218 writel_relaxed(0, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530219 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700220 writel_relaxed(0, host->base + MMCIDATACTRL);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530221 msmsdcc_delay(host);
222}
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530223
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530224static void msmsdcc_hard_reset(struct msmsdcc_host *host)
225{
226 int ret;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530227
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530228 /* Reset the controller */
229 ret = clk_reset(host->clk, CLK_RESET_ASSERT);
230 if (ret)
231 pr_err("%s: Clock assert failed at %u Hz"
232 " with err %d\n", mmc_hostname(host->mmc),
233 host->clk_rate, ret);
234
235 ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
236 if (ret)
237 pr_err("%s: Clock deassert failed at %u Hz"
238 " with err %d\n", mmc_hostname(host->mmc),
239 host->clk_rate, ret);
240
241 /* Give some delay for clock reset to propogate to controller */
242 msmsdcc_delay(host);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530243}
244
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700245static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
246{
247 if (host->plat->sdcc_v4_sup) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530248 if (host->is_sps_mode) {
249 /* Reset DML first */
250 msmsdcc_dml_reset(host);
251 /*
252 * delay the SPS pipe reset in thread context as
253 * sps_connect/sps_disconnect APIs can be called
254 * only from non-atomic context.
255 */
256 host->sps.pipe_reset_pending = true;
257 }
258 mb();
259 msmsdcc_soft_reset(host);
260
261 pr_debug("%s: Applied soft reset to Controller\n",
262 mmc_hostname(host->mmc));
263
264 if (host->is_sps_mode)
265 msmsdcc_dml_init(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700266 } else {
267 /* Give Clock reset (hard reset) to controller */
268 u32 mci_clk = 0;
269 u32 mci_mask0 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700270
271 /* Save the controller state */
272 mci_clk = readl_relaxed(host->base + MMCICLOCK);
273 mci_mask0 = readl_relaxed(host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700274 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700275
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530276 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700277 pr_debug("%s: Controller has been reinitialized\n",
278 mmc_hostname(host->mmc));
279
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700280 /* Restore the contoller state */
281 writel_relaxed(host->pwr, host->base + MMCIPOWER);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530282 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700283 writel_relaxed(mci_clk, host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530284 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700285 writel_relaxed(mci_mask0, host->base + MMCIMASK0);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530286 mb(); /* no delay required after writing to MASK0 register */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700287 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530288
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700289 if (host->dummy_52_needed)
290 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700291}
292
293static int
San Mehat9d2bd732009-09-22 16:44:22 -0700294msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
295{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700296 int retval = 0;
297
San Mehat9d2bd732009-09-22 16:44:22 -0700298 BUG_ON(host->curr.data);
299
300 host->curr.mrq = NULL;
301 host->curr.cmd = NULL;
302
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700303 del_timer(&host->req_tout_timer);
304
San Mehat9d2bd732009-09-22 16:44:22 -0700305 if (mrq->data)
306 mrq->data->bytes_xfered = host->curr.data_xfered;
307 if (mrq->cmd->error == -ETIMEDOUT)
308 mdelay(5);
309
310 /*
311 * Need to drop the host lock here; mmc_request_done may call
312 * back into the driver...
313 */
314 spin_unlock(&host->lock);
315 mmc_request_done(host->mmc, mrq);
316 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700317
318 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700319}
320
321static void
322msmsdcc_stop_data(struct msmsdcc_host *host)
323{
San Mehat9d2bd732009-09-22 16:44:22 -0700324 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530325 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530326 host->curr.wait_for_auto_prog_done = 0;
327 host->curr.got_auto_prog_done = 0;
Krishna Konda3f5d48f2011-07-27 10:47:31 -0700328 writel_relaxed(readl_relaxed(host->base + MMCIDATACTRL) &
329 (~(MCI_DPSM_ENABLE)), host->base + MMCIDATACTRL);
Krishna Konda3e5c4d02011-07-11 16:31:45 -0700330 msmsdcc_delay(host); /* Allow the DPSM to be reset */
San Mehat9d2bd732009-09-22 16:44:22 -0700331}
332
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700333static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700334{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700335 return host->core_memres->start + MMCIFIFO;
336}
337
338static inline unsigned int msmsdcc_get_min_sup_clk_rate(
339 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530340
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700341static inline void msmsdcc_delay(struct msmsdcc_host *host)
342{
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530343 ktime_t start, diff;
344
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700345 mb();
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +0530346 udelay(host->reg_write_delay);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530347
348 if (host->plat->sdcc_v4_sup &&
349 (readl_relaxed(host->base + MCI_STATUS2) &
350 MCI_MCLK_REG_WR_ACTIVE)) {
351 start = ktime_get();
352 while (readl_relaxed(host->base + MCI_STATUS2) &
353 MCI_MCLK_REG_WR_ACTIVE) {
354 diff = ktime_sub(ktime_get(), start);
355 /* poll for max. 1 ms */
356 if (ktime_to_us(diff) > 1000) {
357 pr_warning("%s: previous reg. write is"
358 " still active\n",
359 mmc_hostname(host->mmc));
360 break;
361 }
362 }
363 }
San Mehat9d2bd732009-09-22 16:44:22 -0700364}
365
San Mehat56a8b5b2009-11-21 12:29:46 -0800366static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700367msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
368{
369 writel_relaxed(arg, host->base + MMCIARGUMENT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700370 writel_relaxed(c, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530371 /*
372 * As after sending the command, we don't write any of the
373 * controller registers and just wait for the
374 * CMD_RESPOND_END/CMD_SENT/Command failure notication
375 * from Controller.
376 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700377 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800378}
379
380static void
381msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
382{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700383 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800384
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700385 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
386 writel_relaxed((unsigned int)host->curr.xfer_size,
387 host->base + MMCIDATALENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700388 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
389 msmsdcc_delay(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800390
San Mehat6ac9ea62009-12-02 17:24:58 -0800391 if (host->cmd_cmd) {
392 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700393 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800394 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800395}
396
San Mehat9d2bd732009-09-22 16:44:22 -0700397static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530398msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700399{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530400 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700401 unsigned long flags;
402 struct mmc_request *mrq;
403
404 spin_lock_irqsave(&host->lock, flags);
405 mrq = host->curr.mrq;
406 BUG_ON(!mrq);
407
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530408 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700409 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700410 goto out;
411 }
412
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530413 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700414 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700415 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700416 } else {
417 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530418 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700419 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530420 mmc_hostname(host->mmc), host->dma.result);
421 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700422 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530423 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530424 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700425 host->dma.err.flush[0], host->dma.err.flush[1],
426 host->dma.err.flush[2], host->dma.err.flush[3],
427 host->dma.err.flush[4],
428 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530429 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700430 if (!mrq->data->error)
431 mrq->data->error = -EIO;
432 }
San Mehat9d2bd732009-09-22 16:44:22 -0700433 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents,
434 host->dma.dir);
435
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700436 if (host->curr.user_pages) {
437 struct scatterlist *sg = host->dma.sg;
438 int i;
439
440 for (i = 0; i < host->dma.num_ents; i++, sg++)
441 flush_dcache_page(sg_page(sg));
442 }
443
San Mehat9d2bd732009-09-22 16:44:22 -0700444 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800445 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700446
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530447 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
448 (host->curr.wait_for_auto_prog_done &&
449 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700450 /*
451 * If we've already gotten our DATAEND / DATABLKEND
452 * for this request, then complete it through here.
453 */
San Mehat9d2bd732009-09-22 16:44:22 -0700454
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700455 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700456 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700457 host->curr.xfer_remain -= host->curr.xfer_size;
458 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700459 if (host->dummy_52_needed) {
460 mrq->data->bytes_xfered = host->curr.data_xfered;
461 host->dummy_52_sent = 1;
462 msmsdcc_start_command(host, &dummy52cmd,
463 MCI_CPSM_PROGENA);
464 goto out;
465 }
466 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530467 if (!mrq->data->stop || mrq->cmd->error ||
468 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700469 host->curr.mrq = NULL;
470 host->curr.cmd = NULL;
471 mrq->data->bytes_xfered = host->curr.data_xfered;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700472 del_timer(&host->req_tout_timer);
San Mehat9d2bd732009-09-22 16:44:22 -0700473 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700474
San Mehat9d2bd732009-09-22 16:44:22 -0700475 mmc_request_done(host->mmc, mrq);
476 return;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530477 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
478 || !mrq->sbc)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700479 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530480 }
San Mehat9d2bd732009-09-22 16:44:22 -0700481 }
482
483out:
484 spin_unlock_irqrestore(&host->lock, flags);
485 return;
486}
487
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700488#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
489/**
490 * Callback notification from SPS driver
491 *
492 * This callback function gets triggered called from
493 * SPS driver when requested SPS data transfer is
494 * completed.
495 *
496 * SPS driver invokes this callback in BAM irq context so
497 * SDCC driver schedule a tasklet for further processing
498 * this callback notification at later point of time in
499 * tasklet context and immediately returns control back
500 * to SPS driver.
501 *
502 * @nofity - Pointer to sps event notify sturcture
503 *
504 */
505static void
506msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
507{
508 struct msmsdcc_host *host =
509 (struct msmsdcc_host *)
510 ((struct sps_event_notify *)notify)->user;
511
512 host->sps.notify = *notify;
513 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
514 mmc_hostname(host->mmc), __func__, notify->event_id,
515 notify->data.transfer.iovec.addr,
516 notify->data.transfer.iovec.size,
517 notify->data.transfer.iovec.flags);
518 /* Schedule a tasklet for completing data transfer */
519 tasklet_schedule(&host->sps.tlet);
520}
521
522/**
523 * Tasklet handler for processing SPS callback event
524 *
525 * This function processing SPS event notification and
526 * checks if the SPS transfer is completed or not and
527 * then accordingly notifies status to MMC core layer.
528 *
529 * This function is called in tasklet context.
530 *
531 * @data - Pointer to sdcc driver data
532 *
533 */
534static void msmsdcc_sps_complete_tlet(unsigned long data)
535{
536 unsigned long flags;
537 int i, rc;
538 u32 data_xfered = 0;
539 struct mmc_request *mrq;
540 struct sps_iovec iovec;
541 struct sps_pipe *sps_pipe_handle;
542 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
543 struct sps_event_notify *notify = &host->sps.notify;
544
545 spin_lock_irqsave(&host->lock, flags);
546 if (host->sps.dir == DMA_FROM_DEVICE)
547 sps_pipe_handle = host->sps.prod.pipe_handle;
548 else
549 sps_pipe_handle = host->sps.cons.pipe_handle;
550 mrq = host->curr.mrq;
551
552 if (!mrq) {
553 spin_unlock_irqrestore(&host->lock, flags);
554 return;
555 }
556
557 pr_debug("%s: %s: sps event_id=%d\n",
558 mmc_hostname(host->mmc), __func__,
559 notify->event_id);
560
561 if (msmsdcc_is_dml_busy(host)) {
562 /* oops !!! this should never happen. */
563 pr_err("%s: %s: Received SPS EOT event"
564 " but DML HW is still busy !!!\n",
565 mmc_hostname(host->mmc), __func__);
566 }
567 /*
568 * Got End of transfer event!!! Check if all of the data
569 * has been transferred?
570 */
571 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
572 rc = sps_get_iovec(sps_pipe_handle, &iovec);
573 if (rc) {
574 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
575 mmc_hostname(host->mmc), __func__, rc, i);
576 break;
577 }
578 data_xfered += iovec.size;
579 }
580
581 if (data_xfered == host->curr.xfer_size) {
582 host->curr.data_xfered = host->curr.xfer_size;
583 host->curr.xfer_remain -= host->curr.xfer_size;
584 pr_debug("%s: Data xfer success. data_xfered=0x%x",
585 mmc_hostname(host->mmc),
586 host->curr.xfer_size);
587 } else {
588 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
589 " xfer_size=%d", mmc_hostname(host->mmc),
590 data_xfered, host->curr.xfer_size);
591 msmsdcc_reset_and_restore(host);
592 if (!mrq->data->error)
593 mrq->data->error = -EIO;
594 }
595
596 /* Unmap sg buffers */
597 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
598 host->sps.dir);
599
600 host->sps.sg = NULL;
601 host->sps.busy = 0;
602
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530603 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
604 (host->curr.wait_for_auto_prog_done &&
605 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700606 /*
607 * If we've already gotten our DATAEND / DATABLKEND
608 * for this request, then complete it through here.
609 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700610
611 if (!mrq->data->error) {
612 host->curr.data_xfered = host->curr.xfer_size;
613 host->curr.xfer_remain -= host->curr.xfer_size;
614 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700615 if (host->dummy_52_needed) {
616 mrq->data->bytes_xfered = host->curr.data_xfered;
617 host->dummy_52_sent = 1;
618 msmsdcc_start_command(host, &dummy52cmd,
619 MCI_CPSM_PROGENA);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700620 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700621 return;
622 }
623 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530624 if (!mrq->data->stop || mrq->cmd->error ||
625 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700626 host->curr.mrq = NULL;
627 host->curr.cmd = NULL;
628 mrq->data->bytes_xfered = host->curr.data_xfered;
629 del_timer(&host->req_tout_timer);
630 spin_unlock_irqrestore(&host->lock, flags);
631
632 mmc_request_done(host->mmc, mrq);
633 return;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530634 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
635 || !mrq->sbc)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700636 msmsdcc_start_command(host, mrq->data->stop, 0);
637 }
638 }
639 spin_unlock_irqrestore(&host->lock, flags);
640}
641
642/**
643 * Exit from current SPS data transfer
644 *
645 * This function exits from current SPS data transfer.
646 *
647 * This function should be called when error condition
648 * is encountered during data transfer.
649 *
650 * @host - Pointer to sdcc host structure
651 *
652 */
653static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
654{
655 struct mmc_request *mrq;
656
657 mrq = host->curr.mrq;
658 BUG_ON(!mrq);
659
660 msmsdcc_reset_and_restore(host);
661 if (!mrq->data->error)
662 mrq->data->error = -EIO;
663
664 /* Unmap sg buffers */
665 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
666 host->sps.dir);
667
668 host->sps.sg = NULL;
669 host->sps.busy = 0;
670 if (host->curr.data)
671 msmsdcc_stop_data(host);
672
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530673 if (!mrq->data->stop || mrq->cmd->error ||
674 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700675 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530676 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
677 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700678 msmsdcc_start_command(host, mrq->data->stop, 0);
679
680}
681#else
682static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
683static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
684static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
685#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
686
687static void msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
688
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530689static void
690msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
691 unsigned int result,
692 struct msm_dmov_errdata *err)
693{
694 struct msmsdcc_dma_data *dma_data =
695 container_of(cmd, struct msmsdcc_dma_data, hdr);
696 struct msmsdcc_host *host = dma_data->host;
697
698 dma_data->result = result;
699 if (err)
700 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
701
702 tasklet_schedule(&host->dma_tlet);
703}
704
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700705static int msmsdcc_check_dma_op_req(struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700706{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700707 if (((data->blksz * data->blocks) < MCI_FIFOSIZE) ||
708 ((data->blksz * data->blocks) % MCI_FIFOSIZE))
San Mehat9d2bd732009-09-22 16:44:22 -0700709 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700710 else
711 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700712}
713
714static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
715{
716 struct msmsdcc_nc_dmadata *nc;
717 dmov_box *box;
718 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700719 unsigned int n;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700720 int i;
San Mehat9d2bd732009-09-22 16:44:22 -0700721 struct scatterlist *sg = data->sg;
722
Krishna Konda25786ec2011-07-25 16:21:36 -0700723 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700724 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700725
Krishna Konda25786ec2011-07-25 16:21:36 -0700726 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
727
San Mehat9d2bd732009-09-22 16:44:22 -0700728 host->dma.sg = data->sg;
729 host->dma.num_ents = data->sg_len;
730
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700731 BUG_ON(host->dma.num_ents > NR_SG); /* Prevent memory corruption */
San Mehat56a8b5b2009-11-21 12:29:46 -0800732
San Mehat9d2bd732009-09-22 16:44:22 -0700733 nc = host->dma.nc;
734
San Mehat9d2bd732009-09-22 16:44:22 -0700735 if (data->flags & MMC_DATA_READ)
736 host->dma.dir = DMA_FROM_DEVICE;
737 else
738 host->dma.dir = DMA_TO_DEVICE;
739
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700740 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
San Mehat9d2bd732009-09-22 16:44:22 -0700741 host->curr.user_pages = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700742 box = &nc->cmd[0];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700743 for (i = 0; i < host->dma.num_ents; i++) {
San Mehat9d2bd732009-09-22 16:44:22 -0700744 box->cmd = CMD_MODE_BOX;
745
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700746 /* Initialize sg dma address */
747 sg->dma_address = pfn_to_dma(mmc_dev(host->mmc),
748 page_to_pfn(sg_page(sg)))
749 + sg->offset;
750
751 if (i == (host->dma.num_ents - 1))
San Mehat9d2bd732009-09-22 16:44:22 -0700752 box->cmd |= CMD_LC;
753 rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ?
754 (sg_dma_len(sg) / MCI_FIFOSIZE) + 1 :
755 (sg_dma_len(sg) / MCI_FIFOSIZE) ;
756
757 if (data->flags & MMC_DATA_READ) {
758 box->src_row_addr = msmsdcc_fifo_addr(host);
759 box->dst_row_addr = sg_dma_address(sg);
760
761 box->src_dst_len = (MCI_FIFOSIZE << 16) |
762 (MCI_FIFOSIZE);
763 box->row_offset = MCI_FIFOSIZE;
764
765 box->num_rows = rows * ((1 << 16) + 1);
Krishna Konda25786ec2011-07-25 16:21:36 -0700766 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
San Mehat9d2bd732009-09-22 16:44:22 -0700767 } else {
768 box->src_row_addr = sg_dma_address(sg);
769 box->dst_row_addr = msmsdcc_fifo_addr(host);
770
771 box->src_dst_len = (MCI_FIFOSIZE << 16) |
772 (MCI_FIFOSIZE);
773 box->row_offset = (MCI_FIFOSIZE << 16);
774
775 box->num_rows = rows * ((1 << 16) + 1);
Krishna Konda25786ec2011-07-25 16:21:36 -0700776 box->cmd |= CMD_DST_CRCI(host->dma.crci);
San Mehat9d2bd732009-09-22 16:44:22 -0700777 }
778 box++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700779 sg++;
780 }
781
782 /* location of command block must be 64 bit aligned */
783 BUG_ON(host->dma.cmd_busaddr & 0x07);
784
785 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
786 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
787 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
788 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700789
790 n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
791 host->dma.num_ents, host->dma.dir);
792 /* dsb inside dma_map_sg will write nc out to mem as well */
793
794 if (n != host->dma.num_ents) {
795 pr_err("%s: Unable to map in all sg elements\n",
796 mmc_hostname(host->mmc));
797 host->dma.sg = NULL;
798 host->dma.num_ents = 0;
799 return -ENOMEM;
San Mehat56a8b5b2009-11-21 12:29:46 -0800800 }
San Mehat9d2bd732009-09-22 16:44:22 -0700801
802 return 0;
803}
804
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700805#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
806/**
807 * Submits data transfer request to SPS driver
808 *
809 * This function make sg (scatter gather) data buffers
810 * DMA ready and then submits them to SPS driver for
811 * transfer.
812 *
813 * @host - Pointer to sdcc host structure
814 * @data - Pointer to mmc_data structure
815 *
816 * @return 0 if success else negative value
817 */
818static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
819 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -0800820{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700821 int rc = 0;
822 u32 flags;
823 int i;
824 u32 addr, len, data_cnt;
825 struct scatterlist *sg = data->sg;
826 struct sps_pipe *sps_pipe_handle;
827
828 BUG_ON(data->sg_len > NR_SG); /* Prevent memory corruption */
829
830 host->sps.sg = data->sg;
831 host->sps.num_ents = data->sg_len;
832 host->sps.xfer_req_cnt = 0;
833 if (data->flags & MMC_DATA_READ) {
834 host->sps.dir = DMA_FROM_DEVICE;
835 sps_pipe_handle = host->sps.prod.pipe_handle;
836 } else {
837 host->sps.dir = DMA_TO_DEVICE;
838 sps_pipe_handle = host->sps.cons.pipe_handle;
839 }
840
841 /* Make sg buffers DMA ready */
842 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
843 host->sps.dir);
844
845 if (rc != data->sg_len) {
846 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
847 mmc_hostname(host->mmc), rc);
848 host->sps.sg = NULL;
849 host->sps.num_ents = 0;
850 rc = -ENOMEM;
851 goto dma_map_err;
852 }
853
854 pr_debug("%s: %s: %s: pipe=0x%x, total_xfer=0x%x, sg_len=%d\n",
855 mmc_hostname(host->mmc), __func__,
856 host->sps.dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
857 (u32)sps_pipe_handle, host->curr.xfer_size, data->sg_len);
858
859 for (i = 0; i < data->sg_len; i++) {
860 /*
861 * Check if this is the last buffer to transfer?
862 * If yes then set the INT and EOT flags.
863 */
864 len = sg_dma_len(sg);
865 addr = sg_dma_address(sg);
866 flags = 0;
867 while (len > 0) {
868 if (len > SPS_MAX_DESC_SIZE) {
869 data_cnt = SPS_MAX_DESC_SIZE;
870 } else {
871 data_cnt = len;
872 if (i == data->sg_len - 1)
873 flags = SPS_IOVEC_FLAG_INT |
874 SPS_IOVEC_FLAG_EOT;
875 }
876 rc = sps_transfer_one(sps_pipe_handle, addr,
877 data_cnt, host, flags);
878 if (rc) {
879 pr_err("%s: sps_transfer_one() error! rc=%d,"
880 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
881 mmc_hostname(host->mmc), rc,
882 (u32)sps_pipe_handle, (u32)sg, i);
883 goto dma_map_err;
884 }
885 addr += data_cnt;
886 len -= data_cnt;
887 host->sps.xfer_req_cnt++;
888 }
889 sg++;
890 }
891 goto out;
892
893dma_map_err:
894 /* unmap sg buffers */
895 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
896 host->sps.dir);
897out:
898 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -0700899}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700900#else
901static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
902 struct mmc_data *data) { return 0; }
903#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -0700904
905static void
San Mehat56a8b5b2009-11-21 12:29:46 -0800906msmsdcc_start_command_deferred(struct msmsdcc_host *host,
907 struct mmc_command *cmd, u32 *c)
908{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700909 DBG(host, "op %02x arg %08x flags %08x\n",
910 cmd->opcode, cmd->arg, cmd->flags);
911
San Mehat56a8b5b2009-11-21 12:29:46 -0800912 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
913
914 if (cmd->flags & MMC_RSP_PRESENT) {
915 if (cmd->flags & MMC_RSP_136)
916 *c |= MCI_CPSM_LONGRSP;
917 *c |= MCI_CPSM_RESPONSE;
918 }
919
920 if (/*interrupt*/0)
921 *c |= MCI_CPSM_INTERRUPT;
922
923 if ((((cmd->opcode == 17) || (cmd->opcode == 18)) ||
924 ((cmd->opcode == 24) || (cmd->opcode == 25))) ||
925 (cmd->opcode == 53))
926 *c |= MCI_CSPM_DATCMD;
927
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700928 /* Check if AUTO CMD19 is required or not? */
Subhash Jadavani1d6ba602011-09-21 18:10:54 +0530929 if (host->tuning_needed) {
930 /*
931 * For open ended block read operation (without CMD23),
932 * AUTO_CMD19 bit should be set while sending the READ command.
933 * For close ended block read operation (with CMD23),
934 * AUTO_CMD19 bit should be set while sending CMD23.
935 */
936 if ((cmd->opcode == 23 && (host->curr.mrq->cmd->opcode == 17 ||
937 host->curr.mrq->cmd->opcode == 18)) ||
938 (!host->curr.mrq->sbc &&
939 (cmd->opcode == 17 || cmd->opcode == 18))) {
940 msmsdcc_enable_cdr_cm_sdc4_dll(host);
941 *c |= MCI_CSPM_AUTO_CMD19;
942 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700943 }
944
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +0530945 if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +0530946 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700947 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +0530948 }
949
San Mehat56a8b5b2009-11-21 12:29:46 -0800950 if (cmd == cmd->mrq->stop)
951 *c |= MCI_CSPM_MCIABORT;
952
San Mehat56a8b5b2009-11-21 12:29:46 -0800953 if (host->curr.cmd != NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700954 pr_err("%s: Overlapping command requests\n",
955 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -0800956 }
957 host->curr.cmd = cmd;
958}
959
960static void
961msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
962 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -0700963{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +0530964 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -0700965 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700966 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -0700967 unsigned int pio_irqmask = 0;
968
969 host->curr.data = data;
970 host->curr.xfer_size = data->blksz * data->blocks;
971 host->curr.xfer_remain = host->curr.xfer_size;
972 host->curr.data_xfered = 0;
973 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530974 host->curr.got_auto_prog_done = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700975
976 memset(&host->pio, 0, sizeof(host->pio));
977
San Mehat9d2bd732009-09-22 16:44:22 -0700978 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
979
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530980 if (host->curr.wait_for_auto_prog_done)
981 datactrl |= MCI_AUTO_PROG_DONE;
982
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700983 if (!msmsdcc_check_dma_op_req(data)) {
984 if (host->is_dma_mode && !msmsdcc_config_dma(host, data)) {
985 datactrl |= MCI_DPSM_DMAENABLE;
986 } else if (host->is_sps_mode) {
987 if (!msmsdcc_is_dml_busy(host)) {
988 if (!msmsdcc_sps_start_xfer(host, data)) {
989 /* Now kick start DML transfer */
990 mb();
991 msmsdcc_dml_start_xfer(host, data);
992 datactrl |= MCI_DPSM_DMAENABLE;
993 host->sps.busy = 1;
994 }
995 } else {
996 /*
997 * Can't proceed with new transfer as
998 * previous trasnfer is already in progress.
999 * There is no point of going into PIO mode
1000 * as well. Is this a time to do kernel panic?
1001 */
1002 pr_err("%s: %s: DML HW is busy!!!"
1003 " Can't perform new SPS transfers"
1004 " now\n", mmc_hostname(host->mmc),
1005 __func__);
1006 }
1007 }
1008 }
1009
1010 /* Is data transfer in PIO mode required? */
1011 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001012 host->pio.sg = data->sg;
1013 host->pio.sg_len = data->sg_len;
1014 host->pio.sg_off = 0;
1015
1016 if (data->flags & MMC_DATA_READ) {
1017 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1018 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1019 pio_irqmask |= MCI_RXDATAAVLBLMASK;
1020 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001021 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1022 MCI_TXFIFOEMPTYMASK;
San Mehat9d2bd732009-09-22 16:44:22 -07001023 }
1024
1025 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301026 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
San Mehat9d2bd732009-09-22 16:44:22 -07001027
San Mehat56a8b5b2009-11-21 12:29:46 -08001028 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001029 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001030 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -07001031
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001032 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
1033 /* Use ADM (Application Data Mover) HW for Data transfer */
1034 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001035 host->cmd_timeout = timeout;
1036 host->cmd_pio_irqmask = pio_irqmask;
1037 host->cmd_datactrl = datactrl;
1038 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001039
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001040 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1041 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001042 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001043
1044 if (cmd) {
1045 msmsdcc_start_command_deferred(host, cmd, &c);
1046 host->cmd_c = c;
1047 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001048 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1049 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1050 host->base + MMCIMASK0);
1051 mb();
1052 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001053 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001054 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001055 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001056
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001057 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001058
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001059 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1060 (~(MCI_IRQ_PIO))) | pio_irqmask,
1061 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001062 writel_relaxed(datactrl, base + MMCIDATACTRL);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301063 /*
1064 * We don't need delay after writing to DATA_CTRL register
1065 * if we are not writing to CMD register immediately after
1066 * this. As we already have delay before sending the
1067 * command, we just need mb() here.
1068 */
1069 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001070
1071 if (cmd) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001072 msmsdcc_delay(host); /* Delay between data/command */
San Mehat56a8b5b2009-11-21 12:29:46 -08001073 /* Daisy-chain the command if requested */
1074 msmsdcc_start_command(host, cmd, c);
1075 }
San Mehat9d2bd732009-09-22 16:44:22 -07001076 }
1077}
1078
1079static void
1080msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1081{
San Mehat56a8b5b2009-11-21 12:29:46 -08001082 msmsdcc_start_command_deferred(host, cmd, &c);
1083 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001084}
1085
1086static void
1087msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1088 unsigned int status)
1089{
1090 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001091 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1092 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1093 pr_err("%s: Data CRC error\n",
1094 mmc_hostname(host->mmc));
1095 pr_err("%s: opcode 0x%.8x\n", __func__,
1096 data->mrq->cmd->opcode);
1097 pr_err("%s: blksz %d, blocks %d\n", __func__,
1098 data->blksz, data->blocks);
1099 data->error = -EILSEQ;
1100 }
San Mehat9d2bd732009-09-22 16:44:22 -07001101 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001102 /* CRC is optional for the bus test commands, not all
1103 * cards respond back with CRC. However controller
1104 * waits for the CRC and times out. Hence ignore the
1105 * data timeouts during the Bustest.
1106 */
1107 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1108 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1109 pr_err("%s: Data timeout\n",
1110 mmc_hostname(host->mmc));
1111 data->error = -ETIMEDOUT;
1112 }
San Mehat9d2bd732009-09-22 16:44:22 -07001113 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001114 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001115 data->error = -EIO;
1116 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001117 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001118 data->error = -EIO;
1119 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001120 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001121 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001122 data->error = -EIO;
1123 }
San Mehat9d2bd732009-09-22 16:44:22 -07001124
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001125 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001126 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001127 host->dummy_52_needed = 0;
1128}
San Mehat9d2bd732009-09-22 16:44:22 -07001129
1130static int
1131msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1132{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001133 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001134 uint32_t *ptr = (uint32_t *) buffer;
1135 int count = 0;
1136
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301137 if (remain % 4)
1138 remain = ((remain >> 2) + 1) << 2;
1139
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001140 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1141
1142 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001143 ptr++;
1144 count += sizeof(uint32_t);
1145
1146 remain -= sizeof(uint32_t);
1147 if (remain == 0)
1148 break;
1149 }
1150 return count;
1151}
1152
1153static int
1154msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001155 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001156{
1157 void __iomem *base = host->base;
1158 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001159 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001160
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001161 while (readl_relaxed(base + MMCISTATUS) &
1162 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1163 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001164
San Mehat9d2bd732009-09-22 16:44:22 -07001165 count = min(remain, maxcnt);
1166
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301167 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1168 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001169 ptr += count;
1170 remain -= count;
1171
1172 if (remain == 0)
1173 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001174 }
1175 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001176
1177 return ptr - buffer;
1178}
1179
San Mehat1cd22962010-02-03 12:59:29 -08001180static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001181msmsdcc_pio_irq(int irq, void *dev_id)
1182{
1183 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001184 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001185 uint32_t status;
1186
Murali Palnati36448a42011-09-02 15:06:18 +05301187 spin_lock(&host->lock);
1188
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001189 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001190
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001191 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301192 (MCI_IRQ_PIO)) == 0) {
1193 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001194 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301195 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001196
1197#if IRQ_DEBUG
1198 msmsdcc_print_status(host, "irq1-r", status);
1199#endif
1200
San Mehat9d2bd732009-09-22 16:44:22 -07001201 do {
1202 unsigned long flags;
1203 unsigned int remain, len;
1204 char *buffer;
1205
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001206 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1207 | MCI_RXDATAAVLBL)))
1208 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001209
1210 /* Map the current scatter buffer */
1211 local_irq_save(flags);
1212 buffer = kmap_atomic(sg_page(host->pio.sg),
1213 KM_BIO_SRC_IRQ) + host->pio.sg->offset;
1214 buffer += host->pio.sg_off;
1215 remain = host->pio.sg->length - host->pio.sg_off;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001216
San Mehat9d2bd732009-09-22 16:44:22 -07001217 len = 0;
1218 if (status & MCI_RXACTIVE)
1219 len = msmsdcc_pio_read(host, buffer, remain);
1220 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001221 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001222
1223 /* Unmap the buffer */
1224 kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
1225 local_irq_restore(flags);
1226
1227 host->pio.sg_off += len;
1228 host->curr.xfer_remain -= len;
1229 host->curr.data_xfered += len;
1230 remain -= len;
1231
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001232 if (remain) /* Done with this page? */
1233 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001234
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001235 if (status & MCI_RXACTIVE && host->curr.user_pages)
1236 flush_dcache_page(sg_page(host->pio.sg));
San Mehat9d2bd732009-09-22 16:44:22 -07001237
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001238 if (!--host->pio.sg_len) {
1239 memset(&host->pio, 0, sizeof(host->pio));
1240 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001241 }
1242
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001243 /* Advance to next sg */
1244 host->pio.sg++;
1245 host->pio.sg_off = 0;
1246
1247 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001248 } while (1);
1249
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001250 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1251 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1252 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1253 host->base + MMCIMASK0);
1254 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301255 /*
1256 * back to back write to MASK0 register don't need
1257 * synchronization delay.
1258 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001259 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1260 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1261 }
1262 mb();
1263 } else if (!host->curr.xfer_remain) {
1264 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1265 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1266 mb();
1267 }
San Mehat9d2bd732009-09-22 16:44:22 -07001268
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001269 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001270
1271 return IRQ_HANDLED;
1272}
1273
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001274static void
1275msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1276
1277static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1278 struct mmc_data *data)
1279{
1280 u32 loop_cnt = 0;
1281
1282 /*
1283 * For read commands with data less than fifo size, it is possible to
1284 * get DATAEND first and RXDATA_AVAIL might be set later because of
1285 * synchronization delay through the asynchronous RX FIFO. Thus, for
1286 * such cases, even after DATAEND interrupt is received software
1287 * should poll for RXDATA_AVAIL until the requested data is read out
1288 * of FIFO. This change is needed to get around this abnormal but
1289 * sometimes expected behavior of SDCC3 controller.
1290 *
1291 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1292 * after the data is loaded into RX FIFO. This would amount to less
1293 * than a microsecond and thus looping for 1000 times is good enough
1294 * for that delay.
1295 */
1296 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1297 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1298 spin_unlock(&host->lock);
1299 msmsdcc_pio_irq(1, host);
1300 spin_lock(&host->lock);
1301 }
1302 }
1303 if (loop_cnt == 1000) {
1304 pr_info("%s: Timed out while polling for Rx Data\n",
1305 mmc_hostname(host->mmc));
1306 data->error = -ETIMEDOUT;
1307 msmsdcc_reset_and_restore(host);
1308 }
1309}
1310
San Mehat9d2bd732009-09-22 16:44:22 -07001311static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1312{
1313 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001314
1315 host->curr.cmd = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001316 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1317 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1318 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1319 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -07001320
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001321 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Sahitya Tummala5a0ae912011-07-18 13:34:01 +05301322 pr_debug("%s: Command timeout\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001323 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001324 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
1325 !host->cmd19_tuning_in_progress) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001326 pr_err("%s: Command CRC error\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001327 cmd->error = -EILSEQ;
1328 }
1329
1330 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001331 if (host->curr.data && host->dma.sg &&
1332 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001333 msm_dmov_stop_cmd(host->dma.channel,
1334 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001335 else if (host->curr.data && host->sps.sg &&
1336 host->is_sps_mode){
1337 /* Stop current SPS transfer */
1338 msmsdcc_sps_exit_curr_xfer(host);
1339 }
San Mehat9d2bd732009-09-22 16:44:22 -07001340 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301341 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001342 msmsdcc_stop_data(host);
1343 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301344 } else { /* host->data == NULL */
1345 if (!cmd->error && host->prog_enable) {
1346 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001347 host->prog_enable = 0;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301348 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001349 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301350 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301351 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301352 host->prog_enable = 0;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001353 if (host->dummy_52_needed)
1354 host->dummy_52_needed = 0;
1355 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001356 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301357 msmsdcc_request_end(host, cmd->mrq);
1358 }
1359 }
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301360 } else if ((cmd == host->curr.mrq->sbc) && cmd->data) {
1361 if (cmd->data->flags & MMC_DATA_READ)
1362 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1363 else
1364 msmsdcc_request_start(host, host->curr.mrq);
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301365 } else if (cmd->data) {
1366 if (!(cmd->data->flags & MMC_DATA_READ))
1367 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001368 }
1369}
1370
San Mehat9d2bd732009-09-22 16:44:22 -07001371static irqreturn_t
1372msmsdcc_irq(int irq, void *dev_id)
1373{
1374 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001375 u32 status;
1376 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001377 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001378
1379 spin_lock(&host->lock);
1380
1381 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001382 struct mmc_command *cmd;
1383 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001384
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001385 if (timer) {
1386 timer = 0;
1387 msmsdcc_delay(host);
1388 }
San Mehat865c8062009-11-13 13:42:06 -08001389
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001390 if (!host->clks_on) {
1391 pr_debug("%s: %s: SDIO async irq received\n",
1392 mmc_hostname(host->mmc), __func__);
1393 host->mmc->ios.clock = host->clk_rate;
1394 spin_unlock(&host->lock);
1395 host->mmc->ops->set_ios(host->mmc, &host->mmc->ios);
1396 spin_lock(&host->lock);
1397 if (host->plat->cfg_mpm_sdiowakeup &&
1398 (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
1399 wake_lock(&host->sdio_wlock);
1400 /* only ansyc interrupt can come when clocks are off */
1401 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301402 if (host->clk_rate <=
1403 msmsdcc_get_min_sup_clk_rate(host))
1404 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001405 }
1406
1407 status = readl_relaxed(host->base + MMCISTATUS);
1408
1409 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1410 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001411 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001412
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001413#if IRQ_DEBUG
1414 msmsdcc_print_status(host, "irq0-r", status);
1415#endif
1416 status &= readl_relaxed(host->base + MMCIMASK0);
1417 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301418 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301419 if (host->clk_rate <=
1420 msmsdcc_get_min_sup_clk_rate(host))
1421 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001422#if IRQ_DEBUG
1423 msmsdcc_print_status(host, "irq0-p", status);
1424#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001425
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001426#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
1427 if (status & MCI_SDIOINTROPE) {
1428 if (host->sdcc_suspending)
1429 wake_lock(&host->sdio_suspend_wlock);
1430 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001431 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001432#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001433 data = host->curr.data;
1434
1435 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001436 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1437 MCI_CMDTIMEOUT)) {
1438 if (status & MCI_CMDTIMEOUT)
1439 pr_debug("%s: dummy CMD52 timeout\n",
1440 mmc_hostname(host->mmc));
1441 if (status & MCI_CMDCRCFAIL)
1442 pr_debug("%s: dummy CMD52 CRC failed\n",
1443 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001444 host->dummy_52_sent = 0;
1445 host->dummy_52_needed = 0;
1446 if (data) {
1447 msmsdcc_stop_data(host);
1448 msmsdcc_request_end(host, data->mrq);
1449 }
1450 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001451 spin_unlock(&host->lock);
1452 return IRQ_HANDLED;
1453 }
1454 break;
1455 }
1456
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001457 /*
1458 * Check for proper command response
1459 */
1460 cmd = host->curr.cmd;
1461 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1462 MCI_CMDTIMEOUT | MCI_PROGDONE |
1463 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1464 msmsdcc_do_cmdirq(host, status);
1465 }
1466
1467 if (data) {
1468 /* Check for data errors */
1469 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1470 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1471 msmsdcc_data_err(host, data, status);
1472 host->curr.data_xfered = 0;
1473 if (host->dma.sg && host->is_dma_mode)
1474 msm_dmov_stop_cmd(host->dma.channel,
1475 &host->dma.hdr, 0);
1476 else if (host->sps.sg && host->is_sps_mode) {
1477 /* Stop current SPS transfer */
1478 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301479 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001480 msmsdcc_reset_and_restore(host);
1481 if (host->curr.data)
1482 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301483 if (!data->stop || (host->curr.mrq->sbc
1484 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001485 timer |=
1486 msmsdcc_request_end(host,
1487 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301488 else if ((host->curr.mrq->sbc
1489 && data->error) ||
1490 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001491 msmsdcc_start_command(host,
1492 data->stop,
1493 0);
1494 timer = 1;
1495 }
1496 }
1497 }
1498
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301499 /* Check for prog done */
1500 if (host->curr.wait_for_auto_prog_done &&
1501 (status & MCI_PROGDONE))
1502 host->curr.got_auto_prog_done = 1;
1503
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001504 /* Check for data done */
1505 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1506 host->curr.got_dataend = 1;
1507
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301508 if (host->curr.got_dataend &&
1509 (!host->curr.wait_for_auto_prog_done ||
1510 (host->curr.wait_for_auto_prog_done &&
1511 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001512 /*
1513 * If DMA is still in progress, we complete
1514 * via the completion handler
1515 */
1516 if (!host->dma.busy && !host->sps.busy) {
1517 /*
1518 * There appears to be an issue in the
1519 * controller where if you request a
1520 * small block transfer (< fifo size),
1521 * you may get your DATAEND/DATABLKEND
1522 * irq without the PIO data irq.
1523 *
1524 * Check to see if theres still data
1525 * to be read, and simulate a PIO irq.
1526 */
1527 if (data->flags & MMC_DATA_READ)
1528 msmsdcc_wait_for_rxdata(host,
1529 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001530 if (!data->error) {
1531 host->curr.data_xfered =
1532 host->curr.xfer_size;
1533 host->curr.xfer_remain -=
1534 host->curr.xfer_size;
1535 }
1536
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001537 if (!host->dummy_52_needed) {
1538 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301539 if (!data->stop ||
1540 (host->curr.mrq->sbc
1541 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001542 msmsdcc_request_end(
1543 host,
1544 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301545 else if ((host->curr.mrq->sbc
1546 && data->error) ||
1547 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001548 msmsdcc_start_command(
1549 host,
1550 data->stop, 0);
1551 timer = 1;
1552 }
1553 } else {
1554 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001555 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001556 &dummy52cmd,
1557 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001558 }
1559 }
1560 }
1561 }
1562
San Mehat9d2bd732009-09-22 16:44:22 -07001563 ret = 1;
1564 } while (status);
1565
1566 spin_unlock(&host->lock);
1567
San Mehat9d2bd732009-09-22 16:44:22 -07001568 return IRQ_RETVAL(ret);
1569}
1570
1571static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001572msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1573{
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301574 if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001575 /* Queue/read data, daisy-chain command when data starts */
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301576 if (mrq->sbc)
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301577 msmsdcc_start_data(host, mrq->data, mrq->sbc, 0);
1578 else
1579 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001580 } else {
1581 msmsdcc_start_command(host, mrq->cmd, 0);
1582 }
1583}
1584
1585static void
San Mehat9d2bd732009-09-22 16:44:22 -07001586msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1587{
1588 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001589 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001590
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001591 /*
1592 * Get the SDIO AL client out of LPM.
1593 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001594 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001595 if (host->plat->is_sdio_al_client)
1596 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001597
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301598 /* check if sps pipe reset is pending? */
1599 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1600 msmsdcc_sps_pipes_reset_and_restore(host);
1601 host->sps.pipe_reset_pending = false;
1602 }
1603
San Mehat9d2bd732009-09-22 16:44:22 -07001604 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001605 WARN(host->curr.mrq, "Request in progress\n");
1606 WARN(!host->pwr, "SDCC power is turned off\n");
1607 WARN(!host->clks_on, "SDCC clocks are turned off\n");
1608 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
San Mehat9d2bd732009-09-22 16:44:22 -07001609
1610 if (host->eject) {
1611 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1612 mrq->cmd->error = 0;
1613 mrq->data->bytes_xfered = mrq->data->blksz *
1614 mrq->data->blocks;
1615 } else
1616 mrq->cmd->error = -ENOMEDIUM;
1617
1618 spin_unlock_irqrestore(&host->lock, flags);
1619 mmc_request_done(mmc, mrq);
1620 return;
1621 }
1622
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301623 /*
1624 * Kick the software command timeout timer here.
1625 * Timer expires in 10 secs.
1626 */
1627 mod_timer(&host->req_tout_timer,
1628 (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
San Mehat9d2bd732009-09-22 16:44:22 -07001629
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301630 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301631 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301632 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
1633 mrq->cmd->opcode == 54) {
1634 if (!host->plat->sdcc_v4_sup)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001635 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301636 else
1637 /*
1638 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
1639 * write operations using CMD53 and CMD54.
1640 * Setting this bit with CMD53 would
1641 * automatically triggers PROG_DONE interrupt
1642 * without the need of sending dummy CMD52.
1643 */
1644 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001645 }
San Mehat9d2bd732009-09-22 16:44:22 -07001646 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301647
Pratibhasagar V00b94332011-10-18 14:57:27 +05301648 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301649 mrq->sbc->mrq = mrq;
1650 mrq->sbc->data = mrq->data;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301651 if (mrq->data->flags & MMC_DATA_WRITE) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301652 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301653 msmsdcc_start_command(host, mrq->sbc, 0);
1654 } else {
1655 msmsdcc_request_start(host, mrq);
1656 }
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301657 } else {
1658 msmsdcc_request_start(host, mrq);
1659 }
1660
San Mehat9d2bd732009-09-22 16:44:22 -07001661 spin_unlock_irqrestore(&host->lock, flags);
1662}
1663
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001664static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1665 int min_uV, int max_uV)
1666{
1667 int rc = 0;
1668
1669 if (vreg->set_voltage_sup) {
1670 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1671 if (rc) {
1672 pr_err("%s: regulator_set_voltage(%s) failed."
1673 " min_uV=%d, max_uV=%d, rc=%d\n",
1674 __func__, vreg->name, min_uV, max_uV, rc);
1675 }
1676 }
1677
1678 return rc;
1679}
1680
1681static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1682 int uA_load)
1683{
1684 int rc = 0;
1685
Krishna Kondafea60182011-11-01 16:01:34 -07001686 /* regulators that do not support regulator_set_voltage also
1687 do not support regulator_set_optimum_mode */
1688 if (vreg->set_voltage_sup) {
1689 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1690 if (rc < 0)
1691 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
1692 "uA_load=%d) failed. rc=%d\n", __func__,
1693 vreg->name, uA_load, rc);
1694 else
1695 /* regulator_set_optimum_mode() can return non zero
1696 * value even for success case.
1697 */
1698 rc = 0;
1699 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001700
1701 return rc;
1702}
1703
1704static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1705 struct device *dev)
1706{
1707 int rc = 0;
1708
1709 /* check if regulator is already initialized? */
1710 if (vreg->reg)
1711 goto out;
1712
1713 /* Get the regulator handle */
1714 vreg->reg = regulator_get(dev, vreg->name);
1715 if (IS_ERR(vreg->reg)) {
1716 rc = PTR_ERR(vreg->reg);
1717 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
1718 __func__, vreg->name, rc);
1719 }
1720out:
1721 return rc;
1722}
1723
1724static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
1725{
1726 if (vreg->reg)
1727 regulator_put(vreg->reg);
1728}
1729
1730/* This init function should be called only once for each SDCC slot */
1731static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
1732{
1733 int rc = 0;
1734 struct msm_mmc_slot_reg_data *curr_slot;
1735 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1736 struct device *dev = mmc_dev(host->mmc);
1737
1738 curr_slot = host->plat->vreg_data;
1739 if (!curr_slot)
1740 goto out;
1741
1742 curr_vdd_reg = curr_slot->vdd_data;
1743 curr_vccq_reg = curr_slot->vccq_data;
1744 curr_vddp_reg = curr_slot->vddp_data;
1745
1746 if (is_init) {
1747 /*
1748 * Get the regulator handle from voltage regulator framework
1749 * and then try to set the voltage level for the regulator
1750 */
1751 if (curr_vdd_reg) {
1752 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
1753 if (rc)
1754 goto out;
1755 }
1756 if (curr_vccq_reg) {
1757 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
1758 if (rc)
1759 goto vdd_reg_deinit;
1760 }
1761 if (curr_vddp_reg) {
1762 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
1763 if (rc)
1764 goto vccq_reg_deinit;
1765 }
1766 goto out;
1767 } else {
1768 /* Deregister all regulators from regulator framework */
1769 goto vddp_reg_deinit;
1770 }
1771vddp_reg_deinit:
1772 if (curr_vddp_reg)
1773 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
1774vccq_reg_deinit:
1775 if (curr_vccq_reg)
1776 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
1777vdd_reg_deinit:
1778 if (curr_vdd_reg)
1779 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
1780out:
1781 return rc;
1782}
1783
1784static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
1785{
1786 int rc = 0;
1787
Subhash Jadavanicc922692011-08-01 23:05:01 +05301788 /* Put regulator in HPM (high power mode) */
1789 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
1790 if (rc < 0)
1791 goto out;
1792
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001793 if (!vreg->is_enabled) {
1794 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301795 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
1796 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001797 if (rc)
1798 goto out;
1799
1800 rc = regulator_enable(vreg->reg);
1801 if (rc) {
1802 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
1803 __func__, vreg->name, rc);
1804 goto out;
1805 }
1806 vreg->is_enabled = true;
1807 }
1808
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001809out:
1810 return rc;
1811}
1812
1813static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
1814{
1815 int rc = 0;
1816
1817 /* Never disable regulator marked as always_on */
1818 if (vreg->is_enabled && !vreg->always_on) {
1819 rc = regulator_disable(vreg->reg);
1820 if (rc) {
1821 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
1822 __func__, vreg->name, rc);
1823 goto out;
1824 }
1825 vreg->is_enabled = false;
1826
1827 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
1828 if (rc < 0)
1829 goto out;
1830
1831 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301832 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001833 if (rc)
1834 goto out;
1835 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
1836 /* Put always_on regulator in LPM (low power mode) */
1837 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
1838 if (rc < 0)
1839 goto out;
1840 }
1841out:
1842 return rc;
1843}
1844
1845static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
1846{
1847 int rc = 0, i;
1848 struct msm_mmc_slot_reg_data *curr_slot;
1849 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1850 struct msm_mmc_reg_data *vreg_table[3];
1851
1852 curr_slot = host->plat->vreg_data;
1853 if (!curr_slot)
1854 goto out;
1855
1856 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
1857 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
1858 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
1859
1860 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
1861 if (vreg_table[i]) {
1862 if (enable)
1863 rc = msmsdcc_vreg_enable(vreg_table[i]);
1864 else
1865 rc = msmsdcc_vreg_disable(vreg_table[i]);
1866 if (rc)
1867 goto out;
1868 }
1869 }
1870out:
1871 return rc;
1872}
1873
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301874static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001875{
1876 int rc = 0;
1877
1878 if (host->plat->vreg_data) {
1879 struct msm_mmc_reg_data *vddp_reg =
1880 host->plat->vreg_data->vddp_data;
1881
1882 if (vddp_reg && vddp_reg->is_enabled)
1883 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
1884 }
1885
1886 return rc;
1887}
1888
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301889static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
1890{
1891 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1892 int rc = 0;
1893
1894 if (curr_slot && curr_slot->vddp_data) {
1895 rc = msmsdcc_set_vddp_level(host,
1896 curr_slot->vddp_data->low_vol_level);
1897
1898 if (rc)
1899 pr_err("%s: %s: failed to change vddp level to %d",
1900 mmc_hostname(host->mmc), __func__,
1901 curr_slot->vddp_data->low_vol_level);
1902 }
1903
1904 return rc;
1905}
1906
1907static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
1908{
1909 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1910 int rc = 0;
1911
1912 if (curr_slot && curr_slot->vddp_data) {
1913 rc = msmsdcc_set_vddp_level(host,
1914 curr_slot->vddp_data->high_vol_level);
1915
1916 if (rc)
1917 pr_err("%s: %s: failed to change vddp level to %d",
1918 mmc_hostname(host->mmc), __func__,
1919 curr_slot->vddp_data->high_vol_level);
1920 }
1921
1922 return rc;
1923}
1924
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001925static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
1926{
1927 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
1928 return 1;
1929 return 0;
1930}
1931
1932static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
1933{
1934 if (enable) {
1935 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1936 clk_enable(host->dfab_pclk);
1937 if (!IS_ERR(host->pclk))
1938 clk_enable(host->pclk);
1939 clk_enable(host->clk);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301940 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001941 } else {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301942 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001943 clk_disable(host->clk);
1944 if (!IS_ERR(host->pclk))
1945 clk_disable(host->pclk);
1946 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1947 clk_disable(host->dfab_pclk);
1948 }
1949}
1950
1951static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
1952 unsigned int req_clk)
1953{
1954 unsigned int sel_clk = -1;
1955
1956 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
1957 unsigned char cnt;
1958
1959 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
1960 if (host->plat->sup_clk_table[cnt] > req_clk)
1961 break;
1962 else if (host->plat->sup_clk_table[cnt] == req_clk) {
1963 sel_clk = host->plat->sup_clk_table[cnt];
1964 break;
1965 } else
1966 sel_clk = host->plat->sup_clk_table[cnt];
1967 }
1968 } else {
1969 if ((req_clk < host->plat->msmsdcc_fmax) &&
1970 (req_clk > host->plat->msmsdcc_fmid))
1971 sel_clk = host->plat->msmsdcc_fmid;
1972 else
1973 sel_clk = req_clk;
1974 }
1975
1976 return sel_clk;
1977}
1978
1979static inline unsigned int msmsdcc_get_min_sup_clk_rate(
1980 struct msmsdcc_host *host)
1981{
1982 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
1983 return host->plat->sup_clk_table[0];
1984 else
1985 return host->plat->msmsdcc_fmin;
1986}
1987
1988static inline unsigned int msmsdcc_get_max_sup_clk_rate(
1989 struct msmsdcc_host *host)
1990{
1991 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
1992 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
1993 else
1994 return host->plat->msmsdcc_fmax;
1995}
1996
1997static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05301998{
1999 struct msm_mmc_gpio_data *curr;
2000 int i, rc = 0;
2001
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002002 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302003 for (i = 0; i < curr->size; i++) {
2004 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002005 if (curr->gpio[i].is_always_on &&
2006 curr->gpio[i].is_enabled)
2007 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302008 rc = gpio_request(curr->gpio[i].no,
2009 curr->gpio[i].name);
2010 if (rc) {
2011 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2012 mmc_hostname(host->mmc),
2013 curr->gpio[i].no,
2014 curr->gpio[i].name, rc);
2015 goto free_gpios;
2016 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002017 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302018 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002019 if (curr->gpio[i].is_always_on)
2020 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302021 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002022 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302023 }
2024 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002025 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302026
2027free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002028 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302029 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002030 curr->gpio[i].is_enabled = false;
2031 }
2032out:
2033 return rc;
2034}
2035
2036static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2037{
2038 struct msm_mmc_pad_data *curr;
2039 int i;
2040
2041 curr = host->plat->pin_data->pad_data;
2042 for (i = 0; i < curr->drv->size; i++) {
2043 if (enable)
2044 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2045 curr->drv->on[i].val);
2046 else
2047 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2048 curr->drv->off[i].val);
2049 }
2050
2051 for (i = 0; i < curr->pull->size; i++) {
2052 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002053 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002054 curr->pull->on[i].val);
2055 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002056 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002057 curr->pull->off[i].val);
2058 }
2059
2060 return 0;
2061}
2062
2063static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2064{
2065 int rc = 0;
2066
2067 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2068 return 0;
2069
2070 if (host->plat->pin_data->is_gpio)
2071 rc = msmsdcc_setup_gpio(host, enable);
2072 else
2073 rc = msmsdcc_setup_pad(host, enable);
2074
2075 if (!rc)
2076 host->plat->pin_data->cfg_sts = enable;
2077
2078 return rc;
2079}
2080
2081static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2082{
2083 unsigned int wakeup_irq;
2084
2085 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2086 host->plat->sdiowakeup_irq :
2087 host->core_irqres->start;
2088
2089 if (!host->irq_wake_enabled) {
2090 enable_irq_wake(wakeup_irq);
2091 host->irq_wake_enabled = true;
2092 }
2093}
2094
2095static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2096{
2097 unsigned int wakeup_irq;
2098
2099 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2100 host->plat->sdiowakeup_irq :
2101 host->core_irqres->start;
2102
2103 if (host->irq_wake_enabled) {
2104 disable_irq_wake(wakeup_irq);
2105 host->irq_wake_enabled = false;
2106 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302107}
2108
San Mehat9d2bd732009-09-22 16:44:22 -07002109static void
2110msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2111{
2112 struct msmsdcc_host *host = mmc_priv(mmc);
2113 u32 clk = 0, pwr = 0;
2114 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002115 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002116 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002117
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002118 DBG(host, "ios->clock = %u\n", ios->clock);
Sahitya Tummala7a892482011-01-18 11:22:49 +05302119
San Mehat9d2bd732009-09-22 16:44:22 -07002120 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002121 spin_lock_irqsave(&host->lock, flags);
2122 if (!host->clks_on) {
2123 msmsdcc_setup_clocks(host, true);
2124 host->clks_on = 1;
2125 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2126 if (!host->plat->sdiowakeup_irq) {
2127 writel_relaxed(host->mci_irqenable,
2128 host->base + MMCIMASK0);
2129 mb();
2130 if (host->plat->cfg_mpm_sdiowakeup &&
2131 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2132 host->plat->cfg_mpm_sdiowakeup(
2133 mmc_dev(mmc), SDC_DAT1_DISWAKE);
2134 msmsdcc_disable_irq_wake(host);
2135 } else if (!(mmc->pm_flags &
2136 MMC_PM_WAKE_SDIO_IRQ)) {
2137 writel_relaxed(host->mci_irqenable,
2138 host->base + MMCIMASK0);
2139 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05302140 } else {
2141 writel_relaxed(host->mci_irqenable,
2142 host->base + MMCIMASK0);
2143 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002144 }
San Mehat9d2bd732009-09-22 16:44:22 -07002145 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002146 spin_unlock_irqrestore(&host->lock, flags);
2147
2148 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2149 /*
2150 * For DDR50 mode, controller needs clock rate to be
2151 * double than what is required on the SD card CLK pin.
2152 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302153 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002154 /*
2155 * Make sure that we don't double the clock if
2156 * doubled clock rate is already set
2157 */
2158 if (!host->ddr_doubled_clk_rate ||
2159 (host->ddr_doubled_clk_rate &&
2160 (host->ddr_doubled_clk_rate != ios->clock))) {
2161 host->ddr_doubled_clk_rate =
2162 msmsdcc_get_sup_clk_rate(
2163 host, (ios->clock * 2));
2164 clock = host->ddr_doubled_clk_rate;
2165 }
2166 } else {
2167 host->ddr_doubled_clk_rate = 0;
2168 }
2169
2170 if (clock != host->clk_rate) {
2171 rc = clk_set_rate(host->clk, clock);
2172 if (rc < 0)
2173 pr_debug("%s: failed to set clk rate %u\n",
2174 mmc_hostname(mmc), clock);
2175 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302176 host->reg_write_delay =
2177 (1 + ((3 * USEC_PER_SEC) /
2178 (host->clk_rate ? host->clk_rate :
2179 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002180 }
2181 /*
2182 * give atleast 2 MCLK cycles delay for clocks
2183 * and SDCC core to stabilize
2184 */
2185 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002186 clk |= MCI_CLK_ENABLE;
2187 }
2188
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002189 if (ios->bus_width == MMC_BUS_WIDTH_8)
2190 clk |= MCI_CLK_WIDEBUS_8;
2191 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2192 clk |= MCI_CLK_WIDEBUS_4;
2193 else
2194 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002195
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002196 if (msmsdcc_is_pwrsave(host))
2197 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002198
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002199 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002201 host->tuning_needed = 0;
2202 /*
2203 * Select the controller timing mode according
2204 * to current bus speed mode
2205 */
2206 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2207 (ios->timing == MMC_TIMING_UHS_SDR50)) {
2208 clk |= (4 << 14);
2209 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302210 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002211 clk |= (3 << 14);
2212 } else {
2213 clk |= (2 << 14); /* feedback clock */
2214 }
2215
2216 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2217 clk |= (2 << 23);
2218
2219 if (host->io_pad_pwr_switch)
2220 clk |= IO_PAD_PWR_SWITCH;
2221
2222 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
San Mehat9d2bd732009-09-22 16:44:22 -07002223 pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002224 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2225 pwr |= msmsdcc_setup_vreg(host, !!ios->vdd);
San Mehat9d2bd732009-09-22 16:44:22 -07002226
2227 switch (ios->power_mode) {
2228 case MMC_POWER_OFF:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002229 htc_pwrsink_set(PWRSINK_SDCARD, 0);
2230 if (!host->sdcc_irq_disabled) {
2231 if (host->plat->cfg_mpm_sdiowakeup)
2232 host->plat->cfg_mpm_sdiowakeup(
2233 mmc_dev(mmc), SDC_DAT1_DISABLE);
2234 disable_irq(host->core_irqres->start);
2235 host->sdcc_irq_disabled = 1;
2236 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302237 /*
2238 * As VDD pad rail is always on, set low voltage for VDD
2239 * pad rail when slot is unused (when card is not present
2240 * or during system suspend).
2241 */
2242 msmsdcc_set_vddp_low_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002243 msmsdcc_setup_pins(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002244 break;
2245 case MMC_POWER_UP:
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302246 /* writing PWR_UP bit is redundant */
San Mehat9d2bd732009-09-22 16:44:22 -07002247 pwr |= MCI_PWR_UP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002248 if (host->sdcc_irq_disabled) {
2249 if (host->plat->cfg_mpm_sdiowakeup)
2250 host->plat->cfg_mpm_sdiowakeup(
2251 mmc_dev(mmc), SDC_DAT1_ENABLE);
2252 enable_irq(host->core_irqres->start);
2253 host->sdcc_irq_disabled = 0;
2254 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302255 msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002256 msmsdcc_setup_pins(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07002257 break;
2258 case MMC_POWER_ON:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002259 htc_pwrsink_set(PWRSINK_SDCARD, 100);
San Mehat9d2bd732009-09-22 16:44:22 -07002260 pwr |= MCI_PWR_ON;
2261 break;
2262 }
2263
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002264 spin_lock_irqsave(&host->lock, flags);
2265 if (!host->clks_on) {
2266 /* force the clocks to be on */
2267 msmsdcc_setup_clocks(host, true);
2268 /*
2269 * give atleast 2 MCLK cycles delay for clocks
2270 * and SDCC core to stabilize
2271 */
2272 msmsdcc_delay(host);
2273 }
2274 writel_relaxed(clk, host->base + MMCICLOCK);
2275 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002276
2277 if (host->pwr != pwr) {
2278 host->pwr = pwr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002279 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302280 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002281 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002282 if (!host->clks_on) {
2283 /* force the clocks to be off */
2284 msmsdcc_setup_clocks(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002285 }
2286
2287 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
2288 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2289 if (!host->plat->sdiowakeup_irq) {
2290 writel_relaxed(MCI_SDIOINTMASK,
2291 host->base + MMCIMASK0);
2292 mb();
2293 if (host->plat->cfg_mpm_sdiowakeup &&
2294 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2295 host->plat->cfg_mpm_sdiowakeup(
2296 mmc_dev(mmc), SDC_DAT1_ENWAKE);
2297 msmsdcc_enable_irq_wake(host);
2298 } else if (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2299 writel_relaxed(0, host->base + MMCIMASK0);
2300 } else {
2301 writel_relaxed(MCI_SDIOINTMASK,
2302 host->base + MMCIMASK0);
2303 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302304 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002305 }
2306 msmsdcc_setup_clocks(host, false);
2307 host->clks_on = 0;
2308 }
San Mehat4adbbcc2009-11-08 13:00:37 -08002309 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002310}
2311
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002312int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2313{
2314 struct msmsdcc_host *host = mmc_priv(mmc);
2315 u32 clk;
2316
2317 clk = readl_relaxed(host->base + MMCICLOCK);
2318 pr_debug("Changing to pwr_save=%d", pwrsave);
2319 if (pwrsave && msmsdcc_is_pwrsave(host))
2320 clk |= MCI_CLK_PWRSAVE;
2321 else
2322 clk &= ~MCI_CLK_PWRSAVE;
2323 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302324 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002325
2326 return 0;
2327}
2328
2329static int msmsdcc_get_ro(struct mmc_host *mmc)
2330{
2331 int status = -ENOSYS;
2332 struct msmsdcc_host *host = mmc_priv(mmc);
2333
2334 if (host->plat->wpswitch) {
2335 status = host->plat->wpswitch(mmc_dev(mmc));
2336 } else if (host->plat->wpswitch_gpio) {
2337 status = gpio_request(host->plat->wpswitch_gpio,
2338 "SD_WP_Switch");
2339 if (status) {
2340 pr_err("%s: %s: Failed to request GPIO %d\n",
2341 mmc_hostname(mmc), __func__,
2342 host->plat->wpswitch_gpio);
2343 } else {
2344 status = gpio_direction_input(
2345 host->plat->wpswitch_gpio);
2346 if (!status) {
2347 /*
2348 * Wait for atleast 300ms as debounce
2349 * time for GPIO input to stabilize.
2350 */
2351 msleep(300);
2352 status = gpio_get_value_cansleep(
2353 host->plat->wpswitch_gpio);
2354 status ^= !host->plat->wpswitch_polarity;
2355 }
2356 gpio_free(host->plat->wpswitch_gpio);
2357 }
2358 }
2359
2360 if (status < 0)
2361 status = -ENOSYS;
2362 pr_debug("%s: Card read-only status %d\n", __func__, status);
2363
2364 return status;
2365}
2366
2367#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002368static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2369{
2370 struct msmsdcc_host *host = mmc_priv(mmc);
2371 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002372
2373 if (enable) {
2374 spin_lock_irqsave(&host->lock, flags);
2375 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
2376 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
2377 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2378 spin_unlock_irqrestore(&host->lock, flags);
2379 } else {
2380 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
2381 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
2382 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2383 }
2384 mb();
2385}
2386#endif /* CONFIG_MMC_MSM_SDIO_SUPPORT */
2387
2388#ifdef CONFIG_PM_RUNTIME
2389static int msmsdcc_enable(struct mmc_host *mmc)
2390{
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302391 int rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002392 struct device *dev = mmc->parent;
2393
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302394 if (dev->power.runtime_status == RPM_SUSPENDING) {
2395 if (mmc->suspend_task == current) {
2396 pm_runtime_get_noresume(dev);
2397 goto out;
2398 }
2399 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002400
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302401 rc = pm_runtime_get_sync(dev);
2402
2403 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002404 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2405 __func__, rc);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302406 return rc;
2407 }
2408out:
2409 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002410}
2411
2412static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2413{
2414 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302415 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002416
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302417 if (host->plat->disable_runtime_pm)
2418 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002419 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO)
2420 return -ENOTSUPP;
2421
2422 rc = pm_runtime_put_sync(mmc->parent);
2423
2424 if (rc < 0)
2425 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2426 __func__, rc);
2427 return rc;
2428}
2429#else
2430#define msmsdcc_enable NULL
2431#define msmsdcc_disable NULL
2432#endif
2433
2434static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2435 struct mmc_ios *ios)
2436{
2437 struct msmsdcc_host *host = mmc_priv(mmc);
2438 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302439 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002440
2441 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2442 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302443 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002444 goto out;
2445 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2446 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302447 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002448 goto out;
2449 }
San Mehat9d2bd732009-09-22 16:44:22 -07002450
2451 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002452 /*
2453 * If we are here means voltage switch from high voltage to
2454 * low voltage is required
2455 */
2456
2457 /*
2458 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2459 * register until they become all zeros.
2460 */
2461 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302462 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002463 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2464 mmc_hostname(mmc), __func__);
2465 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002466 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002467
2468 /* Stop SD CLK output. */
2469 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2470 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302471 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002472 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002473
2474 /*
2475 * Switch VDDPX from high voltage to low voltage
2476 * to change the VDD of the SD IO pads.
2477 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302478 rc = msmsdcc_set_vddp_low_vol(host);
2479 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002480 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002481
2482 spin_lock_irqsave(&host->lock, flags);
2483 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2484 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302485 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002486 host->io_pad_pwr_switch = 1;
2487 spin_unlock_irqrestore(&host->lock, flags);
2488
2489 /* Wait 5 ms for the voltage regulater in the card to become stable. */
2490 usleep_range(5000, 5500);
2491
2492 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302493 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002494 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2495 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302496 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002497 spin_unlock_irqrestore(&host->lock, flags);
2498
2499 /*
2500 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
2501 * don't become all ones within 1 ms then a Voltage Switch
2502 * sequence has failed and a power cycle to the card is required.
2503 * Otherwise Voltage Switch sequence is completed successfully.
2504 */
2505 usleep_range(1000, 1500);
2506
2507 spin_lock_irqsave(&host->lock, flags);
2508 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
2509 != (0xF << 1)) {
2510 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
2511 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302512 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002513 goto out_unlock;
2514 }
2515
2516out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302517 /* Enable PWRSAVE */
2518 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2519 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002520 spin_unlock_irqrestore(&host->lock, flags);
2521out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302522 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002523}
2524
2525static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2526 u8 phase);
2527/* Initialize the DLL (Programmable Delay Line ) */
2528static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
2529{
2530 int rc = 0;
2531 u32 wait_timeout;
2532
2533 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
2534 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2535 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2536
2537 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
2538 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2539 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2540
2541 msmsdcc_delay(host);
2542
2543 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
2544 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2545 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2546
2547 /* Initialize the phase to 0 */
2548 rc = msmsdcc_config_cm_sdc4_dll_phase(host, 0);
2549 if (rc)
2550 goto out;
2551
2552 wait_timeout = 1000;
2553 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
2554 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
2555 /* max. wait for 1 sec for LOCK bit to be set */
2556 if (--wait_timeout == 0) {
2557 pr_err("%s: %s: DLL failed to lock at phase: %d",
2558 mmc_hostname(host->mmc), __func__, 0);
2559 rc = -1;
2560 goto out;
2561 }
2562 /* wait for 1ms */
2563 usleep_range(1000, 1500);
2564 }
2565out:
2566 return rc;
2567}
2568
2569/*
2570 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
2571 * calibration sequence. This function should be called before
2572 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
2573 * commands (CMD17/CMD18).
2574 */
2575static void msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
2576{
2577 /* Set CDR_EN bit to 1. */
2578 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) |
2579 MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2580
2581 /* Set CDR_EXT_EN bit to 0. */
2582 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2583 & ~MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2584
2585 /* Set CK_OUT_EN bit to 0. */
2586 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2587 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2588
2589 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2590 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)
2591 ;
2592
2593 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2594 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2595 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2596
2597 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register is 1. */
2598 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN))
2599 ;
2600}
2601
2602static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2603 u8 phase)
2604{
2605 int rc = 0;
2606 u32 mclk_freq = 0;
2607 u32 wait_timeout;
2608
2609 /* Set CDR_EN bit to 0. */
2610 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2611 & ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2612
2613 /* Set CDR_EXT_EN bit to 1. */
2614 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2615 | MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2616
2617 /* Program the MCLK value to MCLK_FREQ bit field */
2618 if (host->clk_rate <= 112000000)
2619 mclk_freq = 0;
2620 else if (host->clk_rate <= 125000000)
2621 mclk_freq = 1;
2622 else if (host->clk_rate <= 137000000)
2623 mclk_freq = 2;
2624 else if (host->clk_rate <= 150000000)
2625 mclk_freq = 3;
2626 else if (host->clk_rate <= 162000000)
2627 mclk_freq = 4;
2628 else if (host->clk_rate <= 175000000)
2629 mclk_freq = 5;
2630 else if (host->clk_rate <= 187000000)
2631 mclk_freq = 6;
2632 else if (host->clk_rate <= 200000000)
2633 mclk_freq = 7;
2634
2635 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2636 & ~(7 << 24)) | (mclk_freq << 24)),
2637 host->base + MCI_DLL_CONFIG);
2638
2639 /* Set CK_OUT_EN bit to 0. */
2640 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2641 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2642
2643 /* Set DLL_EN bit to 1. */
2644 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2645 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
2646
2647 wait_timeout = 1000;
2648 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2649 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN) {
2650 /* max. wait for 1 sec for LOCK bit for be set */
2651 if (--wait_timeout == 0) {
2652 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 0",
2653 mmc_hostname(host->mmc), __func__, phase);
2654 rc = -1;
2655 goto out;
2656 }
2657 /* wait for 1ms */
2658 usleep_range(1000, 1500);
2659 }
2660
2661 /*
2662 * Write the selected DLL clock output phase (0 ... 15)
2663 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
2664 */
2665 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2666 & ~(0xF << 20)) | (phase << 20)),
2667 host->base + MCI_DLL_CONFIG);
2668
2669 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2670 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2671 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2672
2673 wait_timeout = 1000;
2674 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
2675 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)) {
2676 /* max. wait for 1 sec for LOCK bit for be set */
2677 if (--wait_timeout == 0) {
2678 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 1",
2679 mmc_hostname(host->mmc), __func__, phase);
2680 rc = -1;
2681 goto out;
2682 }
2683 /* wait for 1ms */
2684 usleep_range(1000, 1500);
2685 }
2686out:
2687 return rc;
2688}
2689
2690static int msmsdcc_execute_tuning(struct mmc_host *mmc)
2691{
2692 struct msmsdcc_host *host = mmc_priv(mmc);
2693 u8 phase;
2694 u8 *data_buf;
2695 u8 tuned_phases[16], tuned_phase_cnt = 0;
2696 int rc = 0;
2697
2698 /* Tuning is only required for SDR50 & SDR104 modes */
2699 if (!host->tuning_needed) {
2700 rc = 0;
2701 goto out;
2702 }
2703
2704 host->cmd19_tuning_in_progress = 1;
2705 /*
2706 * Make sure that clock is always enabled when DLL
2707 * tuning is in progress. Keeping PWRSAVE ON may
2708 * turn off the clock. So let's disable the PWRSAVE
2709 * here and re-enable it once tuning is completed.
2710 */
2711 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2712 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302713 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002714 /* first of all reset the tuning block */
2715 rc = msmsdcc_init_cm_sdc4_dll(host);
2716 if (rc)
2717 goto out;
2718
2719 data_buf = kmalloc(64, GFP_KERNEL);
2720 if (!data_buf) {
2721 rc = -ENOMEM;
2722 goto out;
2723 }
2724
2725 phase = 0;
2726 do {
2727 struct mmc_command cmd = {0};
2728 struct mmc_data data = {0};
2729 struct mmc_request mrq = {
2730 .cmd = &cmd,
2731 .data = &data
2732 };
2733 struct scatterlist sg;
2734
2735 /* set the phase in delay line hw block */
2736 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2737 if (rc)
2738 goto kfree;
2739
2740 cmd.opcode = MMC_SEND_TUNING_BLOCK;
2741 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
2742
2743 data.blksz = 64;
2744 data.blocks = 1;
2745 data.flags = MMC_DATA_READ;
2746 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
2747
2748 data.sg = &sg;
2749 data.sg_len = 1;
2750 sg_init_one(&sg, data_buf, 64);
2751 memset(data_buf, 0, 64);
2752 mmc_wait_for_req(mmc, &mrq);
2753
2754 if (!cmd.error && !data.error &&
2755 !memcmp(data_buf, cmd19_tuning_block, 64)) {
2756 /* tuning is successful with this tuning point */
2757 tuned_phases[tuned_phase_cnt++] = phase;
2758 }
2759 } while (++phase < 16);
2760
2761 kfree(data_buf);
2762
2763 if (tuned_phase_cnt) {
2764 tuned_phase_cnt--;
2765 tuned_phase_cnt = (tuned_phase_cnt * 3) / 4;
2766 phase = tuned_phases[tuned_phase_cnt];
2767 /*
2768 * Finally set the selected phase in delay
2769 * line hw block.
2770 */
2771 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2772 if (rc)
2773 goto out;
2774 } else {
2775 /* tuning failed */
2776 rc = -EAGAIN;
2777 pr_err("%s: %s: no tuning point found",
2778 mmc_hostname(mmc), __func__);
2779 }
2780 goto out;
2781
2782kfree:
2783 kfree(data_buf);
2784out:
2785 /* re-enable PWESAVE */
2786 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2787 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302788 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002789 host->cmd19_tuning_in_progress = 0;
2790 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07002791}
2792
2793static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002794 .enable = msmsdcc_enable,
2795 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07002796 .request = msmsdcc_request,
2797 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002798 .get_ro = msmsdcc_get_ro,
2799#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002800 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002801#endif
2802 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
2803 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07002804};
2805
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002806static unsigned int
2807msmsdcc_slot_status(struct msmsdcc_host *host)
2808{
2809 int status;
2810 unsigned int gpio_no = host->plat->status_gpio;
2811
2812 status = gpio_request(gpio_no, "SD_HW_Detect");
2813 if (status) {
2814 pr_err("%s: %s: Failed to request GPIO %d\n",
2815 mmc_hostname(host->mmc), __func__, gpio_no);
2816 } else {
2817 status = gpio_direction_input(gpio_no);
2818 if (!status)
2819 status = !gpio_get_value_cansleep(gpio_no);
2820 gpio_free(gpio_no);
2821 }
2822 return status;
2823}
2824
San Mehat9d2bd732009-09-22 16:44:22 -07002825static void
2826msmsdcc_check_status(unsigned long data)
2827{
2828 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
2829 unsigned int status;
2830
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002831 if (host->plat->status || host->plat->status_gpio) {
2832 if (host->plat->status)
2833 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07002834 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002835 status = msmsdcc_slot_status(host);
2836
2837 host->eject = !status;
2838 if (status ^ host->oldstat) {
2839 pr_info("%s: Slot status change detected (%d -> %d)\n",
2840 mmc_hostname(host->mmc), host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07002841 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002842 }
2843 host->oldstat = status;
2844 } else {
2845 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07002846 }
San Mehat9d2bd732009-09-22 16:44:22 -07002847}
2848
2849static irqreturn_t
2850msmsdcc_platform_status_irq(int irq, void *dev_id)
2851{
2852 struct msmsdcc_host *host = dev_id;
2853
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002854 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07002855 msmsdcc_check_status((unsigned long) host);
2856 return IRQ_HANDLED;
2857}
2858
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002859static irqreturn_t
2860msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
2861{
2862 struct msmsdcc_host *host = dev_id;
2863
2864 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
2865 spin_lock(&host->lock);
2866 if (!host->sdio_irq_disabled) {
2867 disable_irq_nosync(irq);
2868 if (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2869 wake_lock(&host->sdio_wlock);
2870 msmsdcc_disable_irq_wake(host);
2871 }
2872 host->sdio_irq_disabled = 1;
2873 }
2874 if (host->plat->is_sdio_al_client) {
2875 if (!host->clks_on) {
2876 msmsdcc_setup_clocks(host, true);
2877 host->clks_on = 1;
2878 }
2879 if (host->sdcc_irq_disabled) {
2880 writel_relaxed(host->mci_irqenable,
2881 host->base + MMCIMASK0);
2882 mb();
2883 enable_irq(host->core_irqres->start);
2884 host->sdcc_irq_disabled = 0;
2885 }
2886 wake_lock(&host->sdio_wlock);
2887 }
2888 spin_unlock(&host->lock);
2889
2890 return IRQ_HANDLED;
2891}
2892
San Mehat9d2bd732009-09-22 16:44:22 -07002893static void
2894msmsdcc_status_notify_cb(int card_present, void *dev_id)
2895{
2896 struct msmsdcc_host *host = dev_id;
2897
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002898 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07002899 card_present);
2900 msmsdcc_check_status((unsigned long) host);
2901}
2902
San Mehat9d2bd732009-09-22 16:44:22 -07002903static int
2904msmsdcc_init_dma(struct msmsdcc_host *host)
2905{
2906 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
2907 host->dma.host = host;
2908 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07002909 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07002910
2911 if (!host->dmares)
2912 return -ENODEV;
2913
2914 host->dma.nc = dma_alloc_coherent(NULL,
2915 sizeof(struct msmsdcc_nc_dmadata),
2916 &host->dma.nc_busaddr,
2917 GFP_KERNEL);
2918 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07002919 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07002920 return -ENOMEM;
2921 }
2922 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
2923 host->dma.cmd_busaddr = host->dma.nc_busaddr;
2924 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
2925 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
2926 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07002927 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07002928
2929 return 0;
2930}
2931
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002932#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
2933/**
2934 * Allocate and Connect a SDCC peripheral's SPS endpoint
2935 *
2936 * This function allocates endpoint context and
2937 * connect it with memory endpoint by calling
2938 * appropriate SPS driver APIs.
2939 *
2940 * Also registers a SPS callback function with
2941 * SPS driver
2942 *
2943 * This function should only be called once typically
2944 * during driver probe.
2945 *
2946 * @host - Pointer to sdcc host structure
2947 * @ep - Pointer to sps endpoint data structure
2948 * @is_produce - 1 means Producer endpoint
2949 * 0 means Consumer endpoint
2950 *
2951 * @return - 0 if successful else negative value.
2952 *
2953 */
2954static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
2955 struct msmsdcc_sps_ep_conn_data *ep,
2956 bool is_producer)
2957{
2958 int rc = 0;
2959 struct sps_pipe *sps_pipe_handle;
2960 struct sps_connect *sps_config = &ep->config;
2961 struct sps_register_event *sps_event = &ep->event;
2962
2963 /* Allocate endpoint context */
2964 sps_pipe_handle = sps_alloc_endpoint();
2965 if (!sps_pipe_handle) {
2966 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
2967 mmc_hostname(host->mmc), is_producer);
2968 rc = -ENOMEM;
2969 goto out;
2970 }
2971
2972 /* Get default connection configuration for an endpoint */
2973 rc = sps_get_config(sps_pipe_handle, sps_config);
2974 if (rc) {
2975 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
2976 " rc=%d", mmc_hostname(host->mmc),
2977 (u32)sps_pipe_handle, rc);
2978 goto get_config_err;
2979 }
2980
2981 /* Modify the default connection configuration */
2982 if (is_producer) {
2983 /*
2984 * For SDCC producer transfer, source should be
2985 * SDCC peripheral where as destination should
2986 * be system memory.
2987 */
2988 sps_config->source = host->sps.bam_handle;
2989 sps_config->destination = SPS_DEV_HANDLE_MEM;
2990 /* Producer pipe will handle this connection */
2991 sps_config->mode = SPS_MODE_SRC;
2992 sps_config->options =
2993 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
2994 } else {
2995 /*
2996 * For SDCC consumer transfer, source should be
2997 * system memory where as destination should
2998 * SDCC peripheral
2999 */
3000 sps_config->source = SPS_DEV_HANDLE_MEM;
3001 sps_config->destination = host->sps.bam_handle;
3002 sps_config->mode = SPS_MODE_DEST;
3003 sps_config->options =
3004 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3005 }
3006
3007 /* Producer pipe index */
3008 sps_config->src_pipe_index = host->sps.src_pipe_index;
3009 /* Consumer pipe index */
3010 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
3011 /*
3012 * This event thresold value is only significant for BAM-to-BAM
3013 * transfer. It's ignored for BAM-to-System mode transfer.
3014 */
3015 sps_config->event_thresh = 0x10;
3016 /*
3017 * Max. no of scatter/gather buffers that can
3018 * be passed by block layer = 32 (NR_SG).
3019 * Each BAM descritor needs 64 bits (8 bytes).
3020 * One BAM descriptor is required per buffer transfer.
3021 * So we would require total 256 (32 * 8) bytes of descriptor FIFO.
3022 * But due to HW limitation we need to allocate atleast one extra
3023 * descriptor memory (256 bytes + 8 bytes). But in order to be
3024 * in power of 2, we are allocating 512 bytes of memory.
3025 */
3026 sps_config->desc.size = 512;
3027 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
3028 sps_config->desc.size,
3029 &sps_config->desc.phys_base,
3030 GFP_KERNEL);
3031
Pratibhasagar V00b94332011-10-18 14:57:27 +05303032 if (!sps_config->desc.base) {
3033 rc = -ENOMEM;
3034 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3035 , mmc_hostname(host->mmc));
3036 goto get_config_err;
3037 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003038 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3039
3040 /* Establish connection between peripheral and memory endpoint */
3041 rc = sps_connect(sps_pipe_handle, sps_config);
3042 if (rc) {
3043 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3044 " rc=%d", mmc_hostname(host->mmc),
3045 (u32)sps_pipe_handle, rc);
3046 goto sps_connect_err;
3047 }
3048
3049 sps_event->mode = SPS_TRIGGER_CALLBACK;
3050 sps_event->options = SPS_O_EOT;
3051 sps_event->callback = msmsdcc_sps_complete_cb;
3052 sps_event->xfer_done = NULL;
3053 sps_event->user = (void *)host;
3054
3055 /* Register callback event for EOT (End of transfer) event. */
3056 rc = sps_register_event(sps_pipe_handle, sps_event);
3057 if (rc) {
3058 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3059 " rc=%d", mmc_hostname(host->mmc),
3060 (u32)sps_pipe_handle, rc);
3061 goto reg_event_err;
3062 }
3063 /* Now save the sps pipe handle */
3064 ep->pipe_handle = sps_pipe_handle;
3065 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3066 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3067 __func__, is_producer ? "READ" : "WRITE",
3068 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3069 goto out;
3070
3071reg_event_err:
3072 sps_disconnect(sps_pipe_handle);
3073sps_connect_err:
3074 dma_free_coherent(mmc_dev(host->mmc),
3075 sps_config->desc.size,
3076 sps_config->desc.base,
3077 sps_config->desc.phys_base);
3078get_config_err:
3079 sps_free_endpoint(sps_pipe_handle);
3080out:
3081 return rc;
3082}
3083
3084/**
3085 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3086 *
3087 * This function disconnect endpoint and deallocates
3088 * endpoint context.
3089 *
3090 * This function should only be called once typically
3091 * during driver remove.
3092 *
3093 * @host - Pointer to sdcc host structure
3094 * @ep - Pointer to sps endpoint data structure
3095 *
3096 */
3097static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3098 struct msmsdcc_sps_ep_conn_data *ep)
3099{
3100 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3101 struct sps_connect *sps_config = &ep->config;
3102 struct sps_register_event *sps_event = &ep->event;
3103
3104 sps_event->xfer_done = NULL;
3105 sps_event->callback = NULL;
3106 sps_register_event(sps_pipe_handle, sps_event);
3107 sps_disconnect(sps_pipe_handle);
3108 dma_free_coherent(mmc_dev(host->mmc),
3109 sps_config->desc.size,
3110 sps_config->desc.base,
3111 sps_config->desc.phys_base);
3112 sps_free_endpoint(sps_pipe_handle);
3113}
3114
3115/**
3116 * Reset SDCC peripheral's SPS endpoint
3117 *
3118 * This function disconnects an endpoint.
3119 *
3120 * This function should be called for reseting
3121 * SPS endpoint when data transfer error is
3122 * encountered during data transfer. This
3123 * can be considered as soft reset to endpoint.
3124 *
3125 * This function should only be called if
3126 * msmsdcc_sps_init() is already called.
3127 *
3128 * @host - Pointer to sdcc host structure
3129 * @ep - Pointer to sps endpoint data structure
3130 *
3131 * @return - 0 if successful else negative value.
3132 */
3133static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3134 struct msmsdcc_sps_ep_conn_data *ep)
3135{
3136 int rc = 0;
3137 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3138
3139 rc = sps_disconnect(sps_pipe_handle);
3140 if (rc) {
3141 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3142 " rc=%d", mmc_hostname(host->mmc), __func__,
3143 (u32)sps_pipe_handle, rc);
3144 goto out;
3145 }
3146 out:
3147 return rc;
3148}
3149
3150/**
3151 * Restore SDCC peripheral's SPS endpoint
3152 *
3153 * This function connects an endpoint.
3154 *
3155 * This function should be called for restoring
3156 * SPS endpoint after data transfer error is
3157 * encountered during data transfer. This
3158 * can be considered as soft reset to endpoint.
3159 *
3160 * This function should only be called if
3161 * msmsdcc_sps_reset_ep() is called before.
3162 *
3163 * @host - Pointer to sdcc host structure
3164 * @ep - Pointer to sps endpoint data structure
3165 *
3166 * @return - 0 if successful else negative value.
3167 */
3168static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3169 struct msmsdcc_sps_ep_conn_data *ep)
3170{
3171 int rc = 0;
3172 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3173 struct sps_connect *sps_config = &ep->config;
3174 struct sps_register_event *sps_event = &ep->event;
3175
3176 /* Establish connection between peripheral and memory endpoint */
3177 rc = sps_connect(sps_pipe_handle, sps_config);
3178 if (rc) {
3179 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3180 " rc=%d", mmc_hostname(host->mmc), __func__,
3181 (u32)sps_pipe_handle, rc);
3182 goto out;
3183 }
3184
3185 /* Register callback event for EOT (End of transfer) event. */
3186 rc = sps_register_event(sps_pipe_handle, sps_event);
3187 if (rc) {
3188 pr_err("%s: %s: sps_register_event() failed!!!"
3189 " pipe_handle=0x%x, rc=%d",
3190 mmc_hostname(host->mmc), __func__,
3191 (u32)sps_pipe_handle, rc);
3192 goto reg_event_err;
3193 }
3194 goto out;
3195
3196reg_event_err:
3197 sps_disconnect(sps_pipe_handle);
3198out:
3199 return rc;
3200}
3201
3202/**
3203 * Initialize SPS HW connected with SDCC core
3204 *
3205 * This function register BAM HW resources with
3206 * SPS driver and then initialize 2 SPS endpoints
3207 *
3208 * This function should only be called once typically
3209 * during driver probe.
3210 *
3211 * @host - Pointer to sdcc host structure
3212 *
3213 * @return - 0 if successful else negative value.
3214 *
3215 */
3216static int msmsdcc_sps_init(struct msmsdcc_host *host)
3217{
3218 int rc = 0;
3219 struct sps_bam_props bam = {0};
3220
3221 host->bam_base = ioremap(host->bam_memres->start,
3222 resource_size(host->bam_memres));
3223 if (!host->bam_base) {
3224 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3225 " size=0x%x", mmc_hostname(host->mmc),
3226 host->bam_memres->start,
3227 (host->bam_memres->end -
3228 host->bam_memres->start));
3229 rc = -ENOMEM;
3230 goto out;
3231 }
3232
3233 bam.phys_addr = host->bam_memres->start;
3234 bam.virt_addr = host->bam_base;
3235 /*
3236 * This event thresold value is only significant for BAM-to-BAM
3237 * transfer. It's ignored for BAM-to-System mode transfer.
3238 */
3239 bam.event_threshold = 0x10; /* Pipe event threshold */
3240 /*
3241 * This threshold controls when the BAM publish
3242 * the descriptor size on the sideband interface.
3243 * SPS HW will only be used when
3244 * data transfer size > MCI_FIFOSIZE (64 bytes).
3245 * PIO mode will be used when
3246 * data transfer size < MCI_FIFOSIZE (64 bytes).
3247 * So set this thresold value to 64 bytes.
3248 */
3249 bam.summing_threshold = 64;
3250 /* SPS driver wll handle the SDCC BAM IRQ */
3251 bam.irq = (u32)host->bam_irqres->start;
3252 bam.manage = SPS_BAM_MGR_LOCAL;
3253
3254 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3255 (u32)bam.phys_addr);
3256 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3257 (u32)bam.virt_addr);
3258
3259 /* Register SDCC Peripheral BAM device to SPS driver */
3260 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3261 if (rc) {
3262 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3263 mmc_hostname(host->mmc), rc);
3264 goto reg_bam_err;
3265 }
3266 pr_info("%s: BAM device registered. bam_handle=0x%x",
3267 mmc_hostname(host->mmc), host->sps.bam_handle);
3268
3269 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3270 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3271
3272 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3273 SPS_PROD_PERIPHERAL);
3274 if (rc)
3275 goto sps_reset_err;
3276 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3277 SPS_CONS_PERIPHERAL);
3278 if (rc)
3279 goto cons_conn_err;
3280
3281 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3282 mmc_hostname(host->mmc),
3283 (unsigned long long)host->bam_memres->start,
3284 (unsigned int)host->bam_irqres->start);
3285 goto out;
3286
3287cons_conn_err:
3288 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3289sps_reset_err:
3290 sps_deregister_bam_device(host->sps.bam_handle);
3291reg_bam_err:
3292 iounmap(host->bam_base);
3293out:
3294 return rc;
3295}
3296
3297/**
3298 * De-initialize SPS HW connected with SDCC core
3299 *
3300 * This function deinitialize SPS endpoints and then
3301 * deregisters BAM resources from SPS driver.
3302 *
3303 * This function should only be called once typically
3304 * during driver remove.
3305 *
3306 * @host - Pointer to sdcc host structure
3307 *
3308 */
3309static void msmsdcc_sps_exit(struct msmsdcc_host *host)
3310{
3311 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
3312 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3313 sps_deregister_bam_device(host->sps.bam_handle);
3314 iounmap(host->bam_base);
3315}
3316#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
3317
3318static ssize_t
3319show_polling(struct device *dev, struct device_attribute *attr, char *buf)
3320{
3321 struct mmc_host *mmc = dev_get_drvdata(dev);
3322 struct msmsdcc_host *host = mmc_priv(mmc);
3323 int poll;
3324 unsigned long flags;
3325
3326 spin_lock_irqsave(&host->lock, flags);
3327 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
3328 spin_unlock_irqrestore(&host->lock, flags);
3329
3330 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
3331}
3332
3333static ssize_t
3334set_polling(struct device *dev, struct device_attribute *attr,
3335 const char *buf, size_t count)
3336{
3337 struct mmc_host *mmc = dev_get_drvdata(dev);
3338 struct msmsdcc_host *host = mmc_priv(mmc);
3339 int value;
3340 unsigned long flags;
3341
3342 sscanf(buf, "%d", &value);
3343
3344 spin_lock_irqsave(&host->lock, flags);
3345 if (value) {
3346 mmc->caps |= MMC_CAP_NEEDS_POLL;
3347 mmc_detect_change(host->mmc, 0);
3348 } else {
3349 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3350 }
3351#ifdef CONFIG_HAS_EARLYSUSPEND
3352 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
3353#endif
3354 spin_unlock_irqrestore(&host->lock, flags);
3355 return count;
3356}
3357
3358static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
3359 show_polling, set_polling);
3360static struct attribute *dev_attrs[] = {
3361 &dev_attr_polling.attr,
3362 NULL,
3363};
3364static struct attribute_group dev_attr_grp = {
3365 .attrs = dev_attrs,
3366};
3367
3368#ifdef CONFIG_HAS_EARLYSUSPEND
3369static void msmsdcc_early_suspend(struct early_suspend *h)
3370{
3371 struct msmsdcc_host *host =
3372 container_of(h, struct msmsdcc_host, early_suspend);
3373 unsigned long flags;
3374
3375 spin_lock_irqsave(&host->lock, flags);
3376 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
3377 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3378 spin_unlock_irqrestore(&host->lock, flags);
3379};
3380static void msmsdcc_late_resume(struct early_suspend *h)
3381{
3382 struct msmsdcc_host *host =
3383 container_of(h, struct msmsdcc_host, early_suspend);
3384 unsigned long flags;
3385
3386 if (host->polling_enabled) {
3387 spin_lock_irqsave(&host->lock, flags);
3388 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
3389 mmc_detect_change(host->mmc, 0);
3390 spin_unlock_irqrestore(&host->lock, flags);
3391 }
3392};
3393#endif
3394
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303395void msmsdcc_print_regs(const char *name, void __iomem *base,
3396 unsigned int no_of_regs)
3397{
3398 unsigned int i;
3399
3400 if (!base)
3401 return;
3402 pr_info("===== %s: Register Dumps @base=0x%x =====\n",
3403 name, (u32)base);
3404 for (i = 0; i < no_of_regs; i = i + 4) {
3405 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x.\n", i*4,
3406 (u32)readl_relaxed(base + i*4),
3407 (u32)readl_relaxed(base + ((i+1)*4)),
3408 (u32)readl_relaxed(base + ((i+2)*4)),
3409 (u32)readl_relaxed(base + ((i+3)*4)));
3410 }
3411}
3412
3413static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
3414{
3415 /* Dump current state of SDCC clocks, power and irq */
3416 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
3417 (host->pwr ? "ON" : "OFF"));
3418 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
3419 mmc_hostname(host->mmc),
3420 (host->clks_on ? "ON" : "OFF"),
3421 (u32)clk_get_rate(host->clk));
3422 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
3423 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
3424
3425 /* Now dump SDCC registers. Don't print FIFO registers */
3426 if (host->clks_on)
3427 msmsdcc_print_regs("SDCC-CORE", host->base, 28);
3428
3429 if (host->curr.data) {
3430 if (msmsdcc_check_dma_op_req(host->curr.data))
3431 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
3432 else if (host->is_dma_mode)
3433 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
3434 mmc_hostname(host->mmc), host->dma.busy,
3435 host->dma.channel, host->dma.crci);
3436 else if (host->is_sps_mode)
3437 pr_info("%s: SPS mode: busy=%d\n",
3438 mmc_hostname(host->mmc), host->sps.busy);
3439
3440 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
3441 mmc_hostname(host->mmc), host->curr.xfer_size,
3442 host->curr.data_xfered, host->curr.xfer_remain);
3443 pr_info("%s: got_dataend=%d, prog_enable=%d,"
3444 " wait_for_auto_prog_done=%d,"
3445 " got_auto_prog_done=%d\n",
3446 mmc_hostname(host->mmc), host->curr.got_dataend,
3447 host->prog_enable, host->curr.wait_for_auto_prog_done,
3448 host->curr.got_auto_prog_done);
3449 }
3450
3451}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003452static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
3453{
3454 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3455 struct mmc_request *mrq;
3456 unsigned long flags;
3457
3458 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003459 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003460 pr_info("%s: %s: dummy CMD52 timeout\n",
3461 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003462 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003463 }
3464
3465 mrq = host->curr.mrq;
3466
3467 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303468 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
3469 mrq->cmd->opcode);
3470 msmsdcc_dump_sdcc_state(host);
3471
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003472 if (!mrq->cmd->error)
3473 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303474 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003475 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003476 if (mrq->data && !mrq->data->error)
3477 mrq->data->error = -ETIMEDOUT;
3478 host->curr.data_xfered = 0;
3479 if (host->dma.sg && host->is_dma_mode) {
3480 msm_dmov_stop_cmd(host->dma.channel,
3481 &host->dma.hdr, 0);
3482 } else if (host->sps.sg && host->is_sps_mode) {
3483 /* Stop current SPS transfer */
3484 msmsdcc_sps_exit_curr_xfer(host);
3485 } else {
3486 msmsdcc_reset_and_restore(host);
3487 msmsdcc_stop_data(host);
3488 if (mrq->data && mrq->data->stop)
3489 msmsdcc_start_command(host,
3490 mrq->data->stop, 0);
3491 else
3492 msmsdcc_request_end(host, mrq);
3493 }
3494 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05303495 host->prog_enable = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003496 msmsdcc_reset_and_restore(host);
3497 msmsdcc_request_end(host, mrq);
3498 }
3499 }
3500 spin_unlock_irqrestore(&host->lock, flags);
3501}
3502
San Mehat9d2bd732009-09-22 16:44:22 -07003503static int
3504msmsdcc_probe(struct platform_device *pdev)
3505{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003506 struct mmc_platform_data *plat = pdev->dev.platform_data;
San Mehat9d2bd732009-09-22 16:44:22 -07003507 struct msmsdcc_host *host;
3508 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003509 unsigned long flags;
3510 struct resource *core_irqres = NULL;
3511 struct resource *bam_irqres = NULL;
3512 struct resource *core_memres = NULL;
3513 struct resource *dml_memres = NULL;
3514 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07003515 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07003516 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05303517 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003518 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07003519
3520 /* must have platform data */
3521 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003522 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003523 ret = -EINVAL;
3524 goto out;
3525 }
3526
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003527 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07003528 return -EINVAL;
3529
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003530 if (plat->is_sdio_al_client)
3531 if (!plat->sdio_lpm_gpio_setup || !plat->sdiowakeup_irq)
3532 return -EINVAL;
3533
San Mehat9d2bd732009-09-22 16:44:22 -07003534 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003535 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003536 return -ENXIO;
3537 }
3538
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003539 for (i = 0; i < pdev->num_resources; i++) {
3540 if (pdev->resource[i].flags & IORESOURCE_MEM) {
3541 if (!strcmp(pdev->resource[i].name,
3542 "sdcc_dml_addr"))
3543 dml_memres = &pdev->resource[i];
3544 else if (!strcmp(pdev->resource[i].name,
3545 "sdcc_bam_addr"))
3546 bam_memres = &pdev->resource[i];
3547 else
3548 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07003549
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003550 }
3551 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
3552 if (!strcmp(pdev->resource[i].name,
3553 "sdcc_bam_irq"))
3554 bam_irqres = &pdev->resource[i];
3555 else
3556 core_irqres = &pdev->resource[i];
3557 }
Krishna Konda25786ec2011-07-25 16:21:36 -07003558 if (pdev->resource[i].flags & IORESOURCE_DMA) {
3559 if (!strncmp(pdev->resource[i].name,
3560 "sdcc_dma_chnl",
3561 sizeof("sdcc_dma_chnl")))
3562 dmares = &pdev->resource[i];
3563 else if (!strncmp(pdev->resource[i].name,
3564 "sdcc_dma_crci",
3565 sizeof("sdcc_dma_crci")))
3566 dma_crci_res = &pdev->resource[i];
3567 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003568 }
3569
3570 if (!core_irqres || !core_memres) {
3571 pr_err("%s: Invalid sdcc core resource\n", __func__);
3572 return -ENXIO;
3573 }
3574
3575 /*
3576 * Both BAM and DML memory resource should be preset.
3577 * BAM IRQ resource should also be present.
3578 */
3579 if ((bam_memres && !dml_memres) ||
3580 (!bam_memres && dml_memres) ||
3581 ((bam_memres && dml_memres) && !bam_irqres)) {
3582 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003583 return -ENXIO;
3584 }
3585
3586 /*
3587 * Setup our host structure
3588 */
San Mehat9d2bd732009-09-22 16:44:22 -07003589 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
3590 if (!mmc) {
3591 ret = -ENOMEM;
3592 goto out;
3593 }
3594
3595 host = mmc_priv(mmc);
3596 host->pdev_id = pdev->id;
3597 host->plat = plat;
3598 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08003599 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05303600
3601 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003602 host->is_sps_mode = 1;
3603 else if (dmares)
3604 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07003605
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003606 host->base = ioremap(core_memres->start,
3607 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07003608 if (!host->base) {
3609 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003610 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003611 }
3612
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003613 host->core_irqres = core_irqres;
3614 host->bam_irqres = bam_irqres;
3615 host->core_memres = core_memres;
3616 host->dml_memres = dml_memres;
3617 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07003618 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07003619 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07003620 spin_lock_init(&host->lock);
3621
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003622#ifdef CONFIG_MMC_EMBEDDED_SDIO
3623 if (plat->embedded_sdio)
3624 mmc_set_embedded_sdio_data(mmc,
3625 &plat->embedded_sdio->cis,
3626 &plat->embedded_sdio->cccr,
3627 plat->embedded_sdio->funcs,
3628 plat->embedded_sdio->num_funcs);
3629#endif
3630
Sahitya Tummala62612cf2010-12-08 15:03:03 +05303631 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
3632 (unsigned long)host);
3633
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003634 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
3635 (unsigned long)host);
3636 if (host->is_dma_mode) {
3637 /* Setup DMA */
3638 ret = msmsdcc_init_dma(host);
3639 if (ret)
3640 goto ioremap_free;
3641 } else {
3642 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003643 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003644 }
3645
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003646 /*
3647 * Setup SDCC clock if derived from Dayatona
3648 * fabric core clock.
3649 */
3650 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07003651 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003652 if (!IS_ERR(host->dfab_pclk)) {
3653 /* Set the clock rate to 64MHz for max. performance */
3654 ret = clk_set_rate(host->dfab_pclk, 64000000);
3655 if (ret)
3656 goto dfab_pclk_put;
3657 ret = clk_enable(host->dfab_pclk);
3658 if (ret)
3659 goto dfab_pclk_put;
3660 } else
3661 goto dma_free;
3662 }
3663
3664 /*
3665 * Setup main peripheral bus clock
3666 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003667 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003668 if (!IS_ERR(host->pclk)) {
3669 ret = clk_enable(host->pclk);
3670 if (ret)
3671 goto pclk_put;
3672
3673 host->pclk_rate = clk_get_rate(host->pclk);
3674 }
3675
3676 /*
3677 * Setup SDC MMC clock
3678 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003679 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07003680 if (IS_ERR(host->clk)) {
3681 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003682 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07003683 }
3684
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003685 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
3686 if (ret) {
3687 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
3688 goto clk_put;
3689 }
3690
3691 ret = clk_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003692 if (ret)
3693 goto clk_put;
3694
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003695 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303696 if (!host->clk_rate)
3697 dev_err(&pdev->dev, "Failed to read MCLK\n");
3698 /*
3699 * Set the register write delay according to min. clock frequency
3700 * supported and update later when the host->clk_rate changes.
3701 */
3702 host->reg_write_delay =
3703 (1 + ((3 * USEC_PER_SEC) /
3704 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003705
3706 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05303707 /* Apply Hard reset to SDCC to put it in power on default state */
3708 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003709
3710 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07003711 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003712 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07003713 goto clk_disable;
3714 }
3715
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003716
3717 /* Clocks has to be running before accessing SPS/DML HW blocks */
3718 if (host->is_sps_mode) {
3719 /* Initialize SPS */
3720 ret = msmsdcc_sps_init(host);
3721 if (ret)
3722 goto vreg_deinit;
3723 /* Initialize DML */
3724 ret = msmsdcc_dml_init(host);
3725 if (ret)
3726 goto sps_exit;
3727 }
San Mehat9d2bd732009-09-22 16:44:22 -07003728
San Mehat9d2bd732009-09-22 16:44:22 -07003729 /*
3730 * Setup MMC host structure
3731 */
3732 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003733 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
3734 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003735 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003736 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
3737 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07003738
San Mehat9d2bd732009-09-22 16:44:22 -07003739 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05303740 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05303741
3742 /*
3743 * If we send the CMD23 before multi block write/read command
3744 * then we need not to send CMD12 at the end of the transfer.
3745 * If we don't send the CMD12 then only way to detect the PROG_DONE
3746 * status is to use the AUTO_PROG_DONE status provided by SDCC4
3747 * controller. So let's enable the CMD23 for SDCC4 only.
3748 */
Sahitya Tummala85fa0702011-09-15 09:39:37 +05303749 if (!plat->disable_cmd23 && host->plat->sdcc_v4_sup)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05303750 mmc->caps |= MMC_CAP_CMD23;
3751
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003752 mmc->caps |= plat->uhs_caps;
3753 /*
3754 * XPC controls the maximum current in the default speed mode of SDXC
3755 * card. XPC=0 means 100mA (max.) but speed class is not supported.
3756 * XPC=1 means 150mA (max.) and speed class is supported.
3757 */
3758 if (plat->xpc_cap)
3759 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
3760 MMC_CAP_SET_XPC_180);
3761
3762 if (plat->nonremovable)
3763 mmc->caps |= MMC_CAP_NONREMOVABLE;
3764#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
3765 mmc->caps |= MMC_CAP_SDIO_IRQ;
3766#endif
3767
3768 if (plat->is_sdio_al_client)
3769 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07003770
Martin K. Petersena36274e2010-09-10 01:33:59 -04003771 mmc->max_segs = NR_SG;
San Mehat9d2bd732009-09-22 16:44:22 -07003772 mmc->max_blk_size = 4096; /* MCI_DATA_CTL BLOCKSIZE up to 4096 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003773 mmc->max_blk_count = 65535;
San Mehat9d2bd732009-09-22 16:44:22 -07003774
3775 mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */
3776 mmc->max_seg_size = mmc->max_req_size;
3777
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003778 writel_relaxed(0, host->base + MMCIMASK0);
3779 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -07003780
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003781 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
3782 mb();
3783 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07003784
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003785 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
3786 DRIVER_NAME " (cmd)", host);
3787 if (ret)
3788 goto dml_exit;
3789
3790 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
3791 DRIVER_NAME " (pio)", host);
3792 if (ret)
3793 goto irq_free;
3794
3795 /*
3796 * Enable SDCC IRQ only when host is powered on. Otherwise, this
3797 * IRQ is un-necessarily being monitored by MPM (Modem power
3798 * management block) during idle-power collapse. The MPM will be
3799 * configured to monitor the DATA1 GPIO line with level-low trigger
3800 * and thus depending on the GPIO status, it prevents TCXO shutdown
3801 * during idle-power collapse.
3802 */
3803 disable_irq(core_irqres->start);
3804 host->sdcc_irq_disabled = 1;
3805
3806 if (plat->sdiowakeup_irq) {
3807 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3808 mmc_hostname(mmc));
3809 ret = request_irq(plat->sdiowakeup_irq,
3810 msmsdcc_platform_sdiowakeup_irq,
3811 IRQF_SHARED | IRQF_TRIGGER_LOW,
3812 DRIVER_NAME "sdiowakeup", host);
3813 if (ret) {
3814 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
3815 plat->sdiowakeup_irq, ret);
3816 goto pio_irq_free;
3817 } else {
3818 spin_lock_irqsave(&host->lock, flags);
3819 if (!host->sdio_irq_disabled) {
3820 disable_irq_nosync(plat->sdiowakeup_irq);
3821 host->sdio_irq_disabled = 1;
3822 }
3823 spin_unlock_irqrestore(&host->lock, flags);
3824 }
3825 }
3826
3827 if (plat->cfg_mpm_sdiowakeup) {
3828 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3829 mmc_hostname(mmc));
3830 }
3831
3832 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
3833 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003834 /*
3835 * Setup card detect change
3836 */
3837
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003838 if (plat->status || plat->status_gpio) {
3839 if (plat->status)
3840 host->oldstat = plat->status(mmc_dev(host->mmc));
3841 else
3842 host->oldstat = msmsdcc_slot_status(host);
3843 host->eject = !host->oldstat;
3844 }
San Mehat9d2bd732009-09-22 16:44:22 -07003845
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003846 if (plat->status_irq) {
3847 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07003848 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003849 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07003850 DRIVER_NAME " (slot)",
3851 host);
3852 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003853 pr_err("Unable to get slot IRQ %d (%d)\n",
3854 plat->status_irq, ret);
3855 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003856 }
3857 } else if (plat->register_status_notify) {
3858 plat->register_status_notify(msmsdcc_status_notify_cb, host);
3859 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003860 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07003861 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003862
3863 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003864
3865 ret = pm_runtime_set_active(&(pdev)->dev);
3866 if (ret < 0)
3867 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3868 __func__, ret);
3869 /*
3870 * There is no notion of suspend/resume for SD/MMC/SDIO
3871 * cards. So host can be suspended/resumed with out
3872 * worrying about its children.
3873 */
3874 pm_suspend_ignore_children(&(pdev)->dev, true);
3875
3876 /*
3877 * MMC/SD/SDIO bus suspend/resume operations are defined
3878 * only for the slots that will be used for non-removable
3879 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
3880 * defined. Otherwise, they simply become card removal and
3881 * insertion events during suspend and resume respectively.
3882 * Hence, enable run-time PM only for slots for which bus
3883 * suspend/resume operations are defined.
3884 */
3885#ifdef CONFIG_MMC_UNSAFE_RESUME
3886 /*
3887 * If this capability is set, MMC core will enable/disable host
3888 * for every claim/release operation on a host. We use this
3889 * notification to increment/decrement runtime pm usage count.
3890 */
3891 mmc->caps |= MMC_CAP_DISABLE;
3892 pm_runtime_enable(&(pdev)->dev);
3893#else
3894 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
3895 mmc->caps |= MMC_CAP_DISABLE;
3896 pm_runtime_enable(&(pdev)->dev);
3897 }
3898#endif
3899 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
3900 (unsigned long)host);
3901
San Mehat9d2bd732009-09-22 16:44:22 -07003902 mmc_add_host(mmc);
3903
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003904#ifdef CONFIG_HAS_EARLYSUSPEND
3905 host->early_suspend.suspend = msmsdcc_early_suspend;
3906 host->early_suspend.resume = msmsdcc_late_resume;
3907 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
3908 register_early_suspend(&host->early_suspend);
3909#endif
San Mehat9d2bd732009-09-22 16:44:22 -07003910
Krishna Konda25786ec2011-07-25 16:21:36 -07003911 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
3912 " dmacrcri %d\n", mmc_hostname(mmc),
3913 (unsigned long long)core_memres->start,
3914 (unsigned int) core_irqres->start,
3915 (unsigned int) plat->status_irq, host->dma.channel,
3916 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003917
3918 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
3919 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
3920 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
3921 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
3922 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
3923 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
3924 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
3925 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
3926 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
3927 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
3928 host->eject);
3929 pr_info("%s: Power save feature enable = %d\n",
3930 mmc_hostname(mmc), msmsdcc_pwrsave);
3931
Krishna Konda25786ec2011-07-25 16:21:36 -07003932 if (host->is_dma_mode && host->dma.channel != -1
3933 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003934 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003935 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003936 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003937 mmc_hostname(mmc), host->dma.cmd_busaddr,
3938 host->dma.cmdptr_busaddr);
3939 } else if (host->is_sps_mode) {
3940 pr_info("%s: SPS-BAM data transfer mode available\n",
3941 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003942 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003943 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003944
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003945#if defined(CONFIG_DEBUG_FS)
3946 msmsdcc_dbg_createhost(host);
3947#endif
3948 if (!plat->status_irq) {
3949 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
3950 if (ret)
3951 goto platform_irq_free;
3952 }
San Mehat9d2bd732009-09-22 16:44:22 -07003953 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003954
3955 platform_irq_free:
3956 del_timer_sync(&host->req_tout_timer);
3957 pm_runtime_disable(&(pdev)->dev);
3958 pm_runtime_set_suspended(&(pdev)->dev);
3959
3960 if (plat->status_irq)
3961 free_irq(plat->status_irq, host);
3962 sdiowakeup_irq_free:
3963 wake_lock_destroy(&host->sdio_suspend_wlock);
3964 if (plat->sdiowakeup_irq)
3965 free_irq(plat->sdiowakeup_irq, host);
3966 pio_irq_free:
3967 if (plat->sdiowakeup_irq)
3968 wake_lock_destroy(&host->sdio_wlock);
3969 free_irq(core_irqres->start, host);
3970 irq_free:
3971 free_irq(core_irqres->start, host);
3972 dml_exit:
3973 if (host->is_sps_mode)
3974 msmsdcc_dml_exit(host);
3975 sps_exit:
3976 if (host->is_sps_mode)
3977 msmsdcc_sps_exit(host);
3978 vreg_deinit:
3979 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07003980 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003981 clk_disable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003982 clk_put:
3983 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003984 pclk_disable:
3985 if (!IS_ERR(host->pclk))
3986 clk_disable(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07003987 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003988 if (!IS_ERR(host->pclk))
3989 clk_put(host->pclk);
3990 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3991 clk_disable(host->dfab_pclk);
3992 dfab_pclk_put:
3993 if (!IS_ERR_OR_NULL(host->dfab_pclk))
3994 clk_put(host->dfab_pclk);
3995 dma_free:
3996 if (host->is_dma_mode) {
3997 if (host->dmares)
3998 dma_free_coherent(NULL,
3999 sizeof(struct msmsdcc_nc_dmadata),
4000 host->dma.nc, host->dma.nc_busaddr);
4001 }
4002 ioremap_free:
4003 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07004004 host_free:
4005 mmc_free_host(mmc);
4006 out:
4007 return ret;
4008}
4009
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004010static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07004011{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004012 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4013 struct mmc_platform_data *plat;
4014 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004015
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004016 if (!mmc)
4017 return -ENXIO;
4018
4019 if (pm_runtime_suspended(&(pdev)->dev))
4020 pm_runtime_resume(&(pdev)->dev);
4021
4022 host = mmc_priv(mmc);
4023
4024 DBG(host, "Removing SDCC device = %d\n", pdev->id);
4025 plat = host->plat;
4026
4027 if (!plat->status_irq)
4028 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
4029
4030 del_timer_sync(&host->req_tout_timer);
4031 tasklet_kill(&host->dma_tlet);
4032 tasklet_kill(&host->sps.tlet);
4033 mmc_remove_host(mmc);
4034
4035 if (plat->status_irq)
4036 free_irq(plat->status_irq, host);
4037
4038 wake_lock_destroy(&host->sdio_suspend_wlock);
4039 if (plat->sdiowakeup_irq) {
4040 wake_lock_destroy(&host->sdio_wlock);
4041 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
4042 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07004043 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004044
4045 free_irq(host->core_irqres->start, host);
4046 free_irq(host->core_irqres->start, host);
4047
4048 clk_put(host->clk);
4049 if (!IS_ERR(host->pclk))
4050 clk_put(host->pclk);
4051 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4052 clk_put(host->dfab_pclk);
4053
4054 msmsdcc_vreg_init(host, false);
4055
4056 if (host->is_dma_mode) {
4057 if (host->dmares)
4058 dma_free_coherent(NULL,
4059 sizeof(struct msmsdcc_nc_dmadata),
4060 host->dma.nc, host->dma.nc_busaddr);
4061 }
4062
4063 if (host->is_sps_mode) {
4064 msmsdcc_dml_exit(host);
4065 msmsdcc_sps_exit(host);
4066 }
4067
4068 iounmap(host->base);
4069 mmc_free_host(mmc);
4070
4071#ifdef CONFIG_HAS_EARLYSUSPEND
4072 unregister_early_suspend(&host->early_suspend);
4073#endif
4074 pm_runtime_disable(&(pdev)->dev);
4075 pm_runtime_set_suspended(&(pdev)->dev);
4076
4077 return 0;
4078}
4079
4080#ifdef CONFIG_MSM_SDIO_AL
4081int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4082{
4083 struct msmsdcc_host *host = mmc_priv(mmc);
4084 unsigned long flags;
4085
4086 spin_lock_irqsave(&host->lock, flags);
4087 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
4088 enable ? "En" : "Dis");
4089
4090 if (enable) {
4091 if (!host->sdcc_irq_disabled) {
4092 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05304093 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004094 host->sdcc_irq_disabled = 1;
4095 }
4096
4097 if (host->clks_on) {
4098 msmsdcc_setup_clocks(host, false);
4099 host->clks_on = 0;
4100 }
4101
4102 if (!host->sdio_gpio_lpm) {
4103 spin_unlock_irqrestore(&host->lock, flags);
4104 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
4105 spin_lock_irqsave(&host->lock, flags);
4106 host->sdio_gpio_lpm = 1;
4107 }
4108
4109 if (host->sdio_irq_disabled) {
4110 msmsdcc_enable_irq_wake(host);
4111 enable_irq(host->plat->sdiowakeup_irq);
4112 host->sdio_irq_disabled = 0;
4113 }
4114 } else {
4115 if (!host->sdio_irq_disabled) {
4116 disable_irq_nosync(host->plat->sdiowakeup_irq);
4117 host->sdio_irq_disabled = 1;
4118 msmsdcc_disable_irq_wake(host);
4119 }
4120
4121 if (host->sdio_gpio_lpm) {
4122 spin_unlock_irqrestore(&host->lock, flags);
4123 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
4124 spin_lock_irqsave(&host->lock, flags);
4125 host->sdio_gpio_lpm = 0;
4126 }
4127
4128 if (!host->clks_on) {
4129 msmsdcc_setup_clocks(host, true);
4130 host->clks_on = 1;
4131 }
4132
4133 if (host->sdcc_irq_disabled) {
4134 writel_relaxed(host->mci_irqenable,
4135 host->base + MMCIMASK0);
4136 mb();
4137 enable_irq(host->core_irqres->start);
4138 host->sdcc_irq_disabled = 0;
4139 }
4140 wake_lock_timeout(&host->sdio_wlock, 1);
4141 }
4142 spin_unlock_irqrestore(&host->lock, flags);
4143 return 0;
4144}
4145#else
4146int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4147{
4148 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004149}
4150#endif
4151
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004152#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07004153static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004154msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004155{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004156 struct mmc_host *mmc = dev_get_drvdata(dev);
4157 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07004158 int rc = 0;
4159
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004160 if (host->plat->is_sdio_al_client)
4161 return 0;
4162
Sahitya Tummala7661a452011-07-18 13:28:35 +05304163 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004164 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004165 host->sdcc_suspending = 1;
4166 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07004167
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004168 /*
4169 * If the clocks are already turned off by SDIO clients (as
4170 * part of LPM), then clocks should be turned on before
4171 * calling mmc_suspend_host() because mmc_suspend_host might
4172 * send some commands to the card. The clocks will be turned
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304173 * off again after mmc_suspend_host. Thus for SDIO
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004174 * cards, clocks will be turned on before mmc_suspend_host
4175 * and turned off after mmc_suspend_host.
4176 */
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304177 if (mmc->card && mmc_card_sdio(mmc->card)) {
4178 mmc->ios.clock = host->clk_rate;
4179 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4180 }
San Mehat9d2bd732009-09-22 16:44:22 -07004181
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004182 /*
4183 * MMC core thinks that host is disabled by now since
4184 * runtime suspend is scheduled after msmsdcc_disable()
4185 * is called. Thus, MMC core will try to enable the host
4186 * while suspending it. This results in a synchronous
4187 * runtime resume request while in runtime suspending
4188 * context and hence inorder to complete this resume
4189 * requet, it will wait for suspend to be complete,
4190 * but runtime suspend also can not proceed further
4191 * until the host is resumed. Thus, it leads to a hang.
4192 * Hence, increase the pm usage count before suspending
4193 * the host so that any resume requests after this will
4194 * simple become pm usage counter increment operations.
4195 */
4196 pm_runtime_get_noresume(dev);
4197 rc = mmc_suspend_host(mmc);
4198 pm_runtime_put_noidle(dev);
4199
4200 if (!rc) {
4201 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
4202 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ)) {
4203 disable_irq(host->core_irqres->start);
4204 host->sdcc_irq_disabled = 1;
4205
4206 /*
4207 * If MMC core level suspend is not supported,
4208 * turn off clocks to allow deep sleep (TCXO
4209 * shutdown).
4210 */
4211 mmc->ios.clock = 0;
4212 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4213 enable_irq(host->core_irqres->start);
4214 host->sdcc_irq_disabled = 0;
4215
4216 if (host->plat->sdiowakeup_irq) {
4217 host->sdio_irq_disabled = 0;
4218 msmsdcc_enable_irq_wake(host);
4219 enable_irq(host->plat->sdiowakeup_irq);
4220 }
4221 }
4222 }
4223 host->sdcc_suspending = 0;
4224 mmc->suspend_task = NULL;
4225 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
4226 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004227 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304228 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004229 return rc;
4230}
4231
4232static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004233msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004234{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004235 struct mmc_host *mmc = dev_get_drvdata(dev);
4236 struct msmsdcc_host *host = mmc_priv(mmc);
4237 unsigned long flags;
4238
4239 if (host->plat->is_sdio_al_client)
4240 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07004241
Sahitya Tummala7661a452011-07-18 13:28:35 +05304242 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004243 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004244 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
4245 if (host->sdcc_irq_disabled) {
4246 enable_irq(host->core_irqres->start);
4247 host->sdcc_irq_disabled = 0;
4248 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304249 mmc->ios.clock = host->clk_rate;
4250 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07004251
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304252 spin_lock_irqsave(&host->lock, flags);
4253 writel_relaxed(host->mci_irqenable,
4254 host->base + MMCIMASK0);
4255 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07004256
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304257 if ((mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) &&
4258 !host->sdio_irq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004259 if (host->plat->sdiowakeup_irq) {
4260 disable_irq_nosync(
4261 host->plat->sdiowakeup_irq);
4262 msmsdcc_disable_irq_wake(host);
4263 host->sdio_irq_disabled = 1;
4264 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304265 }
San Mehat9d2bd732009-09-22 16:44:22 -07004266
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304267 spin_unlock_irqrestore(&host->lock, flags);
4268 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004269
4270 mmc_resume_host(mmc);
4271
4272 /*
4273 * FIXME: Clearing of flags must be handled in clients
4274 * resume handler.
4275 */
4276 spin_lock_irqsave(&host->lock, flags);
4277 mmc->pm_flags = 0;
4278 spin_unlock_irqrestore(&host->lock, flags);
4279
4280 /*
4281 * After resuming the host wait for sometime so that
4282 * the SDIO work will be processed.
4283 */
4284 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO)) {
4285 if ((host->plat->cfg_mpm_sdiowakeup ||
4286 host->plat->sdiowakeup_irq) &&
4287 wake_lock_active(&host->sdio_wlock))
4288 wake_lock_timeout(&host->sdio_wlock, 1);
4289 }
4290
4291 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004292 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304293 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004294 return 0;
4295}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004296
4297static int msmsdcc_runtime_idle(struct device *dev)
4298{
4299 struct mmc_host *mmc = dev_get_drvdata(dev);
4300 struct msmsdcc_host *host = mmc_priv(mmc);
4301
4302 if (host->plat->is_sdio_al_client)
4303 return 0;
4304
4305 /* Idle timeout is not configurable for now */
4306 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
4307
4308 return -EAGAIN;
4309}
4310
4311static int msmsdcc_pm_suspend(struct device *dev)
4312{
4313 struct mmc_host *mmc = dev_get_drvdata(dev);
4314 struct msmsdcc_host *host = mmc_priv(mmc);
4315 int rc = 0;
4316
4317 if (host->plat->is_sdio_al_client)
4318 return 0;
4319
4320
4321 if (host->plat->status_irq)
4322 disable_irq(host->plat->status_irq);
4323
4324 if (!pm_runtime_suspended(dev))
4325 rc = msmsdcc_runtime_suspend(dev);
4326
4327 return rc;
4328}
4329
4330static int msmsdcc_pm_resume(struct device *dev)
4331{
4332 struct mmc_host *mmc = dev_get_drvdata(dev);
4333 struct msmsdcc_host *host = mmc_priv(mmc);
4334 int rc = 0;
4335
4336 if (host->plat->is_sdio_al_client)
4337 return 0;
4338
Sahitya Tummalafb486372011-09-02 19:01:49 +05304339 if (!pm_runtime_suspended(dev))
4340 rc = msmsdcc_runtime_resume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004341 if (host->plat->status_irq) {
4342 msmsdcc_check_status((unsigned long)host);
4343 enable_irq(host->plat->status_irq);
4344 }
4345
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004346 return rc;
4347}
4348
Daniel Walker08ecfde2010-06-23 12:32:20 -07004349#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004350#define msmsdcc_runtime_suspend NULL
4351#define msmsdcc_runtime_resume NULL
4352#define msmsdcc_runtime_idle NULL
4353#define msmsdcc_pm_suspend NULL
4354#define msmsdcc_pm_resume NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07004355#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004356
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004357static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
4358 .runtime_suspend = msmsdcc_runtime_suspend,
4359 .runtime_resume = msmsdcc_runtime_resume,
4360 .runtime_idle = msmsdcc_runtime_idle,
4361 .suspend = msmsdcc_pm_suspend,
4362 .resume = msmsdcc_pm_resume,
4363};
4364
San Mehat9d2bd732009-09-22 16:44:22 -07004365static struct platform_driver msmsdcc_driver = {
4366 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004367 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07004368 .driver = {
4369 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004370 .pm = &msmsdcc_dev_pm_ops,
San Mehat9d2bd732009-09-22 16:44:22 -07004371 },
4372};
4373
4374static int __init msmsdcc_init(void)
4375{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004376#if defined(CONFIG_DEBUG_FS)
4377 int ret = 0;
4378 ret = msmsdcc_dbg_init();
4379 if (ret) {
4380 pr_err("Failed to create debug fs dir \n");
4381 return ret;
4382 }
4383#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004384 return platform_driver_register(&msmsdcc_driver);
4385}
4386
4387static void __exit msmsdcc_exit(void)
4388{
4389 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004390
4391#if defined(CONFIG_DEBUG_FS)
4392 debugfs_remove(debugfs_file);
4393 debugfs_remove(debugfs_dir);
4394#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004395}
4396
4397module_init(msmsdcc_init);
4398module_exit(msmsdcc_exit);
4399
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004400MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07004401MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004402
4403#if defined(CONFIG_DEBUG_FS)
4404
4405static int
4406msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
4407{
4408 file->private_data = inode->i_private;
4409 return 0;
4410}
4411
4412static ssize_t
4413msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
4414 size_t count, loff_t *ppos)
4415{
4416 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
4417 char buf[1024];
4418 int max, i;
4419
4420 i = 0;
4421 max = sizeof(buf) - 1;
4422
4423 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
4424 host->curr.cmd, host->curr.data);
4425 if (host->curr.cmd) {
4426 struct mmc_command *cmd = host->curr.cmd;
4427
4428 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
4429 cmd->opcode, cmd->arg, cmd->flags);
4430 }
4431 if (host->curr.data) {
4432 struct mmc_data *data = host->curr.data;
4433 i += scnprintf(buf + i, max - i,
4434 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
4435 data->timeout_ns, data->timeout_clks,
4436 data->blksz, data->blocks, data->error,
4437 data->flags);
4438 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
4439 host->curr.xfer_size, host->curr.xfer_remain,
4440 host->curr.data_xfered, host->dma.sg);
4441 }
4442
4443 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
4444}
4445
4446static const struct file_operations msmsdcc_dbg_state_ops = {
4447 .read = msmsdcc_dbg_state_read,
4448 .open = msmsdcc_dbg_state_open,
4449};
4450
4451static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
4452{
4453 if (debugfs_dir) {
4454 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
4455 0644, debugfs_dir, host,
4456 &msmsdcc_dbg_state_ops);
4457 }
4458}
4459
4460static int __init msmsdcc_dbg_init(void)
4461{
4462 int err;
4463
4464 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
4465 if (IS_ERR(debugfs_dir)) {
4466 err = PTR_ERR(debugfs_dir);
4467 debugfs_dir = NULL;
4468 return err;
4469 }
4470
4471 return 0;
4472}
4473#endif