blob: 4a475c64576e7613864fe4989e3f4515669df7b9 [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{
Pratibhasagar V1c11da62011-11-14 12:36:35 +0530247 if (host->sdcc_version) {
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
Pratibhasagar V1c11da62011-11-14 12:36:35 +0530348 if (host->sdcc_version &&
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530349 (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
Subhash Jadavani7d572f12011-11-13 13:09:36 +0530969 BUG_ON(!data->sg);
970 BUG_ON(!data->sg_len);
971
San Mehat9d2bd732009-09-22 16:44:22 -0700972 host->curr.data = data;
973 host->curr.xfer_size = data->blksz * data->blocks;
974 host->curr.xfer_remain = host->curr.xfer_size;
975 host->curr.data_xfered = 0;
976 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530977 host->curr.got_auto_prog_done = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700978
979 memset(&host->pio, 0, sizeof(host->pio));
980
San Mehat9d2bd732009-09-22 16:44:22 -0700981 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
982
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530983 if (host->curr.wait_for_auto_prog_done)
984 datactrl |= MCI_AUTO_PROG_DONE;
985
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700986 if (!msmsdcc_check_dma_op_req(data)) {
987 if (host->is_dma_mode && !msmsdcc_config_dma(host, data)) {
988 datactrl |= MCI_DPSM_DMAENABLE;
989 } else if (host->is_sps_mode) {
990 if (!msmsdcc_is_dml_busy(host)) {
991 if (!msmsdcc_sps_start_xfer(host, data)) {
992 /* Now kick start DML transfer */
993 mb();
994 msmsdcc_dml_start_xfer(host, data);
995 datactrl |= MCI_DPSM_DMAENABLE;
996 host->sps.busy = 1;
997 }
998 } else {
999 /*
1000 * Can't proceed with new transfer as
1001 * previous trasnfer is already in progress.
1002 * There is no point of going into PIO mode
1003 * as well. Is this a time to do kernel panic?
1004 */
1005 pr_err("%s: %s: DML HW is busy!!!"
1006 " Can't perform new SPS transfers"
1007 " now\n", mmc_hostname(host->mmc),
1008 __func__);
1009 }
1010 }
1011 }
1012
1013 /* Is data transfer in PIO mode required? */
1014 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001015 host->pio.sg = data->sg;
1016 host->pio.sg_len = data->sg_len;
1017 host->pio.sg_off = 0;
1018
1019 if (data->flags & MMC_DATA_READ) {
1020 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1021 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1022 pio_irqmask |= MCI_RXDATAAVLBLMASK;
1023 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001024 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1025 MCI_TXFIFOEMPTYMASK;
San Mehat9d2bd732009-09-22 16:44:22 -07001026 }
1027
1028 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301029 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
San Mehat9d2bd732009-09-22 16:44:22 -07001030
San Mehat56a8b5b2009-11-21 12:29:46 -08001031 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001032 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001033 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -07001034
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001035 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
1036 /* Use ADM (Application Data Mover) HW for Data transfer */
1037 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001038 host->cmd_timeout = timeout;
1039 host->cmd_pio_irqmask = pio_irqmask;
1040 host->cmd_datactrl = datactrl;
1041 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001042
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001043 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1044 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001045 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001046
1047 if (cmd) {
1048 msmsdcc_start_command_deferred(host, cmd, &c);
1049 host->cmd_c = c;
1050 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001051 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1052 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1053 host->base + MMCIMASK0);
1054 mb();
1055 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001056 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001057 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001058 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001059
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001060 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001061
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001062 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1063 (~(MCI_IRQ_PIO))) | pio_irqmask,
1064 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001065 writel_relaxed(datactrl, base + MMCIDATACTRL);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301066 /*
1067 * We don't need delay after writing to DATA_CTRL register
1068 * if we are not writing to CMD register immediately after
1069 * this. As we already have delay before sending the
1070 * command, we just need mb() here.
1071 */
1072 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001073
1074 if (cmd) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001075 msmsdcc_delay(host); /* Delay between data/command */
San Mehat56a8b5b2009-11-21 12:29:46 -08001076 /* Daisy-chain the command if requested */
1077 msmsdcc_start_command(host, cmd, c);
1078 }
San Mehat9d2bd732009-09-22 16:44:22 -07001079 }
1080}
1081
1082static void
1083msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1084{
San Mehat56a8b5b2009-11-21 12:29:46 -08001085 msmsdcc_start_command_deferred(host, cmd, &c);
1086 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001087}
1088
1089static void
1090msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1091 unsigned int status)
1092{
1093 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001094 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1095 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1096 pr_err("%s: Data CRC error\n",
1097 mmc_hostname(host->mmc));
1098 pr_err("%s: opcode 0x%.8x\n", __func__,
1099 data->mrq->cmd->opcode);
1100 pr_err("%s: blksz %d, blocks %d\n", __func__,
1101 data->blksz, data->blocks);
1102 data->error = -EILSEQ;
1103 }
San Mehat9d2bd732009-09-22 16:44:22 -07001104 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001105 /* CRC is optional for the bus test commands, not all
1106 * cards respond back with CRC. However controller
1107 * waits for the CRC and times out. Hence ignore the
1108 * data timeouts during the Bustest.
1109 */
1110 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1111 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1112 pr_err("%s: Data timeout\n",
1113 mmc_hostname(host->mmc));
1114 data->error = -ETIMEDOUT;
1115 }
San Mehat9d2bd732009-09-22 16:44:22 -07001116 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001117 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001118 data->error = -EIO;
1119 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001120 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001121 data->error = -EIO;
1122 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001123 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001124 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001125 data->error = -EIO;
1126 }
San Mehat9d2bd732009-09-22 16:44:22 -07001127
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001128 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001129 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001130 host->dummy_52_needed = 0;
1131}
San Mehat9d2bd732009-09-22 16:44:22 -07001132
1133static int
1134msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1135{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001136 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001137 uint32_t *ptr = (uint32_t *) buffer;
1138 int count = 0;
1139
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301140 if (remain % 4)
1141 remain = ((remain >> 2) + 1) << 2;
1142
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001143 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1144
1145 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001146 ptr++;
1147 count += sizeof(uint32_t);
1148
1149 remain -= sizeof(uint32_t);
1150 if (remain == 0)
1151 break;
1152 }
1153 return count;
1154}
1155
1156static int
1157msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001158 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001159{
1160 void __iomem *base = host->base;
1161 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001162 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001163
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001164 while (readl_relaxed(base + MMCISTATUS) &
1165 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1166 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001167
San Mehat9d2bd732009-09-22 16:44:22 -07001168 count = min(remain, maxcnt);
1169
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301170 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1171 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001172 ptr += count;
1173 remain -= count;
1174
1175 if (remain == 0)
1176 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001177 }
1178 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001179
1180 return ptr - buffer;
1181}
1182
San Mehat1cd22962010-02-03 12:59:29 -08001183static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001184msmsdcc_pio_irq(int irq, void *dev_id)
1185{
1186 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001187 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001188 uint32_t status;
1189
Murali Palnati36448a42011-09-02 15:06:18 +05301190 spin_lock(&host->lock);
1191
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001192 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001193
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001194 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301195 (MCI_IRQ_PIO)) == 0) {
1196 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001197 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301198 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001199
1200#if IRQ_DEBUG
1201 msmsdcc_print_status(host, "irq1-r", status);
1202#endif
1203
San Mehat9d2bd732009-09-22 16:44:22 -07001204 do {
1205 unsigned long flags;
1206 unsigned int remain, len;
1207 char *buffer;
1208
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001209 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1210 | MCI_RXDATAAVLBL)))
1211 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001212
1213 /* Map the current scatter buffer */
1214 local_irq_save(flags);
1215 buffer = kmap_atomic(sg_page(host->pio.sg),
1216 KM_BIO_SRC_IRQ) + host->pio.sg->offset;
1217 buffer += host->pio.sg_off;
1218 remain = host->pio.sg->length - host->pio.sg_off;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001219
San Mehat9d2bd732009-09-22 16:44:22 -07001220 len = 0;
1221 if (status & MCI_RXACTIVE)
1222 len = msmsdcc_pio_read(host, buffer, remain);
1223 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001224 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001225
1226 /* Unmap the buffer */
1227 kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
1228 local_irq_restore(flags);
1229
1230 host->pio.sg_off += len;
1231 host->curr.xfer_remain -= len;
1232 host->curr.data_xfered += len;
1233 remain -= len;
1234
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001235 if (remain) /* Done with this page? */
1236 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001237
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001238 if (status & MCI_RXACTIVE && host->curr.user_pages)
1239 flush_dcache_page(sg_page(host->pio.sg));
San Mehat9d2bd732009-09-22 16:44:22 -07001240
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001241 if (!--host->pio.sg_len) {
1242 memset(&host->pio, 0, sizeof(host->pio));
1243 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001244 }
1245
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001246 /* Advance to next sg */
1247 host->pio.sg++;
1248 host->pio.sg_off = 0;
1249
1250 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001251 } while (1);
1252
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001253 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1254 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1255 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1256 host->base + MMCIMASK0);
1257 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301258 /*
1259 * back to back write to MASK0 register don't need
1260 * synchronization delay.
1261 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001262 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1263 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1264 }
1265 mb();
1266 } else if (!host->curr.xfer_remain) {
1267 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1268 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1269 mb();
1270 }
San Mehat9d2bd732009-09-22 16:44:22 -07001271
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001272 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001273
1274 return IRQ_HANDLED;
1275}
1276
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001277static void
1278msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1279
1280static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1281 struct mmc_data *data)
1282{
1283 u32 loop_cnt = 0;
1284
1285 /*
1286 * For read commands with data less than fifo size, it is possible to
1287 * get DATAEND first and RXDATA_AVAIL might be set later because of
1288 * synchronization delay through the asynchronous RX FIFO. Thus, for
1289 * such cases, even after DATAEND interrupt is received software
1290 * should poll for RXDATA_AVAIL until the requested data is read out
1291 * of FIFO. This change is needed to get around this abnormal but
1292 * sometimes expected behavior of SDCC3 controller.
1293 *
1294 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1295 * after the data is loaded into RX FIFO. This would amount to less
1296 * than a microsecond and thus looping for 1000 times is good enough
1297 * for that delay.
1298 */
1299 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1300 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1301 spin_unlock(&host->lock);
1302 msmsdcc_pio_irq(1, host);
1303 spin_lock(&host->lock);
1304 }
1305 }
1306 if (loop_cnt == 1000) {
1307 pr_info("%s: Timed out while polling for Rx Data\n",
1308 mmc_hostname(host->mmc));
1309 data->error = -ETIMEDOUT;
1310 msmsdcc_reset_and_restore(host);
1311 }
1312}
1313
San Mehat9d2bd732009-09-22 16:44:22 -07001314static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1315{
1316 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001317
1318 host->curr.cmd = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001319 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1320 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1321 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1322 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -07001323
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001324 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Sahitya Tummala5a0ae912011-07-18 13:34:01 +05301325 pr_debug("%s: Command timeout\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001326 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001327 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
1328 !host->cmd19_tuning_in_progress) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001329 pr_err("%s: Command CRC error\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001330 cmd->error = -EILSEQ;
1331 }
1332
1333 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001334 if (host->curr.data && host->dma.sg &&
1335 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001336 msm_dmov_stop_cmd(host->dma.channel,
1337 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001338 else if (host->curr.data && host->sps.sg &&
1339 host->is_sps_mode){
1340 /* Stop current SPS transfer */
1341 msmsdcc_sps_exit_curr_xfer(host);
1342 }
San Mehat9d2bd732009-09-22 16:44:22 -07001343 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301344 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001345 msmsdcc_stop_data(host);
1346 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301347 } else { /* host->data == NULL */
1348 if (!cmd->error && host->prog_enable) {
1349 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001350 host->prog_enable = 0;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301351 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001352 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301353 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301354 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301355 host->prog_enable = 0;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001356 if (host->dummy_52_needed)
1357 host->dummy_52_needed = 0;
1358 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001359 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301360 msmsdcc_request_end(host, cmd->mrq);
1361 }
1362 }
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301363 } else if ((cmd == host->curr.mrq->sbc) && cmd->data) {
1364 if (cmd->data->flags & MMC_DATA_READ)
1365 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1366 else
1367 msmsdcc_request_start(host, host->curr.mrq);
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301368 } else if (cmd->data) {
1369 if (!(cmd->data->flags & MMC_DATA_READ))
1370 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001371 }
1372}
1373
San Mehat9d2bd732009-09-22 16:44:22 -07001374static irqreturn_t
1375msmsdcc_irq(int irq, void *dev_id)
1376{
1377 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001378 u32 status;
1379 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001380 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001381
1382 spin_lock(&host->lock);
1383
1384 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001385 struct mmc_command *cmd;
1386 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001387
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001388 if (timer) {
1389 timer = 0;
1390 msmsdcc_delay(host);
1391 }
San Mehat865c8062009-11-13 13:42:06 -08001392
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001393 if (!host->clks_on) {
1394 pr_debug("%s: %s: SDIO async irq received\n",
1395 mmc_hostname(host->mmc), __func__);
1396 host->mmc->ios.clock = host->clk_rate;
1397 spin_unlock(&host->lock);
1398 host->mmc->ops->set_ios(host->mmc, &host->mmc->ios);
1399 spin_lock(&host->lock);
1400 if (host->plat->cfg_mpm_sdiowakeup &&
1401 (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
1402 wake_lock(&host->sdio_wlock);
1403 /* only ansyc interrupt can come when clocks are off */
1404 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301405 if (host->clk_rate <=
1406 msmsdcc_get_min_sup_clk_rate(host))
1407 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001408 }
1409
1410 status = readl_relaxed(host->base + MMCISTATUS);
1411
1412 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1413 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001414 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001415
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001416#if IRQ_DEBUG
1417 msmsdcc_print_status(host, "irq0-r", status);
1418#endif
1419 status &= readl_relaxed(host->base + MMCIMASK0);
1420 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301421 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301422 if (host->clk_rate <=
1423 msmsdcc_get_min_sup_clk_rate(host))
1424 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001425#if IRQ_DEBUG
1426 msmsdcc_print_status(host, "irq0-p", status);
1427#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001428
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001429#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
1430 if (status & MCI_SDIOINTROPE) {
1431 if (host->sdcc_suspending)
1432 wake_lock(&host->sdio_suspend_wlock);
1433 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001434 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001435#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001436 data = host->curr.data;
1437
1438 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001439 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1440 MCI_CMDTIMEOUT)) {
1441 if (status & MCI_CMDTIMEOUT)
1442 pr_debug("%s: dummy CMD52 timeout\n",
1443 mmc_hostname(host->mmc));
1444 if (status & MCI_CMDCRCFAIL)
1445 pr_debug("%s: dummy CMD52 CRC failed\n",
1446 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001447 host->dummy_52_sent = 0;
1448 host->dummy_52_needed = 0;
1449 if (data) {
1450 msmsdcc_stop_data(host);
1451 msmsdcc_request_end(host, data->mrq);
1452 }
1453 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001454 spin_unlock(&host->lock);
1455 return IRQ_HANDLED;
1456 }
1457 break;
1458 }
1459
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001460 /*
1461 * Check for proper command response
1462 */
1463 cmd = host->curr.cmd;
1464 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1465 MCI_CMDTIMEOUT | MCI_PROGDONE |
1466 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1467 msmsdcc_do_cmdirq(host, status);
1468 }
1469
1470 if (data) {
1471 /* Check for data errors */
1472 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1473 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1474 msmsdcc_data_err(host, data, status);
1475 host->curr.data_xfered = 0;
1476 if (host->dma.sg && host->is_dma_mode)
1477 msm_dmov_stop_cmd(host->dma.channel,
1478 &host->dma.hdr, 0);
1479 else if (host->sps.sg && host->is_sps_mode) {
1480 /* Stop current SPS transfer */
1481 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301482 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001483 msmsdcc_reset_and_restore(host);
1484 if (host->curr.data)
1485 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301486 if (!data->stop || (host->curr.mrq->sbc
1487 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001488 timer |=
1489 msmsdcc_request_end(host,
1490 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301491 else if ((host->curr.mrq->sbc
1492 && data->error) ||
1493 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001494 msmsdcc_start_command(host,
1495 data->stop,
1496 0);
1497 timer = 1;
1498 }
1499 }
1500 }
1501
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301502 /* Check for prog done */
1503 if (host->curr.wait_for_auto_prog_done &&
1504 (status & MCI_PROGDONE))
1505 host->curr.got_auto_prog_done = 1;
1506
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001507 /* Check for data done */
1508 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1509 host->curr.got_dataend = 1;
1510
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301511 if (host->curr.got_dataend &&
1512 (!host->curr.wait_for_auto_prog_done ||
1513 (host->curr.wait_for_auto_prog_done &&
1514 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001515 /*
1516 * If DMA is still in progress, we complete
1517 * via the completion handler
1518 */
1519 if (!host->dma.busy && !host->sps.busy) {
1520 /*
1521 * There appears to be an issue in the
1522 * controller where if you request a
1523 * small block transfer (< fifo size),
1524 * you may get your DATAEND/DATABLKEND
1525 * irq without the PIO data irq.
1526 *
1527 * Check to see if theres still data
1528 * to be read, and simulate a PIO irq.
1529 */
1530 if (data->flags & MMC_DATA_READ)
1531 msmsdcc_wait_for_rxdata(host,
1532 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001533 if (!data->error) {
1534 host->curr.data_xfered =
1535 host->curr.xfer_size;
1536 host->curr.xfer_remain -=
1537 host->curr.xfer_size;
1538 }
1539
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001540 if (!host->dummy_52_needed) {
1541 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301542 if (!data->stop ||
1543 (host->curr.mrq->sbc
1544 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001545 msmsdcc_request_end(
1546 host,
1547 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301548 else if ((host->curr.mrq->sbc
1549 && data->error) ||
1550 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001551 msmsdcc_start_command(
1552 host,
1553 data->stop, 0);
1554 timer = 1;
1555 }
1556 } else {
1557 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001558 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001559 &dummy52cmd,
1560 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001561 }
1562 }
1563 }
1564 }
1565
San Mehat9d2bd732009-09-22 16:44:22 -07001566 ret = 1;
1567 } while (status);
1568
1569 spin_unlock(&host->lock);
1570
San Mehat9d2bd732009-09-22 16:44:22 -07001571 return IRQ_RETVAL(ret);
1572}
1573
1574static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001575msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1576{
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301577 if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001578 /* Queue/read data, daisy-chain command when data starts */
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301579 if (mrq->sbc)
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301580 msmsdcc_start_data(host, mrq->data, mrq->sbc, 0);
1581 else
1582 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001583 } else {
1584 msmsdcc_start_command(host, mrq->cmd, 0);
1585 }
1586}
1587
1588static void
San Mehat9d2bd732009-09-22 16:44:22 -07001589msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1590{
1591 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001592 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001593
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001594 /*
1595 * Get the SDIO AL client out of LPM.
1596 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001597 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001598 if (host->plat->is_sdio_al_client)
1599 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001600
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301601 /* check if sps pipe reset is pending? */
1602 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1603 msmsdcc_sps_pipes_reset_and_restore(host);
1604 host->sps.pipe_reset_pending = false;
1605 }
1606
San Mehat9d2bd732009-09-22 16:44:22 -07001607 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001608 WARN(host->curr.mrq, "Request in progress\n");
1609 WARN(!host->pwr, "SDCC power is turned off\n");
1610 WARN(!host->clks_on, "SDCC clocks are turned off\n");
1611 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
San Mehat9d2bd732009-09-22 16:44:22 -07001612
1613 if (host->eject) {
1614 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1615 mrq->cmd->error = 0;
1616 mrq->data->bytes_xfered = mrq->data->blksz *
1617 mrq->data->blocks;
1618 } else
1619 mrq->cmd->error = -ENOMEDIUM;
1620
1621 spin_unlock_irqrestore(&host->lock, flags);
1622 mmc_request_done(mmc, mrq);
1623 return;
1624 }
1625
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301626 /*
1627 * Kick the software command timeout timer here.
1628 * Timer expires in 10 secs.
1629 */
1630 mod_timer(&host->req_tout_timer,
1631 (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
San Mehat9d2bd732009-09-22 16:44:22 -07001632
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301633 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301634 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301635 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
1636 mrq->cmd->opcode == 54) {
Pratibhasagar V1c11da62011-11-14 12:36:35 +05301637 if (!host->sdcc_version)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001638 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301639 else
1640 /*
1641 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
1642 * write operations using CMD53 and CMD54.
1643 * Setting this bit with CMD53 would
1644 * automatically triggers PROG_DONE interrupt
1645 * without the need of sending dummy CMD52.
1646 */
1647 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001648 }
San Mehat9d2bd732009-09-22 16:44:22 -07001649 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301650
Pratibhasagar V00b94332011-10-18 14:57:27 +05301651 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301652 mrq->sbc->mrq = mrq;
1653 mrq->sbc->data = mrq->data;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301654 if (mrq->data->flags & MMC_DATA_WRITE) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301655 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301656 msmsdcc_start_command(host, mrq->sbc, 0);
1657 } else {
1658 msmsdcc_request_start(host, mrq);
1659 }
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301660 } else {
1661 msmsdcc_request_start(host, mrq);
1662 }
1663
San Mehat9d2bd732009-09-22 16:44:22 -07001664 spin_unlock_irqrestore(&host->lock, flags);
1665}
1666
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001667static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1668 int min_uV, int max_uV)
1669{
1670 int rc = 0;
1671
1672 if (vreg->set_voltage_sup) {
1673 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1674 if (rc) {
1675 pr_err("%s: regulator_set_voltage(%s) failed."
1676 " min_uV=%d, max_uV=%d, rc=%d\n",
1677 __func__, vreg->name, min_uV, max_uV, rc);
1678 }
1679 }
1680
1681 return rc;
1682}
1683
1684static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1685 int uA_load)
1686{
1687 int rc = 0;
1688
Krishna Kondafea60182011-11-01 16:01:34 -07001689 /* regulators that do not support regulator_set_voltage also
1690 do not support regulator_set_optimum_mode */
1691 if (vreg->set_voltage_sup) {
1692 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1693 if (rc < 0)
1694 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
1695 "uA_load=%d) failed. rc=%d\n", __func__,
1696 vreg->name, uA_load, rc);
1697 else
1698 /* regulator_set_optimum_mode() can return non zero
1699 * value even for success case.
1700 */
1701 rc = 0;
1702 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001703
1704 return rc;
1705}
1706
1707static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1708 struct device *dev)
1709{
1710 int rc = 0;
1711
1712 /* check if regulator is already initialized? */
1713 if (vreg->reg)
1714 goto out;
1715
1716 /* Get the regulator handle */
1717 vreg->reg = regulator_get(dev, vreg->name);
1718 if (IS_ERR(vreg->reg)) {
1719 rc = PTR_ERR(vreg->reg);
1720 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
1721 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001722 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001723 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001724
1725 if (regulator_count_voltages(vreg->reg) > 0)
1726 vreg->set_voltage_sup = 1;
1727
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001728out:
1729 return rc;
1730}
1731
1732static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
1733{
1734 if (vreg->reg)
1735 regulator_put(vreg->reg);
1736}
1737
1738/* This init function should be called only once for each SDCC slot */
1739static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
1740{
1741 int rc = 0;
1742 struct msm_mmc_slot_reg_data *curr_slot;
1743 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1744 struct device *dev = mmc_dev(host->mmc);
1745
1746 curr_slot = host->plat->vreg_data;
1747 if (!curr_slot)
1748 goto out;
1749
1750 curr_vdd_reg = curr_slot->vdd_data;
1751 curr_vccq_reg = curr_slot->vccq_data;
1752 curr_vddp_reg = curr_slot->vddp_data;
1753
1754 if (is_init) {
1755 /*
1756 * Get the regulator handle from voltage regulator framework
1757 * and then try to set the voltage level for the regulator
1758 */
1759 if (curr_vdd_reg) {
1760 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
1761 if (rc)
1762 goto out;
1763 }
1764 if (curr_vccq_reg) {
1765 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
1766 if (rc)
1767 goto vdd_reg_deinit;
1768 }
1769 if (curr_vddp_reg) {
1770 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
1771 if (rc)
1772 goto vccq_reg_deinit;
1773 }
1774 goto out;
1775 } else {
1776 /* Deregister all regulators from regulator framework */
1777 goto vddp_reg_deinit;
1778 }
1779vddp_reg_deinit:
1780 if (curr_vddp_reg)
1781 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
1782vccq_reg_deinit:
1783 if (curr_vccq_reg)
1784 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
1785vdd_reg_deinit:
1786 if (curr_vdd_reg)
1787 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
1788out:
1789 return rc;
1790}
1791
1792static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
1793{
1794 int rc = 0;
1795
Subhash Jadavanicc922692011-08-01 23:05:01 +05301796 /* Put regulator in HPM (high power mode) */
1797 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
1798 if (rc < 0)
1799 goto out;
1800
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001801 if (!vreg->is_enabled) {
1802 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301803 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
1804 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001805 if (rc)
1806 goto out;
1807
1808 rc = regulator_enable(vreg->reg);
1809 if (rc) {
1810 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
1811 __func__, vreg->name, rc);
1812 goto out;
1813 }
1814 vreg->is_enabled = true;
1815 }
1816
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001817out:
1818 return rc;
1819}
1820
1821static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
1822{
1823 int rc = 0;
1824
1825 /* Never disable regulator marked as always_on */
1826 if (vreg->is_enabled && !vreg->always_on) {
1827 rc = regulator_disable(vreg->reg);
1828 if (rc) {
1829 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
1830 __func__, vreg->name, rc);
1831 goto out;
1832 }
1833 vreg->is_enabled = false;
1834
1835 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
1836 if (rc < 0)
1837 goto out;
1838
1839 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301840 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001841 if (rc)
1842 goto out;
1843 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
1844 /* Put always_on regulator in LPM (low power mode) */
1845 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
1846 if (rc < 0)
1847 goto out;
1848 }
1849out:
1850 return rc;
1851}
1852
1853static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
1854{
1855 int rc = 0, i;
1856 struct msm_mmc_slot_reg_data *curr_slot;
1857 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1858 struct msm_mmc_reg_data *vreg_table[3];
1859
1860 curr_slot = host->plat->vreg_data;
1861 if (!curr_slot)
1862 goto out;
1863
1864 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
1865 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
1866 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
1867
1868 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
1869 if (vreg_table[i]) {
1870 if (enable)
1871 rc = msmsdcc_vreg_enable(vreg_table[i]);
1872 else
1873 rc = msmsdcc_vreg_disable(vreg_table[i]);
1874 if (rc)
1875 goto out;
1876 }
1877 }
1878out:
1879 return rc;
1880}
1881
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301882static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001883{
1884 int rc = 0;
1885
1886 if (host->plat->vreg_data) {
1887 struct msm_mmc_reg_data *vddp_reg =
1888 host->plat->vreg_data->vddp_data;
1889
1890 if (vddp_reg && vddp_reg->is_enabled)
1891 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
1892 }
1893
1894 return rc;
1895}
1896
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301897static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
1898{
1899 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1900 int rc = 0;
1901
1902 if (curr_slot && curr_slot->vddp_data) {
1903 rc = msmsdcc_set_vddp_level(host,
1904 curr_slot->vddp_data->low_vol_level);
1905
1906 if (rc)
1907 pr_err("%s: %s: failed to change vddp level to %d",
1908 mmc_hostname(host->mmc), __func__,
1909 curr_slot->vddp_data->low_vol_level);
1910 }
1911
1912 return rc;
1913}
1914
1915static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
1916{
1917 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1918 int rc = 0;
1919
1920 if (curr_slot && curr_slot->vddp_data) {
1921 rc = msmsdcc_set_vddp_level(host,
1922 curr_slot->vddp_data->high_vol_level);
1923
1924 if (rc)
1925 pr_err("%s: %s: failed to change vddp level to %d",
1926 mmc_hostname(host->mmc), __func__,
1927 curr_slot->vddp_data->high_vol_level);
1928 }
1929
1930 return rc;
1931}
1932
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001933static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
1934{
1935 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
1936 return 1;
1937 return 0;
1938}
1939
1940static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
1941{
1942 if (enable) {
1943 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1944 clk_enable(host->dfab_pclk);
1945 if (!IS_ERR(host->pclk))
1946 clk_enable(host->pclk);
1947 clk_enable(host->clk);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301948 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001949 } else {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301950 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001951 clk_disable(host->clk);
1952 if (!IS_ERR(host->pclk))
1953 clk_disable(host->pclk);
1954 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1955 clk_disable(host->dfab_pclk);
1956 }
1957}
1958
1959static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
1960 unsigned int req_clk)
1961{
1962 unsigned int sel_clk = -1;
1963
1964 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
1965 unsigned char cnt;
1966
1967 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
1968 if (host->plat->sup_clk_table[cnt] > req_clk)
1969 break;
1970 else if (host->plat->sup_clk_table[cnt] == req_clk) {
1971 sel_clk = host->plat->sup_clk_table[cnt];
1972 break;
1973 } else
1974 sel_clk = host->plat->sup_clk_table[cnt];
1975 }
1976 } else {
1977 if ((req_clk < host->plat->msmsdcc_fmax) &&
1978 (req_clk > host->plat->msmsdcc_fmid))
1979 sel_clk = host->plat->msmsdcc_fmid;
1980 else
1981 sel_clk = req_clk;
1982 }
1983
1984 return sel_clk;
1985}
1986
1987static inline unsigned int msmsdcc_get_min_sup_clk_rate(
1988 struct msmsdcc_host *host)
1989{
1990 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
1991 return host->plat->sup_clk_table[0];
1992 else
1993 return host->plat->msmsdcc_fmin;
1994}
1995
1996static inline unsigned int msmsdcc_get_max_sup_clk_rate(
1997 struct msmsdcc_host *host)
1998{
1999 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2000 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2001 else
2002 return host->plat->msmsdcc_fmax;
2003}
2004
2005static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302006{
2007 struct msm_mmc_gpio_data *curr;
2008 int i, rc = 0;
2009
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002010 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302011 for (i = 0; i < curr->size; i++) {
2012 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002013 if (curr->gpio[i].is_always_on &&
2014 curr->gpio[i].is_enabled)
2015 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302016 rc = gpio_request(curr->gpio[i].no,
2017 curr->gpio[i].name);
2018 if (rc) {
2019 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2020 mmc_hostname(host->mmc),
2021 curr->gpio[i].no,
2022 curr->gpio[i].name, rc);
2023 goto free_gpios;
2024 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002025 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302026 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002027 if (curr->gpio[i].is_always_on)
2028 continue;
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;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302031 }
2032 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002033 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302034
2035free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002036 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302037 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002038 curr->gpio[i].is_enabled = false;
2039 }
2040out:
2041 return rc;
2042}
2043
2044static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2045{
2046 struct msm_mmc_pad_data *curr;
2047 int i;
2048
2049 curr = host->plat->pin_data->pad_data;
2050 for (i = 0; i < curr->drv->size; i++) {
2051 if (enable)
2052 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2053 curr->drv->on[i].val);
2054 else
2055 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2056 curr->drv->off[i].val);
2057 }
2058
2059 for (i = 0; i < curr->pull->size; i++) {
2060 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002061 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002062 curr->pull->on[i].val);
2063 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002064 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002065 curr->pull->off[i].val);
2066 }
2067
2068 return 0;
2069}
2070
2071static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2072{
2073 int rc = 0;
2074
2075 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2076 return 0;
2077
2078 if (host->plat->pin_data->is_gpio)
2079 rc = msmsdcc_setup_gpio(host, enable);
2080 else
2081 rc = msmsdcc_setup_pad(host, enable);
2082
2083 if (!rc)
2084 host->plat->pin_data->cfg_sts = enable;
2085
2086 return rc;
2087}
2088
2089static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2090{
2091 unsigned int wakeup_irq;
2092
2093 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2094 host->plat->sdiowakeup_irq :
2095 host->core_irqres->start;
2096
2097 if (!host->irq_wake_enabled) {
2098 enable_irq_wake(wakeup_irq);
2099 host->irq_wake_enabled = true;
2100 }
2101}
2102
2103static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2104{
2105 unsigned int wakeup_irq;
2106
2107 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2108 host->plat->sdiowakeup_irq :
2109 host->core_irqres->start;
2110
2111 if (host->irq_wake_enabled) {
2112 disable_irq_wake(wakeup_irq);
2113 host->irq_wake_enabled = false;
2114 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302115}
2116
San Mehat9d2bd732009-09-22 16:44:22 -07002117static void
2118msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2119{
2120 struct msmsdcc_host *host = mmc_priv(mmc);
2121 u32 clk = 0, pwr = 0;
2122 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002123 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002124 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002125
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002126 DBG(host, "ios->clock = %u\n", ios->clock);
Sahitya Tummala7a892482011-01-18 11:22:49 +05302127
San Mehat9d2bd732009-09-22 16:44:22 -07002128 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002129 spin_lock_irqsave(&host->lock, flags);
2130 if (!host->clks_on) {
2131 msmsdcc_setup_clocks(host, true);
2132 host->clks_on = 1;
2133 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2134 if (!host->plat->sdiowakeup_irq) {
2135 writel_relaxed(host->mci_irqenable,
2136 host->base + MMCIMASK0);
2137 mb();
2138 if (host->plat->cfg_mpm_sdiowakeup &&
2139 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2140 host->plat->cfg_mpm_sdiowakeup(
2141 mmc_dev(mmc), SDC_DAT1_DISWAKE);
2142 msmsdcc_disable_irq_wake(host);
2143 } else if (!(mmc->pm_flags &
2144 MMC_PM_WAKE_SDIO_IRQ)) {
2145 writel_relaxed(host->mci_irqenable,
2146 host->base + MMCIMASK0);
2147 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05302148 } else {
2149 writel_relaxed(host->mci_irqenable,
2150 host->base + MMCIMASK0);
2151 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002152 }
San Mehat9d2bd732009-09-22 16:44:22 -07002153 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002154 spin_unlock_irqrestore(&host->lock, flags);
2155
2156 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2157 /*
2158 * For DDR50 mode, controller needs clock rate to be
2159 * double than what is required on the SD card CLK pin.
2160 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302161 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002162 /*
2163 * Make sure that we don't double the clock if
2164 * doubled clock rate is already set
2165 */
2166 if (!host->ddr_doubled_clk_rate ||
2167 (host->ddr_doubled_clk_rate &&
2168 (host->ddr_doubled_clk_rate != ios->clock))) {
2169 host->ddr_doubled_clk_rate =
2170 msmsdcc_get_sup_clk_rate(
2171 host, (ios->clock * 2));
2172 clock = host->ddr_doubled_clk_rate;
2173 }
2174 } else {
2175 host->ddr_doubled_clk_rate = 0;
2176 }
2177
2178 if (clock != host->clk_rate) {
2179 rc = clk_set_rate(host->clk, clock);
2180 if (rc < 0)
2181 pr_debug("%s: failed to set clk rate %u\n",
2182 mmc_hostname(mmc), clock);
2183 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302184 host->reg_write_delay =
2185 (1 + ((3 * USEC_PER_SEC) /
2186 (host->clk_rate ? host->clk_rate :
2187 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002188 }
2189 /*
2190 * give atleast 2 MCLK cycles delay for clocks
2191 * and SDCC core to stabilize
2192 */
2193 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002194 clk |= MCI_CLK_ENABLE;
2195 }
2196
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002197 if (ios->bus_width == MMC_BUS_WIDTH_8)
2198 clk |= MCI_CLK_WIDEBUS_8;
2199 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2200 clk |= MCI_CLK_WIDEBUS_4;
2201 else
2202 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002203
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002204 if (msmsdcc_is_pwrsave(host))
2205 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002206
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002207 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002208
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002209 host->tuning_needed = 0;
2210 /*
2211 * Select the controller timing mode according
2212 * to current bus speed mode
2213 */
2214 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2215 (ios->timing == MMC_TIMING_UHS_SDR50)) {
2216 clk |= (4 << 14);
2217 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302218 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002219 clk |= (3 << 14);
2220 } else {
2221 clk |= (2 << 14); /* feedback clock */
2222 }
2223
2224 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2225 clk |= (2 << 23);
2226
2227 if (host->io_pad_pwr_switch)
2228 clk |= IO_PAD_PWR_SWITCH;
2229
2230 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
San Mehat9d2bd732009-09-22 16:44:22 -07002231 pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002232 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2233 pwr |= msmsdcc_setup_vreg(host, !!ios->vdd);
San Mehat9d2bd732009-09-22 16:44:22 -07002234
2235 switch (ios->power_mode) {
2236 case MMC_POWER_OFF:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002237 htc_pwrsink_set(PWRSINK_SDCARD, 0);
2238 if (!host->sdcc_irq_disabled) {
2239 if (host->plat->cfg_mpm_sdiowakeup)
2240 host->plat->cfg_mpm_sdiowakeup(
2241 mmc_dev(mmc), SDC_DAT1_DISABLE);
2242 disable_irq(host->core_irqres->start);
2243 host->sdcc_irq_disabled = 1;
2244 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302245 /*
2246 * As VDD pad rail is always on, set low voltage for VDD
2247 * pad rail when slot is unused (when card is not present
2248 * or during system suspend).
2249 */
2250 msmsdcc_set_vddp_low_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002251 msmsdcc_setup_pins(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002252 break;
2253 case MMC_POWER_UP:
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302254 /* writing PWR_UP bit is redundant */
San Mehat9d2bd732009-09-22 16:44:22 -07002255 pwr |= MCI_PWR_UP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002256 if (host->sdcc_irq_disabled) {
2257 if (host->plat->cfg_mpm_sdiowakeup)
2258 host->plat->cfg_mpm_sdiowakeup(
2259 mmc_dev(mmc), SDC_DAT1_ENABLE);
2260 enable_irq(host->core_irqres->start);
2261 host->sdcc_irq_disabled = 0;
2262 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302263 msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002264 msmsdcc_setup_pins(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07002265 break;
2266 case MMC_POWER_ON:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002267 htc_pwrsink_set(PWRSINK_SDCARD, 100);
San Mehat9d2bd732009-09-22 16:44:22 -07002268 pwr |= MCI_PWR_ON;
2269 break;
2270 }
2271
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002272 spin_lock_irqsave(&host->lock, flags);
2273 if (!host->clks_on) {
2274 /* force the clocks to be on */
2275 msmsdcc_setup_clocks(host, true);
2276 /*
2277 * give atleast 2 MCLK cycles delay for clocks
2278 * and SDCC core to stabilize
2279 */
2280 msmsdcc_delay(host);
2281 }
2282 writel_relaxed(clk, host->base + MMCICLOCK);
2283 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002284
2285 if (host->pwr != pwr) {
2286 host->pwr = pwr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002287 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302288 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002289 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002290 if (!host->clks_on) {
2291 /* force the clocks to be off */
2292 msmsdcc_setup_clocks(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002293 }
2294
2295 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
2296 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2297 if (!host->plat->sdiowakeup_irq) {
2298 writel_relaxed(MCI_SDIOINTMASK,
2299 host->base + MMCIMASK0);
2300 mb();
2301 if (host->plat->cfg_mpm_sdiowakeup &&
2302 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2303 host->plat->cfg_mpm_sdiowakeup(
2304 mmc_dev(mmc), SDC_DAT1_ENWAKE);
2305 msmsdcc_enable_irq_wake(host);
2306 } else if (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2307 writel_relaxed(0, host->base + MMCIMASK0);
2308 } else {
2309 writel_relaxed(MCI_SDIOINTMASK,
2310 host->base + MMCIMASK0);
2311 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302312 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002313 }
2314 msmsdcc_setup_clocks(host, false);
2315 host->clks_on = 0;
2316 }
San Mehat4adbbcc2009-11-08 13:00:37 -08002317 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002318}
2319
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002320int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2321{
2322 struct msmsdcc_host *host = mmc_priv(mmc);
2323 u32 clk;
2324
2325 clk = readl_relaxed(host->base + MMCICLOCK);
2326 pr_debug("Changing to pwr_save=%d", pwrsave);
2327 if (pwrsave && msmsdcc_is_pwrsave(host))
2328 clk |= MCI_CLK_PWRSAVE;
2329 else
2330 clk &= ~MCI_CLK_PWRSAVE;
2331 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302332 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002333
2334 return 0;
2335}
2336
2337static int msmsdcc_get_ro(struct mmc_host *mmc)
2338{
2339 int status = -ENOSYS;
2340 struct msmsdcc_host *host = mmc_priv(mmc);
2341
2342 if (host->plat->wpswitch) {
2343 status = host->plat->wpswitch(mmc_dev(mmc));
2344 } else if (host->plat->wpswitch_gpio) {
2345 status = gpio_request(host->plat->wpswitch_gpio,
2346 "SD_WP_Switch");
2347 if (status) {
2348 pr_err("%s: %s: Failed to request GPIO %d\n",
2349 mmc_hostname(mmc), __func__,
2350 host->plat->wpswitch_gpio);
2351 } else {
2352 status = gpio_direction_input(
2353 host->plat->wpswitch_gpio);
2354 if (!status) {
2355 /*
2356 * Wait for atleast 300ms as debounce
2357 * time for GPIO input to stabilize.
2358 */
2359 msleep(300);
2360 status = gpio_get_value_cansleep(
2361 host->plat->wpswitch_gpio);
2362 status ^= !host->plat->wpswitch_polarity;
2363 }
2364 gpio_free(host->plat->wpswitch_gpio);
2365 }
2366 }
2367
2368 if (status < 0)
2369 status = -ENOSYS;
2370 pr_debug("%s: Card read-only status %d\n", __func__, status);
2371
2372 return status;
2373}
2374
2375#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002376static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2377{
2378 struct msmsdcc_host *host = mmc_priv(mmc);
2379 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002380
2381 if (enable) {
2382 spin_lock_irqsave(&host->lock, flags);
2383 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
2384 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
2385 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2386 spin_unlock_irqrestore(&host->lock, flags);
2387 } else {
2388 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
2389 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
2390 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2391 }
2392 mb();
2393}
2394#endif /* CONFIG_MMC_MSM_SDIO_SUPPORT */
2395
2396#ifdef CONFIG_PM_RUNTIME
2397static int msmsdcc_enable(struct mmc_host *mmc)
2398{
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302399 int rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002400 struct device *dev = mmc->parent;
2401
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302402 if (dev->power.runtime_status == RPM_SUSPENDING) {
2403 if (mmc->suspend_task == current) {
2404 pm_runtime_get_noresume(dev);
2405 goto out;
2406 }
2407 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002408
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302409 rc = pm_runtime_get_sync(dev);
2410
2411 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002412 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2413 __func__, rc);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302414 return rc;
2415 }
2416out:
2417 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002418}
2419
2420static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2421{
2422 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302423 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002424
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302425 if (host->plat->disable_runtime_pm)
2426 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002427 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO)
2428 return -ENOTSUPP;
2429
2430 rc = pm_runtime_put_sync(mmc->parent);
2431
2432 if (rc < 0)
2433 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2434 __func__, rc);
2435 return rc;
2436}
2437#else
2438#define msmsdcc_enable NULL
2439#define msmsdcc_disable NULL
2440#endif
2441
2442static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2443 struct mmc_ios *ios)
2444{
2445 struct msmsdcc_host *host = mmc_priv(mmc);
2446 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302447 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002448
2449 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2450 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302451 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002452 goto out;
2453 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2454 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302455 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002456 goto out;
2457 }
San Mehat9d2bd732009-09-22 16:44:22 -07002458
2459 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002460 /*
2461 * If we are here means voltage switch from high voltage to
2462 * low voltage is required
2463 */
2464
2465 /*
2466 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2467 * register until they become all zeros.
2468 */
2469 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302470 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002471 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2472 mmc_hostname(mmc), __func__);
2473 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002474 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002475
2476 /* Stop SD CLK output. */
2477 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2478 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302479 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002480 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002481
2482 /*
2483 * Switch VDDPX from high voltage to low voltage
2484 * to change the VDD of the SD IO pads.
2485 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302486 rc = msmsdcc_set_vddp_low_vol(host);
2487 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002488 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002489
2490 spin_lock_irqsave(&host->lock, flags);
2491 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2492 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302493 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002494 host->io_pad_pwr_switch = 1;
2495 spin_unlock_irqrestore(&host->lock, flags);
2496
2497 /* Wait 5 ms for the voltage regulater in the card to become stable. */
2498 usleep_range(5000, 5500);
2499
2500 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302501 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002502 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2503 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302504 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002505 spin_unlock_irqrestore(&host->lock, flags);
2506
2507 /*
2508 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
2509 * don't become all ones within 1 ms then a Voltage Switch
2510 * sequence has failed and a power cycle to the card is required.
2511 * Otherwise Voltage Switch sequence is completed successfully.
2512 */
2513 usleep_range(1000, 1500);
2514
2515 spin_lock_irqsave(&host->lock, flags);
2516 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
2517 != (0xF << 1)) {
2518 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
2519 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302520 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002521 goto out_unlock;
2522 }
2523
2524out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302525 /* Enable PWRSAVE */
2526 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2527 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002528 spin_unlock_irqrestore(&host->lock, flags);
2529out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302530 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002531}
2532
2533static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2534 u8 phase);
2535/* Initialize the DLL (Programmable Delay Line ) */
2536static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
2537{
2538 int rc = 0;
2539 u32 wait_timeout;
2540
2541 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
2542 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2543 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2544
2545 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
2546 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2547 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2548
2549 msmsdcc_delay(host);
2550
2551 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
2552 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2553 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2554
2555 /* Initialize the phase to 0 */
2556 rc = msmsdcc_config_cm_sdc4_dll_phase(host, 0);
2557 if (rc)
2558 goto out;
2559
2560 wait_timeout = 1000;
2561 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
2562 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
2563 /* max. wait for 1 sec for LOCK bit to be set */
2564 if (--wait_timeout == 0) {
2565 pr_err("%s: %s: DLL failed to lock at phase: %d",
2566 mmc_hostname(host->mmc), __func__, 0);
2567 rc = -1;
2568 goto out;
2569 }
2570 /* wait for 1ms */
2571 usleep_range(1000, 1500);
2572 }
2573out:
2574 return rc;
2575}
2576
2577/*
2578 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
2579 * calibration sequence. This function should be called before
2580 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
2581 * commands (CMD17/CMD18).
2582 */
2583static void msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
2584{
2585 /* Set CDR_EN bit to 1. */
2586 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) |
2587 MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2588
2589 /* Set CDR_EXT_EN bit to 0. */
2590 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2591 & ~MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2592
2593 /* Set CK_OUT_EN bit to 0. */
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 becomes '0' */
2598 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)
2599 ;
2600
2601 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2602 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2603 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2604
2605 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register is 1. */
2606 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN))
2607 ;
2608}
2609
2610static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2611 u8 phase)
2612{
2613 int rc = 0;
2614 u32 mclk_freq = 0;
2615 u32 wait_timeout;
2616
2617 /* Set CDR_EN bit to 0. */
2618 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2619 & ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2620
2621 /* Set CDR_EXT_EN bit to 1. */
2622 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2623 | MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2624
2625 /* Program the MCLK value to MCLK_FREQ bit field */
2626 if (host->clk_rate <= 112000000)
2627 mclk_freq = 0;
2628 else if (host->clk_rate <= 125000000)
2629 mclk_freq = 1;
2630 else if (host->clk_rate <= 137000000)
2631 mclk_freq = 2;
2632 else if (host->clk_rate <= 150000000)
2633 mclk_freq = 3;
2634 else if (host->clk_rate <= 162000000)
2635 mclk_freq = 4;
2636 else if (host->clk_rate <= 175000000)
2637 mclk_freq = 5;
2638 else if (host->clk_rate <= 187000000)
2639 mclk_freq = 6;
2640 else if (host->clk_rate <= 200000000)
2641 mclk_freq = 7;
2642
2643 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2644 & ~(7 << 24)) | (mclk_freq << 24)),
2645 host->base + MCI_DLL_CONFIG);
2646
2647 /* Set CK_OUT_EN bit to 0. */
2648 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2649 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2650
2651 /* Set DLL_EN bit to 1. */
2652 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2653 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
2654
2655 wait_timeout = 1000;
2656 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2657 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN) {
2658 /* max. wait for 1 sec for LOCK bit for be set */
2659 if (--wait_timeout == 0) {
2660 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 0",
2661 mmc_hostname(host->mmc), __func__, phase);
2662 rc = -1;
2663 goto out;
2664 }
2665 /* wait for 1ms */
2666 usleep_range(1000, 1500);
2667 }
2668
2669 /*
2670 * Write the selected DLL clock output phase (0 ... 15)
2671 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
2672 */
2673 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2674 & ~(0xF << 20)) | (phase << 20)),
2675 host->base + MCI_DLL_CONFIG);
2676
2677 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2678 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2679 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2680
2681 wait_timeout = 1000;
2682 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
2683 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)) {
2684 /* max. wait for 1 sec for LOCK bit for be set */
2685 if (--wait_timeout == 0) {
2686 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 1",
2687 mmc_hostname(host->mmc), __func__, phase);
2688 rc = -1;
2689 goto out;
2690 }
2691 /* wait for 1ms */
2692 usleep_range(1000, 1500);
2693 }
2694out:
2695 return rc;
2696}
2697
2698static int msmsdcc_execute_tuning(struct mmc_host *mmc)
2699{
2700 struct msmsdcc_host *host = mmc_priv(mmc);
2701 u8 phase;
2702 u8 *data_buf;
2703 u8 tuned_phases[16], tuned_phase_cnt = 0;
2704 int rc = 0;
2705
2706 /* Tuning is only required for SDR50 & SDR104 modes */
2707 if (!host->tuning_needed) {
2708 rc = 0;
2709 goto out;
2710 }
2711
2712 host->cmd19_tuning_in_progress = 1;
2713 /*
2714 * Make sure that clock is always enabled when DLL
2715 * tuning is in progress. Keeping PWRSAVE ON may
2716 * turn off the clock. So let's disable the PWRSAVE
2717 * here and re-enable it once tuning is completed.
2718 */
2719 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2720 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302721 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002722 /* first of all reset the tuning block */
2723 rc = msmsdcc_init_cm_sdc4_dll(host);
2724 if (rc)
2725 goto out;
2726
2727 data_buf = kmalloc(64, GFP_KERNEL);
2728 if (!data_buf) {
2729 rc = -ENOMEM;
2730 goto out;
2731 }
2732
2733 phase = 0;
2734 do {
2735 struct mmc_command cmd = {0};
2736 struct mmc_data data = {0};
2737 struct mmc_request mrq = {
2738 .cmd = &cmd,
2739 .data = &data
2740 };
2741 struct scatterlist sg;
2742
2743 /* set the phase in delay line hw block */
2744 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2745 if (rc)
2746 goto kfree;
2747
2748 cmd.opcode = MMC_SEND_TUNING_BLOCK;
2749 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
2750
2751 data.blksz = 64;
2752 data.blocks = 1;
2753 data.flags = MMC_DATA_READ;
2754 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
2755
2756 data.sg = &sg;
2757 data.sg_len = 1;
2758 sg_init_one(&sg, data_buf, 64);
2759 memset(data_buf, 0, 64);
2760 mmc_wait_for_req(mmc, &mrq);
2761
2762 if (!cmd.error && !data.error &&
2763 !memcmp(data_buf, cmd19_tuning_block, 64)) {
2764 /* tuning is successful with this tuning point */
2765 tuned_phases[tuned_phase_cnt++] = phase;
2766 }
2767 } while (++phase < 16);
2768
2769 kfree(data_buf);
2770
2771 if (tuned_phase_cnt) {
2772 tuned_phase_cnt--;
2773 tuned_phase_cnt = (tuned_phase_cnt * 3) / 4;
2774 phase = tuned_phases[tuned_phase_cnt];
2775 /*
2776 * Finally set the selected phase in delay
2777 * line hw block.
2778 */
2779 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2780 if (rc)
2781 goto out;
2782 } else {
2783 /* tuning failed */
2784 rc = -EAGAIN;
2785 pr_err("%s: %s: no tuning point found",
2786 mmc_hostname(mmc), __func__);
2787 }
2788 goto out;
2789
2790kfree:
2791 kfree(data_buf);
2792out:
2793 /* re-enable PWESAVE */
2794 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2795 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302796 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002797 host->cmd19_tuning_in_progress = 0;
2798 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07002799}
2800
2801static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002802 .enable = msmsdcc_enable,
2803 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07002804 .request = msmsdcc_request,
2805 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002806 .get_ro = msmsdcc_get_ro,
2807#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002808 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002809#endif
2810 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
2811 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07002812};
2813
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002814static unsigned int
2815msmsdcc_slot_status(struct msmsdcc_host *host)
2816{
2817 int status;
2818 unsigned int gpio_no = host->plat->status_gpio;
2819
2820 status = gpio_request(gpio_no, "SD_HW_Detect");
2821 if (status) {
2822 pr_err("%s: %s: Failed to request GPIO %d\n",
2823 mmc_hostname(host->mmc), __func__, gpio_no);
2824 } else {
2825 status = gpio_direction_input(gpio_no);
2826 if (!status)
2827 status = !gpio_get_value_cansleep(gpio_no);
2828 gpio_free(gpio_no);
2829 }
2830 return status;
2831}
2832
San Mehat9d2bd732009-09-22 16:44:22 -07002833static void
2834msmsdcc_check_status(unsigned long data)
2835{
2836 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
2837 unsigned int status;
2838
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002839 if (host->plat->status || host->plat->status_gpio) {
2840 if (host->plat->status)
2841 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07002842 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002843 status = msmsdcc_slot_status(host);
2844
2845 host->eject = !status;
2846 if (status ^ host->oldstat) {
2847 pr_info("%s: Slot status change detected (%d -> %d)\n",
2848 mmc_hostname(host->mmc), host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07002849 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002850 }
2851 host->oldstat = status;
2852 } else {
2853 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07002854 }
San Mehat9d2bd732009-09-22 16:44:22 -07002855}
2856
2857static irqreturn_t
2858msmsdcc_platform_status_irq(int irq, void *dev_id)
2859{
2860 struct msmsdcc_host *host = dev_id;
2861
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002862 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07002863 msmsdcc_check_status((unsigned long) host);
2864 return IRQ_HANDLED;
2865}
2866
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002867static irqreturn_t
2868msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
2869{
2870 struct msmsdcc_host *host = dev_id;
2871
2872 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
2873 spin_lock(&host->lock);
2874 if (!host->sdio_irq_disabled) {
2875 disable_irq_nosync(irq);
2876 if (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2877 wake_lock(&host->sdio_wlock);
2878 msmsdcc_disable_irq_wake(host);
2879 }
2880 host->sdio_irq_disabled = 1;
2881 }
2882 if (host->plat->is_sdio_al_client) {
2883 if (!host->clks_on) {
2884 msmsdcc_setup_clocks(host, true);
2885 host->clks_on = 1;
2886 }
2887 if (host->sdcc_irq_disabled) {
2888 writel_relaxed(host->mci_irqenable,
2889 host->base + MMCIMASK0);
2890 mb();
2891 enable_irq(host->core_irqres->start);
2892 host->sdcc_irq_disabled = 0;
2893 }
2894 wake_lock(&host->sdio_wlock);
2895 }
2896 spin_unlock(&host->lock);
2897
2898 return IRQ_HANDLED;
2899}
2900
San Mehat9d2bd732009-09-22 16:44:22 -07002901static void
2902msmsdcc_status_notify_cb(int card_present, void *dev_id)
2903{
2904 struct msmsdcc_host *host = dev_id;
2905
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002906 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07002907 card_present);
2908 msmsdcc_check_status((unsigned long) host);
2909}
2910
San Mehat9d2bd732009-09-22 16:44:22 -07002911static int
2912msmsdcc_init_dma(struct msmsdcc_host *host)
2913{
2914 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
2915 host->dma.host = host;
2916 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07002917 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07002918
2919 if (!host->dmares)
2920 return -ENODEV;
2921
2922 host->dma.nc = dma_alloc_coherent(NULL,
2923 sizeof(struct msmsdcc_nc_dmadata),
2924 &host->dma.nc_busaddr,
2925 GFP_KERNEL);
2926 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07002927 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07002928 return -ENOMEM;
2929 }
2930 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
2931 host->dma.cmd_busaddr = host->dma.nc_busaddr;
2932 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
2933 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
2934 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07002935 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07002936
2937 return 0;
2938}
2939
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002940#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
2941/**
2942 * Allocate and Connect a SDCC peripheral's SPS endpoint
2943 *
2944 * This function allocates endpoint context and
2945 * connect it with memory endpoint by calling
2946 * appropriate SPS driver APIs.
2947 *
2948 * Also registers a SPS callback function with
2949 * SPS driver
2950 *
2951 * This function should only be called once typically
2952 * during driver probe.
2953 *
2954 * @host - Pointer to sdcc host structure
2955 * @ep - Pointer to sps endpoint data structure
2956 * @is_produce - 1 means Producer endpoint
2957 * 0 means Consumer endpoint
2958 *
2959 * @return - 0 if successful else negative value.
2960 *
2961 */
2962static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
2963 struct msmsdcc_sps_ep_conn_data *ep,
2964 bool is_producer)
2965{
2966 int rc = 0;
2967 struct sps_pipe *sps_pipe_handle;
2968 struct sps_connect *sps_config = &ep->config;
2969 struct sps_register_event *sps_event = &ep->event;
2970
2971 /* Allocate endpoint context */
2972 sps_pipe_handle = sps_alloc_endpoint();
2973 if (!sps_pipe_handle) {
2974 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
2975 mmc_hostname(host->mmc), is_producer);
2976 rc = -ENOMEM;
2977 goto out;
2978 }
2979
2980 /* Get default connection configuration for an endpoint */
2981 rc = sps_get_config(sps_pipe_handle, sps_config);
2982 if (rc) {
2983 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
2984 " rc=%d", mmc_hostname(host->mmc),
2985 (u32)sps_pipe_handle, rc);
2986 goto get_config_err;
2987 }
2988
2989 /* Modify the default connection configuration */
2990 if (is_producer) {
2991 /*
2992 * For SDCC producer transfer, source should be
2993 * SDCC peripheral where as destination should
2994 * be system memory.
2995 */
2996 sps_config->source = host->sps.bam_handle;
2997 sps_config->destination = SPS_DEV_HANDLE_MEM;
2998 /* Producer pipe will handle this connection */
2999 sps_config->mode = SPS_MODE_SRC;
3000 sps_config->options =
3001 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3002 } else {
3003 /*
3004 * For SDCC consumer transfer, source should be
3005 * system memory where as destination should
3006 * SDCC peripheral
3007 */
3008 sps_config->source = SPS_DEV_HANDLE_MEM;
3009 sps_config->destination = host->sps.bam_handle;
3010 sps_config->mode = SPS_MODE_DEST;
3011 sps_config->options =
3012 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3013 }
3014
3015 /* Producer pipe index */
3016 sps_config->src_pipe_index = host->sps.src_pipe_index;
3017 /* Consumer pipe index */
3018 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
3019 /*
3020 * This event thresold value is only significant for BAM-to-BAM
3021 * transfer. It's ignored for BAM-to-System mode transfer.
3022 */
3023 sps_config->event_thresh = 0x10;
3024 /*
3025 * Max. no of scatter/gather buffers that can
3026 * be passed by block layer = 32 (NR_SG).
3027 * Each BAM descritor needs 64 bits (8 bytes).
3028 * One BAM descriptor is required per buffer transfer.
3029 * So we would require total 256 (32 * 8) bytes of descriptor FIFO.
3030 * But due to HW limitation we need to allocate atleast one extra
3031 * descriptor memory (256 bytes + 8 bytes). But in order to be
3032 * in power of 2, we are allocating 512 bytes of memory.
3033 */
3034 sps_config->desc.size = 512;
3035 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
3036 sps_config->desc.size,
3037 &sps_config->desc.phys_base,
3038 GFP_KERNEL);
3039
Pratibhasagar V00b94332011-10-18 14:57:27 +05303040 if (!sps_config->desc.base) {
3041 rc = -ENOMEM;
3042 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3043 , mmc_hostname(host->mmc));
3044 goto get_config_err;
3045 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003046 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3047
3048 /* Establish connection between peripheral and memory endpoint */
3049 rc = sps_connect(sps_pipe_handle, sps_config);
3050 if (rc) {
3051 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3052 " rc=%d", mmc_hostname(host->mmc),
3053 (u32)sps_pipe_handle, rc);
3054 goto sps_connect_err;
3055 }
3056
3057 sps_event->mode = SPS_TRIGGER_CALLBACK;
3058 sps_event->options = SPS_O_EOT;
3059 sps_event->callback = msmsdcc_sps_complete_cb;
3060 sps_event->xfer_done = NULL;
3061 sps_event->user = (void *)host;
3062
3063 /* Register callback event for EOT (End of transfer) event. */
3064 rc = sps_register_event(sps_pipe_handle, sps_event);
3065 if (rc) {
3066 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3067 " rc=%d", mmc_hostname(host->mmc),
3068 (u32)sps_pipe_handle, rc);
3069 goto reg_event_err;
3070 }
3071 /* Now save the sps pipe handle */
3072 ep->pipe_handle = sps_pipe_handle;
3073 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3074 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3075 __func__, is_producer ? "READ" : "WRITE",
3076 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3077 goto out;
3078
3079reg_event_err:
3080 sps_disconnect(sps_pipe_handle);
3081sps_connect_err:
3082 dma_free_coherent(mmc_dev(host->mmc),
3083 sps_config->desc.size,
3084 sps_config->desc.base,
3085 sps_config->desc.phys_base);
3086get_config_err:
3087 sps_free_endpoint(sps_pipe_handle);
3088out:
3089 return rc;
3090}
3091
3092/**
3093 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3094 *
3095 * This function disconnect endpoint and deallocates
3096 * endpoint context.
3097 *
3098 * This function should only be called once typically
3099 * during driver remove.
3100 *
3101 * @host - Pointer to sdcc host structure
3102 * @ep - Pointer to sps endpoint data structure
3103 *
3104 */
3105static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3106 struct msmsdcc_sps_ep_conn_data *ep)
3107{
3108 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3109 struct sps_connect *sps_config = &ep->config;
3110 struct sps_register_event *sps_event = &ep->event;
3111
3112 sps_event->xfer_done = NULL;
3113 sps_event->callback = NULL;
3114 sps_register_event(sps_pipe_handle, sps_event);
3115 sps_disconnect(sps_pipe_handle);
3116 dma_free_coherent(mmc_dev(host->mmc),
3117 sps_config->desc.size,
3118 sps_config->desc.base,
3119 sps_config->desc.phys_base);
3120 sps_free_endpoint(sps_pipe_handle);
3121}
3122
3123/**
3124 * Reset SDCC peripheral's SPS endpoint
3125 *
3126 * This function disconnects an endpoint.
3127 *
3128 * This function should be called for reseting
3129 * SPS endpoint when data transfer error is
3130 * encountered during data transfer. This
3131 * can be considered as soft reset to endpoint.
3132 *
3133 * This function should only be called if
3134 * msmsdcc_sps_init() is already called.
3135 *
3136 * @host - Pointer to sdcc host structure
3137 * @ep - Pointer to sps endpoint data structure
3138 *
3139 * @return - 0 if successful else negative value.
3140 */
3141static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3142 struct msmsdcc_sps_ep_conn_data *ep)
3143{
3144 int rc = 0;
3145 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3146
3147 rc = sps_disconnect(sps_pipe_handle);
3148 if (rc) {
3149 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3150 " rc=%d", mmc_hostname(host->mmc), __func__,
3151 (u32)sps_pipe_handle, rc);
3152 goto out;
3153 }
3154 out:
3155 return rc;
3156}
3157
3158/**
3159 * Restore SDCC peripheral's SPS endpoint
3160 *
3161 * This function connects an endpoint.
3162 *
3163 * This function should be called for restoring
3164 * SPS endpoint after data transfer error is
3165 * encountered during data transfer. This
3166 * can be considered as soft reset to endpoint.
3167 *
3168 * This function should only be called if
3169 * msmsdcc_sps_reset_ep() is called before.
3170 *
3171 * @host - Pointer to sdcc host structure
3172 * @ep - Pointer to sps endpoint data structure
3173 *
3174 * @return - 0 if successful else negative value.
3175 */
3176static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3177 struct msmsdcc_sps_ep_conn_data *ep)
3178{
3179 int rc = 0;
3180 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3181 struct sps_connect *sps_config = &ep->config;
3182 struct sps_register_event *sps_event = &ep->event;
3183
3184 /* Establish connection between peripheral and memory endpoint */
3185 rc = sps_connect(sps_pipe_handle, sps_config);
3186 if (rc) {
3187 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3188 " rc=%d", mmc_hostname(host->mmc), __func__,
3189 (u32)sps_pipe_handle, rc);
3190 goto out;
3191 }
3192
3193 /* Register callback event for EOT (End of transfer) event. */
3194 rc = sps_register_event(sps_pipe_handle, sps_event);
3195 if (rc) {
3196 pr_err("%s: %s: sps_register_event() failed!!!"
3197 " pipe_handle=0x%x, rc=%d",
3198 mmc_hostname(host->mmc), __func__,
3199 (u32)sps_pipe_handle, rc);
3200 goto reg_event_err;
3201 }
3202 goto out;
3203
3204reg_event_err:
3205 sps_disconnect(sps_pipe_handle);
3206out:
3207 return rc;
3208}
3209
3210/**
3211 * Initialize SPS HW connected with SDCC core
3212 *
3213 * This function register BAM HW resources with
3214 * SPS driver and then initialize 2 SPS endpoints
3215 *
3216 * This function should only be called once typically
3217 * during driver probe.
3218 *
3219 * @host - Pointer to sdcc host structure
3220 *
3221 * @return - 0 if successful else negative value.
3222 *
3223 */
3224static int msmsdcc_sps_init(struct msmsdcc_host *host)
3225{
3226 int rc = 0;
3227 struct sps_bam_props bam = {0};
3228
3229 host->bam_base = ioremap(host->bam_memres->start,
3230 resource_size(host->bam_memres));
3231 if (!host->bam_base) {
3232 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3233 " size=0x%x", mmc_hostname(host->mmc),
3234 host->bam_memres->start,
3235 (host->bam_memres->end -
3236 host->bam_memres->start));
3237 rc = -ENOMEM;
3238 goto out;
3239 }
3240
3241 bam.phys_addr = host->bam_memres->start;
3242 bam.virt_addr = host->bam_base;
3243 /*
3244 * This event thresold value is only significant for BAM-to-BAM
3245 * transfer. It's ignored for BAM-to-System mode transfer.
3246 */
3247 bam.event_threshold = 0x10; /* Pipe event threshold */
3248 /*
3249 * This threshold controls when the BAM publish
3250 * the descriptor size on the sideband interface.
3251 * SPS HW will only be used when
3252 * data transfer size > MCI_FIFOSIZE (64 bytes).
3253 * PIO mode will be used when
3254 * data transfer size < MCI_FIFOSIZE (64 bytes).
3255 * So set this thresold value to 64 bytes.
3256 */
3257 bam.summing_threshold = 64;
3258 /* SPS driver wll handle the SDCC BAM IRQ */
3259 bam.irq = (u32)host->bam_irqres->start;
3260 bam.manage = SPS_BAM_MGR_LOCAL;
3261
3262 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3263 (u32)bam.phys_addr);
3264 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3265 (u32)bam.virt_addr);
3266
3267 /* Register SDCC Peripheral BAM device to SPS driver */
3268 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3269 if (rc) {
3270 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3271 mmc_hostname(host->mmc), rc);
3272 goto reg_bam_err;
3273 }
3274 pr_info("%s: BAM device registered. bam_handle=0x%x",
3275 mmc_hostname(host->mmc), host->sps.bam_handle);
3276
3277 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3278 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3279
3280 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3281 SPS_PROD_PERIPHERAL);
3282 if (rc)
3283 goto sps_reset_err;
3284 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3285 SPS_CONS_PERIPHERAL);
3286 if (rc)
3287 goto cons_conn_err;
3288
3289 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3290 mmc_hostname(host->mmc),
3291 (unsigned long long)host->bam_memres->start,
3292 (unsigned int)host->bam_irqres->start);
3293 goto out;
3294
3295cons_conn_err:
3296 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3297sps_reset_err:
3298 sps_deregister_bam_device(host->sps.bam_handle);
3299reg_bam_err:
3300 iounmap(host->bam_base);
3301out:
3302 return rc;
3303}
3304
3305/**
3306 * De-initialize SPS HW connected with SDCC core
3307 *
3308 * This function deinitialize SPS endpoints and then
3309 * deregisters BAM resources from SPS driver.
3310 *
3311 * This function should only be called once typically
3312 * during driver remove.
3313 *
3314 * @host - Pointer to sdcc host structure
3315 *
3316 */
3317static void msmsdcc_sps_exit(struct msmsdcc_host *host)
3318{
3319 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
3320 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3321 sps_deregister_bam_device(host->sps.bam_handle);
3322 iounmap(host->bam_base);
3323}
3324#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
3325
3326static ssize_t
3327show_polling(struct device *dev, struct device_attribute *attr, char *buf)
3328{
3329 struct mmc_host *mmc = dev_get_drvdata(dev);
3330 struct msmsdcc_host *host = mmc_priv(mmc);
3331 int poll;
3332 unsigned long flags;
3333
3334 spin_lock_irqsave(&host->lock, flags);
3335 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
3336 spin_unlock_irqrestore(&host->lock, flags);
3337
3338 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
3339}
3340
3341static ssize_t
3342set_polling(struct device *dev, struct device_attribute *attr,
3343 const char *buf, size_t count)
3344{
3345 struct mmc_host *mmc = dev_get_drvdata(dev);
3346 struct msmsdcc_host *host = mmc_priv(mmc);
3347 int value;
3348 unsigned long flags;
3349
3350 sscanf(buf, "%d", &value);
3351
3352 spin_lock_irqsave(&host->lock, flags);
3353 if (value) {
3354 mmc->caps |= MMC_CAP_NEEDS_POLL;
3355 mmc_detect_change(host->mmc, 0);
3356 } else {
3357 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3358 }
3359#ifdef CONFIG_HAS_EARLYSUSPEND
3360 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
3361#endif
3362 spin_unlock_irqrestore(&host->lock, flags);
3363 return count;
3364}
3365
3366static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
3367 show_polling, set_polling);
3368static struct attribute *dev_attrs[] = {
3369 &dev_attr_polling.attr,
3370 NULL,
3371};
3372static struct attribute_group dev_attr_grp = {
3373 .attrs = dev_attrs,
3374};
3375
3376#ifdef CONFIG_HAS_EARLYSUSPEND
3377static void msmsdcc_early_suspend(struct early_suspend *h)
3378{
3379 struct msmsdcc_host *host =
3380 container_of(h, struct msmsdcc_host, early_suspend);
3381 unsigned long flags;
3382
3383 spin_lock_irqsave(&host->lock, flags);
3384 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
3385 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3386 spin_unlock_irqrestore(&host->lock, flags);
3387};
3388static void msmsdcc_late_resume(struct early_suspend *h)
3389{
3390 struct msmsdcc_host *host =
3391 container_of(h, struct msmsdcc_host, early_suspend);
3392 unsigned long flags;
3393
3394 if (host->polling_enabled) {
3395 spin_lock_irqsave(&host->lock, flags);
3396 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
3397 mmc_detect_change(host->mmc, 0);
3398 spin_unlock_irqrestore(&host->lock, flags);
3399 }
3400};
3401#endif
3402
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303403void msmsdcc_print_regs(const char *name, void __iomem *base,
3404 unsigned int no_of_regs)
3405{
3406 unsigned int i;
3407
3408 if (!base)
3409 return;
3410 pr_info("===== %s: Register Dumps @base=0x%x =====\n",
3411 name, (u32)base);
3412 for (i = 0; i < no_of_regs; i = i + 4) {
3413 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x.\n", i*4,
3414 (u32)readl_relaxed(base + i*4),
3415 (u32)readl_relaxed(base + ((i+1)*4)),
3416 (u32)readl_relaxed(base + ((i+2)*4)),
3417 (u32)readl_relaxed(base + ((i+3)*4)));
3418 }
3419}
3420
3421static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
3422{
3423 /* Dump current state of SDCC clocks, power and irq */
3424 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
3425 (host->pwr ? "ON" : "OFF"));
3426 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
3427 mmc_hostname(host->mmc),
3428 (host->clks_on ? "ON" : "OFF"),
3429 (u32)clk_get_rate(host->clk));
3430 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
3431 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
3432
3433 /* Now dump SDCC registers. Don't print FIFO registers */
3434 if (host->clks_on)
3435 msmsdcc_print_regs("SDCC-CORE", host->base, 28);
3436
3437 if (host->curr.data) {
3438 if (msmsdcc_check_dma_op_req(host->curr.data))
3439 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
3440 else if (host->is_dma_mode)
3441 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
3442 mmc_hostname(host->mmc), host->dma.busy,
3443 host->dma.channel, host->dma.crci);
3444 else if (host->is_sps_mode)
3445 pr_info("%s: SPS mode: busy=%d\n",
3446 mmc_hostname(host->mmc), host->sps.busy);
3447
3448 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
3449 mmc_hostname(host->mmc), host->curr.xfer_size,
3450 host->curr.data_xfered, host->curr.xfer_remain);
3451 pr_info("%s: got_dataend=%d, prog_enable=%d,"
3452 " wait_for_auto_prog_done=%d,"
3453 " got_auto_prog_done=%d\n",
3454 mmc_hostname(host->mmc), host->curr.got_dataend,
3455 host->prog_enable, host->curr.wait_for_auto_prog_done,
3456 host->curr.got_auto_prog_done);
3457 }
3458
3459}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003460static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
3461{
3462 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3463 struct mmc_request *mrq;
3464 unsigned long flags;
3465
3466 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003467 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003468 pr_info("%s: %s: dummy CMD52 timeout\n",
3469 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003470 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003471 }
3472
3473 mrq = host->curr.mrq;
3474
3475 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303476 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
3477 mrq->cmd->opcode);
3478 msmsdcc_dump_sdcc_state(host);
3479
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003480 if (!mrq->cmd->error)
3481 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303482 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003483 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003484 if (mrq->data && !mrq->data->error)
3485 mrq->data->error = -ETIMEDOUT;
3486 host->curr.data_xfered = 0;
3487 if (host->dma.sg && host->is_dma_mode) {
3488 msm_dmov_stop_cmd(host->dma.channel,
3489 &host->dma.hdr, 0);
3490 } else if (host->sps.sg && host->is_sps_mode) {
3491 /* Stop current SPS transfer */
3492 msmsdcc_sps_exit_curr_xfer(host);
3493 } else {
3494 msmsdcc_reset_and_restore(host);
3495 msmsdcc_stop_data(host);
3496 if (mrq->data && mrq->data->stop)
3497 msmsdcc_start_command(host,
3498 mrq->data->stop, 0);
3499 else
3500 msmsdcc_request_end(host, mrq);
3501 }
3502 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05303503 host->prog_enable = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003504 msmsdcc_reset_and_restore(host);
3505 msmsdcc_request_end(host, mrq);
3506 }
3507 }
3508 spin_unlock_irqrestore(&host->lock, flags);
3509}
3510
San Mehat9d2bd732009-09-22 16:44:22 -07003511static int
3512msmsdcc_probe(struct platform_device *pdev)
3513{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003514 struct mmc_platform_data *plat = pdev->dev.platform_data;
San Mehat9d2bd732009-09-22 16:44:22 -07003515 struct msmsdcc_host *host;
3516 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003517 unsigned long flags;
3518 struct resource *core_irqres = NULL;
3519 struct resource *bam_irqres = NULL;
3520 struct resource *core_memres = NULL;
3521 struct resource *dml_memres = NULL;
3522 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07003523 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07003524 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05303525 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003526 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07003527
3528 /* must have platform data */
3529 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003530 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003531 ret = -EINVAL;
3532 goto out;
3533 }
3534
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003535 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07003536 return -EINVAL;
3537
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05303538 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
3539 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
3540 return -EINVAL;
3541 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003542
San Mehat9d2bd732009-09-22 16:44:22 -07003543 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003544 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003545 return -ENXIO;
3546 }
3547
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003548 for (i = 0; i < pdev->num_resources; i++) {
3549 if (pdev->resource[i].flags & IORESOURCE_MEM) {
3550 if (!strcmp(pdev->resource[i].name,
3551 "sdcc_dml_addr"))
3552 dml_memres = &pdev->resource[i];
3553 else if (!strcmp(pdev->resource[i].name,
3554 "sdcc_bam_addr"))
3555 bam_memres = &pdev->resource[i];
3556 else
3557 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07003558
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003559 }
3560 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
3561 if (!strcmp(pdev->resource[i].name,
3562 "sdcc_bam_irq"))
3563 bam_irqres = &pdev->resource[i];
3564 else
3565 core_irqres = &pdev->resource[i];
3566 }
Krishna Konda25786ec2011-07-25 16:21:36 -07003567 if (pdev->resource[i].flags & IORESOURCE_DMA) {
3568 if (!strncmp(pdev->resource[i].name,
3569 "sdcc_dma_chnl",
3570 sizeof("sdcc_dma_chnl")))
3571 dmares = &pdev->resource[i];
3572 else if (!strncmp(pdev->resource[i].name,
3573 "sdcc_dma_crci",
3574 sizeof("sdcc_dma_crci")))
3575 dma_crci_res = &pdev->resource[i];
3576 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003577 }
3578
3579 if (!core_irqres || !core_memres) {
3580 pr_err("%s: Invalid sdcc core resource\n", __func__);
3581 return -ENXIO;
3582 }
3583
3584 /*
3585 * Both BAM and DML memory resource should be preset.
3586 * BAM IRQ resource should also be present.
3587 */
3588 if ((bam_memres && !dml_memres) ||
3589 (!bam_memres && dml_memres) ||
3590 ((bam_memres && dml_memres) && !bam_irqres)) {
3591 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003592 return -ENXIO;
3593 }
3594
3595 /*
3596 * Setup our host structure
3597 */
San Mehat9d2bd732009-09-22 16:44:22 -07003598 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
3599 if (!mmc) {
3600 ret = -ENOMEM;
3601 goto out;
3602 }
3603
3604 host = mmc_priv(mmc);
3605 host->pdev_id = pdev->id;
3606 host->plat = plat;
3607 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08003608 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05303609
3610 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003611 host->is_sps_mode = 1;
3612 else if (dmares)
3613 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07003614
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003615 host->base = ioremap(core_memres->start,
3616 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07003617 if (!host->base) {
3618 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003619 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003620 }
3621
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003622 host->core_irqres = core_irqres;
3623 host->bam_irqres = bam_irqres;
3624 host->core_memres = core_memres;
3625 host->dml_memres = dml_memres;
3626 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07003627 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07003628 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07003629 spin_lock_init(&host->lock);
3630
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003631#ifdef CONFIG_MMC_EMBEDDED_SDIO
3632 if (plat->embedded_sdio)
3633 mmc_set_embedded_sdio_data(mmc,
3634 &plat->embedded_sdio->cis,
3635 &plat->embedded_sdio->cccr,
3636 plat->embedded_sdio->funcs,
3637 plat->embedded_sdio->num_funcs);
3638#endif
3639
Sahitya Tummala62612cf2010-12-08 15:03:03 +05303640 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
3641 (unsigned long)host);
3642
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003643 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
3644 (unsigned long)host);
3645 if (host->is_dma_mode) {
3646 /* Setup DMA */
3647 ret = msmsdcc_init_dma(host);
3648 if (ret)
3649 goto ioremap_free;
3650 } else {
3651 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003652 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003653 }
3654
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003655 /*
3656 * Setup SDCC clock if derived from Dayatona
3657 * fabric core clock.
3658 */
3659 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07003660 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003661 if (!IS_ERR(host->dfab_pclk)) {
3662 /* Set the clock rate to 64MHz for max. performance */
3663 ret = clk_set_rate(host->dfab_pclk, 64000000);
3664 if (ret)
3665 goto dfab_pclk_put;
3666 ret = clk_enable(host->dfab_pclk);
3667 if (ret)
3668 goto dfab_pclk_put;
3669 } else
3670 goto dma_free;
3671 }
3672
3673 /*
3674 * Setup main peripheral bus clock
3675 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003676 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003677 if (!IS_ERR(host->pclk)) {
3678 ret = clk_enable(host->pclk);
3679 if (ret)
3680 goto pclk_put;
3681
3682 host->pclk_rate = clk_get_rate(host->pclk);
3683 }
3684
3685 /*
3686 * Setup SDC MMC clock
3687 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003688 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07003689 if (IS_ERR(host->clk)) {
3690 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003691 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07003692 }
3693
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003694 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
3695 if (ret) {
3696 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
3697 goto clk_put;
3698 }
3699
3700 ret = clk_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003701 if (ret)
3702 goto clk_put;
3703
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003704 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303705 if (!host->clk_rate)
3706 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05303707
3708 /*
3709 * Lookup the Controller Version, to identify the supported features
3710 * Version number read as 0 would indicate SDCC3 or earlier versions
3711 */
3712 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
3713 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
3714 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303715 /*
3716 * Set the register write delay according to min. clock frequency
3717 * supported and update later when the host->clk_rate changes.
3718 */
3719 host->reg_write_delay =
3720 (1 + ((3 * USEC_PER_SEC) /
3721 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003722
3723 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05303724 /* Apply Hard reset to SDCC to put it in power on default state */
3725 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003726
3727 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07003728 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003729 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07003730 goto clk_disable;
3731 }
3732
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003733
3734 /* Clocks has to be running before accessing SPS/DML HW blocks */
3735 if (host->is_sps_mode) {
3736 /* Initialize SPS */
3737 ret = msmsdcc_sps_init(host);
3738 if (ret)
3739 goto vreg_deinit;
3740 /* Initialize DML */
3741 ret = msmsdcc_dml_init(host);
3742 if (ret)
3743 goto sps_exit;
3744 }
San Mehat9d2bd732009-09-22 16:44:22 -07003745
San Mehat9d2bd732009-09-22 16:44:22 -07003746 /*
3747 * Setup MMC host structure
3748 */
3749 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003750 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
3751 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003752 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003753 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
3754 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07003755
San Mehat9d2bd732009-09-22 16:44:22 -07003756 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05303757 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05303758
3759 /*
3760 * If we send the CMD23 before multi block write/read command
3761 * then we need not to send CMD12 at the end of the transfer.
3762 * If we don't send the CMD12 then only way to detect the PROG_DONE
3763 * status is to use the AUTO_PROG_DONE status provided by SDCC4
3764 * controller. So let's enable the CMD23 for SDCC4 only.
3765 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05303766 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05303767 mmc->caps |= MMC_CAP_CMD23;
3768
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003769 mmc->caps |= plat->uhs_caps;
3770 /*
3771 * XPC controls the maximum current in the default speed mode of SDXC
3772 * card. XPC=0 means 100mA (max.) but speed class is not supported.
3773 * XPC=1 means 150mA (max.) and speed class is supported.
3774 */
3775 if (plat->xpc_cap)
3776 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
3777 MMC_CAP_SET_XPC_180);
3778
3779 if (plat->nonremovable)
3780 mmc->caps |= MMC_CAP_NONREMOVABLE;
3781#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
3782 mmc->caps |= MMC_CAP_SDIO_IRQ;
3783#endif
3784
3785 if (plat->is_sdio_al_client)
3786 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07003787
Martin K. Petersena36274e2010-09-10 01:33:59 -04003788 mmc->max_segs = NR_SG;
San Mehat9d2bd732009-09-22 16:44:22 -07003789 mmc->max_blk_size = 4096; /* MCI_DATA_CTL BLOCKSIZE up to 4096 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003790 mmc->max_blk_count = 65535;
San Mehat9d2bd732009-09-22 16:44:22 -07003791
3792 mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */
3793 mmc->max_seg_size = mmc->max_req_size;
3794
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003795 writel_relaxed(0, host->base + MMCIMASK0);
3796 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -07003797
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003798 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
3799 mb();
3800 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07003801
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003802 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
3803 DRIVER_NAME " (cmd)", host);
3804 if (ret)
3805 goto dml_exit;
3806
3807 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
3808 DRIVER_NAME " (pio)", host);
3809 if (ret)
3810 goto irq_free;
3811
3812 /*
3813 * Enable SDCC IRQ only when host is powered on. Otherwise, this
3814 * IRQ is un-necessarily being monitored by MPM (Modem power
3815 * management block) during idle-power collapse. The MPM will be
3816 * configured to monitor the DATA1 GPIO line with level-low trigger
3817 * and thus depending on the GPIO status, it prevents TCXO shutdown
3818 * during idle-power collapse.
3819 */
3820 disable_irq(core_irqres->start);
3821 host->sdcc_irq_disabled = 1;
3822
3823 if (plat->sdiowakeup_irq) {
3824 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3825 mmc_hostname(mmc));
3826 ret = request_irq(plat->sdiowakeup_irq,
3827 msmsdcc_platform_sdiowakeup_irq,
3828 IRQF_SHARED | IRQF_TRIGGER_LOW,
3829 DRIVER_NAME "sdiowakeup", host);
3830 if (ret) {
3831 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
3832 plat->sdiowakeup_irq, ret);
3833 goto pio_irq_free;
3834 } else {
3835 spin_lock_irqsave(&host->lock, flags);
3836 if (!host->sdio_irq_disabled) {
3837 disable_irq_nosync(plat->sdiowakeup_irq);
3838 host->sdio_irq_disabled = 1;
3839 }
3840 spin_unlock_irqrestore(&host->lock, flags);
3841 }
3842 }
3843
3844 if (plat->cfg_mpm_sdiowakeup) {
3845 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3846 mmc_hostname(mmc));
3847 }
3848
3849 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
3850 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003851 /*
3852 * Setup card detect change
3853 */
3854
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003855 if (plat->status || plat->status_gpio) {
3856 if (plat->status)
3857 host->oldstat = plat->status(mmc_dev(host->mmc));
3858 else
3859 host->oldstat = msmsdcc_slot_status(host);
3860 host->eject = !host->oldstat;
3861 }
San Mehat9d2bd732009-09-22 16:44:22 -07003862
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003863 if (plat->status_irq) {
3864 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07003865 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003866 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07003867 DRIVER_NAME " (slot)",
3868 host);
3869 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003870 pr_err("Unable to get slot IRQ %d (%d)\n",
3871 plat->status_irq, ret);
3872 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003873 }
3874 } else if (plat->register_status_notify) {
3875 plat->register_status_notify(msmsdcc_status_notify_cb, host);
3876 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003877 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07003878 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003879
3880 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003881
3882 ret = pm_runtime_set_active(&(pdev)->dev);
3883 if (ret < 0)
3884 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3885 __func__, ret);
3886 /*
3887 * There is no notion of suspend/resume for SD/MMC/SDIO
3888 * cards. So host can be suspended/resumed with out
3889 * worrying about its children.
3890 */
3891 pm_suspend_ignore_children(&(pdev)->dev, true);
3892
3893 /*
3894 * MMC/SD/SDIO bus suspend/resume operations are defined
3895 * only for the slots that will be used for non-removable
3896 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
3897 * defined. Otherwise, they simply become card removal and
3898 * insertion events during suspend and resume respectively.
3899 * Hence, enable run-time PM only for slots for which bus
3900 * suspend/resume operations are defined.
3901 */
3902#ifdef CONFIG_MMC_UNSAFE_RESUME
3903 /*
3904 * If this capability is set, MMC core will enable/disable host
3905 * for every claim/release operation on a host. We use this
3906 * notification to increment/decrement runtime pm usage count.
3907 */
3908 mmc->caps |= MMC_CAP_DISABLE;
3909 pm_runtime_enable(&(pdev)->dev);
3910#else
3911 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
3912 mmc->caps |= MMC_CAP_DISABLE;
3913 pm_runtime_enable(&(pdev)->dev);
3914 }
3915#endif
3916 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
3917 (unsigned long)host);
3918
San Mehat9d2bd732009-09-22 16:44:22 -07003919 mmc_add_host(mmc);
3920
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003921#ifdef CONFIG_HAS_EARLYSUSPEND
3922 host->early_suspend.suspend = msmsdcc_early_suspend;
3923 host->early_suspend.resume = msmsdcc_late_resume;
3924 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
3925 register_early_suspend(&host->early_suspend);
3926#endif
San Mehat9d2bd732009-09-22 16:44:22 -07003927
Krishna Konda25786ec2011-07-25 16:21:36 -07003928 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
3929 " dmacrcri %d\n", mmc_hostname(mmc),
3930 (unsigned long long)core_memres->start,
3931 (unsigned int) core_irqres->start,
3932 (unsigned int) plat->status_irq, host->dma.channel,
3933 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003934
3935 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
3936 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
3937 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
3938 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
3939 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
3940 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
3941 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
3942 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
3943 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
3944 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
3945 host->eject);
3946 pr_info("%s: Power save feature enable = %d\n",
3947 mmc_hostname(mmc), msmsdcc_pwrsave);
3948
Krishna Konda25786ec2011-07-25 16:21:36 -07003949 if (host->is_dma_mode && host->dma.channel != -1
3950 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003951 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003952 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003953 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003954 mmc_hostname(mmc), host->dma.cmd_busaddr,
3955 host->dma.cmdptr_busaddr);
3956 } else if (host->is_sps_mode) {
3957 pr_info("%s: SPS-BAM data transfer mode available\n",
3958 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003959 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003960 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003961
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003962#if defined(CONFIG_DEBUG_FS)
3963 msmsdcc_dbg_createhost(host);
3964#endif
3965 if (!plat->status_irq) {
3966 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
3967 if (ret)
3968 goto platform_irq_free;
3969 }
San Mehat9d2bd732009-09-22 16:44:22 -07003970 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003971
3972 platform_irq_free:
3973 del_timer_sync(&host->req_tout_timer);
3974 pm_runtime_disable(&(pdev)->dev);
3975 pm_runtime_set_suspended(&(pdev)->dev);
3976
3977 if (plat->status_irq)
3978 free_irq(plat->status_irq, host);
3979 sdiowakeup_irq_free:
3980 wake_lock_destroy(&host->sdio_suspend_wlock);
3981 if (plat->sdiowakeup_irq)
3982 free_irq(plat->sdiowakeup_irq, host);
3983 pio_irq_free:
3984 if (plat->sdiowakeup_irq)
3985 wake_lock_destroy(&host->sdio_wlock);
3986 free_irq(core_irqres->start, host);
3987 irq_free:
3988 free_irq(core_irqres->start, host);
3989 dml_exit:
3990 if (host->is_sps_mode)
3991 msmsdcc_dml_exit(host);
3992 sps_exit:
3993 if (host->is_sps_mode)
3994 msmsdcc_sps_exit(host);
3995 vreg_deinit:
3996 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07003997 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003998 clk_disable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003999 clk_put:
4000 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004001 pclk_disable:
4002 if (!IS_ERR(host->pclk))
4003 clk_disable(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07004004 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004005 if (!IS_ERR(host->pclk))
4006 clk_put(host->pclk);
4007 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4008 clk_disable(host->dfab_pclk);
4009 dfab_pclk_put:
4010 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4011 clk_put(host->dfab_pclk);
4012 dma_free:
4013 if (host->is_dma_mode) {
4014 if (host->dmares)
4015 dma_free_coherent(NULL,
4016 sizeof(struct msmsdcc_nc_dmadata),
4017 host->dma.nc, host->dma.nc_busaddr);
4018 }
4019 ioremap_free:
4020 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07004021 host_free:
4022 mmc_free_host(mmc);
4023 out:
4024 return ret;
4025}
4026
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004027static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07004028{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004029 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4030 struct mmc_platform_data *plat;
4031 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004032
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004033 if (!mmc)
4034 return -ENXIO;
4035
4036 if (pm_runtime_suspended(&(pdev)->dev))
4037 pm_runtime_resume(&(pdev)->dev);
4038
4039 host = mmc_priv(mmc);
4040
4041 DBG(host, "Removing SDCC device = %d\n", pdev->id);
4042 plat = host->plat;
4043
4044 if (!plat->status_irq)
4045 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
4046
4047 del_timer_sync(&host->req_tout_timer);
4048 tasklet_kill(&host->dma_tlet);
4049 tasklet_kill(&host->sps.tlet);
4050 mmc_remove_host(mmc);
4051
4052 if (plat->status_irq)
4053 free_irq(plat->status_irq, host);
4054
4055 wake_lock_destroy(&host->sdio_suspend_wlock);
4056 if (plat->sdiowakeup_irq) {
4057 wake_lock_destroy(&host->sdio_wlock);
4058 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
4059 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07004060 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004061
4062 free_irq(host->core_irqres->start, host);
4063 free_irq(host->core_irqres->start, host);
4064
4065 clk_put(host->clk);
4066 if (!IS_ERR(host->pclk))
4067 clk_put(host->pclk);
4068 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4069 clk_put(host->dfab_pclk);
4070
4071 msmsdcc_vreg_init(host, false);
4072
4073 if (host->is_dma_mode) {
4074 if (host->dmares)
4075 dma_free_coherent(NULL,
4076 sizeof(struct msmsdcc_nc_dmadata),
4077 host->dma.nc, host->dma.nc_busaddr);
4078 }
4079
4080 if (host->is_sps_mode) {
4081 msmsdcc_dml_exit(host);
4082 msmsdcc_sps_exit(host);
4083 }
4084
4085 iounmap(host->base);
4086 mmc_free_host(mmc);
4087
4088#ifdef CONFIG_HAS_EARLYSUSPEND
4089 unregister_early_suspend(&host->early_suspend);
4090#endif
4091 pm_runtime_disable(&(pdev)->dev);
4092 pm_runtime_set_suspended(&(pdev)->dev);
4093
4094 return 0;
4095}
4096
4097#ifdef CONFIG_MSM_SDIO_AL
4098int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4099{
4100 struct msmsdcc_host *host = mmc_priv(mmc);
4101 unsigned long flags;
4102
4103 spin_lock_irqsave(&host->lock, flags);
4104 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
4105 enable ? "En" : "Dis");
4106
4107 if (enable) {
4108 if (!host->sdcc_irq_disabled) {
4109 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05304110 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004111 host->sdcc_irq_disabled = 1;
4112 }
4113
4114 if (host->clks_on) {
4115 msmsdcc_setup_clocks(host, false);
4116 host->clks_on = 0;
4117 }
4118
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304119 if (host->plat->sdio_lpm_gpio_setup &&
4120 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004121 spin_unlock_irqrestore(&host->lock, flags);
4122 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
4123 spin_lock_irqsave(&host->lock, flags);
4124 host->sdio_gpio_lpm = 1;
4125 }
4126
4127 if (host->sdio_irq_disabled) {
4128 msmsdcc_enable_irq_wake(host);
4129 enable_irq(host->plat->sdiowakeup_irq);
4130 host->sdio_irq_disabled = 0;
4131 }
4132 } else {
4133 if (!host->sdio_irq_disabled) {
4134 disable_irq_nosync(host->plat->sdiowakeup_irq);
4135 host->sdio_irq_disabled = 1;
4136 msmsdcc_disable_irq_wake(host);
4137 }
4138
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304139 if (host->plat->sdio_lpm_gpio_setup &&
4140 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004141 spin_unlock_irqrestore(&host->lock, flags);
4142 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
4143 spin_lock_irqsave(&host->lock, flags);
4144 host->sdio_gpio_lpm = 0;
4145 }
4146
4147 if (!host->clks_on) {
4148 msmsdcc_setup_clocks(host, true);
4149 host->clks_on = 1;
4150 }
4151
4152 if (host->sdcc_irq_disabled) {
4153 writel_relaxed(host->mci_irqenable,
4154 host->base + MMCIMASK0);
4155 mb();
4156 enable_irq(host->core_irqres->start);
4157 host->sdcc_irq_disabled = 0;
4158 }
4159 wake_lock_timeout(&host->sdio_wlock, 1);
4160 }
4161 spin_unlock_irqrestore(&host->lock, flags);
4162 return 0;
4163}
4164#else
4165int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4166{
4167 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004168}
4169#endif
4170
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004171#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07004172static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004173msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004174{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004175 struct mmc_host *mmc = dev_get_drvdata(dev);
4176 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07004177 int rc = 0;
4178
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004179 if (host->plat->is_sdio_al_client)
4180 return 0;
4181
Sahitya Tummala7661a452011-07-18 13:28:35 +05304182 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004183 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004184 host->sdcc_suspending = 1;
4185 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07004186
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004187 /*
4188 * If the clocks are already turned off by SDIO clients (as
4189 * part of LPM), then clocks should be turned on before
4190 * calling mmc_suspend_host() because mmc_suspend_host might
4191 * send some commands to the card. The clocks will be turned
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304192 * off again after mmc_suspend_host. Thus for SDIO
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004193 * cards, clocks will be turned on before mmc_suspend_host
4194 * and turned off after mmc_suspend_host.
4195 */
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304196 if (mmc->card && mmc_card_sdio(mmc->card)) {
4197 mmc->ios.clock = host->clk_rate;
4198 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4199 }
San Mehat9d2bd732009-09-22 16:44:22 -07004200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004201 /*
4202 * MMC core thinks that host is disabled by now since
4203 * runtime suspend is scheduled after msmsdcc_disable()
4204 * is called. Thus, MMC core will try to enable the host
4205 * while suspending it. This results in a synchronous
4206 * runtime resume request while in runtime suspending
4207 * context and hence inorder to complete this resume
4208 * requet, it will wait for suspend to be complete,
4209 * but runtime suspend also can not proceed further
4210 * until the host is resumed. Thus, it leads to a hang.
4211 * Hence, increase the pm usage count before suspending
4212 * the host so that any resume requests after this will
4213 * simple become pm usage counter increment operations.
4214 */
4215 pm_runtime_get_noresume(dev);
4216 rc = mmc_suspend_host(mmc);
4217 pm_runtime_put_noidle(dev);
4218
4219 if (!rc) {
4220 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
4221 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ)) {
4222 disable_irq(host->core_irqres->start);
4223 host->sdcc_irq_disabled = 1;
4224
4225 /*
4226 * If MMC core level suspend is not supported,
4227 * turn off clocks to allow deep sleep (TCXO
4228 * shutdown).
4229 */
4230 mmc->ios.clock = 0;
4231 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4232 enable_irq(host->core_irqres->start);
4233 host->sdcc_irq_disabled = 0;
4234
4235 if (host->plat->sdiowakeup_irq) {
4236 host->sdio_irq_disabled = 0;
4237 msmsdcc_enable_irq_wake(host);
4238 enable_irq(host->plat->sdiowakeup_irq);
4239 }
4240 }
4241 }
4242 host->sdcc_suspending = 0;
4243 mmc->suspend_task = NULL;
4244 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
4245 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004246 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304247 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004248 return rc;
4249}
4250
4251static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004252msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004253{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004254 struct mmc_host *mmc = dev_get_drvdata(dev);
4255 struct msmsdcc_host *host = mmc_priv(mmc);
4256 unsigned long flags;
4257
4258 if (host->plat->is_sdio_al_client)
4259 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07004260
Sahitya Tummala7661a452011-07-18 13:28:35 +05304261 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004262 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004263 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
4264 if (host->sdcc_irq_disabled) {
4265 enable_irq(host->core_irqres->start);
4266 host->sdcc_irq_disabled = 0;
4267 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304268 mmc->ios.clock = host->clk_rate;
4269 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07004270
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304271 spin_lock_irqsave(&host->lock, flags);
4272 writel_relaxed(host->mci_irqenable,
4273 host->base + MMCIMASK0);
4274 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07004275
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304276 if ((mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) &&
4277 !host->sdio_irq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004278 if (host->plat->sdiowakeup_irq) {
4279 disable_irq_nosync(
4280 host->plat->sdiowakeup_irq);
4281 msmsdcc_disable_irq_wake(host);
4282 host->sdio_irq_disabled = 1;
4283 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304284 }
San Mehat9d2bd732009-09-22 16:44:22 -07004285
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304286 spin_unlock_irqrestore(&host->lock, flags);
4287 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004288
4289 mmc_resume_host(mmc);
4290
4291 /*
4292 * FIXME: Clearing of flags must be handled in clients
4293 * resume handler.
4294 */
4295 spin_lock_irqsave(&host->lock, flags);
4296 mmc->pm_flags = 0;
4297 spin_unlock_irqrestore(&host->lock, flags);
4298
4299 /*
4300 * After resuming the host wait for sometime so that
4301 * the SDIO work will be processed.
4302 */
4303 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO)) {
4304 if ((host->plat->cfg_mpm_sdiowakeup ||
4305 host->plat->sdiowakeup_irq) &&
4306 wake_lock_active(&host->sdio_wlock))
4307 wake_lock_timeout(&host->sdio_wlock, 1);
4308 }
4309
4310 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004311 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304312 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004313 return 0;
4314}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004315
4316static int msmsdcc_runtime_idle(struct device *dev)
4317{
4318 struct mmc_host *mmc = dev_get_drvdata(dev);
4319 struct msmsdcc_host *host = mmc_priv(mmc);
4320
4321 if (host->plat->is_sdio_al_client)
4322 return 0;
4323
4324 /* Idle timeout is not configurable for now */
4325 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
4326
4327 return -EAGAIN;
4328}
4329
4330static int msmsdcc_pm_suspend(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
4339
4340 if (host->plat->status_irq)
4341 disable_irq(host->plat->status_irq);
4342
4343 if (!pm_runtime_suspended(dev))
4344 rc = msmsdcc_runtime_suspend(dev);
4345
4346 return rc;
4347}
4348
4349static int msmsdcc_pm_resume(struct device *dev)
4350{
4351 struct mmc_host *mmc = dev_get_drvdata(dev);
4352 struct msmsdcc_host *host = mmc_priv(mmc);
4353 int rc = 0;
4354
4355 if (host->plat->is_sdio_al_client)
4356 return 0;
4357
Sahitya Tummalafb486372011-09-02 19:01:49 +05304358 if (!pm_runtime_suspended(dev))
4359 rc = msmsdcc_runtime_resume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004360 if (host->plat->status_irq) {
4361 msmsdcc_check_status((unsigned long)host);
4362 enable_irq(host->plat->status_irq);
4363 }
4364
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004365 return rc;
4366}
4367
Daniel Walker08ecfde2010-06-23 12:32:20 -07004368#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004369#define msmsdcc_runtime_suspend NULL
4370#define msmsdcc_runtime_resume NULL
4371#define msmsdcc_runtime_idle NULL
4372#define msmsdcc_pm_suspend NULL
4373#define msmsdcc_pm_resume NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07004374#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004375
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004376static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
4377 .runtime_suspend = msmsdcc_runtime_suspend,
4378 .runtime_resume = msmsdcc_runtime_resume,
4379 .runtime_idle = msmsdcc_runtime_idle,
4380 .suspend = msmsdcc_pm_suspend,
4381 .resume = msmsdcc_pm_resume,
4382};
4383
San Mehat9d2bd732009-09-22 16:44:22 -07004384static struct platform_driver msmsdcc_driver = {
4385 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004386 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07004387 .driver = {
4388 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004389 .pm = &msmsdcc_dev_pm_ops,
San Mehat9d2bd732009-09-22 16:44:22 -07004390 },
4391};
4392
4393static int __init msmsdcc_init(void)
4394{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004395#if defined(CONFIG_DEBUG_FS)
4396 int ret = 0;
4397 ret = msmsdcc_dbg_init();
4398 if (ret) {
4399 pr_err("Failed to create debug fs dir \n");
4400 return ret;
4401 }
4402#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004403 return platform_driver_register(&msmsdcc_driver);
4404}
4405
4406static void __exit msmsdcc_exit(void)
4407{
4408 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004409
4410#if defined(CONFIG_DEBUG_FS)
4411 debugfs_remove(debugfs_file);
4412 debugfs_remove(debugfs_dir);
4413#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004414}
4415
4416module_init(msmsdcc_init);
4417module_exit(msmsdcc_exit);
4418
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004419MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07004420MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004421
4422#if defined(CONFIG_DEBUG_FS)
4423
4424static int
4425msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
4426{
4427 file->private_data = inode->i_private;
4428 return 0;
4429}
4430
4431static ssize_t
4432msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
4433 size_t count, loff_t *ppos)
4434{
4435 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
4436 char buf[1024];
4437 int max, i;
4438
4439 i = 0;
4440 max = sizeof(buf) - 1;
4441
4442 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
4443 host->curr.cmd, host->curr.data);
4444 if (host->curr.cmd) {
4445 struct mmc_command *cmd = host->curr.cmd;
4446
4447 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
4448 cmd->opcode, cmd->arg, cmd->flags);
4449 }
4450 if (host->curr.data) {
4451 struct mmc_data *data = host->curr.data;
4452 i += scnprintf(buf + i, max - i,
4453 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
4454 data->timeout_ns, data->timeout_clks,
4455 data->blksz, data->blocks, data->error,
4456 data->flags);
4457 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
4458 host->curr.xfer_size, host->curr.xfer_remain,
4459 host->curr.data_xfered, host->dma.sg);
4460 }
4461
4462 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
4463}
4464
4465static const struct file_operations msmsdcc_dbg_state_ops = {
4466 .read = msmsdcc_dbg_state_read,
4467 .open = msmsdcc_dbg_state_open,
4468};
4469
4470static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
4471{
4472 if (debugfs_dir) {
4473 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
4474 0644, debugfs_dir, host,
4475 &msmsdcc_dbg_state_ops);
4476 }
4477}
4478
4479static int __init msmsdcc_dbg_init(void)
4480{
4481 int err;
4482
4483 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
4484 if (IS_ERR(debugfs_dir)) {
4485 err = PTR_ERR(debugfs_dir);
4486 debugfs_dir = NULL;
4487 return err;
4488 }
4489
4490 return 0;
4491}
4492#endif