blob: 50c115ae1dd1f68041339b979e1ae9d36d675965 [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.
Krishna Konda941604a2012-01-10 17:46:34 -08006 * Copyright (c) 2009-2012, 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>
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +053022#include <linux/of.h>
San Mehat9d2bd732009-09-22 16:44:22 -070023#include <linux/device.h>
24#include <linux/interrupt.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070025#include <linux/irq.h>
San Mehat9d2bd732009-09-22 16:44:22 -070026#include <linux/delay.h>
27#include <linux/err.h>
28#include <linux/highmem.h>
29#include <linux/log2.h>
30#include <linux/mmc/host.h>
31#include <linux/mmc/card.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070032#include <linux/mmc/mmc.h>
San Mehatb3fa5792009-11-02 18:46:09 -080033#include <linux/mmc/sdio.h>
San Mehat9d2bd732009-09-22 16:44:22 -070034#include <linux/clk.h>
35#include <linux/scatterlist.h>
36#include <linux/platform_device.h>
37#include <linux/dma-mapping.h>
38#include <linux/debugfs.h>
39#include <linux/io.h>
40#include <linux/memory.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070041#include <linux/pm_runtime.h>
42#include <linux/wakelock.h>
Sahitya Tummala7a892482011-01-18 11:22:49 +053043#include <linux/gpio.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070044#include <linux/regulator/consumer.h>
45#include <linux/slab.h>
Subhash Jadavani933e6a62011-12-26 18:05:04 +053046#include <linux/pm_qos_params.h>
San Mehat9d2bd732009-09-22 16:44:22 -070047
48#include <asm/cacheflush.h>
49#include <asm/div64.h>
50#include <asm/sizes.h>
51
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070052#include <asm/mach/mmc.h>
San Mehat9d2bd732009-09-22 16:44:22 -070053#include <mach/msm_iomap.h>
Sahitya Tummalab08bb352010-12-08 15:03:05 +053054#include <mach/clk.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070055#include <mach/dma.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070056#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
Subhash Jadavanie6e1b822012-03-12 18:17:58 +053071/* Use SPS only if transfer size is more than this macro */
72#define SPS_MIN_XFER_SIZE MCI_FIFOSIZE
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070073
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
Subhash Jadavani8766e352011-11-30 11:30:32 +053081static u64 dma_mask = DMA_BIT_MASK(32);
San Mehat9d2bd732009-09-22 16:44:22 -070082static unsigned int msmsdcc_pwrsave = 1;
San Mehat9d2bd732009-09-22 16:44:22 -070083
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070084static struct mmc_command dummy52cmd;
85static struct mmc_request dummy52mrq = {
86 .cmd = &dummy52cmd,
87 .data = NULL,
88 .stop = NULL,
89};
90static struct mmc_command dummy52cmd = {
91 .opcode = SD_IO_RW_DIRECT,
92 .flags = MMC_RSP_PRESENT,
93 .data = NULL,
94 .mrq = &dummy52mrq,
95};
96/*
97 * An array holding the Tuning pattern to compare with when
98 * executing a tuning cycle.
99 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +0530100static const u32 tuning_block_64[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700101 0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
102 0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
103 0xF0FFF0FF, 0x3CCCFC0F, 0xCFCC33CC, 0xEEFFEFFF,
104 0xFDFFFDFF, 0xFFBFFFDF, 0xFFF7FFBB, 0xDE7B7FF7
105};
San Mehat865c8062009-11-13 13:42:06 -0800106
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +0530107static const u32 tuning_block_128[] = {
108 0xFF00FFFF, 0x0000FFFF, 0xCCCCFFFF, 0xCCCC33CC,
109 0xCC3333CC, 0xFFFFCCCC, 0xFFFFEEFF, 0xFFEEEEFF,
110 0xFFDDFFFF, 0xDDDDFFFF, 0xBBFFFFFF, 0xBBFFFFFF,
111 0xFFFFFFBB, 0xFFFFFF77, 0x77FF7777, 0xFFEEDDBB,
112 0x00FFFFFF, 0x00FFFFFF, 0xCCFFFF00, 0xCC33CCCC,
113 0x3333CCCC, 0xFFCCCCCC, 0xFFEEFFFF, 0xEEEEFFFF,
114 0xDDFFFFFF, 0xDDFFFFFF, 0xFFFFFFDD, 0xFFFFFFBB,
115 0xFFFFBBBB, 0xFFFF77FF, 0xFF7777FF, 0xEEDDBB77
116};
117
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700118#if IRQ_DEBUG == 1
119static char *irq_status_bits[] = { "cmdcrcfail", "datcrcfail", "cmdtimeout",
120 "dattimeout", "txunderrun", "rxoverrun",
121 "cmdrespend", "cmdsent", "dataend", NULL,
122 "datablkend", "cmdactive", "txactive",
123 "rxactive", "txhalfempty", "rxhalffull",
124 "txfifofull", "rxfifofull", "txfifoempty",
125 "rxfifoempty", "txdataavlbl", "rxdataavlbl",
126 "sdiointr", "progdone", "atacmdcompl",
127 "sdiointrope", "ccstimeout", NULL, NULL,
128 NULL, NULL, NULL };
129
130static void
131msmsdcc_print_status(struct msmsdcc_host *host, char *hdr, uint32_t status)
San Mehat865c8062009-11-13 13:42:06 -0800132{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700133 int i;
San Mehat8b1c2ba2009-11-16 10:17:30 -0800134
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700135 pr_debug("%s-%s ", mmc_hostname(host->mmc), hdr);
136 for (i = 0; i < 32; i++) {
137 if (status & (1 << i))
138 pr_debug("%s ", irq_status_bits[i]);
San Mehat865c8062009-11-13 13:42:06 -0800139 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700140 pr_debug("\n");
San Mehatc7fc9372009-11-22 17:19:07 -0800141}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700142#endif
San Mehat865c8062009-11-13 13:42:06 -0800143
San Mehat9d2bd732009-09-22 16:44:22 -0700144static void
145msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
146 u32 c);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530147static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530148static inline void msmsdcc_delay(struct msmsdcc_host *host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530149static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -0800150static void msmsdcc_sg_start(struct msmsdcc_host *host);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -0800151static int msmsdcc_vreg_reset(struct msmsdcc_host *host);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530152
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530153static inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
154{
155 unsigned short ret = NR_SG;
156
157 if (host->is_sps_mode) {
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +0530158 ret = SPS_MAX_DESCS;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530159 } else { /* DMA or PIO mode */
160 if (NR_SG > MAX_NR_SG_DMA_PIO)
161 ret = MAX_NR_SG_DMA_PIO;
162 }
163
164 return ret;
165}
166
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530167/* Prevent idle power collapse(pc) while operating in peripheral mode */
168static void msmsdcc_pm_qos_update_latency(struct msmsdcc_host *host, int vote)
169{
170 u32 swfi_latency = 0;
171
172 if (!host->plat->swfi_latency)
173 return;
174
175 swfi_latency = host->plat->swfi_latency + 1;
176
177 if (vote)
178 pm_qos_update_request(&host->pm_qos_req_dma,
179 swfi_latency);
180 else
181 pm_qos_update_request(&host->pm_qos_req_dma,
182 PM_QOS_DEFAULT_VALUE);
183}
184
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700185#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
186static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
187 struct msmsdcc_sps_ep_conn_data *ep);
188static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
189 struct msmsdcc_sps_ep_conn_data *ep);
190#else
191static inline int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
192 struct msmsdcc_sps_ep_conn_data *ep,
193 bool is_producer) { return 0; }
194static inline void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
195 struct msmsdcc_sps_ep_conn_data *ep) { }
196static inline int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
197 struct msmsdcc_sps_ep_conn_data *ep)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530198{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700199 return 0;
200}
201static inline int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
202 struct msmsdcc_sps_ep_conn_data *ep)
203{
204 return 0;
205}
206static inline int msmsdcc_sps_init(struct msmsdcc_host *host) { return 0; }
207static inline void msmsdcc_sps_exit(struct msmsdcc_host *host) {}
208#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530209
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700210/**
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530211 * Apply soft reset to all SDCC BAM pipes
212 *
213 * This function applies soft reset to SDCC BAM pipe.
214 *
215 * This function should be called to recover from error
216 * conditions encountered during CMD/DATA tranfsers with card.
217 *
218 * @host - Pointer to driver's host structure
219 *
220 */
221static void msmsdcc_sps_pipes_reset_and_restore(struct msmsdcc_host *host)
222{
223 int rc;
224
225 /* Reset all SDCC BAM pipes */
226 rc = msmsdcc_sps_reset_ep(host, &host->sps.prod);
227 if (rc)
228 pr_err("%s:msmsdcc_sps_reset_ep(prod) error=%d\n",
229 mmc_hostname(host->mmc), rc);
230 rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
231 if (rc)
232 pr_err("%s:msmsdcc_sps_reset_ep(cons) error=%d\n",
233 mmc_hostname(host->mmc), rc);
234
235 /* Restore all BAM pipes connections */
236 rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
237 if (rc)
238 pr_err("%s:msmsdcc_sps_restore_ep(prod) error=%d\n",
239 mmc_hostname(host->mmc), rc);
240 rc = msmsdcc_sps_restore_ep(host, &host->sps.cons);
241 if (rc)
242 pr_err("%s:msmsdcc_sps_restore_ep(cons) error=%d\n",
243 mmc_hostname(host->mmc), rc);
244}
245
246/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700247 * Apply soft reset
248 *
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530249 * This function applies soft reset to SDCC core and DML core.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700250 *
251 * This function should be called to recover from error
252 * conditions encountered with CMD/DATA tranfsers with card.
253 *
254 * Soft reset should only be used with SDCC controller v4.
255 *
256 * @host - Pointer to driver's host structure
257 *
258 */
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530259static void msmsdcc_soft_reset(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700260{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700261 /*
262 * Reset SDCC controller's DPSM (data path state machine
263 * and CPSM (command path state machine).
264 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700265 writel_relaxed(0, host->base + MMCICOMMAND);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530266 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700267 writel_relaxed(0, host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530268 msmsdcc_sync_reg_wr(host);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530269}
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530270
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530271static void msmsdcc_hard_reset(struct msmsdcc_host *host)
272{
273 int ret;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530274
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530275 /* Reset the controller */
276 ret = clk_reset(host->clk, CLK_RESET_ASSERT);
277 if (ret)
278 pr_err("%s: Clock assert failed at %u Hz"
279 " with err %d\n", mmc_hostname(host->mmc),
280 host->clk_rate, ret);
281
282 ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
283 if (ret)
284 pr_err("%s: Clock deassert failed at %u Hz"
285 " with err %d\n", mmc_hostname(host->mmc),
286 host->clk_rate, ret);
287
Subhash Jadavanidd432952012-03-28 11:25:56 +0530288 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530289 /* Give some delay for clock reset to propogate to controller */
290 msmsdcc_delay(host);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530291}
292
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700293static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
294{
Pratibhasagar V1c11da62011-11-14 12:36:35 +0530295 if (host->sdcc_version) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530296 if (host->is_sps_mode) {
297 /* Reset DML first */
298 msmsdcc_dml_reset(host);
299 /*
300 * delay the SPS pipe reset in thread context as
301 * sps_connect/sps_disconnect APIs can be called
302 * only from non-atomic context.
303 */
304 host->sps.pipe_reset_pending = true;
305 }
306 mb();
307 msmsdcc_soft_reset(host);
308
309 pr_debug("%s: Applied soft reset to Controller\n",
310 mmc_hostname(host->mmc));
311
312 if (host->is_sps_mode)
313 msmsdcc_dml_init(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700314 } else {
315 /* Give Clock reset (hard reset) to controller */
316 u32 mci_clk = 0;
317 u32 mci_mask0 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700318
319 /* Save the controller state */
320 mci_clk = readl_relaxed(host->base + MMCICLOCK);
321 mci_mask0 = readl_relaxed(host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +0530322 host->pwr = readl_relaxed(host->base + MMCIPOWER);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700323 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700324
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530325 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700326 pr_debug("%s: Controller has been reinitialized\n",
327 mmc_hostname(host->mmc));
328
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700329 /* Restore the contoller state */
330 writel_relaxed(host->pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530331 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700332 writel_relaxed(mci_clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530333 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700334 writel_relaxed(mci_mask0, host->base + MMCIMASK0);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530335 mb(); /* no delay required after writing to MASK0 register */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700336 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530337
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700338 if (host->dummy_52_needed)
339 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700340}
341
342static int
San Mehat9d2bd732009-09-22 16:44:22 -0700343msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
344{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700345 int retval = 0;
346
San Mehat9d2bd732009-09-22 16:44:22 -0700347 BUG_ON(host->curr.data);
348
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700349 del_timer(&host->req_tout_timer);
350
San Mehat9d2bd732009-09-22 16:44:22 -0700351 if (mrq->data)
352 mrq->data->bytes_xfered = host->curr.data_xfered;
353 if (mrq->cmd->error == -ETIMEDOUT)
354 mdelay(5);
355
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530356 /* Clear current request information as current request has ended */
357 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
358
San Mehat9d2bd732009-09-22 16:44:22 -0700359 /*
360 * Need to drop the host lock here; mmc_request_done may call
361 * back into the driver...
362 */
363 spin_unlock(&host->lock);
364 mmc_request_done(host->mmc, mrq);
365 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700366
367 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700368}
369
370static void
371msmsdcc_stop_data(struct msmsdcc_host *host)
372{
San Mehat9d2bd732009-09-22 16:44:22 -0700373 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530374 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530375 host->curr.wait_for_auto_prog_done = 0;
376 host->curr.got_auto_prog_done = 0;
Krishna Konda3f5d48f2011-07-27 10:47:31 -0700377 writel_relaxed(readl_relaxed(host->base + MMCIDATACTRL) &
378 (~(MCI_DPSM_ENABLE)), host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530379 msmsdcc_sync_reg_wr(host); /* Allow the DPSM to be reset */
San Mehat9d2bd732009-09-22 16:44:22 -0700380}
381
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700382static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700383{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700384 return host->core_memres->start + MMCIFIFO;
385}
386
387static inline unsigned int msmsdcc_get_min_sup_clk_rate(
388 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530389
Subhash Jadavanidd432952012-03-28 11:25:56 +0530390static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700391{
392 mb();
Subhash Jadavanidd432952012-03-28 11:25:56 +0530393 if (!host->sdcc_version)
394 udelay(host->reg_write_delay);
395 else if (readl_relaxed(host->base + MCI_STATUS2) &
396 MCI_MCLK_REG_WR_ACTIVE) {
397 ktime_t start, diff;
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530398
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530399 start = ktime_get();
400 while (readl_relaxed(host->base + MCI_STATUS2) &
401 MCI_MCLK_REG_WR_ACTIVE) {
402 diff = ktime_sub(ktime_get(), start);
403 /* poll for max. 1 ms */
404 if (ktime_to_us(diff) > 1000) {
405 pr_warning("%s: previous reg. write is"
406 " still active\n",
407 mmc_hostname(host->mmc));
408 break;
409 }
410 }
411 }
San Mehat9d2bd732009-09-22 16:44:22 -0700412}
413
Subhash Jadavanidd432952012-03-28 11:25:56 +0530414static inline void msmsdcc_delay(struct msmsdcc_host *host)
415{
416 udelay(host->reg_write_delay);
417
418}
419
San Mehat56a8b5b2009-11-21 12:29:46 -0800420static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700421msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
422{
423 writel_relaxed(arg, host->base + MMCIARGUMENT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700424 writel_relaxed(c, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530425 /*
426 * As after sending the command, we don't write any of the
427 * controller registers and just wait for the
428 * CMD_RESPOND_END/CMD_SENT/Command failure notication
429 * from Controller.
430 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700431 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800432}
433
434static void
435msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
436{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700437 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800438
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700439 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
440 writel_relaxed((unsigned int)host->curr.xfer_size,
441 host->base + MMCIDATALENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700442 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530443 msmsdcc_sync_reg_wr(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800444
San Mehat6ac9ea62009-12-02 17:24:58 -0800445 if (host->cmd_cmd) {
446 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700447 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800448 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800449}
450
San Mehat9d2bd732009-09-22 16:44:22 -0700451static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530452msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700453{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530454 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700455 unsigned long flags;
456 struct mmc_request *mrq;
457
458 spin_lock_irqsave(&host->lock, flags);
459 mrq = host->curr.mrq;
460 BUG_ON(!mrq);
461
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530462 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700463 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700464 goto out;
465 }
466
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530467 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700468 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700469 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700470 } else {
471 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530472 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700473 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530474 mmc_hostname(host->mmc), host->dma.result);
475 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700476 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530477 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530478 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700479 host->dma.err.flush[0], host->dma.err.flush[1],
480 host->dma.err.flush[2], host->dma.err.flush[3],
481 host->dma.err.flush[4],
482 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530483 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700484 if (!mrq->data->error)
485 mrq->data->error = -EIO;
486 }
San Mehat9d2bd732009-09-22 16:44:22 -0700487 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents,
488 host->dma.dir);
489
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700490 if (host->curr.user_pages) {
491 struct scatterlist *sg = host->dma.sg;
492 int i;
493
494 for (i = 0; i < host->dma.num_ents; i++, sg++)
495 flush_dcache_page(sg_page(sg));
496 }
497
San Mehat9d2bd732009-09-22 16:44:22 -0700498 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800499 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700500
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530501 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
502 (host->curr.wait_for_auto_prog_done &&
503 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700504 /*
505 * If we've already gotten our DATAEND / DATABLKEND
506 * for this request, then complete it through here.
507 */
San Mehat9d2bd732009-09-22 16:44:22 -0700508
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700509 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700510 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700511 host->curr.xfer_remain -= host->curr.xfer_size;
512 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700513 if (host->dummy_52_needed) {
514 mrq->data->bytes_xfered = host->curr.data_xfered;
515 host->dummy_52_sent = 1;
516 msmsdcc_start_command(host, &dummy52cmd,
517 MCI_CPSM_PROGENA);
518 goto out;
519 }
520 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530521 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530522 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700523 mrq->data->bytes_xfered = host->curr.data_xfered;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700524 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530525 /*
526 * Clear current request information as current
527 * request has ended
528 */
529 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
San Mehat9d2bd732009-09-22 16:44:22 -0700530 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700531
San Mehat9d2bd732009-09-22 16:44:22 -0700532 mmc_request_done(host->mmc, mrq);
533 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530534 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
535 || !mrq->sbc)) {
536 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530537 }
San Mehat9d2bd732009-09-22 16:44:22 -0700538 }
539
540out:
541 spin_unlock_irqrestore(&host->lock, flags);
542 return;
543}
544
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700545#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
546/**
547 * Callback notification from SPS driver
548 *
549 * This callback function gets triggered called from
550 * SPS driver when requested SPS data transfer is
551 * completed.
552 *
553 * SPS driver invokes this callback in BAM irq context so
554 * SDCC driver schedule a tasklet for further processing
555 * this callback notification at later point of time in
556 * tasklet context and immediately returns control back
557 * to SPS driver.
558 *
559 * @nofity - Pointer to sps event notify sturcture
560 *
561 */
562static void
563msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
564{
565 struct msmsdcc_host *host =
566 (struct msmsdcc_host *)
567 ((struct sps_event_notify *)notify)->user;
568
569 host->sps.notify = *notify;
570 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
571 mmc_hostname(host->mmc), __func__, notify->event_id,
572 notify->data.transfer.iovec.addr,
573 notify->data.transfer.iovec.size,
574 notify->data.transfer.iovec.flags);
575 /* Schedule a tasklet for completing data transfer */
576 tasklet_schedule(&host->sps.tlet);
577}
578
579/**
580 * Tasklet handler for processing SPS callback event
581 *
582 * This function processing SPS event notification and
583 * checks if the SPS transfer is completed or not and
584 * then accordingly notifies status to MMC core layer.
585 *
586 * This function is called in tasklet context.
587 *
588 * @data - Pointer to sdcc driver data
589 *
590 */
591static void msmsdcc_sps_complete_tlet(unsigned long data)
592{
593 unsigned long flags;
594 int i, rc;
595 u32 data_xfered = 0;
596 struct mmc_request *mrq;
597 struct sps_iovec iovec;
598 struct sps_pipe *sps_pipe_handle;
599 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
600 struct sps_event_notify *notify = &host->sps.notify;
601
602 spin_lock_irqsave(&host->lock, flags);
603 if (host->sps.dir == DMA_FROM_DEVICE)
604 sps_pipe_handle = host->sps.prod.pipe_handle;
605 else
606 sps_pipe_handle = host->sps.cons.pipe_handle;
607 mrq = host->curr.mrq;
608
609 if (!mrq) {
610 spin_unlock_irqrestore(&host->lock, flags);
611 return;
612 }
613
614 pr_debug("%s: %s: sps event_id=%d\n",
615 mmc_hostname(host->mmc), __func__,
616 notify->event_id);
617
618 if (msmsdcc_is_dml_busy(host)) {
619 /* oops !!! this should never happen. */
620 pr_err("%s: %s: Received SPS EOT event"
621 " but DML HW is still busy !!!\n",
622 mmc_hostname(host->mmc), __func__);
623 }
624 /*
625 * Got End of transfer event!!! Check if all of the data
626 * has been transferred?
627 */
628 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
629 rc = sps_get_iovec(sps_pipe_handle, &iovec);
630 if (rc) {
631 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
632 mmc_hostname(host->mmc), __func__, rc, i);
633 break;
634 }
635 data_xfered += iovec.size;
636 }
637
638 if (data_xfered == host->curr.xfer_size) {
639 host->curr.data_xfered = host->curr.xfer_size;
640 host->curr.xfer_remain -= host->curr.xfer_size;
641 pr_debug("%s: Data xfer success. data_xfered=0x%x",
642 mmc_hostname(host->mmc),
643 host->curr.xfer_size);
644 } else {
645 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
646 " xfer_size=%d", mmc_hostname(host->mmc),
647 data_xfered, host->curr.xfer_size);
648 msmsdcc_reset_and_restore(host);
649 if (!mrq->data->error)
650 mrq->data->error = -EIO;
651 }
652
653 /* Unmap sg buffers */
654 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
655 host->sps.dir);
656
657 host->sps.sg = NULL;
658 host->sps.busy = 0;
659
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530660 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
661 (host->curr.wait_for_auto_prog_done &&
662 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700663 /*
664 * If we've already gotten our DATAEND / DATABLKEND
665 * for this request, then complete it through here.
666 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700667
668 if (!mrq->data->error) {
669 host->curr.data_xfered = host->curr.xfer_size;
670 host->curr.xfer_remain -= host->curr.xfer_size;
671 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700672 if (host->dummy_52_needed) {
673 mrq->data->bytes_xfered = host->curr.data_xfered;
674 host->dummy_52_sent = 1;
675 msmsdcc_start_command(host, &dummy52cmd,
676 MCI_CPSM_PROGENA);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700677 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700678 return;
679 }
680 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530681 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530682 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700683 mrq->data->bytes_xfered = host->curr.data_xfered;
684 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530685 /*
686 * Clear current request information as current
687 * request has ended
688 */
689 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700690 spin_unlock_irqrestore(&host->lock, flags);
691
692 mmc_request_done(host->mmc, mrq);
693 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530694 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
695 || !mrq->sbc)) {
696 msmsdcc_start_command(host, mrq->data->stop, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700697 }
698 }
699 spin_unlock_irqrestore(&host->lock, flags);
700}
701
702/**
703 * Exit from current SPS data transfer
704 *
705 * This function exits from current SPS data transfer.
706 *
707 * This function should be called when error condition
708 * is encountered during data transfer.
709 *
710 * @host - Pointer to sdcc host structure
711 *
712 */
713static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
714{
715 struct mmc_request *mrq;
716
717 mrq = host->curr.mrq;
718 BUG_ON(!mrq);
719
720 msmsdcc_reset_and_restore(host);
721 if (!mrq->data->error)
722 mrq->data->error = -EIO;
723
724 /* Unmap sg buffers */
725 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
726 host->sps.dir);
727
728 host->sps.sg = NULL;
729 host->sps.busy = 0;
730 if (host->curr.data)
731 msmsdcc_stop_data(host);
732
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530733 if (!mrq->data->stop || mrq->cmd->error ||
734 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700735 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530736 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
737 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700738 msmsdcc_start_command(host, mrq->data->stop, 0);
739
740}
741#else
742static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
743static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
744static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
745#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
746
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530747static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700748
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530749static void
750msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
751 unsigned int result,
752 struct msm_dmov_errdata *err)
753{
754 struct msmsdcc_dma_data *dma_data =
755 container_of(cmd, struct msmsdcc_dma_data, hdr);
756 struct msmsdcc_host *host = dma_data->host;
757
758 dma_data->result = result;
759 if (err)
760 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
761
762 tasklet_schedule(&host->dma_tlet);
763}
764
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530765static bool msmsdcc_is_dma_possible(struct msmsdcc_host *host,
766 struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700767{
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530768 bool ret = true;
769 u32 xfer_size = data->blksz * data->blocks;
770
771 if (host->is_sps_mode) {
772 /*
773 * BAM Mode: Fall back on PIO if size is less
774 * than or equal to SPS_MIN_XFER_SIZE bytes.
775 */
776 if (xfer_size <= SPS_MIN_XFER_SIZE)
777 ret = false;
778 } else if (host->is_dma_mode) {
779 /*
780 * ADM Mode: Fall back on PIO if size is less than FIFO size
781 * or not integer multiple of FIFO size
782 */
783 if (xfer_size % MCI_FIFOSIZE)
784 ret = false;
785 } else {
786 /* PIO Mode */
787 ret = false;
788 }
789
790 return ret;
San Mehat9d2bd732009-09-22 16:44:22 -0700791}
792
793static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
794{
795 struct msmsdcc_nc_dmadata *nc;
796 dmov_box *box;
797 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700798 unsigned int n;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530799 int i, err = 0, box_cmd_cnt = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700800 struct scatterlist *sg = data->sg;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530801 unsigned int len, offset;
San Mehat9d2bd732009-09-22 16:44:22 -0700802
Krishna Konda25786ec2011-07-25 16:21:36 -0700803 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700804 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700805
Krishna Konda25786ec2011-07-25 16:21:36 -0700806 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
807
San Mehat9d2bd732009-09-22 16:44:22 -0700808 host->dma.sg = data->sg;
809 host->dma.num_ents = data->sg_len;
810
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530811 /* Prevent memory corruption */
812 BUG_ON(host->dma.num_ents > msmsdcc_get_nr_sg(host));
San Mehat56a8b5b2009-11-21 12:29:46 -0800813
San Mehat9d2bd732009-09-22 16:44:22 -0700814 nc = host->dma.nc;
815
San Mehat9d2bd732009-09-22 16:44:22 -0700816 if (data->flags & MMC_DATA_READ)
817 host->dma.dir = DMA_FROM_DEVICE;
818 else
819 host->dma.dir = DMA_TO_DEVICE;
820
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700821 n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
822 host->dma.num_ents, host->dma.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700823
824 if (n != host->dma.num_ents) {
825 pr_err("%s: Unable to map in all sg elements\n",
826 mmc_hostname(host->mmc));
827 host->dma.sg = NULL;
828 host->dma.num_ents = 0;
829 return -ENOMEM;
San Mehat56a8b5b2009-11-21 12:29:46 -0800830 }
San Mehat9d2bd732009-09-22 16:44:22 -0700831
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530832 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
833 host->curr.user_pages = 0;
834 box = &nc->cmd[0];
835 for (i = 0; i < host->dma.num_ents; i++) {
836 len = sg_dma_len(sg);
837 offset = 0;
838
839 do {
840 /* Check if we can do DMA */
841 if (!len || (box_cmd_cnt >= MMC_MAX_DMA_CMDS)) {
842 err = -ENOTSUPP;
843 goto unmap;
844 }
845
846 box->cmd = CMD_MODE_BOX;
847
848 if (len >= MMC_MAX_DMA_BOX_LENGTH) {
849 len = MMC_MAX_DMA_BOX_LENGTH;
850 len -= len % data->blksz;
851 }
852 rows = (len % MCI_FIFOSIZE) ?
853 (len / MCI_FIFOSIZE) + 1 :
854 (len / MCI_FIFOSIZE);
855
856 if (data->flags & MMC_DATA_READ) {
857 box->src_row_addr = msmsdcc_fifo_addr(host);
858 box->dst_row_addr = sg_dma_address(sg) + offset;
859 box->src_dst_len = (MCI_FIFOSIZE << 16) |
860 (MCI_FIFOSIZE);
861 box->row_offset = MCI_FIFOSIZE;
862 box->num_rows = rows * ((1 << 16) + 1);
863 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
864 } else {
865 box->src_row_addr = sg_dma_address(sg) + offset;
866 box->dst_row_addr = msmsdcc_fifo_addr(host);
867 box->src_dst_len = (MCI_FIFOSIZE << 16) |
868 (MCI_FIFOSIZE);
869 box->row_offset = (MCI_FIFOSIZE << 16);
870 box->num_rows = rows * ((1 << 16) + 1);
871 box->cmd |= CMD_DST_CRCI(host->dma.crci);
872 }
873
874 offset += len;
875 len = sg_dma_len(sg) - offset;
876 box++;
877 box_cmd_cnt++;
878 } while (len);
879 sg++;
880 }
881 /* Mark last command */
882 box--;
883 box->cmd |= CMD_LC;
884
885 /* location of command block must be 64 bit aligned */
886 BUG_ON(host->dma.cmd_busaddr & 0x07);
887
888 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
889 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
890 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
891 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
892
893 /* Flush all data to memory before starting dma */
894 mb();
895
896unmap:
897 if (err) {
898 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
899 host->dma.num_ents, host->dma.dir);
900 pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
901 mmc_hostname(host->mmc), err);
902 }
903
904 return err;
San Mehat9d2bd732009-09-22 16:44:22 -0700905}
906
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700907#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
908/**
909 * Submits data transfer request to SPS driver
910 *
911 * This function make sg (scatter gather) data buffers
912 * DMA ready and then submits them to SPS driver for
913 * transfer.
914 *
915 * @host - Pointer to sdcc host structure
916 * @data - Pointer to mmc_data structure
917 *
918 * @return 0 if success else negative value
919 */
920static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
921 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -0800922{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700923 int rc = 0;
924 u32 flags;
925 int i;
926 u32 addr, len, data_cnt;
927 struct scatterlist *sg = data->sg;
928 struct sps_pipe *sps_pipe_handle;
929
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530930 /* Prevent memory corruption */
931 BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700932
933 host->sps.sg = data->sg;
934 host->sps.num_ents = data->sg_len;
935 host->sps.xfer_req_cnt = 0;
936 if (data->flags & MMC_DATA_READ) {
937 host->sps.dir = DMA_FROM_DEVICE;
938 sps_pipe_handle = host->sps.prod.pipe_handle;
939 } else {
940 host->sps.dir = DMA_TO_DEVICE;
941 sps_pipe_handle = host->sps.cons.pipe_handle;
942 }
943
944 /* Make sg buffers DMA ready */
945 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
946 host->sps.dir);
947
948 if (rc != data->sg_len) {
949 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
950 mmc_hostname(host->mmc), rc);
951 host->sps.sg = NULL;
952 host->sps.num_ents = 0;
953 rc = -ENOMEM;
954 goto dma_map_err;
955 }
956
957 pr_debug("%s: %s: %s: pipe=0x%x, total_xfer=0x%x, sg_len=%d\n",
958 mmc_hostname(host->mmc), __func__,
959 host->sps.dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
960 (u32)sps_pipe_handle, host->curr.xfer_size, data->sg_len);
961
962 for (i = 0; i < data->sg_len; i++) {
963 /*
964 * Check if this is the last buffer to transfer?
965 * If yes then set the INT and EOT flags.
966 */
967 len = sg_dma_len(sg);
968 addr = sg_dma_address(sg);
969 flags = 0;
970 while (len > 0) {
971 if (len > SPS_MAX_DESC_SIZE) {
972 data_cnt = SPS_MAX_DESC_SIZE;
973 } else {
974 data_cnt = len;
975 if (i == data->sg_len - 1)
976 flags = SPS_IOVEC_FLAG_INT |
977 SPS_IOVEC_FLAG_EOT;
978 }
979 rc = sps_transfer_one(sps_pipe_handle, addr,
980 data_cnt, host, flags);
981 if (rc) {
982 pr_err("%s: sps_transfer_one() error! rc=%d,"
983 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
984 mmc_hostname(host->mmc), rc,
985 (u32)sps_pipe_handle, (u32)sg, i);
986 goto dma_map_err;
987 }
988 addr += data_cnt;
989 len -= data_cnt;
990 host->sps.xfer_req_cnt++;
991 }
992 sg++;
993 }
994 goto out;
995
996dma_map_err:
997 /* unmap sg buffers */
998 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
999 host->sps.dir);
1000out:
1001 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07001002}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001003#else
1004static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
1005 struct mmc_data *data) { return 0; }
1006#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -07001007
1008static void
San Mehat56a8b5b2009-11-21 12:29:46 -08001009msmsdcc_start_command_deferred(struct msmsdcc_host *host,
1010 struct mmc_command *cmd, u32 *c)
1011{
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301012 DBG(host, "op %02x arg %08x flags %08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001013 cmd->opcode, cmd->arg, cmd->flags);
1014
San Mehat56a8b5b2009-11-21 12:29:46 -08001015 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
1016
1017 if (cmd->flags & MMC_RSP_PRESENT) {
1018 if (cmd->flags & MMC_RSP_136)
1019 *c |= MCI_CPSM_LONGRSP;
1020 *c |= MCI_CPSM_RESPONSE;
1021 }
1022
1023 if (/*interrupt*/0)
1024 *c |= MCI_CPSM_INTERRUPT;
1025
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301026 if (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
1027 cmd->opcode == MMC_READ_MULTIPLE_BLOCK ||
1028 cmd->opcode == MMC_WRITE_BLOCK ||
1029 cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK ||
1030 cmd->opcode == SD_IO_RW_EXTENDED)
San Mehat56a8b5b2009-11-21 12:29:46 -08001031 *c |= MCI_CSPM_DATCMD;
1032
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001033 /* Check if AUTO CMD19 is required or not? */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301034 if (host->tuning_needed &&
1035 !(host->mmc->ios.timing == MMC_TIMING_MMC_HS200)) {
1036
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301037 /*
1038 * For open ended block read operation (without CMD23),
1039 * AUTO_CMD19 bit should be set while sending the READ command.
1040 * For close ended block read operation (with CMD23),
1041 * AUTO_CMD19 bit should be set while sending CMD23.
1042 */
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301043 if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
1044 host->curr.mrq->cmd->opcode ==
1045 MMC_READ_MULTIPLE_BLOCK) ||
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301046 (!host->curr.mrq->sbc &&
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301047 (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
1048 cmd->opcode == MMC_READ_MULTIPLE_BLOCK))) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301049 msmsdcc_enable_cdr_cm_sdc4_dll(host);
1050 *c |= MCI_CSPM_AUTO_CMD19;
1051 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001052 }
1053
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05301054 /* Clear CDR_EN bit for write operations */
1055 if (host->tuning_needed && cmd->mrq->data &&
1056 (cmd->mrq->data->flags & MMC_DATA_WRITE))
1057 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) &
1058 ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
1059
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301060 if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301061 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001062 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301063 }
1064
San Mehat56a8b5b2009-11-21 12:29:46 -08001065 if (cmd == cmd->mrq->stop)
1066 *c |= MCI_CSPM_MCIABORT;
1067
San Mehat56a8b5b2009-11-21 12:29:46 -08001068 if (host->curr.cmd != NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001069 pr_err("%s: Overlapping command requests\n",
1070 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -08001071 }
1072 host->curr.cmd = cmd;
1073}
1074
1075static void
1076msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1077 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001078{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301079 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001080 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001081 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001082 unsigned int pio_irqmask = 0;
1083
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301084 BUG_ON(!data->sg);
1085 BUG_ON(!data->sg_len);
1086
San Mehat9d2bd732009-09-22 16:44:22 -07001087 host->curr.data = data;
1088 host->curr.xfer_size = data->blksz * data->blocks;
1089 host->curr.xfer_remain = host->curr.xfer_size;
1090 host->curr.data_xfered = 0;
1091 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301092 host->curr.got_auto_prog_done = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001093
San Mehat9d2bd732009-09-22 16:44:22 -07001094 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1095
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301096 if (host->curr.wait_for_auto_prog_done)
1097 datactrl |= MCI_AUTO_PROG_DONE;
1098
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05301099 if (msmsdcc_is_dma_possible(host, data)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001100 if (host->is_dma_mode && !msmsdcc_config_dma(host, data)) {
1101 datactrl |= MCI_DPSM_DMAENABLE;
1102 } else if (host->is_sps_mode) {
1103 if (!msmsdcc_is_dml_busy(host)) {
1104 if (!msmsdcc_sps_start_xfer(host, data)) {
1105 /* Now kick start DML transfer */
1106 mb();
1107 msmsdcc_dml_start_xfer(host, data);
1108 datactrl |= MCI_DPSM_DMAENABLE;
1109 host->sps.busy = 1;
1110 }
1111 } else {
1112 /*
1113 * Can't proceed with new transfer as
1114 * previous trasnfer is already in progress.
1115 * There is no point of going into PIO mode
1116 * as well. Is this a time to do kernel panic?
1117 */
1118 pr_err("%s: %s: DML HW is busy!!!"
1119 " Can't perform new SPS transfers"
1120 " now\n", mmc_hostname(host->mmc),
1121 __func__);
1122 }
1123 }
1124 }
1125
1126 /* Is data transfer in PIO mode required? */
1127 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001128 if (data->flags & MMC_DATA_READ) {
1129 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1130 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1131 pio_irqmask |= MCI_RXDATAAVLBLMASK;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001132 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001133 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1134 MCI_TXFIFOEMPTYMASK;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001135
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001136 msmsdcc_sg_start(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001137 }
1138
1139 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301140 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
San Mehat9d2bd732009-09-22 16:44:22 -07001141
San Mehat56a8b5b2009-11-21 12:29:46 -08001142 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001143 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001144 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -07001145
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001146 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
1147 /* Use ADM (Application Data Mover) HW for Data transfer */
1148 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001149 host->cmd_timeout = timeout;
1150 host->cmd_pio_irqmask = pio_irqmask;
1151 host->cmd_datactrl = datactrl;
1152 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001153
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001154 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1155 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001156 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001157
1158 if (cmd) {
1159 msmsdcc_start_command_deferred(host, cmd, &c);
1160 host->cmd_c = c;
1161 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001162 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1163 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1164 host->base + MMCIMASK0);
1165 mb();
1166 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001167 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001168 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001169 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001170
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001171 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001172
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001173 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1174 (~(MCI_IRQ_PIO))) | pio_irqmask,
1175 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001176 writel_relaxed(datactrl, base + MMCIDATACTRL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001177
1178 if (cmd) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05301179 /* Delay between data/command */
1180 msmsdcc_sync_reg_wr(host);
San Mehat56a8b5b2009-11-21 12:29:46 -08001181 /* Daisy-chain the command if requested */
1182 msmsdcc_start_command(host, cmd, c);
Subhash Jadavanidd432952012-03-28 11:25:56 +05301183 } else {
1184 /*
1185 * We don't need delay after writing to DATA_CTRL
1186 * register if we are not writing to CMD register
1187 * immediately after this. As we already have delay
1188 * before sending the command, we just need mb() here.
1189 */
1190 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001191 }
San Mehat9d2bd732009-09-22 16:44:22 -07001192 }
1193}
1194
1195static void
1196msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1197{
San Mehat56a8b5b2009-11-21 12:29:46 -08001198 msmsdcc_start_command_deferred(host, cmd, &c);
1199 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001200}
1201
1202static void
1203msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1204 unsigned int status)
1205{
1206 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001207 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
Subhash Jadavanib30c9822012-03-27 18:03:16 +05301208 || data->mrq->cmd->opcode == MMC_BUS_TEST_R
1209 || data->mrq->cmd->opcode ==
1210 MMC_SEND_TUNING_BLOCK_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001211 pr_err("%s: Data CRC error\n",
1212 mmc_hostname(host->mmc));
1213 pr_err("%s: opcode 0x%.8x\n", __func__,
1214 data->mrq->cmd->opcode);
1215 pr_err("%s: blksz %d, blocks %d\n", __func__,
1216 data->blksz, data->blocks);
1217 data->error = -EILSEQ;
1218 }
San Mehat9d2bd732009-09-22 16:44:22 -07001219 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001220 /* CRC is optional for the bus test commands, not all
1221 * cards respond back with CRC. However controller
1222 * waits for the CRC and times out. Hence ignore the
1223 * data timeouts during the Bustest.
1224 */
1225 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1226 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301227 pr_err("%s: CMD%d: Data timeout\n",
1228 mmc_hostname(host->mmc),
1229 data->mrq->cmd->opcode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001230 data->error = -ETIMEDOUT;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301231 msmsdcc_dump_sdcc_state(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001232 }
San Mehat9d2bd732009-09-22 16:44:22 -07001233 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001234 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001235 data->error = -EIO;
1236 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001237 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001238 data->error = -EIO;
1239 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001240 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001241 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001242 data->error = -EIO;
1243 }
San Mehat9d2bd732009-09-22 16:44:22 -07001244
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001245 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001246 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001247 host->dummy_52_needed = 0;
1248}
San Mehat9d2bd732009-09-22 16:44:22 -07001249
1250static int
1251msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1252{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001253 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001254 uint32_t *ptr = (uint32_t *) buffer;
1255 int count = 0;
1256
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301257 if (remain % 4)
1258 remain = ((remain >> 2) + 1) << 2;
1259
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001260 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1261
1262 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001263 ptr++;
1264 count += sizeof(uint32_t);
1265
1266 remain -= sizeof(uint32_t);
1267 if (remain == 0)
1268 break;
1269 }
1270 return count;
1271}
1272
1273static int
1274msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001275 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001276{
1277 void __iomem *base = host->base;
1278 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001279 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001280
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001281 while (readl_relaxed(base + MMCISTATUS) &
1282 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1283 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001284
San Mehat9d2bd732009-09-22 16:44:22 -07001285 count = min(remain, maxcnt);
1286
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301287 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1288 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001289 ptr += count;
1290 remain -= count;
1291
1292 if (remain == 0)
1293 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001294 }
1295 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001296
1297 return ptr - buffer;
1298}
1299
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001300/*
1301 * Copy up to a word (4 bytes) between a scatterlist
1302 * and a temporary bounce buffer when the word lies across
1303 * two pages. The temporary buffer can then be read to/
1304 * written from the FIFO once.
1305 */
1306static void _msmsdcc_sg_consume_word(struct msmsdcc_host *host)
1307{
1308 struct msmsdcc_pio_data *pio = &host->pio;
1309 unsigned int bytes_avail;
1310
1311 if (host->curr.data->flags & MMC_DATA_READ)
1312 memcpy(pio->sg_miter.addr, pio->bounce_buf,
1313 pio->bounce_buf_len);
1314 else
1315 memcpy(pio->bounce_buf, pio->sg_miter.addr,
1316 pio->bounce_buf_len);
1317
1318 while (pio->bounce_buf_len != 4) {
1319 if (!sg_miter_next(&pio->sg_miter))
1320 break;
1321 bytes_avail = min_t(unsigned int, pio->sg_miter.length,
1322 4 - pio->bounce_buf_len);
1323 if (host->curr.data->flags & MMC_DATA_READ)
1324 memcpy(pio->sg_miter.addr,
1325 &pio->bounce_buf[pio->bounce_buf_len],
1326 bytes_avail);
1327 else
1328 memcpy(&pio->bounce_buf[pio->bounce_buf_len],
1329 pio->sg_miter.addr, bytes_avail);
1330
1331 pio->sg_miter.consumed = bytes_avail;
1332 pio->bounce_buf_len += bytes_avail;
1333 }
1334}
1335
1336/*
1337 * Use sg_miter_next to return as many 4-byte aligned
1338 * chunks as possible, using a temporary 4 byte buffer
1339 * for alignment if necessary
1340 */
1341static int msmsdcc_sg_next(struct msmsdcc_host *host, char **buf, int *len)
1342{
1343 struct msmsdcc_pio_data *pio = &host->pio;
1344 unsigned int length, rlength;
1345 char *buffer;
1346
1347 if (!sg_miter_next(&pio->sg_miter))
1348 return 0;
1349
1350 buffer = pio->sg_miter.addr;
1351 length = pio->sg_miter.length;
1352
1353 if (length < host->curr.xfer_remain) {
1354 rlength = round_down(length, 4);
1355 if (rlength) {
1356 /*
1357 * We have a 4-byte aligned chunk.
1358 * The rounding will be reflected by
1359 * a call to msmsdcc_sg_consumed
1360 */
1361 length = rlength;
1362 goto sg_next_end;
1363 }
1364 /*
1365 * We have a length less than 4 bytes. Check to
1366 * see if more buffer is available, and combine
1367 * to make 4 bytes if possible.
1368 */
1369 pio->bounce_buf_len = length;
1370 memset(pio->bounce_buf, 0, 4);
1371
1372 /*
1373 * On a read, get 4 bytes from FIFO, and distribute
1374 * (4-bouce_buf_len) bytes into consecutive
1375 * sgl buffers when msmsdcc_sg_consumed is called
1376 */
1377 if (host->curr.data->flags & MMC_DATA_READ) {
1378 buffer = pio->bounce_buf;
1379 length = 4;
1380 goto sg_next_end;
1381 } else {
1382 _msmsdcc_sg_consume_word(host);
1383 buffer = pio->bounce_buf;
1384 length = pio->bounce_buf_len;
1385 }
1386 }
1387
1388sg_next_end:
1389 *buf = buffer;
1390 *len = length;
1391 return 1;
1392}
1393
1394/*
1395 * Update sg_miter.consumed based on how many bytes were
1396 * consumed. If the bounce buffer was used to read from FIFO,
1397 * redistribute into sgls.
1398 */
1399static void msmsdcc_sg_consumed(struct msmsdcc_host *host,
1400 unsigned int length)
1401{
1402 struct msmsdcc_pio_data *pio = &host->pio;
1403
1404 if (host->curr.data->flags & MMC_DATA_READ) {
1405 if (length > pio->sg_miter.consumed)
1406 /*
1407 * consumed 4 bytes, but sgl
1408 * describes < 4 bytes
1409 */
1410 _msmsdcc_sg_consume_word(host);
1411 else
1412 pio->sg_miter.consumed = length;
1413 } else
1414 if (length < pio->sg_miter.consumed)
1415 pio->sg_miter.consumed = length;
1416}
1417
1418static void msmsdcc_sg_start(struct msmsdcc_host *host)
1419{
1420 unsigned int sg_miter_flags = SG_MITER_ATOMIC;
1421
1422 host->pio.bounce_buf_len = 0;
1423
1424 if (host->curr.data->flags & MMC_DATA_READ)
1425 sg_miter_flags |= SG_MITER_TO_SG;
1426 else
1427 sg_miter_flags |= SG_MITER_FROM_SG;
1428
1429 sg_miter_start(&host->pio.sg_miter, host->curr.data->sg,
1430 host->curr.data->sg_len, sg_miter_flags);
1431}
1432
1433static void msmsdcc_sg_stop(struct msmsdcc_host *host)
1434{
1435 sg_miter_stop(&host->pio.sg_miter);
1436}
1437
San Mehat1cd22962010-02-03 12:59:29 -08001438static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001439msmsdcc_pio_irq(int irq, void *dev_id)
1440{
1441 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001442 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001443 uint32_t status;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001444 unsigned long flags;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001445 unsigned int remain;
1446 char *buffer;
San Mehat9d2bd732009-09-22 16:44:22 -07001447
Murali Palnati36448a42011-09-02 15:06:18 +05301448 spin_lock(&host->lock);
1449
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001450 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001451
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001452 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301453 (MCI_IRQ_PIO)) == 0) {
1454 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001455 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301456 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001457#if IRQ_DEBUG
1458 msmsdcc_print_status(host, "irq1-r", status);
1459#endif
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001460 local_irq_save(flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001461
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001462 do {
1463 unsigned int len;
San Mehat9d2bd732009-09-22 16:44:22 -07001464
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001465 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1466 | MCI_RXDATAAVLBL)))
1467 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001468
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001469 if (!msmsdcc_sg_next(host, &buffer, &remain))
1470 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001471
San Mehat9d2bd732009-09-22 16:44:22 -07001472 len = 0;
1473 if (status & MCI_RXACTIVE)
1474 len = msmsdcc_pio_read(host, buffer, remain);
1475 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001476 len = msmsdcc_pio_write(host, buffer, remain);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001477
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301478 /* len might have aligned to 32bits above */
1479 if (len > remain)
1480 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001481
San Mehat9d2bd732009-09-22 16:44:22 -07001482 host->curr.xfer_remain -= len;
1483 host->curr.data_xfered += len;
1484 remain -= len;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001485 msmsdcc_sg_consumed(host, len);
San Mehat9d2bd732009-09-22 16:44:22 -07001486
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001487 if (remain) /* Done with this page? */
1488 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001489
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001490 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001491 } while (1);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001492
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001493 msmsdcc_sg_stop(host);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001494 local_irq_restore(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001495
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001496 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1497 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1498 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1499 host->base + MMCIMASK0);
1500 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301501 /*
1502 * back to back write to MASK0 register don't need
1503 * synchronization delay.
1504 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001505 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1506 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1507 }
1508 mb();
1509 } else if (!host->curr.xfer_remain) {
1510 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1511 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1512 mb();
1513 }
San Mehat9d2bd732009-09-22 16:44:22 -07001514
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001515 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001516
1517 return IRQ_HANDLED;
1518}
1519
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001520static void
1521msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1522
1523static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1524 struct mmc_data *data)
1525{
1526 u32 loop_cnt = 0;
1527
1528 /*
1529 * For read commands with data less than fifo size, it is possible to
1530 * get DATAEND first and RXDATA_AVAIL might be set later because of
1531 * synchronization delay through the asynchronous RX FIFO. Thus, for
1532 * such cases, even after DATAEND interrupt is received software
1533 * should poll for RXDATA_AVAIL until the requested data is read out
1534 * of FIFO. This change is needed to get around this abnormal but
1535 * sometimes expected behavior of SDCC3 controller.
1536 *
1537 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1538 * after the data is loaded into RX FIFO. This would amount to less
1539 * than a microsecond and thus looping for 1000 times is good enough
1540 * for that delay.
1541 */
1542 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1543 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1544 spin_unlock(&host->lock);
1545 msmsdcc_pio_irq(1, host);
1546 spin_lock(&host->lock);
1547 }
1548 }
1549 if (loop_cnt == 1000) {
1550 pr_info("%s: Timed out while polling for Rx Data\n",
1551 mmc_hostname(host->mmc));
1552 data->error = -ETIMEDOUT;
1553 msmsdcc_reset_and_restore(host);
1554 }
1555}
1556
San Mehat9d2bd732009-09-22 16:44:22 -07001557static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1558{
1559 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001560
1561 host->curr.cmd = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001562 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1563 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1564 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1565 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -07001566
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001567 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301568 pr_debug("%s: CMD%d: Command timeout\n",
1569 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001570 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001571 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301572 !host->tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301573 pr_err("%s: CMD%d: Command CRC error\n",
1574 mmc_hostname(host->mmc), cmd->opcode);
1575 msmsdcc_dump_sdcc_state(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001576 cmd->error = -EILSEQ;
1577 }
1578
1579 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001580 if (host->curr.data && host->dma.sg &&
1581 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001582 msm_dmov_stop_cmd(host->dma.channel,
1583 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001584 else if (host->curr.data && host->sps.sg &&
1585 host->is_sps_mode){
1586 /* Stop current SPS transfer */
1587 msmsdcc_sps_exit_curr_xfer(host);
1588 }
San Mehat9d2bd732009-09-22 16:44:22 -07001589 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301590 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001591 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301592 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301593 } else { /* host->data == NULL */
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301594 if (!cmd->error && host->prog_enable) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301595 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001596 host->prog_enable = 0;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301597 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001598 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301599 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301600 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301601 host->prog_enable = 0;
Subhash Jadavanied6b0e42012-03-07 16:36:27 +05301602 host->curr.wait_for_auto_prog_done = 0;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001603 if (host->dummy_52_needed)
1604 host->dummy_52_needed = 0;
1605 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001606 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301607 msmsdcc_request_end(host, cmd->mrq);
1608 }
1609 }
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301610 } else if ((cmd == host->curr.mrq->sbc) && cmd->data) {
1611 if (cmd->data->flags & MMC_DATA_READ)
1612 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1613 else
1614 msmsdcc_request_start(host, host->curr.mrq);
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301615 } else if (cmd->data) {
1616 if (!(cmd->data->flags & MMC_DATA_READ))
1617 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001618 }
1619}
1620
San Mehat9d2bd732009-09-22 16:44:22 -07001621static irqreturn_t
1622msmsdcc_irq(int irq, void *dev_id)
1623{
1624 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001625 u32 status;
1626 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001627 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001628
1629 spin_lock(&host->lock);
1630
1631 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001632 struct mmc_command *cmd;
1633 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001634
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001635 if (timer) {
1636 timer = 0;
1637 msmsdcc_delay(host);
1638 }
San Mehat865c8062009-11-13 13:42:06 -08001639
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001640 if (!host->clks_on) {
1641 pr_debug("%s: %s: SDIO async irq received\n",
1642 mmc_hostname(host->mmc), __func__);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301643
1644 /*
1645 * Only async interrupt can come when clocks are off,
1646 * disable further interrupts and enable them when
1647 * clocks are on.
1648 */
1649 if (!host->sdcc_irq_disabled) {
1650 disable_irq_nosync(irq);
1651 host->sdcc_irq_disabled = 1;
1652 }
1653
1654 /*
1655 * If mmc_card_wake_sdio_irq() is set, mmc core layer
1656 * will take care of signaling sdio irq during
1657 * mmc_sdio_resume().
1658 */
1659 if (host->sdcc_suspended)
1660 /*
1661 * This is a wakeup interrupt so hold wakelock
1662 * until SDCC resume is handled.
1663 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001664 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301665 else
1666 mmc_signal_sdio_irq(host->mmc);
1667 ret = 1;
1668 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001669 }
1670
1671 status = readl_relaxed(host->base + MMCISTATUS);
1672
1673 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1674 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001675 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001676
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001677#if IRQ_DEBUG
1678 msmsdcc_print_status(host, "irq0-r", status);
1679#endif
1680 status &= readl_relaxed(host->base + MMCIMASK0);
1681 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301682 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301683 if (host->clk_rate <=
1684 msmsdcc_get_min_sup_clk_rate(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +05301685 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001686#if IRQ_DEBUG
1687 msmsdcc_print_status(host, "irq0-p", status);
1688#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001689
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001690 if (status & MCI_SDIOINTROPE) {
1691 if (host->sdcc_suspending)
1692 wake_lock(&host->sdio_suspend_wlock);
1693 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001694 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001695 data = host->curr.data;
1696
1697 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001698 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1699 MCI_CMDTIMEOUT)) {
1700 if (status & MCI_CMDTIMEOUT)
1701 pr_debug("%s: dummy CMD52 timeout\n",
1702 mmc_hostname(host->mmc));
1703 if (status & MCI_CMDCRCFAIL)
1704 pr_debug("%s: dummy CMD52 CRC failed\n",
1705 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001706 host->dummy_52_sent = 0;
1707 host->dummy_52_needed = 0;
1708 if (data) {
1709 msmsdcc_stop_data(host);
1710 msmsdcc_request_end(host, data->mrq);
1711 }
1712 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001713 spin_unlock(&host->lock);
1714 return IRQ_HANDLED;
1715 }
1716 break;
1717 }
1718
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001719 /*
1720 * Check for proper command response
1721 */
1722 cmd = host->curr.cmd;
1723 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1724 MCI_CMDTIMEOUT | MCI_PROGDONE |
1725 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1726 msmsdcc_do_cmdirq(host, status);
1727 }
1728
Sathish Ambley081d7842011-11-29 11:19:41 -08001729 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001730 /* Check for data errors */
1731 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1732 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1733 msmsdcc_data_err(host, data, status);
1734 host->curr.data_xfered = 0;
1735 if (host->dma.sg && host->is_dma_mode)
1736 msm_dmov_stop_cmd(host->dma.channel,
1737 &host->dma.hdr, 0);
1738 else if (host->sps.sg && host->is_sps_mode) {
1739 /* Stop current SPS transfer */
1740 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301741 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001742 msmsdcc_reset_and_restore(host);
1743 if (host->curr.data)
1744 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301745 if (!data->stop || (host->curr.mrq->sbc
1746 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001747 timer |=
1748 msmsdcc_request_end(host,
1749 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301750 else if ((host->curr.mrq->sbc
1751 && data->error) ||
1752 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001753 msmsdcc_start_command(host,
1754 data->stop,
1755 0);
1756 timer = 1;
1757 }
1758 }
1759 }
1760
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301761 /* Check for prog done */
1762 if (host->curr.wait_for_auto_prog_done &&
1763 (status & MCI_PROGDONE))
1764 host->curr.got_auto_prog_done = 1;
1765
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001766 /* Check for data done */
1767 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1768 host->curr.got_dataend = 1;
1769
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301770 if (host->curr.got_dataend &&
1771 (!host->curr.wait_for_auto_prog_done ||
1772 (host->curr.wait_for_auto_prog_done &&
1773 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001774 /*
1775 * If DMA is still in progress, we complete
1776 * via the completion handler
1777 */
1778 if (!host->dma.busy && !host->sps.busy) {
1779 /*
1780 * There appears to be an issue in the
1781 * controller where if you request a
1782 * small block transfer (< fifo size),
1783 * you may get your DATAEND/DATABLKEND
1784 * irq without the PIO data irq.
1785 *
1786 * Check to see if theres still data
1787 * to be read, and simulate a PIO irq.
1788 */
1789 if (data->flags & MMC_DATA_READ)
1790 msmsdcc_wait_for_rxdata(host,
1791 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001792 if (!data->error) {
1793 host->curr.data_xfered =
1794 host->curr.xfer_size;
1795 host->curr.xfer_remain -=
1796 host->curr.xfer_size;
1797 }
1798
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001799 if (!host->dummy_52_needed) {
1800 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301801 if (!data->stop ||
1802 (host->curr.mrq->sbc
1803 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001804 msmsdcc_request_end(
1805 host,
1806 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301807 else if ((host->curr.mrq->sbc
1808 && data->error) ||
1809 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001810 msmsdcc_start_command(
1811 host,
1812 data->stop, 0);
1813 timer = 1;
1814 }
1815 } else {
1816 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001817 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001818 &dummy52cmd,
1819 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001820 }
1821 }
1822 }
1823 }
1824
San Mehat9d2bd732009-09-22 16:44:22 -07001825 ret = 1;
1826 } while (status);
1827
1828 spin_unlock(&host->lock);
1829
San Mehat9d2bd732009-09-22 16:44:22 -07001830 return IRQ_RETVAL(ret);
1831}
1832
1833static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001834msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1835{
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301836 if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001837 /* Queue/read data, daisy-chain command when data starts */
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301838 if (mrq->sbc)
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301839 msmsdcc_start_data(host, mrq->data, mrq->sbc, 0);
1840 else
1841 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001842 } else {
1843 msmsdcc_start_command(host, mrq->cmd, 0);
1844 }
1845}
1846
1847static void
San Mehat9d2bd732009-09-22 16:44:22 -07001848msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1849{
1850 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001851 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001852
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001853 /*
1854 * Get the SDIO AL client out of LPM.
1855 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001856 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001857 if (host->plat->is_sdio_al_client)
1858 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001859
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301860 /* check if sps pipe reset is pending? */
1861 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1862 msmsdcc_sps_pipes_reset_and_restore(host);
1863 host->sps.pipe_reset_pending = false;
1864 }
1865
San Mehat9d2bd732009-09-22 16:44:22 -07001866 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001867 WARN(host->curr.mrq, "Request in progress\n");
1868 WARN(!host->pwr, "SDCC power is turned off\n");
1869 WARN(!host->clks_on, "SDCC clocks are turned off\n");
1870 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
San Mehat9d2bd732009-09-22 16:44:22 -07001871
1872 if (host->eject) {
1873 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1874 mrq->cmd->error = 0;
1875 mrq->data->bytes_xfered = mrq->data->blksz *
1876 mrq->data->blocks;
1877 } else
1878 mrq->cmd->error = -ENOMEDIUM;
1879
1880 spin_unlock_irqrestore(&host->lock, flags);
1881 mmc_request_done(mmc, mrq);
1882 return;
1883 }
1884
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301885 /*
1886 * Kick the software command timeout timer here.
1887 * Timer expires in 10 secs.
1888 */
1889 mod_timer(&host->req_tout_timer,
1890 (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
San Mehat9d2bd732009-09-22 16:44:22 -07001891
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301892 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301893 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301894 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
1895 mrq->cmd->opcode == 54) {
Pratibhasagar V1c11da62011-11-14 12:36:35 +05301896 if (!host->sdcc_version)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001897 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301898 else
1899 /*
1900 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
1901 * write operations using CMD53 and CMD54.
1902 * Setting this bit with CMD53 would
1903 * automatically triggers PROG_DONE interrupt
1904 * without the need of sending dummy CMD52.
1905 */
1906 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani758cf8c2011-11-13 11:59:55 +05301907 } else if (mrq->cmd->opcode == MMC_WRITE_BLOCK &&
1908 host->sdcc_version) {
1909 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001910 }
San Mehat9d2bd732009-09-22 16:44:22 -07001911 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301912
Pratibhasagar V00b94332011-10-18 14:57:27 +05301913 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301914 mrq->sbc->mrq = mrq;
1915 mrq->sbc->data = mrq->data;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301916 if (mrq->data->flags & MMC_DATA_WRITE) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301917 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301918 msmsdcc_start_command(host, mrq->sbc, 0);
1919 } else {
1920 msmsdcc_request_start(host, mrq);
1921 }
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301922 } else {
1923 msmsdcc_request_start(host, mrq);
1924 }
1925
San Mehat9d2bd732009-09-22 16:44:22 -07001926 spin_unlock_irqrestore(&host->lock, flags);
1927}
1928
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001929static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1930 int min_uV, int max_uV)
1931{
1932 int rc = 0;
1933
1934 if (vreg->set_voltage_sup) {
1935 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1936 if (rc) {
1937 pr_err("%s: regulator_set_voltage(%s) failed."
1938 " min_uV=%d, max_uV=%d, rc=%d\n",
1939 __func__, vreg->name, min_uV, max_uV, rc);
1940 }
1941 }
1942
1943 return rc;
1944}
1945
1946static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1947 int uA_load)
1948{
1949 int rc = 0;
1950
Krishna Kondafea60182011-11-01 16:01:34 -07001951 /* regulators that do not support regulator_set_voltage also
1952 do not support regulator_set_optimum_mode */
1953 if (vreg->set_voltage_sup) {
1954 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1955 if (rc < 0)
1956 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
1957 "uA_load=%d) failed. rc=%d\n", __func__,
1958 vreg->name, uA_load, rc);
1959 else
1960 /* regulator_set_optimum_mode() can return non zero
1961 * value even for success case.
1962 */
1963 rc = 0;
1964 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001965
1966 return rc;
1967}
1968
1969static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1970 struct device *dev)
1971{
1972 int rc = 0;
1973
1974 /* check if regulator is already initialized? */
1975 if (vreg->reg)
1976 goto out;
1977
1978 /* Get the regulator handle */
1979 vreg->reg = regulator_get(dev, vreg->name);
1980 if (IS_ERR(vreg->reg)) {
1981 rc = PTR_ERR(vreg->reg);
1982 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
1983 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001984 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001985 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001986
1987 if (regulator_count_voltages(vreg->reg) > 0)
1988 vreg->set_voltage_sup = 1;
1989
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001990out:
1991 return rc;
1992}
1993
1994static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
1995{
1996 if (vreg->reg)
1997 regulator_put(vreg->reg);
1998}
1999
2000/* This init function should be called only once for each SDCC slot */
2001static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
2002{
2003 int rc = 0;
2004 struct msm_mmc_slot_reg_data *curr_slot;
2005 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
2006 struct device *dev = mmc_dev(host->mmc);
2007
2008 curr_slot = host->plat->vreg_data;
2009 if (!curr_slot)
2010 goto out;
2011
2012 curr_vdd_reg = curr_slot->vdd_data;
2013 curr_vccq_reg = curr_slot->vccq_data;
2014 curr_vddp_reg = curr_slot->vddp_data;
2015
2016 if (is_init) {
2017 /*
2018 * Get the regulator handle from voltage regulator framework
2019 * and then try to set the voltage level for the regulator
2020 */
2021 if (curr_vdd_reg) {
2022 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
2023 if (rc)
2024 goto out;
2025 }
2026 if (curr_vccq_reg) {
2027 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
2028 if (rc)
2029 goto vdd_reg_deinit;
2030 }
2031 if (curr_vddp_reg) {
2032 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
2033 if (rc)
2034 goto vccq_reg_deinit;
2035 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002036 rc = msmsdcc_vreg_reset(host);
2037 if (rc)
2038 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
2039 host->pdev_id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002040 goto out;
2041 } else {
2042 /* Deregister all regulators from regulator framework */
2043 goto vddp_reg_deinit;
2044 }
2045vddp_reg_deinit:
2046 if (curr_vddp_reg)
2047 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
2048vccq_reg_deinit:
2049 if (curr_vccq_reg)
2050 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
2051vdd_reg_deinit:
2052 if (curr_vdd_reg)
2053 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2054out:
2055 return rc;
2056}
2057
2058static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2059{
2060 int rc = 0;
2061
Subhash Jadavanicc922692011-08-01 23:05:01 +05302062 /* Put regulator in HPM (high power mode) */
2063 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2064 if (rc < 0)
2065 goto out;
2066
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002067 if (!vreg->is_enabled) {
2068 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302069 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2070 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002071 if (rc)
2072 goto out;
2073
2074 rc = regulator_enable(vreg->reg);
2075 if (rc) {
2076 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2077 __func__, vreg->name, rc);
2078 goto out;
2079 }
2080 vreg->is_enabled = true;
2081 }
2082
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002083out:
2084 return rc;
2085}
2086
2087static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
2088{
2089 int rc = 0;
2090
2091 /* Never disable regulator marked as always_on */
2092 if (vreg->is_enabled && !vreg->always_on) {
2093 rc = regulator_disable(vreg->reg);
2094 if (rc) {
2095 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2096 __func__, vreg->name, rc);
2097 goto out;
2098 }
2099 vreg->is_enabled = false;
2100
2101 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2102 if (rc < 0)
2103 goto out;
2104
2105 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302106 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002107 if (rc)
2108 goto out;
2109 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
2110 /* Put always_on regulator in LPM (low power mode) */
2111 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2112 if (rc < 0)
2113 goto out;
2114 }
2115out:
2116 return rc;
2117}
2118
2119static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
2120{
2121 int rc = 0, i;
2122 struct msm_mmc_slot_reg_data *curr_slot;
2123 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
2124 struct msm_mmc_reg_data *vreg_table[3];
2125
2126 curr_slot = host->plat->vreg_data;
2127 if (!curr_slot)
2128 goto out;
2129
2130 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
2131 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
2132 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
2133
2134 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2135 if (vreg_table[i]) {
2136 if (enable)
2137 rc = msmsdcc_vreg_enable(vreg_table[i]);
2138 else
2139 rc = msmsdcc_vreg_disable(vreg_table[i]);
2140 if (rc)
2141 goto out;
2142 }
2143 }
2144out:
2145 return rc;
2146}
2147
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002148/*
2149 * Reset vreg by ensuring it is off during probe. A call
2150 * to enable vreg is needed to balance disable vreg
2151 */
2152static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2153{
2154 int rc;
2155
2156 rc = msmsdcc_setup_vreg(host, 1);
2157 if (rc)
2158 return rc;
2159 rc = msmsdcc_setup_vreg(host, 0);
2160 return rc;
2161}
2162
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302163static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002164{
2165 int rc = 0;
2166
2167 if (host->plat->vreg_data) {
2168 struct msm_mmc_reg_data *vddp_reg =
2169 host->plat->vreg_data->vddp_data;
2170
2171 if (vddp_reg && vddp_reg->is_enabled)
2172 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
2173 }
2174
2175 return rc;
2176}
2177
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302178static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
2179{
2180 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2181 int rc = 0;
2182
2183 if (curr_slot && curr_slot->vddp_data) {
2184 rc = msmsdcc_set_vddp_level(host,
2185 curr_slot->vddp_data->low_vol_level);
2186
2187 if (rc)
2188 pr_err("%s: %s: failed to change vddp level to %d",
2189 mmc_hostname(host->mmc), __func__,
2190 curr_slot->vddp_data->low_vol_level);
2191 }
2192
2193 return rc;
2194}
2195
2196static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
2197{
2198 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2199 int rc = 0;
2200
2201 if (curr_slot && curr_slot->vddp_data) {
2202 rc = msmsdcc_set_vddp_level(host,
2203 curr_slot->vddp_data->high_vol_level);
2204
2205 if (rc)
2206 pr_err("%s: %s: failed to change vddp level to %d",
2207 mmc_hostname(host->mmc), __func__,
2208 curr_slot->vddp_data->high_vol_level);
2209 }
2210
2211 return rc;
2212}
2213
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302214static inline int msmsdcc_set_vccq_vol(struct msmsdcc_host *host, int level)
2215{
2216 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2217 int rc = 0;
2218
2219 if (curr_slot && curr_slot->vccq_data) {
2220 rc = msmsdcc_vreg_set_voltage(curr_slot->vccq_data,
2221 level, level);
2222 if (rc)
2223 pr_err("%s: %s: failed to change vccq level to %d",
2224 mmc_hostname(host->mmc), __func__, level);
2225 }
2226
2227 return rc;
2228}
2229
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002230static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2231{
2232 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2233 return 1;
2234 return 0;
2235}
2236
Asutosh Dasf5298c32012-04-03 14:51:47 +05302237/*
2238 * Any function calling msmsdcc_setup_clocks must
2239 * acquire clk_mutex. May sleep.
2240 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002241static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
2242{
2243 if (enable) {
2244 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302245 clk_prepare_enable(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002246 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302247 clk_prepare_enable(host->pclk);
2248 clk_prepare_enable(host->clk);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302249 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302250 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002251 } else {
Subhash Jadavanidd432952012-03-28 11:25:56 +05302252 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302253 msmsdcc_delay(host);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302254 clk_disable_unprepare(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002255 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302256 clk_disable_unprepare(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002257 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302258 clk_disable_unprepare(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002259 }
2260}
2261
2262static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2263 unsigned int req_clk)
2264{
2265 unsigned int sel_clk = -1;
2266
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302267 if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
2268 sel_clk = msmsdcc_get_min_sup_clk_rate(host);
2269 goto out;
2270 }
2271
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002272 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2273 unsigned char cnt;
2274
2275 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2276 if (host->plat->sup_clk_table[cnt] > req_clk)
2277 break;
2278 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2279 sel_clk = host->plat->sup_clk_table[cnt];
2280 break;
2281 } else
2282 sel_clk = host->plat->sup_clk_table[cnt];
2283 }
2284 } else {
2285 if ((req_clk < host->plat->msmsdcc_fmax) &&
2286 (req_clk > host->plat->msmsdcc_fmid))
2287 sel_clk = host->plat->msmsdcc_fmid;
2288 else
2289 sel_clk = req_clk;
2290 }
2291
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302292out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002293 return sel_clk;
2294}
2295
2296static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2297 struct msmsdcc_host *host)
2298{
2299 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2300 return host->plat->sup_clk_table[0];
2301 else
2302 return host->plat->msmsdcc_fmin;
2303}
2304
2305static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2306 struct msmsdcc_host *host)
2307{
2308 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2309 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2310 else
2311 return host->plat->msmsdcc_fmax;
2312}
2313
2314static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302315{
2316 struct msm_mmc_gpio_data *curr;
2317 int i, rc = 0;
2318
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002319 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302320 for (i = 0; i < curr->size; i++) {
2321 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002322 if (curr->gpio[i].is_always_on &&
2323 curr->gpio[i].is_enabled)
2324 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302325 rc = gpio_request(curr->gpio[i].no,
2326 curr->gpio[i].name);
2327 if (rc) {
2328 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2329 mmc_hostname(host->mmc),
2330 curr->gpio[i].no,
2331 curr->gpio[i].name, rc);
2332 goto free_gpios;
2333 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002334 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302335 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002336 if (curr->gpio[i].is_always_on)
2337 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302338 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002339 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302340 }
2341 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002342 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302343
2344free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002345 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302346 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002347 curr->gpio[i].is_enabled = false;
2348 }
2349out:
2350 return rc;
2351}
2352
2353static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2354{
2355 struct msm_mmc_pad_data *curr;
2356 int i;
2357
2358 curr = host->plat->pin_data->pad_data;
2359 for (i = 0; i < curr->drv->size; i++) {
2360 if (enable)
2361 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2362 curr->drv->on[i].val);
2363 else
2364 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2365 curr->drv->off[i].val);
2366 }
2367
2368 for (i = 0; i < curr->pull->size; i++) {
2369 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002370 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002371 curr->pull->on[i].val);
2372 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002373 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002374 curr->pull->off[i].val);
2375 }
2376
2377 return 0;
2378}
2379
2380static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2381{
2382 int rc = 0;
2383
2384 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2385 return 0;
2386
2387 if (host->plat->pin_data->is_gpio)
2388 rc = msmsdcc_setup_gpio(host, enable);
2389 else
2390 rc = msmsdcc_setup_pad(host, enable);
2391
2392 if (!rc)
2393 host->plat->pin_data->cfg_sts = enable;
2394
2395 return rc;
2396}
2397
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302398static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2399{
2400 u32 pwr = 0;
2401 int ret = 0;
2402 struct mmc_host *mmc = host->mmc;
2403
2404 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2405 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2406 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2407 ret = msmsdcc_setup_vreg(host, !!ios->vdd);
2408
2409 if (ret) {
2410 pr_err("%s: Failed to setup voltage regulators\n",
2411 mmc_hostname(host->mmc));
2412 goto out;
2413 }
2414
2415 switch (ios->power_mode) {
2416 case MMC_POWER_OFF:
2417 pwr = MCI_PWR_OFF;
2418 if (host->plat->cfg_mpm_sdiowakeup)
2419 host->plat->cfg_mpm_sdiowakeup(
2420 mmc_dev(mmc), SDC_DAT1_DISABLE);
2421 /*
2422 * As VDD pad rail is always on, set low voltage for VDD
2423 * pad rail when slot is unused (when card is not present
2424 * or during system suspend).
2425 */
2426 msmsdcc_set_vddp_low_vol(host);
2427 msmsdcc_setup_pins(host, false);
2428 break;
2429 case MMC_POWER_UP:
2430 /* writing PWR_UP bit is redundant */
2431 pwr = MCI_PWR_UP;
2432 if (host->plat->cfg_mpm_sdiowakeup)
2433 host->plat->cfg_mpm_sdiowakeup(
2434 mmc_dev(mmc), SDC_DAT1_ENABLE);
2435
2436 msmsdcc_set_vddp_high_vol(host);
2437 msmsdcc_setup_pins(host, true);
2438 break;
2439 case MMC_POWER_ON:
2440 pwr = MCI_PWR_ON;
2441 break;
2442 }
2443
2444out:
2445 return pwr;
2446}
2447
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002448static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2449{
2450 unsigned int wakeup_irq;
2451
2452 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2453 host->plat->sdiowakeup_irq :
2454 host->core_irqres->start;
2455
2456 if (!host->irq_wake_enabled) {
2457 enable_irq_wake(wakeup_irq);
2458 host->irq_wake_enabled = true;
2459 }
2460}
2461
2462static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2463{
2464 unsigned int wakeup_irq;
2465
2466 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2467 host->plat->sdiowakeup_irq :
2468 host->core_irqres->start;
2469
2470 if (host->irq_wake_enabled) {
2471 disable_irq_wake(wakeup_irq);
2472 host->irq_wake_enabled = false;
2473 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302474}
2475
San Mehat9d2bd732009-09-22 16:44:22 -07002476static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302477msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
2478{
2479 struct mmc_host *mmc = host->mmc;
2480
2481 /*
2482 * SDIO_AL clients has different mechanism of handling LPM through
2483 * sdio_al driver itself. The sdio wakeup interrupt is configured as
2484 * part of that. Here, we are interested only in clients like WLAN.
2485 */
2486 if (!(mmc->card && mmc_card_sdio(mmc->card))
2487 || host->plat->is_sdio_al_client)
2488 goto out;
2489
2490 if (!host->sdcc_suspended) {
2491 /*
2492 * When MSM is not in power collapse and we
2493 * are disabling clocks, enable bit 22 in MASK0
2494 * to handle asynchronous SDIO interrupts.
2495 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302496 if (enable_wakeup_irq) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302497 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302498 mb();
2499 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302500 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302501 msmsdcc_sync_reg_wr(host);
2502 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302503 goto out;
2504 } else if (!mmc_card_wake_sdio_irq(mmc)) {
2505 /*
2506 * Wakeup MSM only if SDIO function drivers set
2507 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
2508 */
2509 goto out;
2510 }
2511
2512 if (enable_wakeup_irq) {
2513 if (!host->plat->sdiowakeup_irq) {
2514 /*
2515 * When there is no gpio line that can be configured
2516 * as wakeup interrupt handle it by configuring
2517 * asynchronous sdio interrupts and DAT1 line.
2518 */
2519 writel_relaxed(MCI_SDIOINTMASK,
2520 host->base + MMCIMASK0);
2521 mb();
2522 if (host->plat->cfg_mpm_sdiowakeup)
2523 host->plat->cfg_mpm_sdiowakeup(
2524 mmc_dev(mmc), SDC_DAT1_ENWAKE);
2525 /* configure sdcc core interrupt as wakeup interrupt */
2526 msmsdcc_enable_irq_wake(host);
2527 } else {
2528 /* Let gpio line handle wakeup interrupt */
2529 writel_relaxed(0, host->base + MMCIMASK0);
2530 mb();
2531 if (host->sdio_wakeupirq_disabled) {
2532 host->sdio_wakeupirq_disabled = 0;
2533 /* configure gpio line as wakeup interrupt */
2534 msmsdcc_enable_irq_wake(host);
2535 enable_irq(host->plat->sdiowakeup_irq);
2536 }
2537 }
2538 } else {
2539 if (!host->plat->sdiowakeup_irq) {
2540 /*
2541 * We may not have cleared bit 22 in the interrupt
2542 * handler as the clocks might be off at that time.
2543 */
2544 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302545 msmsdcc_sync_reg_wr(host);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302546 if (host->plat->cfg_mpm_sdiowakeup)
2547 host->plat->cfg_mpm_sdiowakeup(
2548 mmc_dev(mmc), SDC_DAT1_DISWAKE);
2549 msmsdcc_disable_irq_wake(host);
2550 } else if (!host->sdio_wakeupirq_disabled) {
2551 disable_irq_nosync(host->plat->sdiowakeup_irq);
2552 msmsdcc_disable_irq_wake(host);
2553 host->sdio_wakeupirq_disabled = 1;
2554 }
2555 }
2556out:
2557 return;
2558}
2559
2560static void
San Mehat9d2bd732009-09-22 16:44:22 -07002561msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2562{
2563 struct msmsdcc_host *host = mmc_priv(mmc);
2564 u32 clk = 0, pwr = 0;
2565 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002566 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002567 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002568
Sahitya Tummala7a892482011-01-18 11:22:49 +05302569
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302570 /*
2571 * Disable SDCC core interrupt until set_ios is completed.
2572 * This avoids any race conditions with interrupt raised
2573 * when turning on/off the clocks. One possible
2574 * scenario is SDIO operational interrupt while the clock
2575 * is turned off.
Asutosh Dasf5298c32012-04-03 14:51:47 +05302576 * host->lock is being released intermittently below.
2577 * Thus, prevent concurrent access to host.
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302578 */
2579
Asutosh Dasf5298c32012-04-03 14:51:47 +05302580 mutex_lock(&host->clk_mutex);
2581 DBG(host, "ios->clock = %u\n", ios->clock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302582 spin_lock_irqsave(&host->lock, flags);
2583 if (!host->sdcc_irq_disabled) {
2584 spin_unlock_irqrestore(&host->lock, flags);
2585 disable_irq(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002586 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302587 host->sdcc_irq_disabled = 1;
2588 }
2589 spin_unlock_irqrestore(&host->lock, flags);
2590
2591 pwr = msmsdcc_setup_pwr(host, ios);
2592
2593 spin_lock_irqsave(&host->lock, flags);
2594 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002595 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302596 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002597 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302598 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002599 host->clks_on = 1;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302600 writel_relaxed(host->mci_irqenable,
2601 host->base + MMCIMASK0);
2602 mb();
2603 msmsdcc_cfg_sdio_wakeup(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002604 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002605
2606 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2607 /*
2608 * For DDR50 mode, controller needs clock rate to be
2609 * double than what is required on the SD card CLK pin.
2610 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302611 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002612 /*
2613 * Make sure that we don't double the clock if
2614 * doubled clock rate is already set
2615 */
2616 if (!host->ddr_doubled_clk_rate ||
2617 (host->ddr_doubled_clk_rate &&
2618 (host->ddr_doubled_clk_rate != ios->clock))) {
2619 host->ddr_doubled_clk_rate =
2620 msmsdcc_get_sup_clk_rate(
2621 host, (ios->clock * 2));
2622 clock = host->ddr_doubled_clk_rate;
2623 }
2624 } else {
2625 host->ddr_doubled_clk_rate = 0;
2626 }
2627
2628 if (clock != host->clk_rate) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302629 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002630 rc = clk_set_rate(host->clk, clock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302631 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002632 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302633 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002634 mmc_hostname(mmc), clock);
2635 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302636 host->reg_write_delay =
2637 (1 + ((3 * USEC_PER_SEC) /
2638 (host->clk_rate ? host->clk_rate :
2639 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002640 }
2641 /*
2642 * give atleast 2 MCLK cycles delay for clocks
2643 * and SDCC core to stabilize
2644 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302645 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002646 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002647 clk |= MCI_CLK_ENABLE;
2648 }
2649
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002650 if (ios->bus_width == MMC_BUS_WIDTH_8)
2651 clk |= MCI_CLK_WIDEBUS_8;
2652 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2653 clk |= MCI_CLK_WIDEBUS_4;
2654 else
2655 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002656
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002657 if (msmsdcc_is_pwrsave(host))
2658 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002659
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002660 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002661
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002662 host->tuning_needed = 0;
2663 /*
2664 * Select the controller timing mode according
2665 * to current bus speed mode
2666 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302667 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2668 (ios->timing == MMC_TIMING_MMC_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002669 clk |= (4 << 14);
2670 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302671 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002672 clk |= (3 << 14);
2673 } else {
2674 clk |= (2 << 14); /* feedback clock */
2675 }
2676
2677 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2678 clk |= (2 << 23);
2679
Subhash Jadavani00083572012-02-15 16:18:01 +05302680 /* Clear IO_PAD_PWR_SWITCH while powering off the card */
2681 if (!ios->vdd)
2682 host->io_pad_pwr_switch = 0;
2683
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002684 if (host->io_pad_pwr_switch)
2685 clk |= IO_PAD_PWR_SWITCH;
2686
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302687 /* Don't write into registers if clocks are disabled */
2688 if (host->clks_on) {
2689 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
2690 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302691 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002692 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302693 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
2694 host->pwr = pwr;
2695 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302696 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002697 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002698 }
2699
2700 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302701 msmsdcc_cfg_sdio_wakeup(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302702 spin_unlock_irqrestore(&host->lock, flags);
2703 /*
2704 * May get a wake-up interrupt the instant we disable the
2705 * clocks. This would disable the wake-up interrupt.
2706 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002707 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302708 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002709 host->clks_on = 0;
2710 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302711
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302712 if (host->tuning_in_progress)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302713 WARN(!host->clks_on,
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302714 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302715
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302716 /* Let interrupts be disabled if the host is powered off */
2717 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
2718 enable_irq(host->core_irqres->start);
2719 host->sdcc_irq_disabled = 0;
2720 }
2721
San Mehat4adbbcc2009-11-08 13:00:37 -08002722 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302723 mutex_unlock(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07002724}
2725
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002726int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2727{
2728 struct msmsdcc_host *host = mmc_priv(mmc);
2729 u32 clk;
2730
2731 clk = readl_relaxed(host->base + MMCICLOCK);
2732 pr_debug("Changing to pwr_save=%d", pwrsave);
2733 if (pwrsave && msmsdcc_is_pwrsave(host))
2734 clk |= MCI_CLK_PWRSAVE;
2735 else
2736 clk &= ~MCI_CLK_PWRSAVE;
2737 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302738 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002739
2740 return 0;
2741}
2742
2743static int msmsdcc_get_ro(struct mmc_host *mmc)
2744{
2745 int status = -ENOSYS;
2746 struct msmsdcc_host *host = mmc_priv(mmc);
2747
2748 if (host->plat->wpswitch) {
2749 status = host->plat->wpswitch(mmc_dev(mmc));
2750 } else if (host->plat->wpswitch_gpio) {
2751 status = gpio_request(host->plat->wpswitch_gpio,
2752 "SD_WP_Switch");
2753 if (status) {
2754 pr_err("%s: %s: Failed to request GPIO %d\n",
2755 mmc_hostname(mmc), __func__,
2756 host->plat->wpswitch_gpio);
2757 } else {
2758 status = gpio_direction_input(
2759 host->plat->wpswitch_gpio);
2760 if (!status) {
2761 /*
2762 * Wait for atleast 300ms as debounce
2763 * time for GPIO input to stabilize.
2764 */
2765 msleep(300);
2766 status = gpio_get_value_cansleep(
2767 host->plat->wpswitch_gpio);
2768 status ^= !host->plat->wpswitch_polarity;
2769 }
2770 gpio_free(host->plat->wpswitch_gpio);
2771 }
2772 }
2773
2774 if (status < 0)
2775 status = -ENOSYS;
2776 pr_debug("%s: Card read-only status %d\n", __func__, status);
2777
2778 return status;
2779}
2780
San Mehat9d2bd732009-09-22 16:44:22 -07002781static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2782{
2783 struct msmsdcc_host *host = mmc_priv(mmc);
2784 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002785
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302786 /*
2787 * We may come here with clocks turned off in that case don't
2788 * attempt to write into MASK0 register. While turning on the
2789 * clocks mci_irqenable will be written to MASK0 register.
2790 */
2791
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002792 if (enable) {
2793 spin_lock_irqsave(&host->lock, flags);
2794 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302795 if (host->clks_on) {
2796 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002797 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302798 mb();
2799 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002800 spin_unlock_irqrestore(&host->lock, flags);
2801 } else {
2802 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302803 if (host->clks_on) {
2804 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002805 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302806 mb();
2807 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002808 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002809}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002810
2811#ifdef CONFIG_PM_RUNTIME
2812static int msmsdcc_enable(struct mmc_host *mmc)
2813{
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302814 int rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002815 struct device *dev = mmc->parent;
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302816 struct msmsdcc_host *host = mmc_priv(mmc);
2817
2818 msmsdcc_pm_qos_update_latency(host, 1);
2819
2820 if (mmc->card && mmc_card_sdio(mmc->card) && host->is_resumed)
2821 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002822
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302823 if (dev->power.runtime_status == RPM_SUSPENDING) {
2824 if (mmc->suspend_task == current) {
2825 pm_runtime_get_noresume(dev);
2826 goto out;
2827 }
2828 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002829
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302830 rc = pm_runtime_get_sync(dev);
2831
2832 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002833 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2834 __func__, rc);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302835 return rc;
2836 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302837
2838 host->is_resumed = true;
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302839out:
2840 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002841}
2842
2843static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2844{
2845 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302846 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002847
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302848 msmsdcc_pm_qos_update_latency(host, 0);
2849
2850 if (mmc->card && mmc_card_sdio(mmc->card))
2851 return 0;
2852
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302853 if (host->plat->disable_runtime_pm)
2854 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002855
2856 rc = pm_runtime_put_sync(mmc->parent);
2857
2858 if (rc < 0)
2859 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2860 __func__, rc);
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302861 else
2862 host->is_resumed = false;
2863
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002864 return rc;
2865}
2866#else
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302867static int msmsdcc_enable(struct mmc_host *mmc)
2868{
2869 struct msmsdcc_host *host = mmc_priv(mmc);
2870 unsigned long flags;
2871
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302872 msmsdcc_pm_qos_update_latency(host, 1);
2873
Asutosh Dasf5298c32012-04-03 14:51:47 +05302874 mutex_lock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302875 spin_lock_irqsave(&host->lock, flags);
2876 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302877 spin_unlock_irqrestore(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302878 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302879 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302880 host->clks_on = 1;
2881 }
2882 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302883 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302884
2885 return 0;
2886}
2887
2888static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2889{
2890 struct msmsdcc_host *host = mmc_priv(mmc);
2891 unsigned long flags;
2892
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302893 msmsdcc_pm_qos_update_latency(host, 0);
2894
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302895 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302896 return 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302897
Asutosh Dasf5298c32012-04-03 14:51:47 +05302898 mutex_lock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302899 spin_lock_irqsave(&host->lock, flags);
2900 if (host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302901 spin_unlock_irqrestore(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302902 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302903 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302904 host->clks_on = 0;
2905 }
2906 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302907 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302908
2909 return 0;
2910}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002911#endif
2912
2913static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2914 struct mmc_ios *ios)
2915{
2916 struct msmsdcc_host *host = mmc_priv(mmc);
2917 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302918 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002919
Subhash Jadavani00083572012-02-15 16:18:01 +05302920 spin_lock_irqsave(&host->lock, flags);
2921 host->io_pad_pwr_switch = 0;
2922 spin_unlock_irqrestore(&host->lock, flags);
2923
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302924 /*
2925 * For eMMC cards, VccQ voltage range must be changed
2926 * only if it operates in HS200 SDR 1.2V mode or in
2927 * DDR 1.2V mode.
2928 */
2929 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_120) {
2930 rc = msmsdcc_set_vccq_vol(host, 1200000);
2931 goto out;
2932 }
2933
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002934 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2935 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302936 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002937 goto out;
2938 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2939 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302940 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002941 goto out;
2942 }
San Mehat9d2bd732009-09-22 16:44:22 -07002943
2944 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002945 /*
2946 * If we are here means voltage switch from high voltage to
2947 * low voltage is required
2948 */
2949
2950 /*
2951 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2952 * register until they become all zeros.
2953 */
2954 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302955 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002956 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2957 mmc_hostname(mmc), __func__);
2958 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002959 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002960
2961 /* Stop SD CLK output. */
2962 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2963 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302964 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002965 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002966
2967 /*
2968 * Switch VDDPX from high voltage to low voltage
2969 * to change the VDD of the SD IO pads.
2970 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302971 rc = msmsdcc_set_vddp_low_vol(host);
2972 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002973 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002974
2975 spin_lock_irqsave(&host->lock, flags);
2976 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2977 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302978 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002979 host->io_pad_pwr_switch = 1;
2980 spin_unlock_irqrestore(&host->lock, flags);
2981
2982 /* Wait 5 ms for the voltage regulater in the card to become stable. */
2983 usleep_range(5000, 5500);
2984
2985 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302986 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002987 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2988 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302989 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002990 spin_unlock_irqrestore(&host->lock, flags);
2991
2992 /*
2993 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
2994 * don't become all ones within 1 ms then a Voltage Switch
2995 * sequence has failed and a power cycle to the card is required.
2996 * Otherwise Voltage Switch sequence is completed successfully.
2997 */
2998 usleep_range(1000, 1500);
2999
3000 spin_lock_irqsave(&host->lock, flags);
3001 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
3002 != (0xF << 1)) {
3003 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
3004 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303005 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003006 goto out_unlock;
3007 }
3008
3009out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303010 /* Enable PWRSAVE */
3011 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3012 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303013 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003014 spin_unlock_irqrestore(&host->lock, flags);
3015out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303016 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003017}
3018
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303019static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003020{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003021 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003022
3023 /* Program the MCLK value to MCLK_FREQ bit field */
3024 if (host->clk_rate <= 112000000)
3025 mclk_freq = 0;
3026 else if (host->clk_rate <= 125000000)
3027 mclk_freq = 1;
3028 else if (host->clk_rate <= 137000000)
3029 mclk_freq = 2;
3030 else if (host->clk_rate <= 150000000)
3031 mclk_freq = 3;
3032 else if (host->clk_rate <= 162000000)
3033 mclk_freq = 4;
3034 else if (host->clk_rate <= 175000000)
3035 mclk_freq = 5;
3036 else if (host->clk_rate <= 187000000)
3037 mclk_freq = 6;
3038 else if (host->clk_rate <= 200000000)
3039 mclk_freq = 7;
3040
3041 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3042 & ~(7 << 24)) | (mclk_freq << 24)),
3043 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003044}
3045
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303046/* Initialize the DLL (Programmable Delay Line ) */
3047static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003048{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003049 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303050 unsigned long flags;
3051 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003052
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303053 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003054 /*
3055 * Make sure that clock is always enabled when DLL
3056 * tuning is in progress. Keeping PWRSAVE ON may
3057 * turn off the clock. So let's disable the PWRSAVE
3058 * here and re-enable it once tuning is completed.
3059 */
3060 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3061 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303062 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303063
3064 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3065 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3066 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3067
3068 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3069 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3070 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3071
3072 msmsdcc_cm_sdc4_dll_set_freq(host);
3073
3074 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3075 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3076 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3077
3078 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3079 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3080 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3081
3082 /* Set DLL_EN bit to 1. */
3083 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3084 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3085
3086 /* Set CK_OUT_EN bit to 1. */
3087 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3088 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3089
3090 wait_cnt = 50;
3091 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3092 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3093 /* max. wait for 50us sec for LOCK bit to be set */
3094 if (--wait_cnt == 0) {
3095 pr_err("%s: %s: DLL failed to LOCK\n",
3096 mmc_hostname(host->mmc), __func__);
3097 rc = -ETIMEDOUT;
3098 goto out;
3099 }
3100 /* wait for 1us before polling again */
3101 udelay(1);
3102 }
3103
3104out:
3105 /* re-enable PWRSAVE */
3106 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3107 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303108 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303109 spin_unlock_irqrestore(&host->lock, flags);
3110
3111 return rc;
3112}
3113
3114static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3115 u8 poll)
3116{
3117 int rc = 0;
3118 u32 wait_cnt = 50;
3119 u8 ck_out_en = 0;
3120
3121 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3122 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3123 MCI_CK_OUT_EN);
3124
3125 while (ck_out_en != poll) {
3126 if (--wait_cnt == 0) {
3127 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3128 mmc_hostname(host->mmc), __func__, poll);
3129 rc = -ETIMEDOUT;
3130 goto out;
3131 }
3132 udelay(1);
3133
3134 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3135 MCI_CK_OUT_EN);
3136 }
3137out:
3138 return rc;
3139}
3140
3141/*
3142 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3143 * calibration sequence. This function should be called before
3144 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3145 * commands (CMD17/CMD18).
3146 *
3147 * This function gets called when host spinlock acquired.
3148 */
3149static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3150{
3151 int rc = 0;
3152 u32 config;
3153
3154 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3155 config |= MCI_CDR_EN;
3156 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3157 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3158
3159 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3160 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3161 if (rc)
3162 goto err_out;
3163
3164 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3165 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3166 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3167
3168 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3169 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3170 if (rc)
3171 goto err_out;
3172
3173 goto out;
3174
3175err_out:
3176 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3177out:
3178 return rc;
3179}
3180
3181static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3182 u8 phase)
3183{
3184 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303185 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3186 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3187 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303188 unsigned long flags;
3189 u32 config;
3190
3191 spin_lock_irqsave(&host->lock, flags);
3192
3193 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3194 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3195 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3196 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3197
3198 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3199 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3200 if (rc)
3201 goto err_out;
3202
3203 /*
3204 * Write the selected DLL clock output phase (0 ... 15)
3205 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
3206 */
3207 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3208 & ~(0xF << 20))
3209 | (grey_coded_phase_table[phase] << 20)),
3210 host->base + MCI_DLL_CONFIG);
3211
3212 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3213 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3214 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3215
3216 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3217 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3218 if (rc)
3219 goto err_out;
3220
3221 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3222 config |= MCI_CDR_EN;
3223 config &= ~MCI_CDR_EXT_EN;
3224 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3225 goto out;
3226
3227err_out:
3228 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3229 mmc_hostname(host->mmc), __func__, phase);
3230out:
3231 spin_unlock_irqrestore(&host->lock, flags);
3232 return rc;
3233}
3234
3235/*
3236 * Find out the greatest range of consecuitive selected
3237 * DLL clock output phases that can be used as sampling
3238 * setting for SD3.0 UHS-I card read operation (in SDR104
3239 * timing mode) or for eMMC4.5 card read operation (in HS200
3240 * timing mode).
3241 * Select the 3/4 of the range and configure the DLL with the
3242 * selected DLL clock output phase.
3243*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303244static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303245 u8 *phase_table, u8 total_phases)
3246{
Subhash Jadavani6159c622012-03-15 19:05:55 +05303247 #define MAX_PHASES 16
Subhash Jadavani34187042012-03-02 10:59:49 +05303248 int ret;
Subhash Jadavani6159c622012-03-15 19:05:55 +05303249 u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
3250 u8 phases_per_row[MAX_PHASES] = {0};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303251 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303252 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3253 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303254
Subhash Jadavani6159c622012-03-15 19:05:55 +05303255 if (!total_phases || (total_phases > MAX_PHASES)) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303256 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3257 mmc_hostname(host->mmc), __func__, total_phases);
3258 return -EINVAL;
3259 }
3260
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303261 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303262 ranges[row_index][col_index] = phase_table[cnt];
3263 phases_per_row[row_index] += 1;
3264 col_index++;
3265
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303266 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303267 continue;
3268 /* check if next phase in phase_table is consecutive or not */
3269 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3270 row_index++;
3271 col_index = 0;
3272 }
3273 }
3274
Subhash Jadavani6159c622012-03-15 19:05:55 +05303275 if (row_index >= MAX_PHASES)
3276 return -EINVAL;
3277
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303278 /* Check if phase-0 is present in first valid window? */
3279 if (!ranges[0][0]) {
3280 phase_0_found = true;
3281 phase_0_raw_index = 0;
3282 /* Check if cycle exist between 2 valid windows */
3283 for (cnt = 1; cnt <= row_index; cnt++) {
3284 if (phases_per_row[cnt]) {
Subhash Jadavani6159c622012-03-15 19:05:55 +05303285 for (i = 0; i < phases_per_row[cnt]; i++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303286 if (ranges[cnt][i] == 15) {
3287 phase_15_found = true;
3288 phase_15_raw_index = cnt;
3289 break;
3290 }
3291 }
3292 }
3293 }
3294 }
3295
3296 /* If 2 valid windows form cycle then merge them as single window */
3297 if (phase_0_found && phase_15_found) {
3298 /* number of phases in raw where phase 0 is present */
3299 u8 phases_0 = phases_per_row[phase_0_raw_index];
3300 /* number of phases in raw where phase 15 is present */
3301 u8 phases_15 = phases_per_row[phase_15_raw_index];
3302
Subhash Jadavani6159c622012-03-15 19:05:55 +05303303 if (phases_0 + phases_15 >= MAX_PHASES)
3304 /*
3305 * If there are more than 1 phase windows then total
3306 * number of phases in both the windows should not be
3307 * more than or equal to MAX_PHASES.
3308 */
3309 return -EINVAL;
3310
3311 /* Merge 2 cyclic windows */
3312 i = phases_15;
3313 for (cnt = 0; cnt < phases_0; cnt++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303314 ranges[phase_15_raw_index][i] =
3315 ranges[phase_0_raw_index][cnt];
Subhash Jadavani6159c622012-03-15 19:05:55 +05303316 if (++i >= MAX_PHASES)
3317 break;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303318 }
Subhash Jadavani6159c622012-03-15 19:05:55 +05303319
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303320 phases_per_row[phase_0_raw_index] = 0;
3321 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
3322 }
3323
3324 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303325 if (phases_per_row[cnt] > curr_max) {
3326 curr_max = phases_per_row[cnt];
3327 selected_row_index = cnt;
3328 }
3329 }
3330
Subhash Jadavani6159c622012-03-15 19:05:55 +05303331 i = ((curr_max * 3) / 4);
3332 if (i)
3333 i--;
3334
Subhash Jadavani34187042012-03-02 10:59:49 +05303335 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303336
Subhash Jadavani6159c622012-03-15 19:05:55 +05303337 if (ret >= MAX_PHASES) {
3338 ret = -EINVAL;
3339 pr_err("%s: %s: invalid phase selected=%d\n",
3340 mmc_hostname(host->mmc), __func__, ret);
3341 }
3342
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303343 return ret;
3344}
3345
Girish K Sa3f41692012-02-29 12:00:09 +05303346static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303347{
3348 int rc = 0;
3349 struct msmsdcc_host *host = mmc_priv(mmc);
3350 unsigned long flags;
3351 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303352 const u32 *tuning_block_pattern = tuning_block_64;
3353 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303354
3355 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
3356
3357 /* Tuning is only required for SDR104 modes */
3358 if (!host->tuning_needed) {
3359 rc = 0;
3360 goto exit;
3361 }
3362
3363 spin_lock_irqsave(&host->lock, flags);
3364 WARN(!host->pwr, "SDCC power is turned off\n");
3365 WARN(!host->clks_on, "SDCC clocks are turned off\n");
3366 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
3367
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303368 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303369 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
3370 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
3371 tuning_block_pattern = tuning_block_128;
3372 size = sizeof(tuning_block_128);
3373 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303374 spin_unlock_irqrestore(&host->lock, flags);
3375
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003376 /* first of all reset the tuning block */
3377 rc = msmsdcc_init_cm_sdc4_dll(host);
3378 if (rc)
3379 goto out;
3380
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303381 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003382 if (!data_buf) {
3383 rc = -ENOMEM;
3384 goto out;
3385 }
3386
3387 phase = 0;
3388 do {
3389 struct mmc_command cmd = {0};
3390 struct mmc_data data = {0};
3391 struct mmc_request mrq = {
3392 .cmd = &cmd,
3393 .data = &data
3394 };
3395 struct scatterlist sg;
3396
3397 /* set the phase in delay line hw block */
3398 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3399 if (rc)
3400 goto kfree;
3401
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303402 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003403 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
3404
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303405 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003406 data.blocks = 1;
3407 data.flags = MMC_DATA_READ;
3408 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
3409
3410 data.sg = &sg;
3411 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303412 sg_init_one(&sg, data_buf, size);
3413 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003414 mmc_wait_for_req(mmc, &mrq);
3415
3416 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303417 !memcmp(data_buf, tuning_block_pattern, size)) {
3418 /* tuning is successful at this tuning point */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003419 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303420 pr_debug("%s: %s: found good phase = %d\n",
3421 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003422 }
3423 } while (++phase < 16);
3424
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003425 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303426 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303427 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05303428 if (rc < 0)
3429 goto kfree;
3430 else
3431 phase = (u8)rc;
3432
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003433 /*
3434 * Finally set the selected phase in delay
3435 * line hw block.
3436 */
3437 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3438 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303439 goto kfree;
3440 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
3441 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003442 } else {
3443 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303444 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003445 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303446 msmsdcc_dump_sdcc_state(host);
3447 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003448 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003449
3450kfree:
3451 kfree(data_buf);
3452out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303453 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303454 host->tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303455 spin_unlock_irqrestore(&host->lock, flags);
3456exit:
3457 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003458 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07003459}
3460
3461static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003462 .enable = msmsdcc_enable,
3463 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07003464 .request = msmsdcc_request,
3465 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003466 .get_ro = msmsdcc_get_ro,
San Mehat9d2bd732009-09-22 16:44:22 -07003467 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003468 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
3469 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07003470};
3471
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003472static unsigned int
3473msmsdcc_slot_status(struct msmsdcc_host *host)
3474{
3475 int status;
3476 unsigned int gpio_no = host->plat->status_gpio;
3477
3478 status = gpio_request(gpio_no, "SD_HW_Detect");
3479 if (status) {
3480 pr_err("%s: %s: Failed to request GPIO %d\n",
3481 mmc_hostname(host->mmc), __func__, gpio_no);
3482 } else {
3483 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003484 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08003485 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003486 if (host->plat->is_status_gpio_active_low)
3487 status = !status;
3488 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003489 gpio_free(gpio_no);
3490 }
3491 return status;
3492}
3493
San Mehat9d2bd732009-09-22 16:44:22 -07003494static void
3495msmsdcc_check_status(unsigned long data)
3496{
3497 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3498 unsigned int status;
3499
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003500 if (host->plat->status || host->plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08003501 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003502 status = host->plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08003503 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003504 status = msmsdcc_slot_status(host);
3505
Krishna Konda941604a2012-01-10 17:46:34 -08003506 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08003507
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003508 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08003509 if (host->plat->status)
3510 pr_info("%s: Slot status change detected "
3511 "(%d -> %d)\n",
3512 mmc_hostname(host->mmc),
3513 host->oldstat, status);
3514 else if (host->plat->is_status_gpio_active_low)
3515 pr_info("%s: Slot status change detected "
3516 "(%d -> %d) and the card detect GPIO"
3517 " is ACTIVE_LOW\n",
3518 mmc_hostname(host->mmc),
3519 host->oldstat, status);
3520 else
3521 pr_info("%s: Slot status change detected "
3522 "(%d -> %d) and the card detect GPIO"
3523 " is ACTIVE_HIGH\n",
3524 mmc_hostname(host->mmc),
3525 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07003526 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003527 }
3528 host->oldstat = status;
3529 } else {
3530 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07003531 }
San Mehat9d2bd732009-09-22 16:44:22 -07003532}
3533
3534static irqreturn_t
3535msmsdcc_platform_status_irq(int irq, void *dev_id)
3536{
3537 struct msmsdcc_host *host = dev_id;
3538
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003539 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07003540 msmsdcc_check_status((unsigned long) host);
3541 return IRQ_HANDLED;
3542}
3543
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003544static irqreturn_t
3545msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
3546{
3547 struct msmsdcc_host *host = dev_id;
3548
3549 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
3550 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303551 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003552 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303553 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003554 wake_lock(&host->sdio_wlock);
3555 msmsdcc_disable_irq_wake(host);
3556 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303557 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003558 }
3559 if (host->plat->is_sdio_al_client) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003560 wake_lock(&host->sdio_wlock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303561 mmc_signal_sdio_irq(host->mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003562 }
3563 spin_unlock(&host->lock);
3564
3565 return IRQ_HANDLED;
3566}
3567
San Mehat9d2bd732009-09-22 16:44:22 -07003568static void
3569msmsdcc_status_notify_cb(int card_present, void *dev_id)
3570{
3571 struct msmsdcc_host *host = dev_id;
3572
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003573 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07003574 card_present);
3575 msmsdcc_check_status((unsigned long) host);
3576}
3577
San Mehat9d2bd732009-09-22 16:44:22 -07003578static int
3579msmsdcc_init_dma(struct msmsdcc_host *host)
3580{
3581 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
3582 host->dma.host = host;
3583 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003584 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003585
3586 if (!host->dmares)
3587 return -ENODEV;
3588
3589 host->dma.nc = dma_alloc_coherent(NULL,
3590 sizeof(struct msmsdcc_nc_dmadata),
3591 &host->dma.nc_busaddr,
3592 GFP_KERNEL);
3593 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003594 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07003595 return -ENOMEM;
3596 }
3597 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
3598 host->dma.cmd_busaddr = host->dma.nc_busaddr;
3599 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
3600 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
3601 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07003602 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07003603
3604 return 0;
3605}
3606
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003607#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
3608/**
3609 * Allocate and Connect a SDCC peripheral's SPS endpoint
3610 *
3611 * This function allocates endpoint context and
3612 * connect it with memory endpoint by calling
3613 * appropriate SPS driver APIs.
3614 *
3615 * Also registers a SPS callback function with
3616 * SPS driver
3617 *
3618 * This function should only be called once typically
3619 * during driver probe.
3620 *
3621 * @host - Pointer to sdcc host structure
3622 * @ep - Pointer to sps endpoint data structure
3623 * @is_produce - 1 means Producer endpoint
3624 * 0 means Consumer endpoint
3625 *
3626 * @return - 0 if successful else negative value.
3627 *
3628 */
3629static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
3630 struct msmsdcc_sps_ep_conn_data *ep,
3631 bool is_producer)
3632{
3633 int rc = 0;
3634 struct sps_pipe *sps_pipe_handle;
3635 struct sps_connect *sps_config = &ep->config;
3636 struct sps_register_event *sps_event = &ep->event;
3637
3638 /* Allocate endpoint context */
3639 sps_pipe_handle = sps_alloc_endpoint();
3640 if (!sps_pipe_handle) {
3641 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
3642 mmc_hostname(host->mmc), is_producer);
3643 rc = -ENOMEM;
3644 goto out;
3645 }
3646
3647 /* Get default connection configuration for an endpoint */
3648 rc = sps_get_config(sps_pipe_handle, sps_config);
3649 if (rc) {
3650 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
3651 " rc=%d", mmc_hostname(host->mmc),
3652 (u32)sps_pipe_handle, rc);
3653 goto get_config_err;
3654 }
3655
3656 /* Modify the default connection configuration */
3657 if (is_producer) {
3658 /*
3659 * For SDCC producer transfer, source should be
3660 * SDCC peripheral where as destination should
3661 * be system memory.
3662 */
3663 sps_config->source = host->sps.bam_handle;
3664 sps_config->destination = SPS_DEV_HANDLE_MEM;
3665 /* Producer pipe will handle this connection */
3666 sps_config->mode = SPS_MODE_SRC;
3667 sps_config->options =
3668 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3669 } else {
3670 /*
3671 * For SDCC consumer transfer, source should be
3672 * system memory where as destination should
3673 * SDCC peripheral
3674 */
3675 sps_config->source = SPS_DEV_HANDLE_MEM;
3676 sps_config->destination = host->sps.bam_handle;
3677 sps_config->mode = SPS_MODE_DEST;
3678 sps_config->options =
3679 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3680 }
3681
3682 /* Producer pipe index */
3683 sps_config->src_pipe_index = host->sps.src_pipe_index;
3684 /* Consumer pipe index */
3685 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
3686 /*
3687 * This event thresold value is only significant for BAM-to-BAM
3688 * transfer. It's ignored for BAM-to-System mode transfer.
3689 */
3690 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05303691
3692 /* Allocate maximum descriptor fifo size */
3693 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
3694 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003695 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
3696 sps_config->desc.size,
3697 &sps_config->desc.phys_base,
3698 GFP_KERNEL);
3699
Pratibhasagar V00b94332011-10-18 14:57:27 +05303700 if (!sps_config->desc.base) {
3701 rc = -ENOMEM;
3702 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3703 , mmc_hostname(host->mmc));
3704 goto get_config_err;
3705 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003706 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3707
3708 /* Establish connection between peripheral and memory endpoint */
3709 rc = sps_connect(sps_pipe_handle, sps_config);
3710 if (rc) {
3711 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3712 " rc=%d", mmc_hostname(host->mmc),
3713 (u32)sps_pipe_handle, rc);
3714 goto sps_connect_err;
3715 }
3716
3717 sps_event->mode = SPS_TRIGGER_CALLBACK;
3718 sps_event->options = SPS_O_EOT;
3719 sps_event->callback = msmsdcc_sps_complete_cb;
3720 sps_event->xfer_done = NULL;
3721 sps_event->user = (void *)host;
3722
3723 /* Register callback event for EOT (End of transfer) event. */
3724 rc = sps_register_event(sps_pipe_handle, sps_event);
3725 if (rc) {
3726 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3727 " rc=%d", mmc_hostname(host->mmc),
3728 (u32)sps_pipe_handle, rc);
3729 goto reg_event_err;
3730 }
3731 /* Now save the sps pipe handle */
3732 ep->pipe_handle = sps_pipe_handle;
3733 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3734 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3735 __func__, is_producer ? "READ" : "WRITE",
3736 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3737 goto out;
3738
3739reg_event_err:
3740 sps_disconnect(sps_pipe_handle);
3741sps_connect_err:
3742 dma_free_coherent(mmc_dev(host->mmc),
3743 sps_config->desc.size,
3744 sps_config->desc.base,
3745 sps_config->desc.phys_base);
3746get_config_err:
3747 sps_free_endpoint(sps_pipe_handle);
3748out:
3749 return rc;
3750}
3751
3752/**
3753 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3754 *
3755 * This function disconnect endpoint and deallocates
3756 * endpoint context.
3757 *
3758 * This function should only be called once typically
3759 * during driver remove.
3760 *
3761 * @host - Pointer to sdcc host structure
3762 * @ep - Pointer to sps endpoint data structure
3763 *
3764 */
3765static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3766 struct msmsdcc_sps_ep_conn_data *ep)
3767{
3768 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3769 struct sps_connect *sps_config = &ep->config;
3770 struct sps_register_event *sps_event = &ep->event;
3771
3772 sps_event->xfer_done = NULL;
3773 sps_event->callback = NULL;
3774 sps_register_event(sps_pipe_handle, sps_event);
3775 sps_disconnect(sps_pipe_handle);
3776 dma_free_coherent(mmc_dev(host->mmc),
3777 sps_config->desc.size,
3778 sps_config->desc.base,
3779 sps_config->desc.phys_base);
3780 sps_free_endpoint(sps_pipe_handle);
3781}
3782
3783/**
3784 * Reset SDCC peripheral's SPS endpoint
3785 *
3786 * This function disconnects an endpoint.
3787 *
3788 * This function should be called for reseting
3789 * SPS endpoint when data transfer error is
3790 * encountered during data transfer. This
3791 * can be considered as soft reset to endpoint.
3792 *
3793 * This function should only be called if
3794 * msmsdcc_sps_init() is already called.
3795 *
3796 * @host - Pointer to sdcc host structure
3797 * @ep - Pointer to sps endpoint data structure
3798 *
3799 * @return - 0 if successful else negative value.
3800 */
3801static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3802 struct msmsdcc_sps_ep_conn_data *ep)
3803{
3804 int rc = 0;
3805 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3806
3807 rc = sps_disconnect(sps_pipe_handle);
3808 if (rc) {
3809 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3810 " rc=%d", mmc_hostname(host->mmc), __func__,
3811 (u32)sps_pipe_handle, rc);
3812 goto out;
3813 }
3814 out:
3815 return rc;
3816}
3817
3818/**
3819 * Restore SDCC peripheral's SPS endpoint
3820 *
3821 * This function connects an endpoint.
3822 *
3823 * This function should be called for restoring
3824 * SPS endpoint after data transfer error is
3825 * encountered during data transfer. This
3826 * can be considered as soft reset to endpoint.
3827 *
3828 * This function should only be called if
3829 * msmsdcc_sps_reset_ep() is called before.
3830 *
3831 * @host - Pointer to sdcc host structure
3832 * @ep - Pointer to sps endpoint data structure
3833 *
3834 * @return - 0 if successful else negative value.
3835 */
3836static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3837 struct msmsdcc_sps_ep_conn_data *ep)
3838{
3839 int rc = 0;
3840 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3841 struct sps_connect *sps_config = &ep->config;
3842 struct sps_register_event *sps_event = &ep->event;
3843
3844 /* Establish connection between peripheral and memory endpoint */
3845 rc = sps_connect(sps_pipe_handle, sps_config);
3846 if (rc) {
3847 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3848 " rc=%d", mmc_hostname(host->mmc), __func__,
3849 (u32)sps_pipe_handle, rc);
3850 goto out;
3851 }
3852
3853 /* Register callback event for EOT (End of transfer) event. */
3854 rc = sps_register_event(sps_pipe_handle, sps_event);
3855 if (rc) {
3856 pr_err("%s: %s: sps_register_event() failed!!!"
3857 " pipe_handle=0x%x, rc=%d",
3858 mmc_hostname(host->mmc), __func__,
3859 (u32)sps_pipe_handle, rc);
3860 goto reg_event_err;
3861 }
3862 goto out;
3863
3864reg_event_err:
3865 sps_disconnect(sps_pipe_handle);
3866out:
3867 return rc;
3868}
3869
3870/**
3871 * Initialize SPS HW connected with SDCC core
3872 *
3873 * This function register BAM HW resources with
3874 * SPS driver and then initialize 2 SPS endpoints
3875 *
3876 * This function should only be called once typically
3877 * during driver probe.
3878 *
3879 * @host - Pointer to sdcc host structure
3880 *
3881 * @return - 0 if successful else negative value.
3882 *
3883 */
3884static int msmsdcc_sps_init(struct msmsdcc_host *host)
3885{
3886 int rc = 0;
3887 struct sps_bam_props bam = {0};
3888
3889 host->bam_base = ioremap(host->bam_memres->start,
3890 resource_size(host->bam_memres));
3891 if (!host->bam_base) {
3892 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3893 " size=0x%x", mmc_hostname(host->mmc),
3894 host->bam_memres->start,
3895 (host->bam_memres->end -
3896 host->bam_memres->start));
3897 rc = -ENOMEM;
3898 goto out;
3899 }
3900
3901 bam.phys_addr = host->bam_memres->start;
3902 bam.virt_addr = host->bam_base;
3903 /*
3904 * This event thresold value is only significant for BAM-to-BAM
3905 * transfer. It's ignored for BAM-to-System mode transfer.
3906 */
3907 bam.event_threshold = 0x10; /* Pipe event threshold */
3908 /*
3909 * This threshold controls when the BAM publish
3910 * the descriptor size on the sideband interface.
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05303911 * SPS HW will be used for data transfer size even
3912 * less than SDCC FIFO size. So let's set BAM summing
3913 * thresold to SPS_MIN_XFER_SIZE bytes.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003914 */
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05303915 bam.summing_threshold = SPS_MIN_XFER_SIZE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003916 /* SPS driver wll handle the SDCC BAM IRQ */
3917 bam.irq = (u32)host->bam_irqres->start;
3918 bam.manage = SPS_BAM_MGR_LOCAL;
3919
3920 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3921 (u32)bam.phys_addr);
3922 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3923 (u32)bam.virt_addr);
3924
3925 /* Register SDCC Peripheral BAM device to SPS driver */
3926 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3927 if (rc) {
3928 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3929 mmc_hostname(host->mmc), rc);
3930 goto reg_bam_err;
3931 }
3932 pr_info("%s: BAM device registered. bam_handle=0x%x",
3933 mmc_hostname(host->mmc), host->sps.bam_handle);
3934
3935 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3936 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3937
3938 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3939 SPS_PROD_PERIPHERAL);
3940 if (rc)
3941 goto sps_reset_err;
3942 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3943 SPS_CONS_PERIPHERAL);
3944 if (rc)
3945 goto cons_conn_err;
3946
3947 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3948 mmc_hostname(host->mmc),
3949 (unsigned long long)host->bam_memres->start,
3950 (unsigned int)host->bam_irqres->start);
3951 goto out;
3952
3953cons_conn_err:
3954 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3955sps_reset_err:
3956 sps_deregister_bam_device(host->sps.bam_handle);
3957reg_bam_err:
3958 iounmap(host->bam_base);
3959out:
3960 return rc;
3961}
3962
3963/**
3964 * De-initialize SPS HW connected with SDCC core
3965 *
3966 * This function deinitialize SPS endpoints and then
3967 * deregisters BAM resources from SPS driver.
3968 *
3969 * This function should only be called once typically
3970 * during driver remove.
3971 *
3972 * @host - Pointer to sdcc host structure
3973 *
3974 */
3975static void msmsdcc_sps_exit(struct msmsdcc_host *host)
3976{
3977 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
3978 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3979 sps_deregister_bam_device(host->sps.bam_handle);
3980 iounmap(host->bam_base);
3981}
3982#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
3983
3984static ssize_t
3985show_polling(struct device *dev, struct device_attribute *attr, char *buf)
3986{
3987 struct mmc_host *mmc = dev_get_drvdata(dev);
3988 struct msmsdcc_host *host = mmc_priv(mmc);
3989 int poll;
3990 unsigned long flags;
3991
3992 spin_lock_irqsave(&host->lock, flags);
3993 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
3994 spin_unlock_irqrestore(&host->lock, flags);
3995
3996 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
3997}
3998
3999static ssize_t
4000set_polling(struct device *dev, struct device_attribute *attr,
4001 const char *buf, size_t count)
4002{
4003 struct mmc_host *mmc = dev_get_drvdata(dev);
4004 struct msmsdcc_host *host = mmc_priv(mmc);
4005 int value;
4006 unsigned long flags;
4007
4008 sscanf(buf, "%d", &value);
4009
4010 spin_lock_irqsave(&host->lock, flags);
4011 if (value) {
4012 mmc->caps |= MMC_CAP_NEEDS_POLL;
4013 mmc_detect_change(host->mmc, 0);
4014 } else {
4015 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4016 }
4017#ifdef CONFIG_HAS_EARLYSUSPEND
4018 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
4019#endif
4020 spin_unlock_irqrestore(&host->lock, flags);
4021 return count;
4022}
4023
4024static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
4025 show_polling, set_polling);
4026static struct attribute *dev_attrs[] = {
4027 &dev_attr_polling.attr,
4028 NULL,
4029};
4030static struct attribute_group dev_attr_grp = {
4031 .attrs = dev_attrs,
4032};
4033
4034#ifdef CONFIG_HAS_EARLYSUSPEND
4035static void msmsdcc_early_suspend(struct early_suspend *h)
4036{
4037 struct msmsdcc_host *host =
4038 container_of(h, struct msmsdcc_host, early_suspend);
4039 unsigned long flags;
4040
4041 spin_lock_irqsave(&host->lock, flags);
4042 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
4043 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4044 spin_unlock_irqrestore(&host->lock, flags);
4045};
4046static void msmsdcc_late_resume(struct early_suspend *h)
4047{
4048 struct msmsdcc_host *host =
4049 container_of(h, struct msmsdcc_host, early_suspend);
4050 unsigned long flags;
4051
4052 if (host->polling_enabled) {
4053 spin_lock_irqsave(&host->lock, flags);
4054 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
4055 mmc_detect_change(host->mmc, 0);
4056 spin_unlock_irqrestore(&host->lock, flags);
4057 }
4058};
4059#endif
4060
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304061void msmsdcc_print_regs(const char *name, void __iomem *base,
4062 unsigned int no_of_regs)
4063{
4064 unsigned int i;
4065
4066 if (!base)
4067 return;
4068 pr_info("===== %s: Register Dumps @base=0x%x =====\n",
4069 name, (u32)base);
4070 for (i = 0; i < no_of_regs; i = i + 4) {
4071 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x.\n", i*4,
4072 (u32)readl_relaxed(base + i*4),
4073 (u32)readl_relaxed(base + ((i+1)*4)),
4074 (u32)readl_relaxed(base + ((i+2)*4)),
4075 (u32)readl_relaxed(base + ((i+3)*4)));
4076 }
4077}
4078
4079static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
4080{
4081 /* Dump current state of SDCC clocks, power and irq */
4082 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
4083 (host->pwr ? "ON" : "OFF"));
4084 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
4085 mmc_hostname(host->mmc),
4086 (host->clks_on ? "ON" : "OFF"),
4087 (u32)clk_get_rate(host->clk));
4088 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
4089 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
4090
4091 /* Now dump SDCC registers. Don't print FIFO registers */
4092 if (host->clks_on)
4093 msmsdcc_print_regs("SDCC-CORE", host->base, 28);
4094
4095 if (host->curr.data) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304096 if (!msmsdcc_is_dma_possible(host, host->curr.data))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304097 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
4098 else if (host->is_dma_mode)
4099 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
4100 mmc_hostname(host->mmc), host->dma.busy,
4101 host->dma.channel, host->dma.crci);
4102 else if (host->is_sps_mode)
4103 pr_info("%s: SPS mode: busy=%d\n",
4104 mmc_hostname(host->mmc), host->sps.busy);
4105
4106 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
4107 mmc_hostname(host->mmc), host->curr.xfer_size,
4108 host->curr.data_xfered, host->curr.xfer_remain);
4109 pr_info("%s: got_dataend=%d, prog_enable=%d,"
4110 " wait_for_auto_prog_done=%d,"
4111 " got_auto_prog_done=%d\n",
4112 mmc_hostname(host->mmc), host->curr.got_dataend,
4113 host->prog_enable, host->curr.wait_for_auto_prog_done,
4114 host->curr.got_auto_prog_done);
4115 }
4116
4117}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004118static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
4119{
4120 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4121 struct mmc_request *mrq;
4122 unsigned long flags;
4123
4124 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004125 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004126 pr_info("%s: %s: dummy CMD52 timeout\n",
4127 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004128 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004129 }
4130
4131 mrq = host->curr.mrq;
4132
4133 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304134 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
4135 mrq->cmd->opcode);
4136 msmsdcc_dump_sdcc_state(host);
4137
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004138 if (!mrq->cmd->error)
4139 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304140 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004141 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004142 if (mrq->data && !mrq->data->error)
4143 mrq->data->error = -ETIMEDOUT;
4144 host->curr.data_xfered = 0;
4145 if (host->dma.sg && host->is_dma_mode) {
4146 msm_dmov_stop_cmd(host->dma.channel,
4147 &host->dma.hdr, 0);
4148 } else if (host->sps.sg && host->is_sps_mode) {
4149 /* Stop current SPS transfer */
4150 msmsdcc_sps_exit_curr_xfer(host);
4151 } else {
4152 msmsdcc_reset_and_restore(host);
4153 msmsdcc_stop_data(host);
4154 if (mrq->data && mrq->data->stop)
4155 msmsdcc_start_command(host,
4156 mrq->data->stop, 0);
4157 else
4158 msmsdcc_request_end(host, mrq);
4159 }
4160 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304161 host->prog_enable = 0;
Subhash Jadavanied6b0e42012-03-07 16:36:27 +05304162 host->curr.wait_for_auto_prog_done = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004163 msmsdcc_reset_and_restore(host);
4164 msmsdcc_request_end(host, mrq);
4165 }
4166 }
4167 spin_unlock_irqrestore(&host->lock, flags);
4168}
4169
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304170static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
4171{
4172 int i, ret;
4173 struct mmc_platform_data *pdata;
4174 struct device_node *np = dev->of_node;
4175 u32 bus_width = 0;
4176 u32 *clk_table;
4177 int clk_table_len;
4178 u32 *sup_voltages;
4179 int sup_volt_len;
4180
4181 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
4182 if (!pdata) {
4183 dev_err(dev, "could not allocate memory for platform data\n");
4184 goto err;
4185 }
4186
4187 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
4188 if (bus_width == 8) {
4189 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
4190 } else if (bus_width == 4) {
4191 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
4192 } else {
4193 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
4194 pdata->mmc_bus_width = 0;
4195 }
4196
4197 if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
4198 size_t sz;
4199 sz = sup_volt_len / sizeof(*sup_voltages);
4200 if (sz > 0) {
4201 sup_voltages = devm_kzalloc(dev,
4202 sz * sizeof(*sup_voltages), GFP_KERNEL);
4203 if (!sup_voltages) {
4204 dev_err(dev, "No memory for supported voltage\n");
4205 goto err;
4206 }
4207
4208 ret = of_property_read_u32_array(np,
4209 "qcom,sdcc-sup-voltages", sup_voltages, sz);
4210 if (ret < 0) {
4211 dev_err(dev, "error while reading voltage"
4212 "ranges %d\n", ret);
4213 goto err;
4214 }
4215 } else {
4216 dev_err(dev, "No supported voltages\n");
4217 goto err;
4218 }
4219 for (i = 0; i < sz; i += 2) {
4220 u32 mask;
4221
4222 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
4223 sup_voltages[i + 1]);
4224 if (!mask)
4225 dev_err(dev, "Invalide voltage range %d\n", i);
4226 pdata->ocr_mask |= mask;
4227 }
4228 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
4229 } else {
4230 dev_err(dev, "Supported voltage range not specified\n");
4231 }
4232
4233 if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
4234 size_t sz;
4235 sz = clk_table_len / sizeof(*clk_table);
4236
4237 if (sz > 0) {
4238 clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
4239 GFP_KERNEL);
4240 if (!clk_table) {
4241 dev_err(dev, "No memory for clock table\n");
4242 goto err;
4243 }
4244
4245 ret = of_property_read_u32_array(np,
4246 "qcom,sdcc-clk-rates", clk_table, sz);
4247 if (ret < 0) {
4248 dev_err(dev, "error while reading clk"
4249 "table %d\n", ret);
4250 goto err;
4251 }
4252 } else {
4253 dev_err(dev, "clk_table not specified\n");
4254 goto err;
4255 }
4256 pdata->sup_clk_table = clk_table;
4257 pdata->sup_clk_cnt = sz;
4258 } else {
4259 dev_err(dev, "Supported clock rates not specified\n");
4260 }
4261
4262 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
4263 pdata->nonremovable = true;
4264 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
4265 pdata->disable_cmd23 = true;
4266
4267 return pdata;
4268err:
4269 return NULL;
4270}
4271
San Mehat9d2bd732009-09-22 16:44:22 -07004272static int
4273msmsdcc_probe(struct platform_device *pdev)
4274{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304275 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07004276 struct msmsdcc_host *host;
4277 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004278 unsigned long flags;
4279 struct resource *core_irqres = NULL;
4280 struct resource *bam_irqres = NULL;
4281 struct resource *core_memres = NULL;
4282 struct resource *dml_memres = NULL;
4283 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07004284 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07004285 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05304286 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004287 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07004288
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304289 if (pdev->dev.of_node) {
4290 plat = msmsdcc_populate_pdata(&pdev->dev);
4291 of_property_read_u32((&pdev->dev)->of_node,
4292 "cell-index", &pdev->id);
4293 } else {
4294 plat = pdev->dev.platform_data;
4295 }
4296
San Mehat9d2bd732009-09-22 16:44:22 -07004297 /* must have platform data */
4298 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004299 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004300 ret = -EINVAL;
4301 goto out;
4302 }
4303
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004304 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07004305 return -EINVAL;
4306
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304307 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
4308 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
4309 return -EINVAL;
4310 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004311
San Mehat9d2bd732009-09-22 16:44:22 -07004312 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004313 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004314 return -ENXIO;
4315 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304316 if (pdev->dev.of_node) {
4317 /*
4318 * Device tree iomem resources are only accessible by index.
4319 * index = 0 -> SDCC register interface
4320 * index = 1 -> DML register interface
4321 * index = 2 -> BAM register interface
4322 * IRQ resources:
4323 * index = 0 -> SDCC IRQ
4324 * index = 1 -> BAM IRQ
4325 */
4326 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
4327 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
4328 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
4329 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
4330 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
4331 } else {
4332 for (i = 0; i < pdev->num_resources; i++) {
4333 if (pdev->resource[i].flags & IORESOURCE_MEM) {
4334 if (!strncmp(pdev->resource[i].name,
4335 "sdcc_dml_addr",
4336 sizeof("sdcc_dml_addr")))
4337 dml_memres = &pdev->resource[i];
4338 else if (!strncmp(pdev->resource[i].name,
4339 "sdcc_bam_addr",
4340 sizeof("sdcc_bam_addr")))
4341 bam_memres = &pdev->resource[i];
4342 else
4343 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07004344
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304345 }
4346 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
4347 if (!strncmp(pdev->resource[i].name,
4348 "sdcc_bam_irq",
4349 sizeof("sdcc_bam_irq")))
4350 bam_irqres = &pdev->resource[i];
4351 else
4352 core_irqres = &pdev->resource[i];
4353 }
4354 if (pdev->resource[i].flags & IORESOURCE_DMA) {
4355 if (!strncmp(pdev->resource[i].name,
4356 "sdcc_dma_chnl",
4357 sizeof("sdcc_dma_chnl")))
4358 dmares = &pdev->resource[i];
4359 else if (!strncmp(pdev->resource[i].name,
4360 "sdcc_dma_crci",
4361 sizeof("sdcc_dma_crci")))
4362 dma_crci_res = &pdev->resource[i];
4363 }
Krishna Konda25786ec2011-07-25 16:21:36 -07004364 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004365 }
4366
4367 if (!core_irqres || !core_memres) {
4368 pr_err("%s: Invalid sdcc core resource\n", __func__);
4369 return -ENXIO;
4370 }
4371
4372 /*
4373 * Both BAM and DML memory resource should be preset.
4374 * BAM IRQ resource should also be present.
4375 */
4376 if ((bam_memres && !dml_memres) ||
4377 (!bam_memres && dml_memres) ||
4378 ((bam_memres && dml_memres) && !bam_irqres)) {
4379 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004380 return -ENXIO;
4381 }
4382
4383 /*
4384 * Setup our host structure
4385 */
San Mehat9d2bd732009-09-22 16:44:22 -07004386 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
4387 if (!mmc) {
4388 ret = -ENOMEM;
4389 goto out;
4390 }
4391
4392 host = mmc_priv(mmc);
4393 host->pdev_id = pdev->id;
4394 host->plat = plat;
4395 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08004396 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05304397
4398 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004399 host->is_sps_mode = 1;
4400 else if (dmares)
4401 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07004402
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004403 host->base = ioremap(core_memres->start,
4404 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07004405 if (!host->base) {
4406 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004407 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004408 }
4409
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004410 host->core_irqres = core_irqres;
4411 host->bam_irqres = bam_irqres;
4412 host->core_memres = core_memres;
4413 host->dml_memres = dml_memres;
4414 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07004415 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07004416 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07004417 spin_lock_init(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304418 mutex_init(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07004419
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004420#ifdef CONFIG_MMC_EMBEDDED_SDIO
4421 if (plat->embedded_sdio)
4422 mmc_set_embedded_sdio_data(mmc,
4423 &plat->embedded_sdio->cis,
4424 &plat->embedded_sdio->cccr,
4425 plat->embedded_sdio->funcs,
4426 plat->embedded_sdio->num_funcs);
4427#endif
4428
Sahitya Tummala62612cf2010-12-08 15:03:03 +05304429 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
4430 (unsigned long)host);
4431
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004432 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
4433 (unsigned long)host);
4434 if (host->is_dma_mode) {
4435 /* Setup DMA */
4436 ret = msmsdcc_init_dma(host);
4437 if (ret)
4438 goto ioremap_free;
4439 } else {
4440 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004441 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004442 }
4443
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004444 /*
4445 * Setup SDCC clock if derived from Dayatona
4446 * fabric core clock.
4447 */
4448 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07004449 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004450 if (!IS_ERR(host->dfab_pclk)) {
4451 /* Set the clock rate to 64MHz for max. performance */
4452 ret = clk_set_rate(host->dfab_pclk, 64000000);
4453 if (ret)
4454 goto dfab_pclk_put;
Asutosh Dasf5298c32012-04-03 14:51:47 +05304455 ret = clk_prepare_enable(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004456 if (ret)
4457 goto dfab_pclk_put;
4458 } else
4459 goto dma_free;
4460 }
4461
4462 /*
4463 * Setup main peripheral bus clock
4464 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004465 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004466 if (!IS_ERR(host->pclk)) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05304467 ret = clk_prepare_enable(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004468 if (ret)
4469 goto pclk_put;
4470
4471 host->pclk_rate = clk_get_rate(host->pclk);
4472 }
4473
4474 /*
4475 * Setup SDC MMC clock
4476 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004477 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07004478 if (IS_ERR(host->clk)) {
4479 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004480 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07004481 }
4482
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004483 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
4484 if (ret) {
4485 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
4486 goto clk_put;
4487 }
4488
Asutosh Dasf5298c32012-04-03 14:51:47 +05304489 ret = clk_prepare_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004490 if (ret)
4491 goto clk_put;
4492
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004493 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304494 if (!host->clk_rate)
4495 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304496
4497 /*
4498 * Lookup the Controller Version, to identify the supported features
4499 * Version number read as 0 would indicate SDCC3 or earlier versions
4500 */
4501 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
4502 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
4503 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304504 /*
4505 * Set the register write delay according to min. clock frequency
4506 * supported and update later when the host->clk_rate changes.
4507 */
4508 host->reg_write_delay =
4509 (1 + ((3 * USEC_PER_SEC) /
4510 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004511
4512 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05304513 /* Apply Hard reset to SDCC to put it in power on default state */
4514 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004515
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304516 /* pm qos request to prevent apps idle power collapse */
4517 if (host->plat->swfi_latency)
4518 pm_qos_add_request(&host->pm_qos_req_dma,
4519 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
4520
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004521 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07004522 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004523 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07004524 goto clk_disable;
4525 }
4526
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004527
4528 /* Clocks has to be running before accessing SPS/DML HW blocks */
4529 if (host->is_sps_mode) {
4530 /* Initialize SPS */
4531 ret = msmsdcc_sps_init(host);
4532 if (ret)
4533 goto vreg_deinit;
4534 /* Initialize DML */
4535 ret = msmsdcc_dml_init(host);
4536 if (ret)
4537 goto sps_exit;
4538 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05304539 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07004540
San Mehat9d2bd732009-09-22 16:44:22 -07004541 /*
4542 * Setup MMC host structure
4543 */
4544 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004545 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
4546 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004547 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004548 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
4549 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07004550
San Mehat9d2bd732009-09-22 16:44:22 -07004551 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05304552 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304553
4554 /*
4555 * If we send the CMD23 before multi block write/read command
4556 * then we need not to send CMD12 at the end of the transfer.
4557 * If we don't send the CMD12 then only way to detect the PROG_DONE
4558 * status is to use the AUTO_PROG_DONE status provided by SDCC4
4559 * controller. So let's enable the CMD23 for SDCC4 only.
4560 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304561 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304562 mmc->caps |= MMC_CAP_CMD23;
4563
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004564 mmc->caps |= plat->uhs_caps;
4565 /*
4566 * XPC controls the maximum current in the default speed mode of SDXC
4567 * card. XPC=0 means 100mA (max.) but speed class is not supported.
4568 * XPC=1 means 150mA (max.) and speed class is supported.
4569 */
4570 if (plat->xpc_cap)
4571 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
4572 MMC_CAP_SET_XPC_180);
4573
Subhash Jadavani0a0c6272012-03-24 23:13:18 +05304574 mmc->caps2 |= MMC_CAP2_BOOTPART_NOACC;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304575 if (pdev->dev.of_node) {
4576 if (of_get_property((&pdev->dev)->of_node,
4577 "qcom,sdcc-hs200", NULL))
4578 mmc->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
4579 }
4580
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004581 if (plat->nonremovable)
4582 mmc->caps |= MMC_CAP_NONREMOVABLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004583 mmc->caps |= MMC_CAP_SDIO_IRQ;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004584
4585 if (plat->is_sdio_al_client)
4586 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07004587
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304588 mmc->max_segs = msmsdcc_get_nr_sg(host);
4589 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
4590 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07004591
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304592 mmc->max_req_size = MMC_MAX_REQ_SIZE;
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +05304593 mmc->max_seg_size = mmc->max_req_size;
San Mehat9d2bd732009-09-22 16:44:22 -07004594
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004595 writel_relaxed(0, host->base + MMCIMASK0);
4596 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05304597 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004598
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004599 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
4600 mb();
4601 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07004602
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004603 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
4604 DRIVER_NAME " (cmd)", host);
4605 if (ret)
4606 goto dml_exit;
4607
4608 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
4609 DRIVER_NAME " (pio)", host);
4610 if (ret)
4611 goto irq_free;
4612
4613 /*
4614 * Enable SDCC IRQ only when host is powered on. Otherwise, this
4615 * IRQ is un-necessarily being monitored by MPM (Modem power
4616 * management block) during idle-power collapse. The MPM will be
4617 * configured to monitor the DATA1 GPIO line with level-low trigger
4618 * and thus depending on the GPIO status, it prevents TCXO shutdown
4619 * during idle-power collapse.
4620 */
4621 disable_irq(core_irqres->start);
4622 host->sdcc_irq_disabled = 1;
4623
4624 if (plat->sdiowakeup_irq) {
4625 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4626 mmc_hostname(mmc));
4627 ret = request_irq(plat->sdiowakeup_irq,
4628 msmsdcc_platform_sdiowakeup_irq,
4629 IRQF_SHARED | IRQF_TRIGGER_LOW,
4630 DRIVER_NAME "sdiowakeup", host);
4631 if (ret) {
4632 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
4633 plat->sdiowakeup_irq, ret);
4634 goto pio_irq_free;
4635 } else {
4636 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304637 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004638 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304639 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004640 }
4641 spin_unlock_irqrestore(&host->lock, flags);
4642 }
4643 }
4644
4645 if (plat->cfg_mpm_sdiowakeup) {
4646 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4647 mmc_hostname(mmc));
4648 }
4649
4650 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
4651 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004652 /*
4653 * Setup card detect change
4654 */
4655
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004656 if (plat->status || plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08004657 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004658 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08004659 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004660 host->oldstat = msmsdcc_slot_status(host);
Krishna Konda360aa422011-12-06 18:27:41 -08004661
Krishna Konda941604a2012-01-10 17:46:34 -08004662 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004663 }
San Mehat9d2bd732009-09-22 16:44:22 -07004664
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004665 if (plat->status_irq) {
4666 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07004667 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004668 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07004669 DRIVER_NAME " (slot)",
4670 host);
4671 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004672 pr_err("Unable to get slot IRQ %d (%d)\n",
4673 plat->status_irq, ret);
4674 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004675 }
4676 } else if (plat->register_status_notify) {
4677 plat->register_status_notify(msmsdcc_status_notify_cb, host);
4678 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004679 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07004680 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004681
4682 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004683
4684 ret = pm_runtime_set_active(&(pdev)->dev);
4685 if (ret < 0)
4686 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
4687 __func__, ret);
4688 /*
4689 * There is no notion of suspend/resume for SD/MMC/SDIO
4690 * cards. So host can be suspended/resumed with out
4691 * worrying about its children.
4692 */
4693 pm_suspend_ignore_children(&(pdev)->dev, true);
4694
4695 /*
4696 * MMC/SD/SDIO bus suspend/resume operations are defined
4697 * only for the slots that will be used for non-removable
4698 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
4699 * defined. Otherwise, they simply become card removal and
4700 * insertion events during suspend and resume respectively.
4701 * Hence, enable run-time PM only for slots for which bus
4702 * suspend/resume operations are defined.
4703 */
4704#ifdef CONFIG_MMC_UNSAFE_RESUME
4705 /*
4706 * If this capability is set, MMC core will enable/disable host
4707 * for every claim/release operation on a host. We use this
4708 * notification to increment/decrement runtime pm usage count.
4709 */
4710 mmc->caps |= MMC_CAP_DISABLE;
4711 pm_runtime_enable(&(pdev)->dev);
4712#else
4713 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
4714 mmc->caps |= MMC_CAP_DISABLE;
4715 pm_runtime_enable(&(pdev)->dev);
4716 }
4717#endif
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05304718#ifndef CONFIG_PM_RUNTIME
4719 mmc_set_disable_delay(mmc, MSM_MMC_DISABLE_TIMEOUT);
4720#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004721 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
4722 (unsigned long)host);
4723
San Mehat9d2bd732009-09-22 16:44:22 -07004724 mmc_add_host(mmc);
4725
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004726#ifdef CONFIG_HAS_EARLYSUSPEND
4727 host->early_suspend.suspend = msmsdcc_early_suspend;
4728 host->early_suspend.resume = msmsdcc_late_resume;
4729 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
4730 register_early_suspend(&host->early_suspend);
4731#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004732
Krishna Konda25786ec2011-07-25 16:21:36 -07004733 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
4734 " dmacrcri %d\n", mmc_hostname(mmc),
4735 (unsigned long long)core_memres->start,
4736 (unsigned int) core_irqres->start,
4737 (unsigned int) plat->status_irq, host->dma.channel,
4738 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004739
4740 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
4741 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
4742 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
4743 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
4744 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
4745 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
4746 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
4747 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
4748 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
4749 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
4750 host->eject);
4751 pr_info("%s: Power save feature enable = %d\n",
4752 mmc_hostname(mmc), msmsdcc_pwrsave);
4753
Krishna Konda25786ec2011-07-25 16:21:36 -07004754 if (host->is_dma_mode && host->dma.channel != -1
4755 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004756 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004757 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004758 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004759 mmc_hostname(mmc), host->dma.cmd_busaddr,
4760 host->dma.cmdptr_busaddr);
4761 } else if (host->is_sps_mode) {
4762 pr_info("%s: SPS-BAM data transfer mode available\n",
4763 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004764 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004765 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004766
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004767#if defined(CONFIG_DEBUG_FS)
4768 msmsdcc_dbg_createhost(host);
4769#endif
4770 if (!plat->status_irq) {
4771 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
4772 if (ret)
4773 goto platform_irq_free;
4774 }
San Mehat9d2bd732009-09-22 16:44:22 -07004775 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004776
4777 platform_irq_free:
4778 del_timer_sync(&host->req_tout_timer);
4779 pm_runtime_disable(&(pdev)->dev);
4780 pm_runtime_set_suspended(&(pdev)->dev);
4781
4782 if (plat->status_irq)
4783 free_irq(plat->status_irq, host);
4784 sdiowakeup_irq_free:
4785 wake_lock_destroy(&host->sdio_suspend_wlock);
4786 if (plat->sdiowakeup_irq)
4787 free_irq(plat->sdiowakeup_irq, host);
4788 pio_irq_free:
4789 if (plat->sdiowakeup_irq)
4790 wake_lock_destroy(&host->sdio_wlock);
4791 free_irq(core_irqres->start, host);
4792 irq_free:
4793 free_irq(core_irqres->start, host);
4794 dml_exit:
4795 if (host->is_sps_mode)
4796 msmsdcc_dml_exit(host);
4797 sps_exit:
4798 if (host->is_sps_mode)
4799 msmsdcc_sps_exit(host);
4800 vreg_deinit:
4801 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07004802 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004803 clk_disable(host->clk);
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304804 if (host->plat->swfi_latency)
4805 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07004806 clk_put:
4807 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004808 pclk_disable:
4809 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05304810 clk_disable_unprepare(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07004811 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004812 if (!IS_ERR(host->pclk))
4813 clk_put(host->pclk);
4814 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05304815 clk_disable_unprepare(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004816 dfab_pclk_put:
4817 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4818 clk_put(host->dfab_pclk);
4819 dma_free:
4820 if (host->is_dma_mode) {
4821 if (host->dmares)
4822 dma_free_coherent(NULL,
4823 sizeof(struct msmsdcc_nc_dmadata),
4824 host->dma.nc, host->dma.nc_busaddr);
4825 }
4826 ioremap_free:
4827 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07004828 host_free:
4829 mmc_free_host(mmc);
4830 out:
4831 return ret;
4832}
4833
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004834static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07004835{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004836 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4837 struct mmc_platform_data *plat;
4838 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004839
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004840 if (!mmc)
4841 return -ENXIO;
4842
4843 if (pm_runtime_suspended(&(pdev)->dev))
4844 pm_runtime_resume(&(pdev)->dev);
4845
4846 host = mmc_priv(mmc);
4847
4848 DBG(host, "Removing SDCC device = %d\n", pdev->id);
4849 plat = host->plat;
4850
4851 if (!plat->status_irq)
4852 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
4853
4854 del_timer_sync(&host->req_tout_timer);
4855 tasklet_kill(&host->dma_tlet);
4856 tasklet_kill(&host->sps.tlet);
4857 mmc_remove_host(mmc);
4858
4859 if (plat->status_irq)
4860 free_irq(plat->status_irq, host);
4861
4862 wake_lock_destroy(&host->sdio_suspend_wlock);
4863 if (plat->sdiowakeup_irq) {
4864 wake_lock_destroy(&host->sdio_wlock);
4865 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
4866 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07004867 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004868
4869 free_irq(host->core_irqres->start, host);
4870 free_irq(host->core_irqres->start, host);
4871
4872 clk_put(host->clk);
4873 if (!IS_ERR(host->pclk))
4874 clk_put(host->pclk);
4875 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4876 clk_put(host->dfab_pclk);
4877
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304878 if (host->plat->swfi_latency)
4879 pm_qos_remove_request(&host->pm_qos_req_dma);
4880
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004881 msmsdcc_vreg_init(host, false);
4882
4883 if (host->is_dma_mode) {
4884 if (host->dmares)
4885 dma_free_coherent(NULL,
4886 sizeof(struct msmsdcc_nc_dmadata),
4887 host->dma.nc, host->dma.nc_busaddr);
4888 }
4889
4890 if (host->is_sps_mode) {
4891 msmsdcc_dml_exit(host);
4892 msmsdcc_sps_exit(host);
4893 }
4894
4895 iounmap(host->base);
4896 mmc_free_host(mmc);
4897
4898#ifdef CONFIG_HAS_EARLYSUSPEND
4899 unregister_early_suspend(&host->early_suspend);
4900#endif
4901 pm_runtime_disable(&(pdev)->dev);
4902 pm_runtime_set_suspended(&(pdev)->dev);
4903
4904 return 0;
4905}
4906
4907#ifdef CONFIG_MSM_SDIO_AL
4908int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4909{
4910 struct msmsdcc_host *host = mmc_priv(mmc);
4911 unsigned long flags;
4912
Asutosh Dasf5298c32012-04-03 14:51:47 +05304913 mutex_lock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004914 spin_lock_irqsave(&host->lock, flags);
4915 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
4916 enable ? "En" : "Dis");
4917
4918 if (enable) {
4919 if (!host->sdcc_irq_disabled) {
4920 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05304921 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004922 host->sdcc_irq_disabled = 1;
4923 }
4924
4925 if (host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05304926 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004927 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304928 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004929 host->clks_on = 0;
4930 }
4931
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304932 if (host->plat->sdio_lpm_gpio_setup &&
4933 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004934 spin_unlock_irqrestore(&host->lock, flags);
4935 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
4936 spin_lock_irqsave(&host->lock, flags);
4937 host->sdio_gpio_lpm = 1;
4938 }
4939
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304940 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004941 msmsdcc_enable_irq_wake(host);
4942 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304943 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004944 }
4945 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304946 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004947 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304948 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004949 msmsdcc_disable_irq_wake(host);
4950 }
4951
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304952 if (host->plat->sdio_lpm_gpio_setup &&
4953 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004954 spin_unlock_irqrestore(&host->lock, flags);
4955 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
4956 spin_lock_irqsave(&host->lock, flags);
4957 host->sdio_gpio_lpm = 0;
4958 }
4959
4960 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05304961 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004962 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304963 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004964 host->clks_on = 1;
4965 }
4966
4967 if (host->sdcc_irq_disabled) {
4968 writel_relaxed(host->mci_irqenable,
4969 host->base + MMCIMASK0);
4970 mb();
4971 enable_irq(host->core_irqres->start);
4972 host->sdcc_irq_disabled = 0;
4973 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004974 }
4975 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304976 mutex_unlock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004977 return 0;
4978}
4979#else
4980int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4981{
4982 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004983}
4984#endif
4985
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004986#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07004987static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004988msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004989{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004990 struct mmc_host *mmc = dev_get_drvdata(dev);
4991 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07004992 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304993 unsigned long flags;
4994
San Mehat9d2bd732009-09-22 16:44:22 -07004995
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004996 if (host->plat->is_sdio_al_client)
4997 return 0;
Sahitya Tummala7661a452011-07-18 13:28:35 +05304998 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004999 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005000 host->sdcc_suspending = 1;
5001 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07005002
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005003 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005004 * MMC core thinks that host is disabled by now since
5005 * runtime suspend is scheduled after msmsdcc_disable()
5006 * is called. Thus, MMC core will try to enable the host
5007 * while suspending it. This results in a synchronous
5008 * runtime resume request while in runtime suspending
5009 * context and hence inorder to complete this resume
5010 * requet, it will wait for suspend to be complete,
5011 * but runtime suspend also can not proceed further
5012 * until the host is resumed. Thus, it leads to a hang.
5013 * Hence, increase the pm usage count before suspending
5014 * the host so that any resume requests after this will
5015 * simple become pm usage counter increment operations.
5016 */
5017 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05305018 /* If there is pending detect work abort runtime suspend */
5019 if (unlikely(work_busy(&mmc->detect.work)))
5020 rc = -EAGAIN;
5021 else
5022 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005023 pm_runtime_put_noidle(dev);
5024
5025 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305026 spin_lock_irqsave(&host->lock, flags);
5027 host->sdcc_suspended = true;
5028 spin_unlock_irqrestore(&host->lock, flags);
5029 if (mmc->card && mmc_card_sdio(mmc->card) &&
5030 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005031 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305032 * If SDIO function driver doesn't want
5033 * to power off the card, atleast turn off
5034 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005035 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305036 mmc_host_clk_hold(mmc);
5037 spin_lock_irqsave(&mmc->clk_lock, flags);
5038 mmc->clk_old = mmc->ios.clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005039 mmc->ios.clock = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305040 mmc->clk_gated = true;
5041 spin_unlock_irqrestore(&mmc->clk_lock, flags);
5042 mmc_set_ios(mmc);
5043 mmc_host_clk_release(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005044 }
5045 }
5046 host->sdcc_suspending = 0;
5047 mmc->suspend_task = NULL;
5048 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
5049 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005050 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05305051 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
San Mehat9d2bd732009-09-22 16:44:22 -07005052 return rc;
5053}
5054
5055static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005056msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07005057{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005058 struct mmc_host *mmc = dev_get_drvdata(dev);
5059 struct msmsdcc_host *host = mmc_priv(mmc);
5060 unsigned long flags;
5061
5062 if (host->plat->is_sdio_al_client)
5063 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07005064
Sahitya Tummala7661a452011-07-18 13:28:35 +05305065 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005066 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305067 if (mmc->card && mmc_card_sdio(mmc->card) &&
5068 mmc_card_keep_power(mmc)) {
5069 mmc_host_clk_hold(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305070 mmc->ios.clock = host->clk_rate;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305071 mmc_set_ios(mmc);
5072 mmc_host_clk_release(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305073 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005074
5075 mmc_resume_host(mmc);
5076
5077 /*
5078 * FIXME: Clearing of flags must be handled in clients
5079 * resume handler.
5080 */
5081 spin_lock_irqsave(&host->lock, flags);
5082 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305083 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005084 spin_unlock_irqrestore(&host->lock, flags);
5085
5086 /*
5087 * After resuming the host wait for sometime so that
5088 * the SDIO work will be processed.
5089 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305090 if (mmc->card && mmc_card_sdio(mmc->card)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005091 if ((host->plat->cfg_mpm_sdiowakeup ||
5092 host->plat->sdiowakeup_irq) &&
5093 wake_lock_active(&host->sdio_wlock))
5094 wake_lock_timeout(&host->sdio_wlock, 1);
5095 }
5096
5097 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005098 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05305099 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005100 return 0;
5101}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005102
5103static int msmsdcc_runtime_idle(struct device *dev)
5104{
5105 struct mmc_host *mmc = dev_get_drvdata(dev);
5106 struct msmsdcc_host *host = mmc_priv(mmc);
5107
5108 if (host->plat->is_sdio_al_client)
5109 return 0;
5110
5111 /* Idle timeout is not configurable for now */
5112 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
5113
5114 return -EAGAIN;
5115}
5116
5117static int msmsdcc_pm_suspend(struct device *dev)
5118{
5119 struct mmc_host *mmc = dev_get_drvdata(dev);
5120 struct msmsdcc_host *host = mmc_priv(mmc);
5121 int rc = 0;
5122
5123 if (host->plat->is_sdio_al_client)
5124 return 0;
5125
5126
5127 if (host->plat->status_irq)
5128 disable_irq(host->plat->status_irq);
5129
Subhash Jadavani18702212012-03-19 18:50:18 +05305130 if (!pm_runtime_suspended(dev)) {
5131 if (!(mmc->card && mmc_card_sdio(mmc->card))) {
5132 /*
5133 * decrement power.usage_counter if it's
5134 * not zero earlier
5135 */
5136 pm_runtime_put_noidle(dev);
5137 rc = pm_runtime_suspend(dev);
5138 }
5139
5140 /*
5141 * if device runtime PM status is still not suspended
5142 * then perform suspend here.
5143 */
5144 if (!pm_runtime_suspended(dev))
5145 rc = msmsdcc_runtime_suspend(dev);
5146 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005147
5148 return rc;
5149}
5150
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305151static int msmsdcc_suspend_noirq(struct device *dev)
5152{
5153 struct mmc_host *mmc = dev_get_drvdata(dev);
5154 struct msmsdcc_host *host = mmc_priv(mmc);
5155 int rc = 0;
5156
5157 /*
5158 * After platform suspend there may be active request
5159 * which might have enabled clocks. For example, in SDIO
5160 * case, ksdioirq thread might have scheduled after sdcc
5161 * suspend but before system freeze. In that case abort
5162 * suspend and retry instead of keeping the clocks on
5163 * during suspend and not allowing TCXO.
5164 */
5165
Asutosh Dasf5298c32012-04-03 14:51:47 +05305166 if (host->clks_on && !host->plat->is_sdio_al_client) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305167 pr_warn("%s: clocks are on after suspend, aborting system "
5168 "suspend\n", mmc_hostname(mmc));
5169 rc = -EAGAIN;
5170 }
5171
5172 return rc;
5173}
5174
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005175static int msmsdcc_pm_resume(struct device *dev)
5176{
5177 struct mmc_host *mmc = dev_get_drvdata(dev);
5178 struct msmsdcc_host *host = mmc_priv(mmc);
5179 int rc = 0;
5180
5181 if (host->plat->is_sdio_al_client)
5182 return 0;
5183
Sahitya Tummalafb486372011-09-02 19:01:49 +05305184 if (!pm_runtime_suspended(dev))
5185 rc = msmsdcc_runtime_resume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005186 if (host->plat->status_irq) {
5187 msmsdcc_check_status((unsigned long)host);
5188 enable_irq(host->plat->status_irq);
5189 }
5190
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005191 return rc;
5192}
5193
Daniel Walker08ecfde2010-06-23 12:32:20 -07005194#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005195#define msmsdcc_runtime_suspend NULL
5196#define msmsdcc_runtime_resume NULL
5197#define msmsdcc_runtime_idle NULL
5198#define msmsdcc_pm_suspend NULL
5199#define msmsdcc_pm_resume NULL
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305200#define msmsdcc_suspend_noirq NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07005201#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005202
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005203static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
5204 .runtime_suspend = msmsdcc_runtime_suspend,
5205 .runtime_resume = msmsdcc_runtime_resume,
5206 .runtime_idle = msmsdcc_runtime_idle,
5207 .suspend = msmsdcc_pm_suspend,
5208 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305209 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005210};
5211
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305212static const struct of_device_id msmsdcc_dt_match[] = {
5213 {.compatible = "qcom,msm-sdcc"},
5214
5215};
5216MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
5217
San Mehat9d2bd732009-09-22 16:44:22 -07005218static struct platform_driver msmsdcc_driver = {
5219 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005220 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07005221 .driver = {
5222 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005223 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305224 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07005225 },
5226};
5227
5228static int __init msmsdcc_init(void)
5229{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005230#if defined(CONFIG_DEBUG_FS)
5231 int ret = 0;
5232 ret = msmsdcc_dbg_init();
5233 if (ret) {
5234 pr_err("Failed to create debug fs dir \n");
5235 return ret;
5236 }
5237#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005238 return platform_driver_register(&msmsdcc_driver);
5239}
5240
5241static void __exit msmsdcc_exit(void)
5242{
5243 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005244
5245#if defined(CONFIG_DEBUG_FS)
5246 debugfs_remove(debugfs_file);
5247 debugfs_remove(debugfs_dir);
5248#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005249}
5250
5251module_init(msmsdcc_init);
5252module_exit(msmsdcc_exit);
5253
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005254MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07005255MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005256
5257#if defined(CONFIG_DEBUG_FS)
5258
5259static int
5260msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
5261{
5262 file->private_data = inode->i_private;
5263 return 0;
5264}
5265
5266static ssize_t
5267msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
5268 size_t count, loff_t *ppos)
5269{
5270 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08005271 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005272 int max, i;
5273
5274 i = 0;
5275 max = sizeof(buf) - 1;
5276
5277 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
5278 host->curr.cmd, host->curr.data);
5279 if (host->curr.cmd) {
5280 struct mmc_command *cmd = host->curr.cmd;
5281
5282 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
5283 cmd->opcode, cmd->arg, cmd->flags);
5284 }
5285 if (host->curr.data) {
5286 struct mmc_data *data = host->curr.data;
5287 i += scnprintf(buf + i, max - i,
5288 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
5289 data->timeout_ns, data->timeout_clks,
5290 data->blksz, data->blocks, data->error,
5291 data->flags);
5292 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
5293 host->curr.xfer_size, host->curr.xfer_remain,
5294 host->curr.data_xfered, host->dma.sg);
5295 }
5296
5297 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
5298}
5299
5300static const struct file_operations msmsdcc_dbg_state_ops = {
5301 .read = msmsdcc_dbg_state_read,
5302 .open = msmsdcc_dbg_state_open,
5303};
5304
5305static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
5306{
5307 if (debugfs_dir) {
5308 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
5309 0644, debugfs_dir, host,
5310 &msmsdcc_dbg_state_ops);
5311 }
5312}
5313
5314static int __init msmsdcc_dbg_init(void)
5315{
5316 int err;
5317
5318 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
5319 if (IS_ERR(debugfs_dir)) {
5320 err = PTR_ERR(debugfs_dir);
5321 debugfs_dir = NULL;
5322 return err;
5323 }
5324
5325 return 0;
5326}
5327#endif