blob: 0d11dca34a7594d3090a5367320ee0a48977790d [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>
Subhash Jadavanic9b85752012-04-13 11:16:49 +053057#include <mach/mpm.h>
San Mehat9d2bd732009-09-22 16:44:22 -070058
San Mehat9d2bd732009-09-22 16:44:22 -070059#include "msm_sdcc.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070060#include "msm_sdcc_dml.h"
San Mehat9d2bd732009-09-22 16:44:22 -070061
62#define DRIVER_NAME "msm-sdcc"
63
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070064#define DBG(host, fmt, args...) \
65 pr_debug("%s: %s: " fmt "\n", mmc_hostname(host->mmc), __func__ , args)
66
67#define IRQ_DEBUG 0
68#define SPS_SDCC_PRODUCER_PIPE_INDEX 1
69#define SPS_SDCC_CONSUMER_PIPE_INDEX 2
70#define SPS_CONS_PERIPHERAL 0
71#define SPS_PROD_PERIPHERAL 1
Subhash Jadavanie6e1b822012-03-12 18:17:58 +053072/* Use SPS only if transfer size is more than this macro */
73#define SPS_MIN_XFER_SIZE MCI_FIFOSIZE
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070074
75#if defined(CONFIG_DEBUG_FS)
76static void msmsdcc_dbg_createhost(struct msmsdcc_host *);
77static struct dentry *debugfs_dir;
78static struct dentry *debugfs_file;
79static int msmsdcc_dbg_init(void);
80#endif
81
Asutosh Dasaccacd42012-03-08 14:33:17 +053082static int msmsdcc_prep_xfer(struct msmsdcc_host *host, struct mmc_data
83 *data);
84
Subhash Jadavani8766e352011-11-30 11:30:32 +053085static u64 dma_mask = DMA_BIT_MASK(32);
San Mehat9d2bd732009-09-22 16:44:22 -070086static unsigned int msmsdcc_pwrsave = 1;
San Mehat9d2bd732009-09-22 16:44:22 -070087
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070088static struct mmc_command dummy52cmd;
89static struct mmc_request dummy52mrq = {
90 .cmd = &dummy52cmd,
91 .data = NULL,
92 .stop = NULL,
93};
94static struct mmc_command dummy52cmd = {
95 .opcode = SD_IO_RW_DIRECT,
96 .flags = MMC_RSP_PRESENT,
97 .data = NULL,
98 .mrq = &dummy52mrq,
99};
100/*
101 * An array holding the Tuning pattern to compare with when
102 * executing a tuning cycle.
103 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +0530104static const u32 tuning_block_64[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700105 0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
106 0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
107 0xF0FFF0FF, 0x3CCCFC0F, 0xCFCC33CC, 0xEEFFEFFF,
108 0xFDFFFDFF, 0xFFBFFFDF, 0xFFF7FFBB, 0xDE7B7FF7
109};
San Mehat865c8062009-11-13 13:42:06 -0800110
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +0530111static const u32 tuning_block_128[] = {
112 0xFF00FFFF, 0x0000FFFF, 0xCCCCFFFF, 0xCCCC33CC,
113 0xCC3333CC, 0xFFFFCCCC, 0xFFFFEEFF, 0xFFEEEEFF,
114 0xFFDDFFFF, 0xDDDDFFFF, 0xBBFFFFFF, 0xBBFFFFFF,
115 0xFFFFFFBB, 0xFFFFFF77, 0x77FF7777, 0xFFEEDDBB,
116 0x00FFFFFF, 0x00FFFFFF, 0xCCFFFF00, 0xCC33CCCC,
117 0x3333CCCC, 0xFFCCCCCC, 0xFFEEFFFF, 0xEEEEFFFF,
118 0xDDFFFFFF, 0xDDFFFFFF, 0xFFFFFFDD, 0xFFFFFFBB,
119 0xFFFFBBBB, 0xFFFF77FF, 0xFF7777FF, 0xEEDDBB77
120};
121
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700122#if IRQ_DEBUG == 1
123static char *irq_status_bits[] = { "cmdcrcfail", "datcrcfail", "cmdtimeout",
124 "dattimeout", "txunderrun", "rxoverrun",
125 "cmdrespend", "cmdsent", "dataend", NULL,
126 "datablkend", "cmdactive", "txactive",
127 "rxactive", "txhalfempty", "rxhalffull",
128 "txfifofull", "rxfifofull", "txfifoempty",
129 "rxfifoempty", "txdataavlbl", "rxdataavlbl",
130 "sdiointr", "progdone", "atacmdcompl",
131 "sdiointrope", "ccstimeout", NULL, NULL,
132 NULL, NULL, NULL };
133
134static void
135msmsdcc_print_status(struct msmsdcc_host *host, char *hdr, uint32_t status)
San Mehat865c8062009-11-13 13:42:06 -0800136{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700137 int i;
San Mehat8b1c2ba2009-11-16 10:17:30 -0800138
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700139 pr_debug("%s-%s ", mmc_hostname(host->mmc), hdr);
140 for (i = 0; i < 32; i++) {
141 if (status & (1 << i))
142 pr_debug("%s ", irq_status_bits[i]);
San Mehat865c8062009-11-13 13:42:06 -0800143 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700144 pr_debug("\n");
San Mehatc7fc9372009-11-22 17:19:07 -0800145}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700146#endif
San Mehat865c8062009-11-13 13:42:06 -0800147
San Mehat9d2bd732009-09-22 16:44:22 -0700148static void
149msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
150 u32 c);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530151static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530152static inline void msmsdcc_delay(struct msmsdcc_host *host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530153static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -0800154static void msmsdcc_sg_start(struct msmsdcc_host *host);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -0800155static int msmsdcc_vreg_reset(struct msmsdcc_host *host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -0700156static int msmsdcc_runtime_resume(struct device *dev);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530157
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530158static inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
159{
160 unsigned short ret = NR_SG;
161
162 if (host->is_sps_mode) {
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +0530163 ret = SPS_MAX_DESCS;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530164 } else { /* DMA or PIO mode */
165 if (NR_SG > MAX_NR_SG_DMA_PIO)
166 ret = MAX_NR_SG_DMA_PIO;
167 }
168
169 return ret;
170}
171
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530172/* Prevent idle power collapse(pc) while operating in peripheral mode */
173static void msmsdcc_pm_qos_update_latency(struct msmsdcc_host *host, int vote)
174{
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -0700175 if (!host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530176 return;
177
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530178 if (vote)
179 pm_qos_update_request(&host->pm_qos_req_dma,
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -0700180 host->cpu_dma_latency);
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530181 else
182 pm_qos_update_request(&host->pm_qos_req_dma,
183 PM_QOS_DEFAULT_VALUE);
184}
185
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700186#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
187static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
188 struct msmsdcc_sps_ep_conn_data *ep);
189static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
190 struct msmsdcc_sps_ep_conn_data *ep);
191#else
192static inline int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
193 struct msmsdcc_sps_ep_conn_data *ep,
194 bool is_producer) { return 0; }
195static inline void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
196 struct msmsdcc_sps_ep_conn_data *ep) { }
197static inline int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
198 struct msmsdcc_sps_ep_conn_data *ep)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530199{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700200 return 0;
201}
202static inline int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
203 struct msmsdcc_sps_ep_conn_data *ep)
204{
205 return 0;
206}
207static inline int msmsdcc_sps_init(struct msmsdcc_host *host) { return 0; }
208static inline void msmsdcc_sps_exit(struct msmsdcc_host *host) {}
209#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530210
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700211/**
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530212 * Apply soft reset to all SDCC BAM pipes
213 *
214 * This function applies soft reset to SDCC BAM pipe.
215 *
216 * This function should be called to recover from error
217 * conditions encountered during CMD/DATA tranfsers with card.
218 *
219 * @host - Pointer to driver's host structure
220 *
221 */
222static void msmsdcc_sps_pipes_reset_and_restore(struct msmsdcc_host *host)
223{
224 int rc;
225
226 /* Reset all SDCC BAM pipes */
227 rc = msmsdcc_sps_reset_ep(host, &host->sps.prod);
228 if (rc)
229 pr_err("%s:msmsdcc_sps_reset_ep(prod) error=%d\n",
230 mmc_hostname(host->mmc), rc);
231 rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
232 if (rc)
233 pr_err("%s:msmsdcc_sps_reset_ep(cons) error=%d\n",
234 mmc_hostname(host->mmc), rc);
235
236 /* Restore all BAM pipes connections */
237 rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
238 if (rc)
239 pr_err("%s:msmsdcc_sps_restore_ep(prod) error=%d\n",
240 mmc_hostname(host->mmc), rc);
241 rc = msmsdcc_sps_restore_ep(host, &host->sps.cons);
242 if (rc)
243 pr_err("%s:msmsdcc_sps_restore_ep(cons) error=%d\n",
244 mmc_hostname(host->mmc), rc);
245}
246
247/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700248 * Apply soft reset
249 *
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530250 * This function applies soft reset to SDCC core and DML core.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700251 *
252 * This function should be called to recover from error
253 * conditions encountered with CMD/DATA tranfsers with card.
254 *
255 * Soft reset should only be used with SDCC controller v4.
256 *
257 * @host - Pointer to driver's host structure
258 *
259 */
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530260static void msmsdcc_soft_reset(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700261{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700262 /*
263 * Reset SDCC controller's DPSM (data path state machine
264 * and CPSM (command path state machine).
265 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700266 writel_relaxed(0, host->base + MMCICOMMAND);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530267 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700268 writel_relaxed(0, host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530269 msmsdcc_sync_reg_wr(host);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530270}
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530271
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530272static void msmsdcc_hard_reset(struct msmsdcc_host *host)
273{
274 int ret;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530275
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530276 /* Reset the controller */
277 ret = clk_reset(host->clk, CLK_RESET_ASSERT);
278 if (ret)
279 pr_err("%s: Clock assert failed at %u Hz"
280 " with err %d\n", mmc_hostname(host->mmc),
281 host->clk_rate, ret);
282
283 ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
284 if (ret)
285 pr_err("%s: Clock deassert failed at %u Hz"
286 " with err %d\n", mmc_hostname(host->mmc),
287 host->clk_rate, ret);
288
Subhash Jadavanidd432952012-03-28 11:25:56 +0530289 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530290 /* Give some delay for clock reset to propogate to controller */
291 msmsdcc_delay(host);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530292}
293
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700294static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
295{
Pratibhasagar V1c11da62011-11-14 12:36:35 +0530296 if (host->sdcc_version) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530297 if (host->is_sps_mode) {
298 /* Reset DML first */
299 msmsdcc_dml_reset(host);
300 /*
301 * delay the SPS pipe reset in thread context as
302 * sps_connect/sps_disconnect APIs can be called
303 * only from non-atomic context.
304 */
305 host->sps.pipe_reset_pending = true;
306 }
307 mb();
308 msmsdcc_soft_reset(host);
309
310 pr_debug("%s: Applied soft reset to Controller\n",
311 mmc_hostname(host->mmc));
312
313 if (host->is_sps_mode)
314 msmsdcc_dml_init(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700315 } else {
316 /* Give Clock reset (hard reset) to controller */
317 u32 mci_clk = 0;
318 u32 mci_mask0 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700319
320 /* Save the controller state */
321 mci_clk = readl_relaxed(host->base + MMCICLOCK);
322 mci_mask0 = readl_relaxed(host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +0530323 host->pwr = readl_relaxed(host->base + MMCIPOWER);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700324 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700325
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530326 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700327 pr_debug("%s: Controller has been reinitialized\n",
328 mmc_hostname(host->mmc));
329
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700330 /* Restore the contoller state */
331 writel_relaxed(host->pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530332 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700333 writel_relaxed(mci_clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530334 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700335 writel_relaxed(mci_mask0, host->base + MMCIMASK0);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530336 mb(); /* no delay required after writing to MASK0 register */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700337 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530338
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700339 if (host->dummy_52_needed)
340 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700341}
342
343static int
San Mehat9d2bd732009-09-22 16:44:22 -0700344msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
345{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700346 int retval = 0;
347
San Mehat9d2bd732009-09-22 16:44:22 -0700348 BUG_ON(host->curr.data);
349
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700350 del_timer(&host->req_tout_timer);
351
San Mehat9d2bd732009-09-22 16:44:22 -0700352 if (mrq->data)
353 mrq->data->bytes_xfered = host->curr.data_xfered;
354 if (mrq->cmd->error == -ETIMEDOUT)
355 mdelay(5);
356
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530357 /* Clear current request information as current request has ended */
358 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
359
San Mehat9d2bd732009-09-22 16:44:22 -0700360 /*
361 * Need to drop the host lock here; mmc_request_done may call
362 * back into the driver...
363 */
364 spin_unlock(&host->lock);
365 mmc_request_done(host->mmc, mrq);
366 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700367
368 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700369}
370
371static void
372msmsdcc_stop_data(struct msmsdcc_host *host)
373{
San Mehat9d2bd732009-09-22 16:44:22 -0700374 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530375 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530376 host->curr.wait_for_auto_prog_done = 0;
377 host->curr.got_auto_prog_done = 0;
Krishna Konda3f5d48f2011-07-27 10:47:31 -0700378 writel_relaxed(readl_relaxed(host->base + MMCIDATACTRL) &
379 (~(MCI_DPSM_ENABLE)), host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530380 msmsdcc_sync_reg_wr(host); /* Allow the DPSM to be reset */
San Mehat9d2bd732009-09-22 16:44:22 -0700381}
382
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700383static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700384{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700385 return host->core_memres->start + MMCIFIFO;
386}
387
388static inline unsigned int msmsdcc_get_min_sup_clk_rate(
389 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530390
Subhash Jadavanidd432952012-03-28 11:25:56 +0530391static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700392{
393 mb();
Subhash Jadavanidd432952012-03-28 11:25:56 +0530394 if (!host->sdcc_version)
395 udelay(host->reg_write_delay);
396 else if (readl_relaxed(host->base + MCI_STATUS2) &
397 MCI_MCLK_REG_WR_ACTIVE) {
398 ktime_t start, diff;
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530399
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530400 start = ktime_get();
401 while (readl_relaxed(host->base + MCI_STATUS2) &
402 MCI_MCLK_REG_WR_ACTIVE) {
403 diff = ktime_sub(ktime_get(), start);
404 /* poll for max. 1 ms */
405 if (ktime_to_us(diff) > 1000) {
406 pr_warning("%s: previous reg. write is"
407 " still active\n",
408 mmc_hostname(host->mmc));
409 break;
410 }
411 }
412 }
San Mehat9d2bd732009-09-22 16:44:22 -0700413}
414
Subhash Jadavanidd432952012-03-28 11:25:56 +0530415static inline void msmsdcc_delay(struct msmsdcc_host *host)
416{
417 udelay(host->reg_write_delay);
418
419}
420
San Mehat56a8b5b2009-11-21 12:29:46 -0800421static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700422msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
423{
424 writel_relaxed(arg, host->base + MMCIARGUMENT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700425 writel_relaxed(c, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530426 /*
427 * As after sending the command, we don't write any of the
428 * controller registers and just wait for the
429 * CMD_RESPOND_END/CMD_SENT/Command failure notication
430 * from Controller.
431 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700432 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800433}
434
435static void
436msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
437{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700438 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800439
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700440 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
441 writel_relaxed((unsigned int)host->curr.xfer_size,
442 host->base + MMCIDATALENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700443 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530444 msmsdcc_sync_reg_wr(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800445
San Mehat6ac9ea62009-12-02 17:24:58 -0800446 if (host->cmd_cmd) {
447 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700448 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800449 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800450}
451
San Mehat9d2bd732009-09-22 16:44:22 -0700452static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530453msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700454{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530455 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700456 unsigned long flags;
457 struct mmc_request *mrq;
458
459 spin_lock_irqsave(&host->lock, flags);
460 mrq = host->curr.mrq;
461 BUG_ON(!mrq);
462
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530463 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700464 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700465 goto out;
466 }
467
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530468 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700469 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700470 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700471 } else {
472 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530473 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700474 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530475 mmc_hostname(host->mmc), host->dma.result);
476 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700477 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530478 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530479 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700480 host->dma.err.flush[0], host->dma.err.flush[1],
481 host->dma.err.flush[2], host->dma.err.flush[3],
482 host->dma.err.flush[4],
483 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530484 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700485 if (!mrq->data->error)
486 mrq->data->error = -EIO;
487 }
Asutosh Dasaccacd42012-03-08 14:33:17 +0530488 if (!mrq->data->host_cookie)
489 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
490 host->dma.num_ents, host->dma.dir);
San Mehat9d2bd732009-09-22 16:44:22 -0700491
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700492 if (host->curr.user_pages) {
493 struct scatterlist *sg = host->dma.sg;
494 int i;
495
496 for (i = 0; i < host->dma.num_ents; i++, sg++)
497 flush_dcache_page(sg_page(sg));
498 }
499
San Mehat9d2bd732009-09-22 16:44:22 -0700500 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800501 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700502
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530503 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
504 (host->curr.wait_for_auto_prog_done &&
505 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700506 /*
507 * If we've already gotten our DATAEND / DATABLKEND
508 * for this request, then complete it through here.
509 */
San Mehat9d2bd732009-09-22 16:44:22 -0700510
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700511 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700512 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700513 host->curr.xfer_remain -= host->curr.xfer_size;
514 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700515 if (host->dummy_52_needed) {
516 mrq->data->bytes_xfered = host->curr.data_xfered;
517 host->dummy_52_sent = 1;
518 msmsdcc_start_command(host, &dummy52cmd,
519 MCI_CPSM_PROGENA);
520 goto out;
521 }
522 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530523 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530524 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700525 mrq->data->bytes_xfered = host->curr.data_xfered;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700526 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530527 /*
528 * Clear current request information as current
529 * request has ended
530 */
531 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
San Mehat9d2bd732009-09-22 16:44:22 -0700532 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700533
San Mehat9d2bd732009-09-22 16:44:22 -0700534 mmc_request_done(host->mmc, mrq);
535 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530536 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
537 || !mrq->sbc)) {
538 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530539 }
San Mehat9d2bd732009-09-22 16:44:22 -0700540 }
541
542out:
543 spin_unlock_irqrestore(&host->lock, flags);
544 return;
545}
546
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700547#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
548/**
549 * Callback notification from SPS driver
550 *
551 * This callback function gets triggered called from
552 * SPS driver when requested SPS data transfer is
553 * completed.
554 *
555 * SPS driver invokes this callback in BAM irq context so
556 * SDCC driver schedule a tasklet for further processing
557 * this callback notification at later point of time in
558 * tasklet context and immediately returns control back
559 * to SPS driver.
560 *
561 * @nofity - Pointer to sps event notify sturcture
562 *
563 */
564static void
565msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
566{
567 struct msmsdcc_host *host =
568 (struct msmsdcc_host *)
569 ((struct sps_event_notify *)notify)->user;
570
571 host->sps.notify = *notify;
572 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
573 mmc_hostname(host->mmc), __func__, notify->event_id,
574 notify->data.transfer.iovec.addr,
575 notify->data.transfer.iovec.size,
576 notify->data.transfer.iovec.flags);
577 /* Schedule a tasklet for completing data transfer */
578 tasklet_schedule(&host->sps.tlet);
579}
580
581/**
582 * Tasklet handler for processing SPS callback event
583 *
584 * This function processing SPS event notification and
585 * checks if the SPS transfer is completed or not and
586 * then accordingly notifies status to MMC core layer.
587 *
588 * This function is called in tasklet context.
589 *
590 * @data - Pointer to sdcc driver data
591 *
592 */
593static void msmsdcc_sps_complete_tlet(unsigned long data)
594{
595 unsigned long flags;
596 int i, rc;
597 u32 data_xfered = 0;
598 struct mmc_request *mrq;
599 struct sps_iovec iovec;
600 struct sps_pipe *sps_pipe_handle;
601 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
602 struct sps_event_notify *notify = &host->sps.notify;
603
604 spin_lock_irqsave(&host->lock, flags);
605 if (host->sps.dir == DMA_FROM_DEVICE)
606 sps_pipe_handle = host->sps.prod.pipe_handle;
607 else
608 sps_pipe_handle = host->sps.cons.pipe_handle;
609 mrq = host->curr.mrq;
610
611 if (!mrq) {
612 spin_unlock_irqrestore(&host->lock, flags);
613 return;
614 }
615
616 pr_debug("%s: %s: sps event_id=%d\n",
617 mmc_hostname(host->mmc), __func__,
618 notify->event_id);
619
620 if (msmsdcc_is_dml_busy(host)) {
621 /* oops !!! this should never happen. */
622 pr_err("%s: %s: Received SPS EOT event"
623 " but DML HW is still busy !!!\n",
624 mmc_hostname(host->mmc), __func__);
625 }
626 /*
627 * Got End of transfer event!!! Check if all of the data
628 * has been transferred?
629 */
630 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
631 rc = sps_get_iovec(sps_pipe_handle, &iovec);
632 if (rc) {
633 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
634 mmc_hostname(host->mmc), __func__, rc, i);
635 break;
636 }
637 data_xfered += iovec.size;
638 }
639
640 if (data_xfered == host->curr.xfer_size) {
641 host->curr.data_xfered = host->curr.xfer_size;
642 host->curr.xfer_remain -= host->curr.xfer_size;
643 pr_debug("%s: Data xfer success. data_xfered=0x%x",
644 mmc_hostname(host->mmc),
645 host->curr.xfer_size);
646 } else {
647 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
648 " xfer_size=%d", mmc_hostname(host->mmc),
649 data_xfered, host->curr.xfer_size);
650 msmsdcc_reset_and_restore(host);
651 if (!mrq->data->error)
652 mrq->data->error = -EIO;
653 }
654
655 /* Unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +0530656 if (!mrq->data->host_cookie)
657 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
658 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700659 host->sps.sg = NULL;
660 host->sps.busy = 0;
661
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530662 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
663 (host->curr.wait_for_auto_prog_done &&
664 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700665 /*
666 * If we've already gotten our DATAEND / DATABLKEND
667 * for this request, then complete it through here.
668 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700669
670 if (!mrq->data->error) {
671 host->curr.data_xfered = host->curr.xfer_size;
672 host->curr.xfer_remain -= host->curr.xfer_size;
673 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700674 if (host->dummy_52_needed) {
675 mrq->data->bytes_xfered = host->curr.data_xfered;
676 host->dummy_52_sent = 1;
677 msmsdcc_start_command(host, &dummy52cmd,
678 MCI_CPSM_PROGENA);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700679 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700680 return;
681 }
682 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530683 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530684 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700685 mrq->data->bytes_xfered = host->curr.data_xfered;
686 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530687 /*
688 * Clear current request information as current
689 * request has ended
690 */
691 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700692 spin_unlock_irqrestore(&host->lock, flags);
693
694 mmc_request_done(host->mmc, mrq);
695 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530696 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
697 || !mrq->sbc)) {
698 msmsdcc_start_command(host, mrq->data->stop, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700699 }
700 }
701 spin_unlock_irqrestore(&host->lock, flags);
702}
703
704/**
705 * Exit from current SPS data transfer
706 *
707 * This function exits from current SPS data transfer.
708 *
709 * This function should be called when error condition
710 * is encountered during data transfer.
711 *
712 * @host - Pointer to sdcc host structure
713 *
714 */
715static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
716{
717 struct mmc_request *mrq;
718
719 mrq = host->curr.mrq;
720 BUG_ON(!mrq);
721
722 msmsdcc_reset_and_restore(host);
723 if (!mrq->data->error)
724 mrq->data->error = -EIO;
725
726 /* Unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +0530727 if (!mrq->data->host_cookie)
728 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
729 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700730
731 host->sps.sg = NULL;
732 host->sps.busy = 0;
733 if (host->curr.data)
734 msmsdcc_stop_data(host);
735
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530736 if (!mrq->data->stop || mrq->cmd->error ||
737 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700738 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530739 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
740 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700741 msmsdcc_start_command(host, mrq->data->stop, 0);
742
743}
744#else
745static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
746static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
747static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
748#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
749
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530750static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700751
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530752static void
753msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
754 unsigned int result,
755 struct msm_dmov_errdata *err)
756{
757 struct msmsdcc_dma_data *dma_data =
758 container_of(cmd, struct msmsdcc_dma_data, hdr);
759 struct msmsdcc_host *host = dma_data->host;
760
761 dma_data->result = result;
762 if (err)
763 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
764
765 tasklet_schedule(&host->dma_tlet);
766}
767
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530768static bool msmsdcc_is_dma_possible(struct msmsdcc_host *host,
769 struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700770{
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530771 bool ret = true;
772 u32 xfer_size = data->blksz * data->blocks;
773
774 if (host->is_sps_mode) {
775 /*
776 * BAM Mode: Fall back on PIO if size is less
777 * than or equal to SPS_MIN_XFER_SIZE bytes.
778 */
779 if (xfer_size <= SPS_MIN_XFER_SIZE)
780 ret = false;
781 } else if (host->is_dma_mode) {
782 /*
783 * ADM Mode: Fall back on PIO if size is less than FIFO size
784 * or not integer multiple of FIFO size
785 */
786 if (xfer_size % MCI_FIFOSIZE)
787 ret = false;
788 } else {
789 /* PIO Mode */
790 ret = false;
791 }
792
793 return ret;
San Mehat9d2bd732009-09-22 16:44:22 -0700794}
795
796static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
797{
798 struct msmsdcc_nc_dmadata *nc;
799 dmov_box *box;
800 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700801 unsigned int n;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530802 int i, err = 0, box_cmd_cnt = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700803 struct scatterlist *sg = data->sg;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530804 unsigned int len, offset;
San Mehat9d2bd732009-09-22 16:44:22 -0700805
Krishna Konda25786ec2011-07-25 16:21:36 -0700806 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700807 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700808
Krishna Konda25786ec2011-07-25 16:21:36 -0700809 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
810
San Mehat9d2bd732009-09-22 16:44:22 -0700811 host->dma.sg = data->sg;
812 host->dma.num_ents = data->sg_len;
813
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530814 /* Prevent memory corruption */
815 BUG_ON(host->dma.num_ents > msmsdcc_get_nr_sg(host));
San Mehat56a8b5b2009-11-21 12:29:46 -0800816
San Mehat9d2bd732009-09-22 16:44:22 -0700817 nc = host->dma.nc;
818
San Mehat9d2bd732009-09-22 16:44:22 -0700819 if (data->flags & MMC_DATA_READ)
820 host->dma.dir = DMA_FROM_DEVICE;
821 else
822 host->dma.dir = DMA_TO_DEVICE;
823
Asutosh Dasaccacd42012-03-08 14:33:17 +0530824 if (!data->host_cookie) {
825 n = msmsdcc_prep_xfer(host, data);
826 if (unlikely(n < 0)) {
827 host->dma.sg = NULL;
828 host->dma.num_ents = 0;
829 return -ENOMEM;
830 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800831 }
San Mehat9d2bd732009-09-22 16:44:22 -0700832
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530833 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
834 host->curr.user_pages = 0;
835 box = &nc->cmd[0];
836 for (i = 0; i < host->dma.num_ents; i++) {
837 len = sg_dma_len(sg);
838 offset = 0;
839
840 do {
841 /* Check if we can do DMA */
842 if (!len || (box_cmd_cnt >= MMC_MAX_DMA_CMDS)) {
843 err = -ENOTSUPP;
844 goto unmap;
845 }
846
847 box->cmd = CMD_MODE_BOX;
848
849 if (len >= MMC_MAX_DMA_BOX_LENGTH) {
850 len = MMC_MAX_DMA_BOX_LENGTH;
851 len -= len % data->blksz;
852 }
853 rows = (len % MCI_FIFOSIZE) ?
854 (len / MCI_FIFOSIZE) + 1 :
855 (len / MCI_FIFOSIZE);
856
857 if (data->flags & MMC_DATA_READ) {
858 box->src_row_addr = msmsdcc_fifo_addr(host);
859 box->dst_row_addr = sg_dma_address(sg) + offset;
860 box->src_dst_len = (MCI_FIFOSIZE << 16) |
861 (MCI_FIFOSIZE);
862 box->row_offset = MCI_FIFOSIZE;
863 box->num_rows = rows * ((1 << 16) + 1);
864 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
865 } else {
866 box->src_row_addr = sg_dma_address(sg) + offset;
867 box->dst_row_addr = msmsdcc_fifo_addr(host);
868 box->src_dst_len = (MCI_FIFOSIZE << 16) |
869 (MCI_FIFOSIZE);
870 box->row_offset = (MCI_FIFOSIZE << 16);
871 box->num_rows = rows * ((1 << 16) + 1);
872 box->cmd |= CMD_DST_CRCI(host->dma.crci);
873 }
874
875 offset += len;
876 len = sg_dma_len(sg) - offset;
877 box++;
878 box_cmd_cnt++;
879 } while (len);
880 sg++;
881 }
882 /* Mark last command */
883 box--;
884 box->cmd |= CMD_LC;
885
886 /* location of command block must be 64 bit aligned */
887 BUG_ON(host->dma.cmd_busaddr & 0x07);
888
889 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
890 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
891 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
892 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
893
894 /* Flush all data to memory before starting dma */
895 mb();
896
897unmap:
898 if (err) {
Asutosh Dasaccacd42012-03-08 14:33:17 +0530899 if (!data->host_cookie)
900 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
901 host->dma.num_ents, host->dma.dir);
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530902 pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
903 mmc_hostname(host->mmc), err);
904 }
905
906 return err;
San Mehat9d2bd732009-09-22 16:44:22 -0700907}
908
Asutosh Dasaccacd42012-03-08 14:33:17 +0530909static int msmsdcc_prep_xfer(struct msmsdcc_host *host,
910 struct mmc_data *data)
911{
912 int rc = 0;
913 unsigned int dir;
914
915 /* Prevent memory corruption */
916 BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
917
918 if (data->flags & MMC_DATA_READ)
919 dir = DMA_FROM_DEVICE;
920 else
921 dir = DMA_TO_DEVICE;
922
923 /* Make sg buffers DMA ready */
924 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
925 dir);
926
927 if (unlikely(rc != data->sg_len)) {
928 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
929 mmc_hostname(host->mmc), rc);
930 rc = -ENOMEM;
931 goto dma_map_err;
932 }
933
934 pr_debug("%s: %s: %s: sg_len=%d\n",
935 mmc_hostname(host->mmc), __func__,
936 dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
937 data->sg_len);
938
939 goto out;
940
941dma_map_err:
942 dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
943 data->flags);
944out:
945 return rc;
946}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700947#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
948/**
949 * Submits data transfer request to SPS driver
950 *
951 * This function make sg (scatter gather) data buffers
952 * DMA ready and then submits them to SPS driver for
953 * transfer.
954 *
955 * @host - Pointer to sdcc host structure
956 * @data - Pointer to mmc_data structure
957 *
958 * @return 0 if success else negative value
959 */
960static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
Asutosh Dasaccacd42012-03-08 14:33:17 +0530961 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -0800962{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700963 int rc = 0;
964 u32 flags;
965 int i;
966 u32 addr, len, data_cnt;
967 struct scatterlist *sg = data->sg;
968 struct sps_pipe *sps_pipe_handle;
969
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700970 host->sps.sg = data->sg;
971 host->sps.num_ents = data->sg_len;
972 host->sps.xfer_req_cnt = 0;
973 if (data->flags & MMC_DATA_READ) {
974 host->sps.dir = DMA_FROM_DEVICE;
975 sps_pipe_handle = host->sps.prod.pipe_handle;
976 } else {
977 host->sps.dir = DMA_TO_DEVICE;
978 sps_pipe_handle = host->sps.cons.pipe_handle;
979 }
980
Asutosh Dasaccacd42012-03-08 14:33:17 +0530981 if (!data->host_cookie) {
982 rc = msmsdcc_prep_xfer(host, data);
983 if (unlikely(rc < 0)) {
984 host->dma.sg = NULL;
985 host->dma.num_ents = 0;
986 goto out;
987 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700988 }
989
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700990 for (i = 0; i < data->sg_len; i++) {
991 /*
992 * Check if this is the last buffer to transfer?
993 * If yes then set the INT and EOT flags.
994 */
995 len = sg_dma_len(sg);
996 addr = sg_dma_address(sg);
997 flags = 0;
998 while (len > 0) {
999 if (len > SPS_MAX_DESC_SIZE) {
1000 data_cnt = SPS_MAX_DESC_SIZE;
1001 } else {
1002 data_cnt = len;
1003 if (i == data->sg_len - 1)
1004 flags = SPS_IOVEC_FLAG_INT |
1005 SPS_IOVEC_FLAG_EOT;
1006 }
1007 rc = sps_transfer_one(sps_pipe_handle, addr,
1008 data_cnt, host, flags);
1009 if (rc) {
1010 pr_err("%s: sps_transfer_one() error! rc=%d,"
1011 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
1012 mmc_hostname(host->mmc), rc,
1013 (u32)sps_pipe_handle, (u32)sg, i);
1014 goto dma_map_err;
1015 }
1016 addr += data_cnt;
1017 len -= data_cnt;
1018 host->sps.xfer_req_cnt++;
1019 }
1020 sg++;
1021 }
1022 goto out;
1023
1024dma_map_err:
1025 /* unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +05301026 if (!data->host_cookie)
1027 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
1028 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001029out:
1030 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07001031}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001032#else
1033static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
1034 struct mmc_data *data) { return 0; }
1035#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -07001036
1037static void
San Mehat56a8b5b2009-11-21 12:29:46 -08001038msmsdcc_start_command_deferred(struct msmsdcc_host *host,
1039 struct mmc_command *cmd, u32 *c)
1040{
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301041 DBG(host, "op %02x arg %08x flags %08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001042 cmd->opcode, cmd->arg, cmd->flags);
1043
San Mehat56a8b5b2009-11-21 12:29:46 -08001044 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
1045
1046 if (cmd->flags & MMC_RSP_PRESENT) {
1047 if (cmd->flags & MMC_RSP_136)
1048 *c |= MCI_CPSM_LONGRSP;
1049 *c |= MCI_CPSM_RESPONSE;
1050 }
1051
1052 if (/*interrupt*/0)
1053 *c |= MCI_CPSM_INTERRUPT;
1054
Asutosh Das05049132012-05-09 12:38:15 +05301055 /* DAT_CMD bit should be set for all ADTC */
1056 if (mmc_cmd_type(cmd) == MMC_CMD_ADTC)
San Mehat56a8b5b2009-11-21 12:29:46 -08001057 *c |= MCI_CSPM_DATCMD;
1058
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001059 /* Check if AUTO CMD19 is required or not? */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301060 if (host->tuning_needed &&
1061 !(host->mmc->ios.timing == MMC_TIMING_MMC_HS200)) {
1062
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301063 /*
1064 * For open ended block read operation (without CMD23),
1065 * AUTO_CMD19 bit should be set while sending the READ command.
1066 * For close ended block read operation (with CMD23),
1067 * AUTO_CMD19 bit should be set while sending CMD23.
1068 */
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301069 if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
1070 host->curr.mrq->cmd->opcode ==
1071 MMC_READ_MULTIPLE_BLOCK) ||
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301072 (!host->curr.mrq->sbc &&
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301073 (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
1074 cmd->opcode == MMC_READ_MULTIPLE_BLOCK))) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301075 msmsdcc_enable_cdr_cm_sdc4_dll(host);
1076 *c |= MCI_CSPM_AUTO_CMD19;
1077 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001078 }
1079
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05301080 /* Clear CDR_EN bit for write operations */
1081 if (host->tuning_needed && cmd->mrq->data &&
1082 (cmd->mrq->data->flags & MMC_DATA_WRITE))
1083 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) &
1084 ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
1085
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301086 if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301087 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001088 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301089 }
1090
San Mehat56a8b5b2009-11-21 12:29:46 -08001091 if (cmd == cmd->mrq->stop)
1092 *c |= MCI_CSPM_MCIABORT;
1093
San Mehat56a8b5b2009-11-21 12:29:46 -08001094 if (host->curr.cmd != NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001095 pr_err("%s: Overlapping command requests\n",
1096 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -08001097 }
1098 host->curr.cmd = cmd;
1099}
1100
1101static void
1102msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1103 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001104{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301105 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001106 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001107 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001108 unsigned int pio_irqmask = 0;
1109
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301110 BUG_ON(!data->sg);
1111 BUG_ON(!data->sg_len);
1112
San Mehat9d2bd732009-09-22 16:44:22 -07001113 host->curr.data = data;
1114 host->curr.xfer_size = data->blksz * data->blocks;
1115 host->curr.xfer_remain = host->curr.xfer_size;
1116 host->curr.data_xfered = 0;
1117 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301118 host->curr.got_auto_prog_done = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001119
San Mehat9d2bd732009-09-22 16:44:22 -07001120 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1121
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301122 if (host->curr.wait_for_auto_prog_done)
1123 datactrl |= MCI_AUTO_PROG_DONE;
1124
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05301125 if (msmsdcc_is_dma_possible(host, data)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001126 if (host->is_dma_mode && !msmsdcc_config_dma(host, data)) {
1127 datactrl |= MCI_DPSM_DMAENABLE;
1128 } else if (host->is_sps_mode) {
1129 if (!msmsdcc_is_dml_busy(host)) {
1130 if (!msmsdcc_sps_start_xfer(host, data)) {
1131 /* Now kick start DML transfer */
1132 mb();
1133 msmsdcc_dml_start_xfer(host, data);
1134 datactrl |= MCI_DPSM_DMAENABLE;
1135 host->sps.busy = 1;
1136 }
1137 } else {
1138 /*
1139 * Can't proceed with new transfer as
1140 * previous trasnfer is already in progress.
1141 * There is no point of going into PIO mode
1142 * as well. Is this a time to do kernel panic?
1143 */
1144 pr_err("%s: %s: DML HW is busy!!!"
1145 " Can't perform new SPS transfers"
1146 " now\n", mmc_hostname(host->mmc),
1147 __func__);
1148 }
1149 }
1150 }
1151
1152 /* Is data transfer in PIO mode required? */
1153 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001154 if (data->flags & MMC_DATA_READ) {
1155 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1156 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1157 pio_irqmask |= MCI_RXDATAAVLBLMASK;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001158 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001159 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1160 MCI_TXFIFOEMPTYMASK;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001161
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001162 msmsdcc_sg_start(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001163 }
1164
1165 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301166 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
San Mehat9d2bd732009-09-22 16:44:22 -07001167
San Mehat56a8b5b2009-11-21 12:29:46 -08001168 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001169 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001170 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -07001171
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001172 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
1173 /* Use ADM (Application Data Mover) HW for Data transfer */
1174 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001175 host->cmd_timeout = timeout;
1176 host->cmd_pio_irqmask = pio_irqmask;
1177 host->cmd_datactrl = datactrl;
1178 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001179
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001180 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1181 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001182 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001183
1184 if (cmd) {
1185 msmsdcc_start_command_deferred(host, cmd, &c);
1186 host->cmd_c = c;
1187 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001188 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1189 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1190 host->base + MMCIMASK0);
1191 mb();
1192 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001193 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001194 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001195 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001196
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001197 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001198
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001199 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1200 (~(MCI_IRQ_PIO))) | pio_irqmask,
1201 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001202 writel_relaxed(datactrl, base + MMCIDATACTRL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001203
1204 if (cmd) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05301205 /* Delay between data/command */
1206 msmsdcc_sync_reg_wr(host);
San Mehat56a8b5b2009-11-21 12:29:46 -08001207 /* Daisy-chain the command if requested */
1208 msmsdcc_start_command(host, cmd, c);
Subhash Jadavanidd432952012-03-28 11:25:56 +05301209 } else {
1210 /*
1211 * We don't need delay after writing to DATA_CTRL
1212 * register if we are not writing to CMD register
1213 * immediately after this. As we already have delay
1214 * before sending the command, we just need mb() here.
1215 */
1216 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001217 }
San Mehat9d2bd732009-09-22 16:44:22 -07001218 }
1219}
1220
1221static void
1222msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1223{
San Mehat56a8b5b2009-11-21 12:29:46 -08001224 msmsdcc_start_command_deferred(host, cmd, &c);
1225 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001226}
1227
1228static void
1229msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1230 unsigned int status)
1231{
1232 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001233 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
Subhash Jadavanib30c9822012-03-27 18:03:16 +05301234 || data->mrq->cmd->opcode == MMC_BUS_TEST_R
1235 || data->mrq->cmd->opcode ==
1236 MMC_SEND_TUNING_BLOCK_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001237 pr_err("%s: Data CRC error\n",
1238 mmc_hostname(host->mmc));
1239 pr_err("%s: opcode 0x%.8x\n", __func__,
1240 data->mrq->cmd->opcode);
1241 pr_err("%s: blksz %d, blocks %d\n", __func__,
1242 data->blksz, data->blocks);
1243 data->error = -EILSEQ;
1244 }
San Mehat9d2bd732009-09-22 16:44:22 -07001245 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001246 /* CRC is optional for the bus test commands, not all
1247 * cards respond back with CRC. However controller
1248 * waits for the CRC and times out. Hence ignore the
1249 * data timeouts during the Bustest.
1250 */
1251 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1252 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301253 pr_err("%s: CMD%d: Data timeout\n",
1254 mmc_hostname(host->mmc),
1255 data->mrq->cmd->opcode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001256 data->error = -ETIMEDOUT;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301257 msmsdcc_dump_sdcc_state(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001258 }
San Mehat9d2bd732009-09-22 16:44:22 -07001259 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001260 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001261 data->error = -EIO;
1262 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001263 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001264 data->error = -EIO;
1265 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001266 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001267 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001268 data->error = -EIO;
1269 }
San Mehat9d2bd732009-09-22 16:44:22 -07001270
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001271 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001272 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001273 host->dummy_52_needed = 0;
1274}
San Mehat9d2bd732009-09-22 16:44:22 -07001275
1276static int
1277msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1278{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001279 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001280 uint32_t *ptr = (uint32_t *) buffer;
1281 int count = 0;
1282
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301283 if (remain % 4)
1284 remain = ((remain >> 2) + 1) << 2;
1285
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001286 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1287
1288 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001289 ptr++;
1290 count += sizeof(uint32_t);
1291
1292 remain -= sizeof(uint32_t);
1293 if (remain == 0)
1294 break;
1295 }
1296 return count;
1297}
1298
1299static int
1300msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001301 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001302{
1303 void __iomem *base = host->base;
1304 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001305 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001306
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001307 while (readl_relaxed(base + MMCISTATUS) &
1308 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1309 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001310
San Mehat9d2bd732009-09-22 16:44:22 -07001311 count = min(remain, maxcnt);
1312
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301313 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1314 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001315 ptr += count;
1316 remain -= count;
1317
1318 if (remain == 0)
1319 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001320 }
1321 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001322
1323 return ptr - buffer;
1324}
1325
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001326/*
1327 * Copy up to a word (4 bytes) between a scatterlist
1328 * and a temporary bounce buffer when the word lies across
1329 * two pages. The temporary buffer can then be read to/
1330 * written from the FIFO once.
1331 */
1332static void _msmsdcc_sg_consume_word(struct msmsdcc_host *host)
1333{
1334 struct msmsdcc_pio_data *pio = &host->pio;
1335 unsigned int bytes_avail;
1336
1337 if (host->curr.data->flags & MMC_DATA_READ)
1338 memcpy(pio->sg_miter.addr, pio->bounce_buf,
1339 pio->bounce_buf_len);
1340 else
1341 memcpy(pio->bounce_buf, pio->sg_miter.addr,
1342 pio->bounce_buf_len);
1343
1344 while (pio->bounce_buf_len != 4) {
1345 if (!sg_miter_next(&pio->sg_miter))
1346 break;
1347 bytes_avail = min_t(unsigned int, pio->sg_miter.length,
1348 4 - pio->bounce_buf_len);
1349 if (host->curr.data->flags & MMC_DATA_READ)
1350 memcpy(pio->sg_miter.addr,
1351 &pio->bounce_buf[pio->bounce_buf_len],
1352 bytes_avail);
1353 else
1354 memcpy(&pio->bounce_buf[pio->bounce_buf_len],
1355 pio->sg_miter.addr, bytes_avail);
1356
1357 pio->sg_miter.consumed = bytes_avail;
1358 pio->bounce_buf_len += bytes_avail;
1359 }
1360}
1361
1362/*
1363 * Use sg_miter_next to return as many 4-byte aligned
1364 * chunks as possible, using a temporary 4 byte buffer
1365 * for alignment if necessary
1366 */
1367static int msmsdcc_sg_next(struct msmsdcc_host *host, char **buf, int *len)
1368{
1369 struct msmsdcc_pio_data *pio = &host->pio;
1370 unsigned int length, rlength;
1371 char *buffer;
1372
1373 if (!sg_miter_next(&pio->sg_miter))
1374 return 0;
1375
1376 buffer = pio->sg_miter.addr;
1377 length = pio->sg_miter.length;
1378
1379 if (length < host->curr.xfer_remain) {
1380 rlength = round_down(length, 4);
1381 if (rlength) {
1382 /*
1383 * We have a 4-byte aligned chunk.
1384 * The rounding will be reflected by
1385 * a call to msmsdcc_sg_consumed
1386 */
1387 length = rlength;
1388 goto sg_next_end;
1389 }
1390 /*
1391 * We have a length less than 4 bytes. Check to
1392 * see if more buffer is available, and combine
1393 * to make 4 bytes if possible.
1394 */
1395 pio->bounce_buf_len = length;
1396 memset(pio->bounce_buf, 0, 4);
1397
1398 /*
1399 * On a read, get 4 bytes from FIFO, and distribute
1400 * (4-bouce_buf_len) bytes into consecutive
1401 * sgl buffers when msmsdcc_sg_consumed is called
1402 */
1403 if (host->curr.data->flags & MMC_DATA_READ) {
1404 buffer = pio->bounce_buf;
1405 length = 4;
1406 goto sg_next_end;
1407 } else {
1408 _msmsdcc_sg_consume_word(host);
1409 buffer = pio->bounce_buf;
1410 length = pio->bounce_buf_len;
1411 }
1412 }
1413
1414sg_next_end:
1415 *buf = buffer;
1416 *len = length;
1417 return 1;
1418}
1419
1420/*
1421 * Update sg_miter.consumed based on how many bytes were
1422 * consumed. If the bounce buffer was used to read from FIFO,
1423 * redistribute into sgls.
1424 */
1425static void msmsdcc_sg_consumed(struct msmsdcc_host *host,
1426 unsigned int length)
1427{
1428 struct msmsdcc_pio_data *pio = &host->pio;
1429
1430 if (host->curr.data->flags & MMC_DATA_READ) {
1431 if (length > pio->sg_miter.consumed)
1432 /*
1433 * consumed 4 bytes, but sgl
1434 * describes < 4 bytes
1435 */
1436 _msmsdcc_sg_consume_word(host);
1437 else
1438 pio->sg_miter.consumed = length;
1439 } else
1440 if (length < pio->sg_miter.consumed)
1441 pio->sg_miter.consumed = length;
1442}
1443
1444static void msmsdcc_sg_start(struct msmsdcc_host *host)
1445{
1446 unsigned int sg_miter_flags = SG_MITER_ATOMIC;
1447
1448 host->pio.bounce_buf_len = 0;
1449
1450 if (host->curr.data->flags & MMC_DATA_READ)
1451 sg_miter_flags |= SG_MITER_TO_SG;
1452 else
1453 sg_miter_flags |= SG_MITER_FROM_SG;
1454
1455 sg_miter_start(&host->pio.sg_miter, host->curr.data->sg,
1456 host->curr.data->sg_len, sg_miter_flags);
1457}
1458
1459static void msmsdcc_sg_stop(struct msmsdcc_host *host)
1460{
1461 sg_miter_stop(&host->pio.sg_miter);
1462}
1463
San Mehat1cd22962010-02-03 12:59:29 -08001464static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001465msmsdcc_pio_irq(int irq, void *dev_id)
1466{
1467 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001468 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001469 uint32_t status;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001470 unsigned long flags;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001471 unsigned int remain;
1472 char *buffer;
San Mehat9d2bd732009-09-22 16:44:22 -07001473
Murali Palnati36448a42011-09-02 15:06:18 +05301474 spin_lock(&host->lock);
1475
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001476 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001477
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001478 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301479 (MCI_IRQ_PIO)) == 0) {
1480 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001481 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301482 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001483#if IRQ_DEBUG
1484 msmsdcc_print_status(host, "irq1-r", status);
1485#endif
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001486 local_irq_save(flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001487
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001488 do {
1489 unsigned int len;
San Mehat9d2bd732009-09-22 16:44:22 -07001490
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001491 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1492 | MCI_RXDATAAVLBL)))
1493 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001494
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001495 if (!msmsdcc_sg_next(host, &buffer, &remain))
1496 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001497
San Mehat9d2bd732009-09-22 16:44:22 -07001498 len = 0;
1499 if (status & MCI_RXACTIVE)
1500 len = msmsdcc_pio_read(host, buffer, remain);
1501 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001502 len = msmsdcc_pio_write(host, buffer, remain);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001503
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301504 /* len might have aligned to 32bits above */
1505 if (len > remain)
1506 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001507
San Mehat9d2bd732009-09-22 16:44:22 -07001508 host->curr.xfer_remain -= len;
1509 host->curr.data_xfered += len;
1510 remain -= len;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001511 msmsdcc_sg_consumed(host, len);
San Mehat9d2bd732009-09-22 16:44:22 -07001512
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001513 if (remain) /* Done with this page? */
1514 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001515
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001516 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001517 } while (1);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001518
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001519 msmsdcc_sg_stop(host);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001520 local_irq_restore(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001521
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001522 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1523 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1524 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1525 host->base + MMCIMASK0);
1526 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301527 /*
1528 * back to back write to MASK0 register don't need
1529 * synchronization delay.
1530 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001531 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1532 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1533 }
1534 mb();
1535 } else if (!host->curr.xfer_remain) {
1536 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1537 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1538 mb();
1539 }
San Mehat9d2bd732009-09-22 16:44:22 -07001540
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001541 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001542
1543 return IRQ_HANDLED;
1544}
1545
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001546static void
1547msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1548
1549static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1550 struct mmc_data *data)
1551{
1552 u32 loop_cnt = 0;
1553
1554 /*
1555 * For read commands with data less than fifo size, it is possible to
1556 * get DATAEND first and RXDATA_AVAIL might be set later because of
1557 * synchronization delay through the asynchronous RX FIFO. Thus, for
1558 * such cases, even after DATAEND interrupt is received software
1559 * should poll for RXDATA_AVAIL until the requested data is read out
1560 * of FIFO. This change is needed to get around this abnormal but
1561 * sometimes expected behavior of SDCC3 controller.
1562 *
1563 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1564 * after the data is loaded into RX FIFO. This would amount to less
1565 * than a microsecond and thus looping for 1000 times is good enough
1566 * for that delay.
1567 */
1568 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1569 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1570 spin_unlock(&host->lock);
1571 msmsdcc_pio_irq(1, host);
1572 spin_lock(&host->lock);
1573 }
1574 }
1575 if (loop_cnt == 1000) {
1576 pr_info("%s: Timed out while polling for Rx Data\n",
1577 mmc_hostname(host->mmc));
1578 data->error = -ETIMEDOUT;
1579 msmsdcc_reset_and_restore(host);
1580 }
1581}
1582
San Mehat9d2bd732009-09-22 16:44:22 -07001583static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1584{
1585 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001586
1587 host->curr.cmd = NULL;
subhashj8046ae12012-05-02 12:14:52 +05301588 if (mmc_resp_type(cmd))
1589 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1590 /*
1591 * Read rest of the response registers only if
1592 * long response is expected for this command
1593 */
1594 if (mmc_resp_type(cmd) & MMC_RSP_136) {
1595 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1596 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1597 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
1598 }
San Mehat9d2bd732009-09-22 16:44:22 -07001599
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001600 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301601 pr_debug("%s: CMD%d: Command timeout\n",
1602 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001603 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001604 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301605 !host->tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301606 pr_err("%s: CMD%d: Command CRC error\n",
1607 mmc_hostname(host->mmc), cmd->opcode);
1608 msmsdcc_dump_sdcc_state(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001609 cmd->error = -EILSEQ;
1610 }
1611
1612 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001613 if (host->curr.data && host->dma.sg &&
1614 host->is_dma_mode)
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001615 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001616 else if (host->curr.data && host->sps.sg &&
1617 host->is_sps_mode){
1618 /* Stop current SPS transfer */
1619 msmsdcc_sps_exit_curr_xfer(host);
1620 }
San Mehat9d2bd732009-09-22 16:44:22 -07001621 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301622 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001623 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301624 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301625 } else { /* host->data == NULL */
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301626 if (!cmd->error && host->prog_enable) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301627 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001628 host->prog_enable = 0;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301629 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001630 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301631 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301632 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301633 host->prog_enable = 0;
Subhash Jadavanied6b0e42012-03-07 16:36:27 +05301634 host->curr.wait_for_auto_prog_done = 0;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001635 if (host->dummy_52_needed)
1636 host->dummy_52_needed = 0;
1637 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001638 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301639 msmsdcc_request_end(host, cmd->mrq);
1640 }
1641 }
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301642 } else if ((cmd == host->curr.mrq->sbc) && cmd->data) {
1643 if (cmd->data->flags & MMC_DATA_READ)
1644 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1645 else
1646 msmsdcc_request_start(host, host->curr.mrq);
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301647 } else if (cmd->data) {
1648 if (!(cmd->data->flags & MMC_DATA_READ))
1649 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001650 }
1651}
1652
San Mehat9d2bd732009-09-22 16:44:22 -07001653static irqreturn_t
1654msmsdcc_irq(int irq, void *dev_id)
1655{
1656 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001657 u32 status;
1658 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001659 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001660
1661 spin_lock(&host->lock);
1662
1663 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001664 struct mmc_command *cmd;
1665 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001666
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001667 if (timer) {
1668 timer = 0;
1669 msmsdcc_delay(host);
1670 }
San Mehat865c8062009-11-13 13:42:06 -08001671
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001672 if (!host->clks_on) {
1673 pr_debug("%s: %s: SDIO async irq received\n",
1674 mmc_hostname(host->mmc), __func__);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301675
1676 /*
1677 * Only async interrupt can come when clocks are off,
1678 * disable further interrupts and enable them when
1679 * clocks are on.
1680 */
1681 if (!host->sdcc_irq_disabled) {
1682 disable_irq_nosync(irq);
1683 host->sdcc_irq_disabled = 1;
1684 }
1685
1686 /*
1687 * If mmc_card_wake_sdio_irq() is set, mmc core layer
1688 * will take care of signaling sdio irq during
1689 * mmc_sdio_resume().
1690 */
1691 if (host->sdcc_suspended)
1692 /*
1693 * This is a wakeup interrupt so hold wakelock
1694 * until SDCC resume is handled.
1695 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001696 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301697 else
1698 mmc_signal_sdio_irq(host->mmc);
1699 ret = 1;
1700 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001701 }
1702
1703 status = readl_relaxed(host->base + MMCISTATUS);
1704
1705 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1706 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001707 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001708
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001709#if IRQ_DEBUG
1710 msmsdcc_print_status(host, "irq0-r", status);
1711#endif
1712 status &= readl_relaxed(host->base + MMCIMASK0);
1713 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301714 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301715 if (host->clk_rate <=
1716 msmsdcc_get_min_sup_clk_rate(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +05301717 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001718#if IRQ_DEBUG
1719 msmsdcc_print_status(host, "irq0-p", status);
1720#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001721
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001722 if (status & MCI_SDIOINTROPE) {
1723 if (host->sdcc_suspending)
1724 wake_lock(&host->sdio_suspend_wlock);
1725 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001726 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001727 data = host->curr.data;
1728
1729 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001730 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1731 MCI_CMDTIMEOUT)) {
1732 if (status & MCI_CMDTIMEOUT)
1733 pr_debug("%s: dummy CMD52 timeout\n",
1734 mmc_hostname(host->mmc));
1735 if (status & MCI_CMDCRCFAIL)
1736 pr_debug("%s: dummy CMD52 CRC failed\n",
1737 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001738 host->dummy_52_sent = 0;
1739 host->dummy_52_needed = 0;
1740 if (data) {
1741 msmsdcc_stop_data(host);
1742 msmsdcc_request_end(host, data->mrq);
1743 }
1744 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001745 spin_unlock(&host->lock);
1746 return IRQ_HANDLED;
1747 }
1748 break;
1749 }
1750
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001751 /*
1752 * Check for proper command response
1753 */
1754 cmd = host->curr.cmd;
1755 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1756 MCI_CMDTIMEOUT | MCI_PROGDONE |
1757 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1758 msmsdcc_do_cmdirq(host, status);
1759 }
1760
Sathish Ambley081d7842011-11-29 11:19:41 -08001761 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001762 /* Check for data errors */
1763 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1764 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1765 msmsdcc_data_err(host, data, status);
1766 host->curr.data_xfered = 0;
1767 if (host->dma.sg && host->is_dma_mode)
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001768 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001769 else if (host->sps.sg && host->is_sps_mode) {
1770 /* Stop current SPS transfer */
1771 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301772 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001773 msmsdcc_reset_and_restore(host);
1774 if (host->curr.data)
1775 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301776 if (!data->stop || (host->curr.mrq->sbc
1777 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001778 timer |=
1779 msmsdcc_request_end(host,
1780 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301781 else if ((host->curr.mrq->sbc
1782 && data->error) ||
1783 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001784 msmsdcc_start_command(host,
1785 data->stop,
1786 0);
1787 timer = 1;
1788 }
1789 }
1790 }
1791
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301792 /* Check for prog done */
1793 if (host->curr.wait_for_auto_prog_done &&
1794 (status & MCI_PROGDONE))
1795 host->curr.got_auto_prog_done = 1;
1796
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001797 /* Check for data done */
1798 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1799 host->curr.got_dataend = 1;
1800
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301801 if (host->curr.got_dataend &&
1802 (!host->curr.wait_for_auto_prog_done ||
1803 (host->curr.wait_for_auto_prog_done &&
1804 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001805 /*
1806 * If DMA is still in progress, we complete
1807 * via the completion handler
1808 */
1809 if (!host->dma.busy && !host->sps.busy) {
1810 /*
1811 * There appears to be an issue in the
1812 * controller where if you request a
1813 * small block transfer (< fifo size),
1814 * you may get your DATAEND/DATABLKEND
1815 * irq without the PIO data irq.
1816 *
1817 * Check to see if theres still data
1818 * to be read, and simulate a PIO irq.
1819 */
1820 if (data->flags & MMC_DATA_READ)
1821 msmsdcc_wait_for_rxdata(host,
1822 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001823 if (!data->error) {
1824 host->curr.data_xfered =
1825 host->curr.xfer_size;
1826 host->curr.xfer_remain -=
1827 host->curr.xfer_size;
1828 }
1829
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001830 if (!host->dummy_52_needed) {
1831 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301832 if (!data->stop ||
1833 (host->curr.mrq->sbc
1834 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001835 msmsdcc_request_end(
1836 host,
1837 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301838 else if ((host->curr.mrq->sbc
1839 && data->error) ||
1840 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001841 msmsdcc_start_command(
1842 host,
1843 data->stop, 0);
1844 timer = 1;
1845 }
1846 } else {
1847 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001848 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001849 &dummy52cmd,
1850 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001851 }
1852 }
1853 }
1854 }
1855
San Mehat9d2bd732009-09-22 16:44:22 -07001856 ret = 1;
1857 } while (status);
1858
1859 spin_unlock(&host->lock);
1860
San Mehat9d2bd732009-09-22 16:44:22 -07001861 return IRQ_RETVAL(ret);
1862}
1863
1864static void
Asutosh Dasaccacd42012-03-08 14:33:17 +05301865msmsdcc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
1866 bool is_first_request)
1867{
1868 struct msmsdcc_host *host = mmc_priv(mmc);
1869 struct mmc_data *data = mrq->data;
1870 int rc = 0;
1871
1872 if (unlikely(!data)) {
1873 pr_err("%s: %s cannot prepare null data\n", mmc_hostname(mmc),
1874 __func__);
1875 return;
1876 }
1877 if (unlikely(data->host_cookie)) {
1878 /* Very wrong */
1879 data->host_cookie = 0;
1880 pr_err("%s: %s Request reposted for prepare\n",
1881 mmc_hostname(mmc), __func__);
1882 return;
1883 }
1884
1885 if (!msmsdcc_is_dma_possible(host, data))
1886 return;
1887
1888 rc = msmsdcc_prep_xfer(host, data);
1889 if (unlikely(rc < 0)) {
1890 data->host_cookie = 0;
1891 return;
1892 }
1893
1894 data->host_cookie = 1;
1895}
1896
1897static void
1898msmsdcc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, int err)
1899{
1900 struct msmsdcc_host *host = mmc_priv(mmc);
1901 unsigned int dir;
1902 struct mmc_data *data = mrq->data;
1903
1904 if (unlikely(!data)) {
1905 pr_err("%s: %s cannot cleanup null data\n", mmc_hostname(mmc),
1906 __func__);
1907 return;
1908 }
1909 if (data->flags & MMC_DATA_READ)
1910 dir = DMA_FROM_DEVICE;
1911 else
1912 dir = DMA_TO_DEVICE;
1913
1914 if (data->host_cookie)
1915 dma_unmap_sg(mmc_dev(host->mmc), data->sg,
1916 data->sg_len, dir);
1917
1918 data->host_cookie = 0;
1919}
1920
1921static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001922msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1923{
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301924 if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001925 /* Queue/read data, daisy-chain command when data starts */
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301926 if (mrq->sbc)
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301927 msmsdcc_start_data(host, mrq->data, mrq->sbc, 0);
1928 else
1929 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001930 } else {
1931 msmsdcc_start_command(host, mrq->cmd, 0);
1932 }
1933}
1934
1935static void
San Mehat9d2bd732009-09-22 16:44:22 -07001936msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1937{
1938 struct msmsdcc_host *host = mmc_priv(mmc);
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05301939 unsigned long flags, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001940
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001941 /*
1942 * Get the SDIO AL client out of LPM.
1943 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001944 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001945 if (host->plat->is_sdio_al_client)
1946 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001947
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301948 /* check if sps pipe reset is pending? */
1949 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1950 msmsdcc_sps_pipes_reset_and_restore(host);
1951 host->sps.pipe_reset_pending = false;
1952 }
1953
San Mehat9d2bd732009-09-22 16:44:22 -07001954 spin_lock_irqsave(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001955
1956 if (host->eject) {
1957 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1958 mrq->cmd->error = 0;
1959 mrq->data->bytes_xfered = mrq->data->blksz *
1960 mrq->data->blocks;
1961 } else
1962 mrq->cmd->error = -ENOMEDIUM;
1963
1964 spin_unlock_irqrestore(&host->lock, flags);
1965 mmc_request_done(mmc, mrq);
1966 return;
1967 }
1968
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301969 /*
subhashjf181c292012-05-02 13:07:40 +05301970 * Don't start the request if SDCC is not in proper state to handle it
1971 */
1972 if (!host->pwr || !host->clks_on || host->sdcc_irq_disabled) {
1973 WARN(1, "%s: %s: SDCC is in bad state. don't process"
1974 " new request (CMD%d)\n", mmc_hostname(host->mmc),
1975 __func__, mrq->cmd->opcode);
1976 msmsdcc_dump_sdcc_state(host);
1977 mrq->cmd->error = -EIO;
1978 if (mrq->data) {
1979 mrq->data->error = -EIO;
1980 mrq->data->bytes_xfered = 0;
1981 }
1982 spin_unlock_irqrestore(&host->lock, flags);
1983 mmc_request_done(mmc, mrq);
1984 return;
1985 }
1986
1987 WARN(host->curr.mrq, "%s: %s: New request (CMD%d) received while"
1988 " other request (CMD%d) is in progress\n",
1989 mmc_hostname(host->mmc), __func__,
1990 mrq->cmd->opcode, host->curr.mrq->cmd->opcode);
1991
1992 /*
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05301993 * Set timeout value to 10 secs (or more in case of buggy cards)
1994 */
1995 if ((mmc->card) && (mmc->card->quirks & MMC_QUIRK_INAND_DATA_TIMEOUT))
1996 timeout = 20000;
1997 else
1998 timeout = MSM_MMC_REQ_TIMEOUT;
1999 /*
2000 * Kick the software request timeout timer here with the timeout
2001 * value identified above
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302002 */
2003 mod_timer(&host->req_tout_timer,
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302004 (jiffies + msecs_to_jiffies(timeout)));
San Mehat9d2bd732009-09-22 16:44:22 -07002005
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302006 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302007 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302008 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
2009 mrq->cmd->opcode == 54) {
Pratibhasagar V1c11da62011-11-14 12:36:35 +05302010 if (!host->sdcc_version)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002011 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302012 else
2013 /*
2014 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
2015 * write operations using CMD53 and CMD54.
2016 * Setting this bit with CMD53 would
2017 * automatically triggers PROG_DONE interrupt
2018 * without the need of sending dummy CMD52.
2019 */
2020 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani758cf8c2011-11-13 11:59:55 +05302021 } else if (mrq->cmd->opcode == MMC_WRITE_BLOCK &&
2022 host->sdcc_version) {
2023 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002024 }
San Mehat9d2bd732009-09-22 16:44:22 -07002025 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302026
Pratibhasagar V00b94332011-10-18 14:57:27 +05302027 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302028 mrq->sbc->mrq = mrq;
2029 mrq->sbc->data = mrq->data;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302030 if (mrq->data->flags & MMC_DATA_WRITE) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302031 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302032 msmsdcc_start_command(host, mrq->sbc, 0);
2033 } else {
2034 msmsdcc_request_start(host, mrq);
2035 }
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302036 } else {
2037 msmsdcc_request_start(host, mrq);
2038 }
2039
San Mehat9d2bd732009-09-22 16:44:22 -07002040 spin_unlock_irqrestore(&host->lock, flags);
2041}
2042
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002043static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
2044 int min_uV, int max_uV)
2045{
2046 int rc = 0;
2047
2048 if (vreg->set_voltage_sup) {
2049 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
2050 if (rc) {
2051 pr_err("%s: regulator_set_voltage(%s) failed."
2052 " min_uV=%d, max_uV=%d, rc=%d\n",
2053 __func__, vreg->name, min_uV, max_uV, rc);
2054 }
2055 }
2056
2057 return rc;
2058}
2059
2060static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
2061 int uA_load)
2062{
2063 int rc = 0;
2064
Krishna Kondafea60182011-11-01 16:01:34 -07002065 /* regulators that do not support regulator_set_voltage also
2066 do not support regulator_set_optimum_mode */
2067 if (vreg->set_voltage_sup) {
2068 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
2069 if (rc < 0)
2070 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
2071 "uA_load=%d) failed. rc=%d\n", __func__,
2072 vreg->name, uA_load, rc);
2073 else
2074 /* regulator_set_optimum_mode() can return non zero
2075 * value even for success case.
2076 */
2077 rc = 0;
2078 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002079
2080 return rc;
2081}
2082
2083static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
2084 struct device *dev)
2085{
2086 int rc = 0;
2087
2088 /* check if regulator is already initialized? */
2089 if (vreg->reg)
2090 goto out;
2091
2092 /* Get the regulator handle */
2093 vreg->reg = regulator_get(dev, vreg->name);
2094 if (IS_ERR(vreg->reg)) {
2095 rc = PTR_ERR(vreg->reg);
2096 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
2097 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002098 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002099 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002100
2101 if (regulator_count_voltages(vreg->reg) > 0)
2102 vreg->set_voltage_sup = 1;
2103
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002104out:
2105 return rc;
2106}
2107
2108static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
2109{
2110 if (vreg->reg)
2111 regulator_put(vreg->reg);
2112}
2113
2114/* This init function should be called only once for each SDCC slot */
2115static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
2116{
2117 int rc = 0;
2118 struct msm_mmc_slot_reg_data *curr_slot;
2119 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
2120 struct device *dev = mmc_dev(host->mmc);
2121
2122 curr_slot = host->plat->vreg_data;
2123 if (!curr_slot)
2124 goto out;
2125
2126 curr_vdd_reg = curr_slot->vdd_data;
2127 curr_vccq_reg = curr_slot->vccq_data;
2128 curr_vddp_reg = curr_slot->vddp_data;
2129
2130 if (is_init) {
2131 /*
2132 * Get the regulator handle from voltage regulator framework
2133 * and then try to set the voltage level for the regulator
2134 */
2135 if (curr_vdd_reg) {
2136 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
2137 if (rc)
2138 goto out;
2139 }
2140 if (curr_vccq_reg) {
2141 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
2142 if (rc)
2143 goto vdd_reg_deinit;
2144 }
2145 if (curr_vddp_reg) {
2146 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
2147 if (rc)
2148 goto vccq_reg_deinit;
2149 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002150 rc = msmsdcc_vreg_reset(host);
2151 if (rc)
2152 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
2153 host->pdev_id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002154 goto out;
2155 } else {
2156 /* Deregister all regulators from regulator framework */
2157 goto vddp_reg_deinit;
2158 }
2159vddp_reg_deinit:
2160 if (curr_vddp_reg)
2161 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
2162vccq_reg_deinit:
2163 if (curr_vccq_reg)
2164 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
2165vdd_reg_deinit:
2166 if (curr_vdd_reg)
2167 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2168out:
2169 return rc;
2170}
2171
2172static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2173{
2174 int rc = 0;
2175
Subhash Jadavanicc922692011-08-01 23:05:01 +05302176 /* Put regulator in HPM (high power mode) */
2177 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2178 if (rc < 0)
2179 goto out;
2180
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002181 if (!vreg->is_enabled) {
2182 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302183 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2184 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002185 if (rc)
2186 goto out;
2187
2188 rc = regulator_enable(vreg->reg);
2189 if (rc) {
2190 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2191 __func__, vreg->name, rc);
2192 goto out;
2193 }
2194 vreg->is_enabled = true;
2195 }
2196
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002197out:
2198 return rc;
2199}
2200
2201static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
2202{
2203 int rc = 0;
2204
2205 /* Never disable regulator marked as always_on */
2206 if (vreg->is_enabled && !vreg->always_on) {
2207 rc = regulator_disable(vreg->reg);
2208 if (rc) {
2209 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2210 __func__, vreg->name, rc);
2211 goto out;
2212 }
2213 vreg->is_enabled = false;
2214
2215 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2216 if (rc < 0)
2217 goto out;
2218
2219 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302220 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002221 if (rc)
2222 goto out;
2223 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
2224 /* Put always_on regulator in LPM (low power mode) */
2225 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2226 if (rc < 0)
2227 goto out;
2228 }
2229out:
2230 return rc;
2231}
2232
2233static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
2234{
2235 int rc = 0, i;
2236 struct msm_mmc_slot_reg_data *curr_slot;
2237 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
2238 struct msm_mmc_reg_data *vreg_table[3];
2239
2240 curr_slot = host->plat->vreg_data;
2241 if (!curr_slot)
2242 goto out;
2243
2244 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
2245 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
2246 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
2247
2248 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2249 if (vreg_table[i]) {
2250 if (enable)
2251 rc = msmsdcc_vreg_enable(vreg_table[i]);
2252 else
2253 rc = msmsdcc_vreg_disable(vreg_table[i]);
2254 if (rc)
2255 goto out;
2256 }
2257 }
2258out:
2259 return rc;
2260}
2261
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002262/*
2263 * Reset vreg by ensuring it is off during probe. A call
2264 * to enable vreg is needed to balance disable vreg
2265 */
2266static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2267{
2268 int rc;
2269
2270 rc = msmsdcc_setup_vreg(host, 1);
2271 if (rc)
2272 return rc;
2273 rc = msmsdcc_setup_vreg(host, 0);
2274 return rc;
2275}
2276
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302277static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002278{
2279 int rc = 0;
2280
2281 if (host->plat->vreg_data) {
2282 struct msm_mmc_reg_data *vddp_reg =
2283 host->plat->vreg_data->vddp_data;
2284
2285 if (vddp_reg && vddp_reg->is_enabled)
2286 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
2287 }
2288
2289 return rc;
2290}
2291
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302292static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
2293{
2294 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2295 int rc = 0;
2296
2297 if (curr_slot && curr_slot->vddp_data) {
2298 rc = msmsdcc_set_vddp_level(host,
2299 curr_slot->vddp_data->low_vol_level);
2300
2301 if (rc)
2302 pr_err("%s: %s: failed to change vddp level to %d",
2303 mmc_hostname(host->mmc), __func__,
2304 curr_slot->vddp_data->low_vol_level);
2305 }
2306
2307 return rc;
2308}
2309
2310static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
2311{
2312 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2313 int rc = 0;
2314
2315 if (curr_slot && curr_slot->vddp_data) {
2316 rc = msmsdcc_set_vddp_level(host,
2317 curr_slot->vddp_data->high_vol_level);
2318
2319 if (rc)
2320 pr_err("%s: %s: failed to change vddp level to %d",
2321 mmc_hostname(host->mmc), __func__,
2322 curr_slot->vddp_data->high_vol_level);
2323 }
2324
2325 return rc;
2326}
2327
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302328static inline int msmsdcc_set_vccq_vol(struct msmsdcc_host *host, int level)
2329{
2330 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2331 int rc = 0;
2332
2333 if (curr_slot && curr_slot->vccq_data) {
2334 rc = msmsdcc_vreg_set_voltage(curr_slot->vccq_data,
2335 level, level);
2336 if (rc)
2337 pr_err("%s: %s: failed to change vccq level to %d",
2338 mmc_hostname(host->mmc), __func__, level);
2339 }
2340
2341 return rc;
2342}
2343
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002344static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2345{
2346 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2347 return 1;
2348 return 0;
2349}
2350
Asutosh Dasf5298c32012-04-03 14:51:47 +05302351/*
2352 * Any function calling msmsdcc_setup_clocks must
2353 * acquire clk_mutex. May sleep.
2354 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002355static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
2356{
2357 if (enable) {
2358 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302359 clk_prepare_enable(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002360 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302361 clk_prepare_enable(host->pclk);
2362 clk_prepare_enable(host->clk);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302363 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302364 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002365 } else {
Subhash Jadavanidd432952012-03-28 11:25:56 +05302366 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302367 msmsdcc_delay(host);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302368 clk_disable_unprepare(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002369 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302370 clk_disable_unprepare(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002371 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302372 clk_disable_unprepare(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002373 }
2374}
2375
2376static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2377 unsigned int req_clk)
2378{
2379 unsigned int sel_clk = -1;
2380
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302381 if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
2382 sel_clk = msmsdcc_get_min_sup_clk_rate(host);
2383 goto out;
2384 }
2385
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002386 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2387 unsigned char cnt;
2388
2389 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2390 if (host->plat->sup_clk_table[cnt] > req_clk)
2391 break;
2392 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2393 sel_clk = host->plat->sup_clk_table[cnt];
2394 break;
2395 } else
2396 sel_clk = host->plat->sup_clk_table[cnt];
2397 }
2398 } else {
2399 if ((req_clk < host->plat->msmsdcc_fmax) &&
2400 (req_clk > host->plat->msmsdcc_fmid))
2401 sel_clk = host->plat->msmsdcc_fmid;
2402 else
2403 sel_clk = req_clk;
2404 }
2405
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302406out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002407 return sel_clk;
2408}
2409
2410static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2411 struct msmsdcc_host *host)
2412{
2413 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2414 return host->plat->sup_clk_table[0];
2415 else
2416 return host->plat->msmsdcc_fmin;
2417}
2418
2419static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2420 struct msmsdcc_host *host)
2421{
2422 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2423 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2424 else
2425 return host->plat->msmsdcc_fmax;
2426}
2427
2428static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302429{
2430 struct msm_mmc_gpio_data *curr;
2431 int i, rc = 0;
2432
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002433 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302434 for (i = 0; i < curr->size; i++) {
2435 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002436 if (curr->gpio[i].is_always_on &&
2437 curr->gpio[i].is_enabled)
2438 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302439 rc = gpio_request(curr->gpio[i].no,
2440 curr->gpio[i].name);
2441 if (rc) {
2442 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2443 mmc_hostname(host->mmc),
2444 curr->gpio[i].no,
2445 curr->gpio[i].name, rc);
2446 goto free_gpios;
2447 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002448 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302449 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002450 if (curr->gpio[i].is_always_on)
2451 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302452 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002453 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302454 }
2455 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002456 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302457
2458free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002459 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302460 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002461 curr->gpio[i].is_enabled = false;
2462 }
2463out:
2464 return rc;
2465}
2466
2467static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2468{
2469 struct msm_mmc_pad_data *curr;
2470 int i;
2471
2472 curr = host->plat->pin_data->pad_data;
2473 for (i = 0; i < curr->drv->size; i++) {
2474 if (enable)
2475 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2476 curr->drv->on[i].val);
2477 else
2478 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2479 curr->drv->off[i].val);
2480 }
2481
2482 for (i = 0; i < curr->pull->size; i++) {
2483 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002484 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002485 curr->pull->on[i].val);
2486 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002487 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002488 curr->pull->off[i].val);
2489 }
2490
2491 return 0;
2492}
2493
2494static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2495{
2496 int rc = 0;
2497
2498 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2499 return 0;
2500
2501 if (host->plat->pin_data->is_gpio)
2502 rc = msmsdcc_setup_gpio(host, enable);
2503 else
2504 rc = msmsdcc_setup_pad(host, enable);
2505
2506 if (!rc)
2507 host->plat->pin_data->cfg_sts = enable;
2508
2509 return rc;
2510}
2511
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302512static int msmsdcc_cfg_mpm_sdiowakeup(struct msmsdcc_host *host,
2513 unsigned mode)
2514{
2515 int ret = 0;
2516 unsigned int pin = host->plat->mpm_sdiowakeup_int;
2517
2518 if (!pin)
2519 return 0;
2520
2521 switch (mode) {
2522 case SDC_DAT1_DISABLE:
2523 ret = msm_mpm_enable_pin(pin, 0);
2524 break;
2525 case SDC_DAT1_ENABLE:
2526 ret = msm_mpm_set_pin_type(pin, IRQ_TYPE_LEVEL_LOW);
2527 ret = msm_mpm_enable_pin(pin, 1);
2528 break;
2529 case SDC_DAT1_ENWAKE:
2530 ret = msm_mpm_set_pin_wake(pin, 1);
2531 break;
2532 case SDC_DAT1_DISWAKE:
2533 ret = msm_mpm_set_pin_wake(pin, 0);
2534 break;
2535 default:
2536 ret = -EINVAL;
2537 break;
2538 }
2539
2540 return ret;
2541}
2542
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302543static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2544{
2545 u32 pwr = 0;
2546 int ret = 0;
2547 struct mmc_host *mmc = host->mmc;
2548
2549 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2550 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2551 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2552 ret = msmsdcc_setup_vreg(host, !!ios->vdd);
2553
2554 if (ret) {
2555 pr_err("%s: Failed to setup voltage regulators\n",
2556 mmc_hostname(host->mmc));
2557 goto out;
2558 }
2559
2560 switch (ios->power_mode) {
2561 case MMC_POWER_OFF:
2562 pwr = MCI_PWR_OFF;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302563 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302564 /*
2565 * As VDD pad rail is always on, set low voltage for VDD
2566 * pad rail when slot is unused (when card is not present
2567 * or during system suspend).
2568 */
2569 msmsdcc_set_vddp_low_vol(host);
2570 msmsdcc_setup_pins(host, false);
2571 break;
2572 case MMC_POWER_UP:
2573 /* writing PWR_UP bit is redundant */
2574 pwr = MCI_PWR_UP;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302575 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302576
2577 msmsdcc_set_vddp_high_vol(host);
2578 msmsdcc_setup_pins(host, true);
2579 break;
2580 case MMC_POWER_ON:
2581 pwr = MCI_PWR_ON;
2582 break;
2583 }
2584
2585out:
2586 return pwr;
2587}
2588
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002589static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2590{
2591 unsigned int wakeup_irq;
2592
2593 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2594 host->plat->sdiowakeup_irq :
2595 host->core_irqres->start;
2596
2597 if (!host->irq_wake_enabled) {
2598 enable_irq_wake(wakeup_irq);
2599 host->irq_wake_enabled = true;
2600 }
2601}
2602
2603static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2604{
2605 unsigned int wakeup_irq;
2606
2607 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2608 host->plat->sdiowakeup_irq :
2609 host->core_irqres->start;
2610
2611 if (host->irq_wake_enabled) {
2612 disable_irq_wake(wakeup_irq);
2613 host->irq_wake_enabled = false;
2614 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302615}
2616
San Mehat9d2bd732009-09-22 16:44:22 -07002617static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302618msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
2619{
2620 struct mmc_host *mmc = host->mmc;
2621
2622 /*
2623 * SDIO_AL clients has different mechanism of handling LPM through
2624 * sdio_al driver itself. The sdio wakeup interrupt is configured as
2625 * part of that. Here, we are interested only in clients like WLAN.
2626 */
2627 if (!(mmc->card && mmc_card_sdio(mmc->card))
2628 || host->plat->is_sdio_al_client)
2629 goto out;
2630
2631 if (!host->sdcc_suspended) {
2632 /*
2633 * When MSM is not in power collapse and we
2634 * are disabling clocks, enable bit 22 in MASK0
2635 * to handle asynchronous SDIO interrupts.
2636 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302637 if (enable_wakeup_irq) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302638 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302639 mb();
2640 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302641 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302642 msmsdcc_sync_reg_wr(host);
2643 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302644 goto out;
2645 } else if (!mmc_card_wake_sdio_irq(mmc)) {
2646 /*
2647 * Wakeup MSM only if SDIO function drivers set
2648 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
2649 */
2650 goto out;
2651 }
2652
2653 if (enable_wakeup_irq) {
2654 if (!host->plat->sdiowakeup_irq) {
2655 /*
2656 * When there is no gpio line that can be configured
2657 * as wakeup interrupt handle it by configuring
2658 * asynchronous sdio interrupts and DAT1 line.
2659 */
2660 writel_relaxed(MCI_SDIOINTMASK,
2661 host->base + MMCIMASK0);
2662 mb();
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302663 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302664 /* configure sdcc core interrupt as wakeup interrupt */
2665 msmsdcc_enable_irq_wake(host);
2666 } else {
2667 /* Let gpio line handle wakeup interrupt */
2668 writel_relaxed(0, host->base + MMCIMASK0);
2669 mb();
2670 if (host->sdio_wakeupirq_disabled) {
2671 host->sdio_wakeupirq_disabled = 0;
2672 /* configure gpio line as wakeup interrupt */
2673 msmsdcc_enable_irq_wake(host);
2674 enable_irq(host->plat->sdiowakeup_irq);
2675 }
2676 }
2677 } else {
2678 if (!host->plat->sdiowakeup_irq) {
2679 /*
2680 * We may not have cleared bit 22 in the interrupt
2681 * handler as the clocks might be off at that time.
2682 */
2683 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302684 msmsdcc_sync_reg_wr(host);
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302685 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302686 msmsdcc_disable_irq_wake(host);
2687 } else if (!host->sdio_wakeupirq_disabled) {
2688 disable_irq_nosync(host->plat->sdiowakeup_irq);
2689 msmsdcc_disable_irq_wake(host);
2690 host->sdio_wakeupirq_disabled = 1;
2691 }
2692 }
2693out:
2694 return;
2695}
2696
2697static void
San Mehat9d2bd732009-09-22 16:44:22 -07002698msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2699{
2700 struct msmsdcc_host *host = mmc_priv(mmc);
2701 u32 clk = 0, pwr = 0;
2702 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002703 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002704 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002705
Sahitya Tummala7a892482011-01-18 11:22:49 +05302706
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302707 /*
2708 * Disable SDCC core interrupt until set_ios is completed.
2709 * This avoids any race conditions with interrupt raised
2710 * when turning on/off the clocks. One possible
2711 * scenario is SDIO operational interrupt while the clock
2712 * is turned off.
Asutosh Dasf5298c32012-04-03 14:51:47 +05302713 * host->lock is being released intermittently below.
2714 * Thus, prevent concurrent access to host.
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302715 */
2716
Asutosh Dasf5298c32012-04-03 14:51:47 +05302717 mutex_lock(&host->clk_mutex);
2718 DBG(host, "ios->clock = %u\n", ios->clock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302719 spin_lock_irqsave(&host->lock, flags);
2720 if (!host->sdcc_irq_disabled) {
2721 spin_unlock_irqrestore(&host->lock, flags);
2722 disable_irq(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002723 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302724 host->sdcc_irq_disabled = 1;
2725 }
2726 spin_unlock_irqrestore(&host->lock, flags);
2727
2728 pwr = msmsdcc_setup_pwr(host, ios);
2729
2730 spin_lock_irqsave(&host->lock, flags);
2731 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002732 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302733 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002734 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302735 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002736 host->clks_on = 1;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302737 writel_relaxed(host->mci_irqenable,
2738 host->base + MMCIMASK0);
2739 mb();
2740 msmsdcc_cfg_sdio_wakeup(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002741 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002742
2743 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2744 /*
2745 * For DDR50 mode, controller needs clock rate to be
2746 * double than what is required on the SD card CLK pin.
2747 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302748 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002749 /*
2750 * Make sure that we don't double the clock if
2751 * doubled clock rate is already set
2752 */
2753 if (!host->ddr_doubled_clk_rate ||
2754 (host->ddr_doubled_clk_rate &&
2755 (host->ddr_doubled_clk_rate != ios->clock))) {
2756 host->ddr_doubled_clk_rate =
2757 msmsdcc_get_sup_clk_rate(
2758 host, (ios->clock * 2));
2759 clock = host->ddr_doubled_clk_rate;
2760 }
2761 } else {
2762 host->ddr_doubled_clk_rate = 0;
2763 }
2764
2765 if (clock != host->clk_rate) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302766 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002767 rc = clk_set_rate(host->clk, clock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302768 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002769 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302770 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002771 mmc_hostname(mmc), clock);
2772 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302773 host->reg_write_delay =
2774 (1 + ((3 * USEC_PER_SEC) /
2775 (host->clk_rate ? host->clk_rate :
2776 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002777 }
2778 /*
2779 * give atleast 2 MCLK cycles delay for clocks
2780 * and SDCC core to stabilize
2781 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302782 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002783 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002784 clk |= MCI_CLK_ENABLE;
2785 }
2786
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002787 if (ios->bus_width == MMC_BUS_WIDTH_8)
2788 clk |= MCI_CLK_WIDEBUS_8;
2789 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2790 clk |= MCI_CLK_WIDEBUS_4;
2791 else
2792 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002793
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002794 if (msmsdcc_is_pwrsave(host))
2795 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002796
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002797 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002798
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002799 host->tuning_needed = 0;
2800 /*
2801 * Select the controller timing mode according
2802 * to current bus speed mode
2803 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302804 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2805 (ios->timing == MMC_TIMING_MMC_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002806 clk |= (4 << 14);
2807 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302808 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002809 clk |= (3 << 14);
2810 } else {
2811 clk |= (2 << 14); /* feedback clock */
2812 }
2813
2814 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2815 clk |= (2 << 23);
2816
Subhash Jadavani00083572012-02-15 16:18:01 +05302817 /* Clear IO_PAD_PWR_SWITCH while powering off the card */
2818 if (!ios->vdd)
2819 host->io_pad_pwr_switch = 0;
2820
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002821 if (host->io_pad_pwr_switch)
2822 clk |= IO_PAD_PWR_SWITCH;
2823
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302824 /* Don't write into registers if clocks are disabled */
2825 if (host->clks_on) {
2826 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
2827 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302828 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002829 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302830 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
2831 host->pwr = pwr;
2832 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302833 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002834 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002835 }
2836
2837 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302838 msmsdcc_cfg_sdio_wakeup(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302839 spin_unlock_irqrestore(&host->lock, flags);
2840 /*
2841 * May get a wake-up interrupt the instant we disable the
2842 * clocks. This would disable the wake-up interrupt.
2843 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002844 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302845 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002846 host->clks_on = 0;
2847 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302848
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302849 if (host->tuning_in_progress)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302850 WARN(!host->clks_on,
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302851 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302852
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302853 /* Let interrupts be disabled if the host is powered off */
2854 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
2855 enable_irq(host->core_irqres->start);
2856 host->sdcc_irq_disabled = 0;
2857 }
2858
San Mehat4adbbcc2009-11-08 13:00:37 -08002859 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302860 mutex_unlock(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07002861}
2862
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002863int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2864{
2865 struct msmsdcc_host *host = mmc_priv(mmc);
2866 u32 clk;
2867
2868 clk = readl_relaxed(host->base + MMCICLOCK);
2869 pr_debug("Changing to pwr_save=%d", pwrsave);
2870 if (pwrsave && msmsdcc_is_pwrsave(host))
2871 clk |= MCI_CLK_PWRSAVE;
2872 else
2873 clk &= ~MCI_CLK_PWRSAVE;
2874 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302875 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002876
2877 return 0;
2878}
2879
2880static int msmsdcc_get_ro(struct mmc_host *mmc)
2881{
2882 int status = -ENOSYS;
2883 struct msmsdcc_host *host = mmc_priv(mmc);
2884
2885 if (host->plat->wpswitch) {
2886 status = host->plat->wpswitch(mmc_dev(mmc));
2887 } else if (host->plat->wpswitch_gpio) {
2888 status = gpio_request(host->plat->wpswitch_gpio,
2889 "SD_WP_Switch");
2890 if (status) {
2891 pr_err("%s: %s: Failed to request GPIO %d\n",
2892 mmc_hostname(mmc), __func__,
2893 host->plat->wpswitch_gpio);
2894 } else {
2895 status = gpio_direction_input(
2896 host->plat->wpswitch_gpio);
2897 if (!status) {
2898 /*
2899 * Wait for atleast 300ms as debounce
2900 * time for GPIO input to stabilize.
2901 */
2902 msleep(300);
2903 status = gpio_get_value_cansleep(
2904 host->plat->wpswitch_gpio);
2905 status ^= !host->plat->wpswitch_polarity;
2906 }
2907 gpio_free(host->plat->wpswitch_gpio);
2908 }
2909 }
2910
2911 if (status < 0)
2912 status = -ENOSYS;
2913 pr_debug("%s: Card read-only status %d\n", __func__, status);
2914
2915 return status;
2916}
2917
San Mehat9d2bd732009-09-22 16:44:22 -07002918static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2919{
2920 struct msmsdcc_host *host = mmc_priv(mmc);
2921 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002922
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302923 /*
2924 * We may come here with clocks turned off in that case don't
2925 * attempt to write into MASK0 register. While turning on the
2926 * clocks mci_irqenable will be written to MASK0 register.
2927 */
2928
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002929 if (enable) {
2930 spin_lock_irqsave(&host->lock, flags);
2931 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302932 if (host->clks_on) {
2933 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002934 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302935 mb();
2936 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002937 spin_unlock_irqrestore(&host->lock, flags);
2938 } else {
2939 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302940 if (host->clks_on) {
2941 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002942 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302943 mb();
2944 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002945 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002946}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002947
2948#ifdef CONFIG_PM_RUNTIME
subhashj245831e2012-04-30 18:46:17 +05302949static void msmsdcc_print_rpm_info(struct msmsdcc_host *host)
2950{
2951 struct device *dev = mmc_dev(host->mmc);
2952
2953 pr_info("%s: RPM: runtime_status=%d, usage_count=%d,"
2954 " is_suspended=%d, disable_depth=%d, runtime_error=%d,"
2955 " request_pending=%d, request=%d\n",
2956 mmc_hostname(host->mmc), dev->power.runtime_status,
2957 atomic_read(&dev->power.usage_count),
2958 dev->power.is_suspended, dev->power.disable_depth,
2959 dev->power.runtime_error, dev->power.request_pending,
2960 dev->power.request);
2961}
2962
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002963static int msmsdcc_enable(struct mmc_host *mmc)
2964{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002965 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002966 struct device *dev = mmc->parent;
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302967 struct msmsdcc_host *host = mmc_priv(mmc);
2968
2969 msmsdcc_pm_qos_update_latency(host, 1);
2970
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002971 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302972 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002973
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002974 if (host->sdcc_suspended && host->pending_resume &&
2975 !pm_runtime_suspended(dev)) {
2976 host->pending_resume = false;
2977 pm_runtime_get_noresume(dev);
2978 rc = msmsdcc_runtime_resume(dev);
2979 goto out;
2980 }
2981
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302982 if (dev->power.runtime_status == RPM_SUSPENDING) {
2983 if (mmc->suspend_task == current) {
2984 pm_runtime_get_noresume(dev);
2985 goto out;
2986 }
2987 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002988
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302989 rc = pm_runtime_get_sync(dev);
2990
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002991out:
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302992 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002993 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2994 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05302995 msmsdcc_print_rpm_info(host);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302996 return rc;
2997 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302998
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302999 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003000}
3001
3002static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
3003{
3004 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303005 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003006
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303007 msmsdcc_pm_qos_update_latency(host, 0);
3008
3009 if (mmc->card && mmc_card_sdio(mmc->card))
3010 return 0;
3011
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303012 if (host->plat->disable_runtime_pm)
3013 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003014
3015 rc = pm_runtime_put_sync(mmc->parent);
3016
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003017 /*
3018 * Ignore -EAGAIN as that is not fatal, it means that
3019 * either runtime usage count is non-zero or the runtime
3020 * pm itself is disabled or not in proper state to process
3021 * idle notification.
3022 */
3023 if (rc < 0 && (rc != -EAGAIN)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003024 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3025 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303026 msmsdcc_print_rpm_info(host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003027 return rc;
3028 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303029
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003030 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003031}
3032#else
subhashj245831e2012-04-30 18:46:17 +05303033static void msmsdcc_print_rpm_info(struct msmsdcc_host *host) {}
3034
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303035static int msmsdcc_enable(struct mmc_host *mmc)
3036{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003037 struct device *dev = mmc->parent;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303038 struct msmsdcc_host *host = mmc_priv(mmc);
3039 unsigned long flags;
Sujit Reddy Thumma7f5051c2012-05-04 10:14:07 +05303040 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303041
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303042 msmsdcc_pm_qos_update_latency(host, 1);
3043
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003044 if (mmc->card && mmc_card_sdio(mmc->card))
3045 return 0;
3046
3047 if (host->sdcc_suspended && host->pending_resume) {
3048 host->pending_resume = false;
3049 rc = msmsdcc_runtime_resume(dev);
3050 goto out;
3051 }
3052
Asutosh Dasf5298c32012-04-03 14:51:47 +05303053 mutex_lock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303054 spin_lock_irqsave(&host->lock, flags);
3055 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05303056 spin_unlock_irqrestore(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303057 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303058 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303059 host->clks_on = 1;
3060 }
3061 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303062 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303063
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003064out:
3065 if (rc < 0) {
3066 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3067 __func__, rc);
3068 return rc;
3069 }
3070
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303071 return 0;
3072}
3073
3074static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
3075{
3076 struct msmsdcc_host *host = mmc_priv(mmc);
3077 unsigned long flags;
3078
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303079 msmsdcc_pm_qos_update_latency(host, 0);
3080
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303081 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303082 return 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303083
Asutosh Dasf5298c32012-04-03 14:51:47 +05303084 mutex_lock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303085 spin_lock_irqsave(&host->lock, flags);
3086 if (host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05303087 spin_unlock_irqrestore(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303088 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303089 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303090 host->clks_on = 0;
3091 }
3092 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303093 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303094
3095 return 0;
3096}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003097#endif
3098
3099static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
3100 struct mmc_ios *ios)
3101{
3102 struct msmsdcc_host *host = mmc_priv(mmc);
3103 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303104 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003105
Subhash Jadavani00083572012-02-15 16:18:01 +05303106 spin_lock_irqsave(&host->lock, flags);
3107 host->io_pad_pwr_switch = 0;
3108 spin_unlock_irqrestore(&host->lock, flags);
3109
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303110 /*
3111 * For eMMC cards, VccQ voltage range must be changed
3112 * only if it operates in HS200 SDR 1.2V mode or in
3113 * DDR 1.2V mode.
3114 */
3115 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_120) {
3116 rc = msmsdcc_set_vccq_vol(host, 1200000);
3117 goto out;
3118 }
3119
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003120 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
3121 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303122 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003123 goto out;
3124 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
3125 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303126 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003127 goto out;
3128 }
San Mehat9d2bd732009-09-22 16:44:22 -07003129
3130 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003131 /*
3132 * If we are here means voltage switch from high voltage to
3133 * low voltage is required
3134 */
3135
3136 /*
3137 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
3138 * register until they become all zeros.
3139 */
3140 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303141 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003142 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
3143 mmc_hostname(mmc), __func__);
3144 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07003145 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003146
3147 /* Stop SD CLK output. */
3148 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3149 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303150 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003151 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003152
3153 /*
3154 * Switch VDDPX from high voltage to low voltage
3155 * to change the VDD of the SD IO pads.
3156 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303157 rc = msmsdcc_set_vddp_low_vol(host);
3158 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003159 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003160
3161 spin_lock_irqsave(&host->lock, flags);
3162 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3163 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303164 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003165 host->io_pad_pwr_switch = 1;
3166 spin_unlock_irqrestore(&host->lock, flags);
3167
3168 /* Wait 5 ms for the voltage regulater in the card to become stable. */
3169 usleep_range(5000, 5500);
3170
3171 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303172 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003173 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3174 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303175 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003176 spin_unlock_irqrestore(&host->lock, flags);
3177
3178 /*
3179 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
3180 * don't become all ones within 1 ms then a Voltage Switch
3181 * sequence has failed and a power cycle to the card is required.
3182 * Otherwise Voltage Switch sequence is completed successfully.
3183 */
3184 usleep_range(1000, 1500);
3185
3186 spin_lock_irqsave(&host->lock, flags);
3187 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
3188 != (0xF << 1)) {
3189 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
3190 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303191 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003192 goto out_unlock;
3193 }
3194
3195out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303196 /* Enable PWRSAVE */
3197 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3198 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303199 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003200 spin_unlock_irqrestore(&host->lock, flags);
3201out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303202 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003203}
3204
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303205static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003206{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003207 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003208
3209 /* Program the MCLK value to MCLK_FREQ bit field */
3210 if (host->clk_rate <= 112000000)
3211 mclk_freq = 0;
3212 else if (host->clk_rate <= 125000000)
3213 mclk_freq = 1;
3214 else if (host->clk_rate <= 137000000)
3215 mclk_freq = 2;
3216 else if (host->clk_rate <= 150000000)
3217 mclk_freq = 3;
3218 else if (host->clk_rate <= 162000000)
3219 mclk_freq = 4;
3220 else if (host->clk_rate <= 175000000)
3221 mclk_freq = 5;
3222 else if (host->clk_rate <= 187000000)
3223 mclk_freq = 6;
3224 else if (host->clk_rate <= 200000000)
3225 mclk_freq = 7;
3226
3227 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3228 & ~(7 << 24)) | (mclk_freq << 24)),
3229 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003230}
3231
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303232/* Initialize the DLL (Programmable Delay Line ) */
3233static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003234{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003235 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303236 unsigned long flags;
3237 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003238
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303239 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003240 /*
3241 * Make sure that clock is always enabled when DLL
3242 * tuning is in progress. Keeping PWRSAVE ON may
3243 * turn off the clock. So let's disable the PWRSAVE
3244 * here and re-enable it once tuning is completed.
3245 */
3246 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3247 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303248 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303249
3250 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3251 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3252 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3253
3254 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3255 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3256 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3257
3258 msmsdcc_cm_sdc4_dll_set_freq(host);
3259
3260 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3261 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3262 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3263
3264 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3265 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3266 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3267
3268 /* Set DLL_EN bit to 1. */
3269 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3270 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3271
3272 /* Set CK_OUT_EN bit to 1. */
3273 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3274 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3275
3276 wait_cnt = 50;
3277 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3278 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3279 /* max. wait for 50us sec for LOCK bit to be set */
3280 if (--wait_cnt == 0) {
3281 pr_err("%s: %s: DLL failed to LOCK\n",
3282 mmc_hostname(host->mmc), __func__);
3283 rc = -ETIMEDOUT;
3284 goto out;
3285 }
3286 /* wait for 1us before polling again */
3287 udelay(1);
3288 }
3289
3290out:
3291 /* re-enable PWRSAVE */
3292 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3293 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303294 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303295 spin_unlock_irqrestore(&host->lock, flags);
3296
3297 return rc;
3298}
3299
3300static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3301 u8 poll)
3302{
3303 int rc = 0;
3304 u32 wait_cnt = 50;
3305 u8 ck_out_en = 0;
3306
3307 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3308 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3309 MCI_CK_OUT_EN);
3310
3311 while (ck_out_en != poll) {
3312 if (--wait_cnt == 0) {
3313 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3314 mmc_hostname(host->mmc), __func__, poll);
3315 rc = -ETIMEDOUT;
3316 goto out;
3317 }
3318 udelay(1);
3319
3320 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3321 MCI_CK_OUT_EN);
3322 }
3323out:
3324 return rc;
3325}
3326
3327/*
3328 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3329 * calibration sequence. This function should be called before
3330 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3331 * commands (CMD17/CMD18).
3332 *
3333 * This function gets called when host spinlock acquired.
3334 */
3335static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3336{
3337 int rc = 0;
3338 u32 config;
3339
3340 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3341 config |= MCI_CDR_EN;
3342 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3343 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3344
3345 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3346 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3347 if (rc)
3348 goto err_out;
3349
3350 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3351 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3352 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3353
3354 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3355 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3356 if (rc)
3357 goto err_out;
3358
3359 goto out;
3360
3361err_out:
3362 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3363out:
3364 return rc;
3365}
3366
3367static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3368 u8 phase)
3369{
3370 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303371 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3372 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3373 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303374 unsigned long flags;
3375 u32 config;
3376
3377 spin_lock_irqsave(&host->lock, flags);
3378
3379 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3380 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3381 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3382 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3383
3384 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3385 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3386 if (rc)
3387 goto err_out;
3388
3389 /*
3390 * Write the selected DLL clock output phase (0 ... 15)
3391 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
3392 */
3393 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3394 & ~(0xF << 20))
3395 | (grey_coded_phase_table[phase] << 20)),
3396 host->base + MCI_DLL_CONFIG);
3397
3398 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3399 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3400 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3401
3402 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3403 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3404 if (rc)
3405 goto err_out;
3406
3407 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3408 config |= MCI_CDR_EN;
3409 config &= ~MCI_CDR_EXT_EN;
3410 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3411 goto out;
3412
3413err_out:
3414 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3415 mmc_hostname(host->mmc), __func__, phase);
3416out:
3417 spin_unlock_irqrestore(&host->lock, flags);
3418 return rc;
3419}
3420
3421/*
3422 * Find out the greatest range of consecuitive selected
3423 * DLL clock output phases that can be used as sampling
3424 * setting for SD3.0 UHS-I card read operation (in SDR104
3425 * timing mode) or for eMMC4.5 card read operation (in HS200
3426 * timing mode).
3427 * Select the 3/4 of the range and configure the DLL with the
3428 * selected DLL clock output phase.
3429*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303430static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303431 u8 *phase_table, u8 total_phases)
3432{
Subhash Jadavani6159c622012-03-15 19:05:55 +05303433 #define MAX_PHASES 16
Subhash Jadavani34187042012-03-02 10:59:49 +05303434 int ret;
Subhash Jadavani6159c622012-03-15 19:05:55 +05303435 u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
3436 u8 phases_per_row[MAX_PHASES] = {0};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303437 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303438 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3439 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303440
Subhash Jadavani6159c622012-03-15 19:05:55 +05303441 if (!total_phases || (total_phases > MAX_PHASES)) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303442 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3443 mmc_hostname(host->mmc), __func__, total_phases);
3444 return -EINVAL;
3445 }
3446
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303447 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303448 ranges[row_index][col_index] = phase_table[cnt];
3449 phases_per_row[row_index] += 1;
3450 col_index++;
3451
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303452 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303453 continue;
3454 /* check if next phase in phase_table is consecutive or not */
3455 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3456 row_index++;
3457 col_index = 0;
3458 }
3459 }
3460
Subhash Jadavani6159c622012-03-15 19:05:55 +05303461 if (row_index >= MAX_PHASES)
3462 return -EINVAL;
3463
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303464 /* Check if phase-0 is present in first valid window? */
3465 if (!ranges[0][0]) {
3466 phase_0_found = true;
3467 phase_0_raw_index = 0;
3468 /* Check if cycle exist between 2 valid windows */
3469 for (cnt = 1; cnt <= row_index; cnt++) {
3470 if (phases_per_row[cnt]) {
Subhash Jadavani6159c622012-03-15 19:05:55 +05303471 for (i = 0; i < phases_per_row[cnt]; i++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303472 if (ranges[cnt][i] == 15) {
3473 phase_15_found = true;
3474 phase_15_raw_index = cnt;
3475 break;
3476 }
3477 }
3478 }
3479 }
3480 }
3481
3482 /* If 2 valid windows form cycle then merge them as single window */
3483 if (phase_0_found && phase_15_found) {
3484 /* number of phases in raw where phase 0 is present */
3485 u8 phases_0 = phases_per_row[phase_0_raw_index];
3486 /* number of phases in raw where phase 15 is present */
3487 u8 phases_15 = phases_per_row[phase_15_raw_index];
3488
Subhash Jadavani6159c622012-03-15 19:05:55 +05303489 if (phases_0 + phases_15 >= MAX_PHASES)
3490 /*
3491 * If there are more than 1 phase windows then total
3492 * number of phases in both the windows should not be
3493 * more than or equal to MAX_PHASES.
3494 */
3495 return -EINVAL;
3496
3497 /* Merge 2 cyclic windows */
3498 i = phases_15;
3499 for (cnt = 0; cnt < phases_0; cnt++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303500 ranges[phase_15_raw_index][i] =
3501 ranges[phase_0_raw_index][cnt];
Subhash Jadavani6159c622012-03-15 19:05:55 +05303502 if (++i >= MAX_PHASES)
3503 break;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303504 }
Subhash Jadavani6159c622012-03-15 19:05:55 +05303505
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303506 phases_per_row[phase_0_raw_index] = 0;
3507 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
3508 }
3509
3510 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303511 if (phases_per_row[cnt] > curr_max) {
3512 curr_max = phases_per_row[cnt];
3513 selected_row_index = cnt;
3514 }
3515 }
3516
Subhash Jadavani6159c622012-03-15 19:05:55 +05303517 i = ((curr_max * 3) / 4);
3518 if (i)
3519 i--;
3520
Subhash Jadavani34187042012-03-02 10:59:49 +05303521 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303522
Subhash Jadavani6159c622012-03-15 19:05:55 +05303523 if (ret >= MAX_PHASES) {
3524 ret = -EINVAL;
3525 pr_err("%s: %s: invalid phase selected=%d\n",
3526 mmc_hostname(host->mmc), __func__, ret);
3527 }
3528
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303529 return ret;
3530}
3531
Girish K Sa3f41692012-02-29 12:00:09 +05303532static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303533{
3534 int rc = 0;
3535 struct msmsdcc_host *host = mmc_priv(mmc);
3536 unsigned long flags;
3537 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303538 const u32 *tuning_block_pattern = tuning_block_64;
3539 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303540
3541 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
3542
3543 /* Tuning is only required for SDR104 modes */
3544 if (!host->tuning_needed) {
3545 rc = 0;
3546 goto exit;
3547 }
3548
3549 spin_lock_irqsave(&host->lock, flags);
3550 WARN(!host->pwr, "SDCC power is turned off\n");
3551 WARN(!host->clks_on, "SDCC clocks are turned off\n");
3552 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
3553
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303554 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303555 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
3556 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
3557 tuning_block_pattern = tuning_block_128;
3558 size = sizeof(tuning_block_128);
3559 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303560 spin_unlock_irqrestore(&host->lock, flags);
3561
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003562 /* first of all reset the tuning block */
3563 rc = msmsdcc_init_cm_sdc4_dll(host);
3564 if (rc)
3565 goto out;
3566
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303567 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003568 if (!data_buf) {
3569 rc = -ENOMEM;
3570 goto out;
3571 }
3572
3573 phase = 0;
3574 do {
3575 struct mmc_command cmd = {0};
3576 struct mmc_data data = {0};
3577 struct mmc_request mrq = {
3578 .cmd = &cmd,
3579 .data = &data
3580 };
3581 struct scatterlist sg;
3582
3583 /* set the phase in delay line hw block */
3584 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3585 if (rc)
3586 goto kfree;
3587
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303588 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003589 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
3590
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303591 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003592 data.blocks = 1;
3593 data.flags = MMC_DATA_READ;
3594 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
3595
3596 data.sg = &sg;
3597 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303598 sg_init_one(&sg, data_buf, size);
3599 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003600 mmc_wait_for_req(mmc, &mrq);
3601
3602 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303603 !memcmp(data_buf, tuning_block_pattern, size)) {
3604 /* tuning is successful at this tuning point */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003605 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303606 pr_debug("%s: %s: found good phase = %d\n",
3607 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003608 }
3609 } while (++phase < 16);
3610
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003611 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303612 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303613 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05303614 if (rc < 0)
3615 goto kfree;
3616 else
3617 phase = (u8)rc;
3618
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003619 /*
3620 * Finally set the selected phase in delay
3621 * line hw block.
3622 */
3623 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3624 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303625 goto kfree;
3626 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
3627 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003628 } else {
3629 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303630 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003631 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303632 msmsdcc_dump_sdcc_state(host);
3633 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003634 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003635
3636kfree:
3637 kfree(data_buf);
3638out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303639 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303640 host->tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303641 spin_unlock_irqrestore(&host->lock, flags);
3642exit:
3643 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003644 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07003645}
3646
3647static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003648 .enable = msmsdcc_enable,
3649 .disable = msmsdcc_disable,
Asutosh Dasaccacd42012-03-08 14:33:17 +05303650 .pre_req = msmsdcc_pre_req,
3651 .post_req = msmsdcc_post_req,
San Mehat9d2bd732009-09-22 16:44:22 -07003652 .request = msmsdcc_request,
3653 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003654 .get_ro = msmsdcc_get_ro,
San Mehat9d2bd732009-09-22 16:44:22 -07003655 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003656 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
3657 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07003658};
3659
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003660static unsigned int
3661msmsdcc_slot_status(struct msmsdcc_host *host)
3662{
3663 int status;
3664 unsigned int gpio_no = host->plat->status_gpio;
3665
3666 status = gpio_request(gpio_no, "SD_HW_Detect");
3667 if (status) {
3668 pr_err("%s: %s: Failed to request GPIO %d\n",
3669 mmc_hostname(host->mmc), __func__, gpio_no);
3670 } else {
3671 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003672 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08003673 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003674 if (host->plat->is_status_gpio_active_low)
3675 status = !status;
3676 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003677 gpio_free(gpio_no);
3678 }
3679 return status;
3680}
3681
San Mehat9d2bd732009-09-22 16:44:22 -07003682static void
3683msmsdcc_check_status(unsigned long data)
3684{
3685 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3686 unsigned int status;
3687
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003688 if (host->plat->status || host->plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08003689 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003690 status = host->plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08003691 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003692 status = msmsdcc_slot_status(host);
3693
Krishna Konda941604a2012-01-10 17:46:34 -08003694 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08003695
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003696 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08003697 if (host->plat->status)
3698 pr_info("%s: Slot status change detected "
3699 "(%d -> %d)\n",
3700 mmc_hostname(host->mmc),
3701 host->oldstat, status);
3702 else if (host->plat->is_status_gpio_active_low)
3703 pr_info("%s: Slot status change detected "
3704 "(%d -> %d) and the card detect GPIO"
3705 " is ACTIVE_LOW\n",
3706 mmc_hostname(host->mmc),
3707 host->oldstat, status);
3708 else
3709 pr_info("%s: Slot status change detected "
3710 "(%d -> %d) and the card detect GPIO"
3711 " is ACTIVE_HIGH\n",
3712 mmc_hostname(host->mmc),
3713 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07003714 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003715 }
3716 host->oldstat = status;
3717 } else {
3718 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07003719 }
San Mehat9d2bd732009-09-22 16:44:22 -07003720}
3721
3722static irqreturn_t
3723msmsdcc_platform_status_irq(int irq, void *dev_id)
3724{
3725 struct msmsdcc_host *host = dev_id;
3726
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003727 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07003728 msmsdcc_check_status((unsigned long) host);
3729 return IRQ_HANDLED;
3730}
3731
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003732static irqreturn_t
3733msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
3734{
3735 struct msmsdcc_host *host = dev_id;
3736
3737 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
3738 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303739 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003740 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303741 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003742 wake_lock(&host->sdio_wlock);
3743 msmsdcc_disable_irq_wake(host);
3744 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303745 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003746 }
3747 if (host->plat->is_sdio_al_client) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003748 wake_lock(&host->sdio_wlock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303749 mmc_signal_sdio_irq(host->mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003750 }
3751 spin_unlock(&host->lock);
3752
3753 return IRQ_HANDLED;
3754}
3755
San Mehat9d2bd732009-09-22 16:44:22 -07003756static void
3757msmsdcc_status_notify_cb(int card_present, void *dev_id)
3758{
3759 struct msmsdcc_host *host = dev_id;
3760
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003761 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07003762 card_present);
3763 msmsdcc_check_status((unsigned long) host);
3764}
3765
San Mehat9d2bd732009-09-22 16:44:22 -07003766static int
3767msmsdcc_init_dma(struct msmsdcc_host *host)
3768{
3769 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
3770 host->dma.host = host;
3771 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003772 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003773
3774 if (!host->dmares)
3775 return -ENODEV;
3776
3777 host->dma.nc = dma_alloc_coherent(NULL,
3778 sizeof(struct msmsdcc_nc_dmadata),
3779 &host->dma.nc_busaddr,
3780 GFP_KERNEL);
3781 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003782 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07003783 return -ENOMEM;
3784 }
3785 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
3786 host->dma.cmd_busaddr = host->dma.nc_busaddr;
3787 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
3788 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
3789 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07003790 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07003791
3792 return 0;
3793}
3794
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003795#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
3796/**
3797 * Allocate and Connect a SDCC peripheral's SPS endpoint
3798 *
3799 * This function allocates endpoint context and
3800 * connect it with memory endpoint by calling
3801 * appropriate SPS driver APIs.
3802 *
3803 * Also registers a SPS callback function with
3804 * SPS driver
3805 *
3806 * This function should only be called once typically
3807 * during driver probe.
3808 *
3809 * @host - Pointer to sdcc host structure
3810 * @ep - Pointer to sps endpoint data structure
3811 * @is_produce - 1 means Producer endpoint
3812 * 0 means Consumer endpoint
3813 *
3814 * @return - 0 if successful else negative value.
3815 *
3816 */
3817static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
3818 struct msmsdcc_sps_ep_conn_data *ep,
3819 bool is_producer)
3820{
3821 int rc = 0;
3822 struct sps_pipe *sps_pipe_handle;
3823 struct sps_connect *sps_config = &ep->config;
3824 struct sps_register_event *sps_event = &ep->event;
3825
3826 /* Allocate endpoint context */
3827 sps_pipe_handle = sps_alloc_endpoint();
3828 if (!sps_pipe_handle) {
3829 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
3830 mmc_hostname(host->mmc), is_producer);
3831 rc = -ENOMEM;
3832 goto out;
3833 }
3834
3835 /* Get default connection configuration for an endpoint */
3836 rc = sps_get_config(sps_pipe_handle, sps_config);
3837 if (rc) {
3838 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
3839 " rc=%d", mmc_hostname(host->mmc),
3840 (u32)sps_pipe_handle, rc);
3841 goto get_config_err;
3842 }
3843
3844 /* Modify the default connection configuration */
3845 if (is_producer) {
3846 /*
3847 * For SDCC producer transfer, source should be
3848 * SDCC peripheral where as destination should
3849 * be system memory.
3850 */
3851 sps_config->source = host->sps.bam_handle;
3852 sps_config->destination = SPS_DEV_HANDLE_MEM;
3853 /* Producer pipe will handle this connection */
3854 sps_config->mode = SPS_MODE_SRC;
3855 sps_config->options =
3856 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3857 } else {
3858 /*
3859 * For SDCC consumer transfer, source should be
3860 * system memory where as destination should
3861 * SDCC peripheral
3862 */
3863 sps_config->source = SPS_DEV_HANDLE_MEM;
3864 sps_config->destination = host->sps.bam_handle;
3865 sps_config->mode = SPS_MODE_DEST;
3866 sps_config->options =
3867 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3868 }
3869
3870 /* Producer pipe index */
3871 sps_config->src_pipe_index = host->sps.src_pipe_index;
3872 /* Consumer pipe index */
3873 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
3874 /*
3875 * This event thresold value is only significant for BAM-to-BAM
3876 * transfer. It's ignored for BAM-to-System mode transfer.
3877 */
3878 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05303879
3880 /* Allocate maximum descriptor fifo size */
3881 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
3882 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003883 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
3884 sps_config->desc.size,
3885 &sps_config->desc.phys_base,
3886 GFP_KERNEL);
3887
Pratibhasagar V00b94332011-10-18 14:57:27 +05303888 if (!sps_config->desc.base) {
3889 rc = -ENOMEM;
3890 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3891 , mmc_hostname(host->mmc));
3892 goto get_config_err;
3893 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003894 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3895
3896 /* Establish connection between peripheral and memory endpoint */
3897 rc = sps_connect(sps_pipe_handle, sps_config);
3898 if (rc) {
3899 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3900 " rc=%d", mmc_hostname(host->mmc),
3901 (u32)sps_pipe_handle, rc);
3902 goto sps_connect_err;
3903 }
3904
3905 sps_event->mode = SPS_TRIGGER_CALLBACK;
3906 sps_event->options = SPS_O_EOT;
3907 sps_event->callback = msmsdcc_sps_complete_cb;
3908 sps_event->xfer_done = NULL;
3909 sps_event->user = (void *)host;
3910
3911 /* Register callback event for EOT (End of transfer) event. */
3912 rc = sps_register_event(sps_pipe_handle, sps_event);
3913 if (rc) {
3914 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3915 " rc=%d", mmc_hostname(host->mmc),
3916 (u32)sps_pipe_handle, rc);
3917 goto reg_event_err;
3918 }
3919 /* Now save the sps pipe handle */
3920 ep->pipe_handle = sps_pipe_handle;
3921 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3922 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3923 __func__, is_producer ? "READ" : "WRITE",
3924 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3925 goto out;
3926
3927reg_event_err:
3928 sps_disconnect(sps_pipe_handle);
3929sps_connect_err:
3930 dma_free_coherent(mmc_dev(host->mmc),
3931 sps_config->desc.size,
3932 sps_config->desc.base,
3933 sps_config->desc.phys_base);
3934get_config_err:
3935 sps_free_endpoint(sps_pipe_handle);
3936out:
3937 return rc;
3938}
3939
3940/**
3941 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3942 *
3943 * This function disconnect endpoint and deallocates
3944 * endpoint context.
3945 *
3946 * This function should only be called once typically
3947 * during driver remove.
3948 *
3949 * @host - Pointer to sdcc host structure
3950 * @ep - Pointer to sps endpoint data structure
3951 *
3952 */
3953static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3954 struct msmsdcc_sps_ep_conn_data *ep)
3955{
3956 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3957 struct sps_connect *sps_config = &ep->config;
3958 struct sps_register_event *sps_event = &ep->event;
3959
3960 sps_event->xfer_done = NULL;
3961 sps_event->callback = NULL;
3962 sps_register_event(sps_pipe_handle, sps_event);
3963 sps_disconnect(sps_pipe_handle);
3964 dma_free_coherent(mmc_dev(host->mmc),
3965 sps_config->desc.size,
3966 sps_config->desc.base,
3967 sps_config->desc.phys_base);
3968 sps_free_endpoint(sps_pipe_handle);
3969}
3970
3971/**
3972 * Reset SDCC peripheral's SPS endpoint
3973 *
3974 * This function disconnects an endpoint.
3975 *
3976 * This function should be called for reseting
3977 * SPS endpoint when data transfer error is
3978 * encountered during data transfer. This
3979 * can be considered as soft reset to endpoint.
3980 *
3981 * This function should only be called if
3982 * msmsdcc_sps_init() is already called.
3983 *
3984 * @host - Pointer to sdcc host structure
3985 * @ep - Pointer to sps endpoint data structure
3986 *
3987 * @return - 0 if successful else negative value.
3988 */
3989static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3990 struct msmsdcc_sps_ep_conn_data *ep)
3991{
3992 int rc = 0;
3993 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3994
3995 rc = sps_disconnect(sps_pipe_handle);
3996 if (rc) {
3997 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3998 " rc=%d", mmc_hostname(host->mmc), __func__,
3999 (u32)sps_pipe_handle, rc);
4000 goto out;
4001 }
4002 out:
4003 return rc;
4004}
4005
4006/**
4007 * Restore SDCC peripheral's SPS endpoint
4008 *
4009 * This function connects an endpoint.
4010 *
4011 * This function should be called for restoring
4012 * SPS endpoint after data transfer error is
4013 * encountered during data transfer. This
4014 * can be considered as soft reset to endpoint.
4015 *
4016 * This function should only be called if
4017 * msmsdcc_sps_reset_ep() is called before.
4018 *
4019 * @host - Pointer to sdcc host structure
4020 * @ep - Pointer to sps endpoint data structure
4021 *
4022 * @return - 0 if successful else negative value.
4023 */
4024static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
4025 struct msmsdcc_sps_ep_conn_data *ep)
4026{
4027 int rc = 0;
4028 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4029 struct sps_connect *sps_config = &ep->config;
4030 struct sps_register_event *sps_event = &ep->event;
4031
4032 /* Establish connection between peripheral and memory endpoint */
4033 rc = sps_connect(sps_pipe_handle, sps_config);
4034 if (rc) {
4035 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
4036 " rc=%d", mmc_hostname(host->mmc), __func__,
4037 (u32)sps_pipe_handle, rc);
4038 goto out;
4039 }
4040
4041 /* Register callback event for EOT (End of transfer) event. */
4042 rc = sps_register_event(sps_pipe_handle, sps_event);
4043 if (rc) {
4044 pr_err("%s: %s: sps_register_event() failed!!!"
4045 " pipe_handle=0x%x, rc=%d",
4046 mmc_hostname(host->mmc), __func__,
4047 (u32)sps_pipe_handle, rc);
4048 goto reg_event_err;
4049 }
4050 goto out;
4051
4052reg_event_err:
4053 sps_disconnect(sps_pipe_handle);
4054out:
4055 return rc;
4056}
4057
4058/**
4059 * Initialize SPS HW connected with SDCC core
4060 *
4061 * This function register BAM HW resources with
4062 * SPS driver and then initialize 2 SPS endpoints
4063 *
4064 * This function should only be called once typically
4065 * during driver probe.
4066 *
4067 * @host - Pointer to sdcc host structure
4068 *
4069 * @return - 0 if successful else negative value.
4070 *
4071 */
4072static int msmsdcc_sps_init(struct msmsdcc_host *host)
4073{
4074 int rc = 0;
4075 struct sps_bam_props bam = {0};
4076
4077 host->bam_base = ioremap(host->bam_memres->start,
4078 resource_size(host->bam_memres));
4079 if (!host->bam_base) {
4080 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
4081 " size=0x%x", mmc_hostname(host->mmc),
4082 host->bam_memres->start,
4083 (host->bam_memres->end -
4084 host->bam_memres->start));
4085 rc = -ENOMEM;
4086 goto out;
4087 }
4088
4089 bam.phys_addr = host->bam_memres->start;
4090 bam.virt_addr = host->bam_base;
4091 /*
4092 * This event thresold value is only significant for BAM-to-BAM
4093 * transfer. It's ignored for BAM-to-System mode transfer.
4094 */
4095 bam.event_threshold = 0x10; /* Pipe event threshold */
4096 /*
4097 * This threshold controls when the BAM publish
4098 * the descriptor size on the sideband interface.
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304099 * SPS HW will be used for data transfer size even
4100 * less than SDCC FIFO size. So let's set BAM summing
4101 * thresold to SPS_MIN_XFER_SIZE bytes.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004102 */
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304103 bam.summing_threshold = SPS_MIN_XFER_SIZE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004104 /* SPS driver wll handle the SDCC BAM IRQ */
4105 bam.irq = (u32)host->bam_irqres->start;
4106 bam.manage = SPS_BAM_MGR_LOCAL;
4107
4108 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
4109 (u32)bam.phys_addr);
4110 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
4111 (u32)bam.virt_addr);
4112
4113 /* Register SDCC Peripheral BAM device to SPS driver */
4114 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
4115 if (rc) {
4116 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
4117 mmc_hostname(host->mmc), rc);
4118 goto reg_bam_err;
4119 }
4120 pr_info("%s: BAM device registered. bam_handle=0x%x",
4121 mmc_hostname(host->mmc), host->sps.bam_handle);
4122
4123 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
4124 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
4125
4126 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
4127 SPS_PROD_PERIPHERAL);
4128 if (rc)
4129 goto sps_reset_err;
4130 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
4131 SPS_CONS_PERIPHERAL);
4132 if (rc)
4133 goto cons_conn_err;
4134
4135 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
4136 mmc_hostname(host->mmc),
4137 (unsigned long long)host->bam_memres->start,
4138 (unsigned int)host->bam_irqres->start);
4139 goto out;
4140
4141cons_conn_err:
4142 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4143sps_reset_err:
4144 sps_deregister_bam_device(host->sps.bam_handle);
4145reg_bam_err:
4146 iounmap(host->bam_base);
4147out:
4148 return rc;
4149}
4150
4151/**
4152 * De-initialize SPS HW connected with SDCC core
4153 *
4154 * This function deinitialize SPS endpoints and then
4155 * deregisters BAM resources from SPS driver.
4156 *
4157 * This function should only be called once typically
4158 * during driver remove.
4159 *
4160 * @host - Pointer to sdcc host structure
4161 *
4162 */
4163static void msmsdcc_sps_exit(struct msmsdcc_host *host)
4164{
4165 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
4166 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4167 sps_deregister_bam_device(host->sps.bam_handle);
4168 iounmap(host->bam_base);
4169}
4170#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
4171
4172static ssize_t
4173show_polling(struct device *dev, struct device_attribute *attr, char *buf)
4174{
4175 struct mmc_host *mmc = dev_get_drvdata(dev);
4176 struct msmsdcc_host *host = mmc_priv(mmc);
4177 int poll;
4178 unsigned long flags;
4179
4180 spin_lock_irqsave(&host->lock, flags);
4181 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
4182 spin_unlock_irqrestore(&host->lock, flags);
4183
4184 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
4185}
4186
4187static ssize_t
4188set_polling(struct device *dev, struct device_attribute *attr,
4189 const char *buf, size_t count)
4190{
4191 struct mmc_host *mmc = dev_get_drvdata(dev);
4192 struct msmsdcc_host *host = mmc_priv(mmc);
4193 int value;
4194 unsigned long flags;
4195
4196 sscanf(buf, "%d", &value);
4197
4198 spin_lock_irqsave(&host->lock, flags);
4199 if (value) {
4200 mmc->caps |= MMC_CAP_NEEDS_POLL;
4201 mmc_detect_change(host->mmc, 0);
4202 } else {
4203 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4204 }
4205#ifdef CONFIG_HAS_EARLYSUSPEND
4206 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
4207#endif
4208 spin_unlock_irqrestore(&host->lock, flags);
4209 return count;
4210}
4211
4212static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
4213 show_polling, set_polling);
4214static struct attribute *dev_attrs[] = {
4215 &dev_attr_polling.attr,
4216 NULL,
4217};
4218static struct attribute_group dev_attr_grp = {
4219 .attrs = dev_attrs,
4220};
4221
4222#ifdef CONFIG_HAS_EARLYSUSPEND
4223static void msmsdcc_early_suspend(struct early_suspend *h)
4224{
4225 struct msmsdcc_host *host =
4226 container_of(h, struct msmsdcc_host, early_suspend);
4227 unsigned long flags;
4228
4229 spin_lock_irqsave(&host->lock, flags);
4230 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
4231 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4232 spin_unlock_irqrestore(&host->lock, flags);
4233};
4234static void msmsdcc_late_resume(struct early_suspend *h)
4235{
4236 struct msmsdcc_host *host =
4237 container_of(h, struct msmsdcc_host, early_suspend);
4238 unsigned long flags;
4239
4240 if (host->polling_enabled) {
4241 spin_lock_irqsave(&host->lock, flags);
4242 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
4243 mmc_detect_change(host->mmc, 0);
4244 spin_unlock_irqrestore(&host->lock, flags);
4245 }
4246};
4247#endif
4248
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304249static void msmsdcc_print_regs(const char *name, void __iomem *base,
4250 u32 phys_base, unsigned int no_of_regs)
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304251{
4252 unsigned int i;
4253
4254 if (!base)
4255 return;
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304256
4257 pr_info("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
4258 " =====\n", name, phys_base, (u32)base);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304259 for (i = 0; i < no_of_regs; i = i + 4) {
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304260 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
4261 (u32)readl_relaxed(base + i*4),
4262 (u32)readl_relaxed(base + ((i+1)*4)),
4263 (u32)readl_relaxed(base + ((i+2)*4)),
4264 (u32)readl_relaxed(base + ((i+3)*4)));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304265 }
4266}
4267
4268static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
4269{
4270 /* Dump current state of SDCC clocks, power and irq */
4271 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304272 (host->pwr ? "ON" : "OFF"));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304273 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304274 mmc_hostname(host->mmc), (host->clks_on ? "ON" : "OFF"),
4275 (u32)clk_get_rate(host->clk));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304276 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
4277 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
4278
4279 /* Now dump SDCC registers. Don't print FIFO registers */
4280 if (host->clks_on)
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304281 msmsdcc_print_regs("SDCC-CORE", host->base,
4282 host->core_memres->start, 28);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304283
4284 if (host->curr.data) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304285 if (!msmsdcc_is_dma_possible(host, host->curr.data))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304286 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
4287 else if (host->is_dma_mode)
4288 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
4289 mmc_hostname(host->mmc), host->dma.busy,
4290 host->dma.channel, host->dma.crci);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304291 else if (host->is_sps_mode) {
subhashj245831e2012-04-30 18:46:17 +05304292 if (host->sps.busy && host->clks_on)
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304293 msmsdcc_print_regs("SDCC-DML", host->dml_base,
4294 host->dml_memres->start,
4295 16);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304296 pr_info("%s: SPS mode: busy=%d\n",
4297 mmc_hostname(host->mmc), host->sps.busy);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304298 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304299
4300 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
4301 mmc_hostname(host->mmc), host->curr.xfer_size,
4302 host->curr.data_xfered, host->curr.xfer_remain);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304303 }
4304
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304305 pr_info("%s: got_dataend=%d, prog_enable=%d,"
4306 " wait_for_auto_prog_done=%d, got_auto_prog_done=%d\n",
4307 mmc_hostname(host->mmc), host->curr.got_dataend,
4308 host->prog_enable, host->curr.wait_for_auto_prog_done,
4309 host->curr.got_auto_prog_done);
subhashj245831e2012-04-30 18:46:17 +05304310 msmsdcc_print_rpm_info(host);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304311}
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304312
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004313static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
4314{
4315 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4316 struct mmc_request *mrq;
4317 unsigned long flags;
4318
4319 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004320 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004321 pr_info("%s: %s: dummy CMD52 timeout\n",
4322 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004323 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004324 }
4325
4326 mrq = host->curr.mrq;
4327
4328 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304329 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
4330 mrq->cmd->opcode);
4331 msmsdcc_dump_sdcc_state(host);
4332
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004333 if (!mrq->cmd->error)
4334 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304335 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004336 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004337 if (mrq->data && !mrq->data->error)
4338 mrq->data->error = -ETIMEDOUT;
4339 host->curr.data_xfered = 0;
4340 if (host->dma.sg && host->is_dma_mode) {
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07004341 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004342 } else if (host->sps.sg && host->is_sps_mode) {
4343 /* Stop current SPS transfer */
4344 msmsdcc_sps_exit_curr_xfer(host);
4345 } else {
4346 msmsdcc_reset_and_restore(host);
4347 msmsdcc_stop_data(host);
4348 if (mrq->data && mrq->data->stop)
4349 msmsdcc_start_command(host,
4350 mrq->data->stop, 0);
4351 else
4352 msmsdcc_request_end(host, mrq);
4353 }
4354 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304355 host->prog_enable = 0;
Subhash Jadavanied6b0e42012-03-07 16:36:27 +05304356 host->curr.wait_for_auto_prog_done = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004357 msmsdcc_reset_and_restore(host);
4358 msmsdcc_request_end(host, mrq);
4359 }
4360 }
4361 spin_unlock_irqrestore(&host->lock, flags);
4362}
4363
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304364static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
4365{
4366 int i, ret;
4367 struct mmc_platform_data *pdata;
4368 struct device_node *np = dev->of_node;
4369 u32 bus_width = 0;
4370 u32 *clk_table;
4371 int clk_table_len;
4372 u32 *sup_voltages;
4373 int sup_volt_len;
4374
4375 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
4376 if (!pdata) {
4377 dev_err(dev, "could not allocate memory for platform data\n");
4378 goto err;
4379 }
4380
4381 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
4382 if (bus_width == 8) {
4383 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
4384 } else if (bus_width == 4) {
4385 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
4386 } else {
4387 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
4388 pdata->mmc_bus_width = 0;
4389 }
4390
4391 if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
4392 size_t sz;
4393 sz = sup_volt_len / sizeof(*sup_voltages);
4394 if (sz > 0) {
4395 sup_voltages = devm_kzalloc(dev,
4396 sz * sizeof(*sup_voltages), GFP_KERNEL);
4397 if (!sup_voltages) {
4398 dev_err(dev, "No memory for supported voltage\n");
4399 goto err;
4400 }
4401
4402 ret = of_property_read_u32_array(np,
4403 "qcom,sdcc-sup-voltages", sup_voltages, sz);
4404 if (ret < 0) {
4405 dev_err(dev, "error while reading voltage"
4406 "ranges %d\n", ret);
4407 goto err;
4408 }
4409 } else {
4410 dev_err(dev, "No supported voltages\n");
4411 goto err;
4412 }
4413 for (i = 0; i < sz; i += 2) {
4414 u32 mask;
4415
4416 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
4417 sup_voltages[i + 1]);
4418 if (!mask)
4419 dev_err(dev, "Invalide voltage range %d\n", i);
4420 pdata->ocr_mask |= mask;
4421 }
4422 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
4423 } else {
4424 dev_err(dev, "Supported voltage range not specified\n");
4425 }
4426
4427 if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
4428 size_t sz;
4429 sz = clk_table_len / sizeof(*clk_table);
4430
4431 if (sz > 0) {
4432 clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
4433 GFP_KERNEL);
4434 if (!clk_table) {
4435 dev_err(dev, "No memory for clock table\n");
4436 goto err;
4437 }
4438
4439 ret = of_property_read_u32_array(np,
4440 "qcom,sdcc-clk-rates", clk_table, sz);
4441 if (ret < 0) {
4442 dev_err(dev, "error while reading clk"
4443 "table %d\n", ret);
4444 goto err;
4445 }
4446 } else {
4447 dev_err(dev, "clk_table not specified\n");
4448 goto err;
4449 }
4450 pdata->sup_clk_table = clk_table;
4451 pdata->sup_clk_cnt = sz;
4452 } else {
4453 dev_err(dev, "Supported clock rates not specified\n");
4454 }
4455
4456 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
4457 pdata->nonremovable = true;
4458 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
4459 pdata->disable_cmd23 = true;
4460
4461 return pdata;
4462err:
4463 return NULL;
4464}
4465
San Mehat9d2bd732009-09-22 16:44:22 -07004466static int
4467msmsdcc_probe(struct platform_device *pdev)
4468{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304469 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07004470 struct msmsdcc_host *host;
4471 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004472 unsigned long flags;
4473 struct resource *core_irqres = NULL;
4474 struct resource *bam_irqres = NULL;
4475 struct resource *core_memres = NULL;
4476 struct resource *dml_memres = NULL;
4477 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07004478 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07004479 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05304480 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004481 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07004482
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304483 if (pdev->dev.of_node) {
4484 plat = msmsdcc_populate_pdata(&pdev->dev);
4485 of_property_read_u32((&pdev->dev)->of_node,
4486 "cell-index", &pdev->id);
4487 } else {
4488 plat = pdev->dev.platform_data;
4489 }
4490
San Mehat9d2bd732009-09-22 16:44:22 -07004491 /* must have platform data */
4492 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004493 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004494 ret = -EINVAL;
4495 goto out;
4496 }
4497
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004498 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07004499 return -EINVAL;
4500
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304501 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
4502 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
4503 return -EINVAL;
4504 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004505
San Mehat9d2bd732009-09-22 16:44:22 -07004506 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004507 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004508 return -ENXIO;
4509 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304510 if (pdev->dev.of_node) {
4511 /*
4512 * Device tree iomem resources are only accessible by index.
4513 * index = 0 -> SDCC register interface
4514 * index = 1 -> DML register interface
4515 * index = 2 -> BAM register interface
4516 * IRQ resources:
4517 * index = 0 -> SDCC IRQ
4518 * index = 1 -> BAM IRQ
4519 */
4520 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
4521 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
4522 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
4523 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
4524 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
4525 } else {
4526 for (i = 0; i < pdev->num_resources; i++) {
4527 if (pdev->resource[i].flags & IORESOURCE_MEM) {
4528 if (!strncmp(pdev->resource[i].name,
4529 "sdcc_dml_addr",
4530 sizeof("sdcc_dml_addr")))
4531 dml_memres = &pdev->resource[i];
4532 else if (!strncmp(pdev->resource[i].name,
4533 "sdcc_bam_addr",
4534 sizeof("sdcc_bam_addr")))
4535 bam_memres = &pdev->resource[i];
4536 else
4537 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07004538
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304539 }
4540 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
4541 if (!strncmp(pdev->resource[i].name,
4542 "sdcc_bam_irq",
4543 sizeof("sdcc_bam_irq")))
4544 bam_irqres = &pdev->resource[i];
4545 else
4546 core_irqres = &pdev->resource[i];
4547 }
4548 if (pdev->resource[i].flags & IORESOURCE_DMA) {
4549 if (!strncmp(pdev->resource[i].name,
4550 "sdcc_dma_chnl",
4551 sizeof("sdcc_dma_chnl")))
4552 dmares = &pdev->resource[i];
4553 else if (!strncmp(pdev->resource[i].name,
4554 "sdcc_dma_crci",
4555 sizeof("sdcc_dma_crci")))
4556 dma_crci_res = &pdev->resource[i];
4557 }
Krishna Konda25786ec2011-07-25 16:21:36 -07004558 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004559 }
4560
4561 if (!core_irqres || !core_memres) {
4562 pr_err("%s: Invalid sdcc core resource\n", __func__);
4563 return -ENXIO;
4564 }
4565
4566 /*
4567 * Both BAM and DML memory resource should be preset.
4568 * BAM IRQ resource should also be present.
4569 */
4570 if ((bam_memres && !dml_memres) ||
4571 (!bam_memres && dml_memres) ||
4572 ((bam_memres && dml_memres) && !bam_irqres)) {
4573 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004574 return -ENXIO;
4575 }
4576
4577 /*
4578 * Setup our host structure
4579 */
San Mehat9d2bd732009-09-22 16:44:22 -07004580 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
4581 if (!mmc) {
4582 ret = -ENOMEM;
4583 goto out;
4584 }
4585
4586 host = mmc_priv(mmc);
4587 host->pdev_id = pdev->id;
4588 host->plat = plat;
4589 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08004590 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05304591
4592 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004593 host->is_sps_mode = 1;
4594 else if (dmares)
4595 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07004596
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004597 host->base = ioremap(core_memres->start,
4598 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07004599 if (!host->base) {
4600 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004601 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004602 }
4603
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004604 host->core_irqres = core_irqres;
4605 host->bam_irqres = bam_irqres;
4606 host->core_memres = core_memres;
4607 host->dml_memres = dml_memres;
4608 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07004609 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07004610 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07004611 spin_lock_init(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304612 mutex_init(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07004613
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004614#ifdef CONFIG_MMC_EMBEDDED_SDIO
4615 if (plat->embedded_sdio)
4616 mmc_set_embedded_sdio_data(mmc,
4617 &plat->embedded_sdio->cis,
4618 &plat->embedded_sdio->cccr,
4619 plat->embedded_sdio->funcs,
4620 plat->embedded_sdio->num_funcs);
4621#endif
4622
Sahitya Tummala62612cf2010-12-08 15:03:03 +05304623 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
4624 (unsigned long)host);
4625
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004626 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
4627 (unsigned long)host);
4628 if (host->is_dma_mode) {
4629 /* Setup DMA */
4630 ret = msmsdcc_init_dma(host);
4631 if (ret)
4632 goto ioremap_free;
4633 } else {
4634 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004635 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004636 }
4637
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004638 /*
4639 * Setup SDCC clock if derived from Dayatona
4640 * fabric core clock.
4641 */
4642 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07004643 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004644 if (!IS_ERR(host->dfab_pclk)) {
4645 /* Set the clock rate to 64MHz for max. performance */
4646 ret = clk_set_rate(host->dfab_pclk, 64000000);
4647 if (ret)
4648 goto dfab_pclk_put;
Asutosh Dasf5298c32012-04-03 14:51:47 +05304649 ret = clk_prepare_enable(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004650 if (ret)
4651 goto dfab_pclk_put;
4652 } else
4653 goto dma_free;
4654 }
4655
4656 /*
4657 * Setup main peripheral bus clock
4658 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004659 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004660 if (!IS_ERR(host->pclk)) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05304661 ret = clk_prepare_enable(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004662 if (ret)
4663 goto pclk_put;
4664
4665 host->pclk_rate = clk_get_rate(host->pclk);
4666 }
4667
4668 /*
4669 * Setup SDC MMC clock
4670 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004671 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07004672 if (IS_ERR(host->clk)) {
4673 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004674 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07004675 }
4676
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004677 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
4678 if (ret) {
4679 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
4680 goto clk_put;
4681 }
4682
Asutosh Dasf5298c32012-04-03 14:51:47 +05304683 ret = clk_prepare_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004684 if (ret)
4685 goto clk_put;
4686
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004687 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304688 if (!host->clk_rate)
4689 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304690
4691 /*
4692 * Lookup the Controller Version, to identify the supported features
4693 * Version number read as 0 would indicate SDCC3 or earlier versions
4694 */
4695 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
4696 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
4697 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304698 /*
4699 * Set the register write delay according to min. clock frequency
4700 * supported and update later when the host->clk_rate changes.
4701 */
4702 host->reg_write_delay =
4703 (1 + ((3 * USEC_PER_SEC) /
4704 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004705
4706 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05304707 /* Apply Hard reset to SDCC to put it in power on default state */
4708 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004709
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004710#define MSM_MMC_DEFAULT_CPUDMA_LATENCY 200 /* usecs */
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304711 /* pm qos request to prevent apps idle power collapse */
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004712 if (host->plat->cpu_dma_latency)
4713 host->cpu_dma_latency = host->plat->cpu_dma_latency;
4714 else
4715 host->cpu_dma_latency = MSM_MMC_DEFAULT_CPUDMA_LATENCY;
4716 pm_qos_add_request(&host->pm_qos_req_dma,
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304717 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
4718
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004719 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07004720 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004721 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07004722 goto clk_disable;
4723 }
4724
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004725
4726 /* Clocks has to be running before accessing SPS/DML HW blocks */
4727 if (host->is_sps_mode) {
4728 /* Initialize SPS */
4729 ret = msmsdcc_sps_init(host);
4730 if (ret)
4731 goto vreg_deinit;
4732 /* Initialize DML */
4733 ret = msmsdcc_dml_init(host);
4734 if (ret)
4735 goto sps_exit;
4736 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05304737 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07004738
San Mehat9d2bd732009-09-22 16:44:22 -07004739 /*
4740 * Setup MMC host structure
4741 */
4742 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004743 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
4744 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004745 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004746 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
4747 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07004748
San Mehat9d2bd732009-09-22 16:44:22 -07004749 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05304750 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304751
4752 /*
4753 * If we send the CMD23 before multi block write/read command
4754 * then we need not to send CMD12 at the end of the transfer.
4755 * If we don't send the CMD12 then only way to detect the PROG_DONE
4756 * status is to use the AUTO_PROG_DONE status provided by SDCC4
4757 * controller. So let's enable the CMD23 for SDCC4 only.
4758 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304759 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304760 mmc->caps |= MMC_CAP_CMD23;
4761
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004762 mmc->caps |= plat->uhs_caps;
4763 /*
4764 * XPC controls the maximum current in the default speed mode of SDXC
4765 * card. XPC=0 means 100mA (max.) but speed class is not supported.
4766 * XPC=1 means 150mA (max.) and speed class is supported.
4767 */
4768 if (plat->xpc_cap)
4769 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
4770 MMC_CAP_SET_XPC_180);
4771
Subhash Jadavani6bb34a82012-04-18 13:18:40 +05304772 mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304773 if (pdev->dev.of_node) {
4774 if (of_get_property((&pdev->dev)->of_node,
4775 "qcom,sdcc-hs200", NULL))
4776 mmc->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
4777 }
4778
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004779 if (plat->nonremovable)
4780 mmc->caps |= MMC_CAP_NONREMOVABLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004781 mmc->caps |= MMC_CAP_SDIO_IRQ;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004782
4783 if (plat->is_sdio_al_client)
4784 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07004785
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304786 mmc->max_segs = msmsdcc_get_nr_sg(host);
4787 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
4788 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07004789
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304790 mmc->max_req_size = MMC_MAX_REQ_SIZE;
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +05304791 mmc->max_seg_size = mmc->max_req_size;
San Mehat9d2bd732009-09-22 16:44:22 -07004792
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004793 writel_relaxed(0, host->base + MMCIMASK0);
4794 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05304795 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004796
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004797 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
4798 mb();
4799 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07004800
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004801 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
4802 DRIVER_NAME " (cmd)", host);
4803 if (ret)
4804 goto dml_exit;
4805
4806 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
4807 DRIVER_NAME " (pio)", host);
4808 if (ret)
4809 goto irq_free;
4810
4811 /*
4812 * Enable SDCC IRQ only when host is powered on. Otherwise, this
4813 * IRQ is un-necessarily being monitored by MPM (Modem power
4814 * management block) during idle-power collapse. The MPM will be
4815 * configured to monitor the DATA1 GPIO line with level-low trigger
4816 * and thus depending on the GPIO status, it prevents TCXO shutdown
4817 * during idle-power collapse.
4818 */
4819 disable_irq(core_irqres->start);
4820 host->sdcc_irq_disabled = 1;
4821
4822 if (plat->sdiowakeup_irq) {
4823 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4824 mmc_hostname(mmc));
4825 ret = request_irq(plat->sdiowakeup_irq,
4826 msmsdcc_platform_sdiowakeup_irq,
4827 IRQF_SHARED | IRQF_TRIGGER_LOW,
4828 DRIVER_NAME "sdiowakeup", host);
4829 if (ret) {
4830 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
4831 plat->sdiowakeup_irq, ret);
4832 goto pio_irq_free;
4833 } else {
4834 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304835 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004836 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304837 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004838 }
4839 spin_unlock_irqrestore(&host->lock, flags);
4840 }
4841 }
4842
Subhash Jadavanic9b85752012-04-13 11:16:49 +05304843 if (host->plat->mpm_sdiowakeup_int) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004844 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4845 mmc_hostname(mmc));
4846 }
4847
4848 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
4849 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004850 /*
4851 * Setup card detect change
4852 */
4853
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004854 if (plat->status || plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08004855 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004856 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08004857 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004858 host->oldstat = msmsdcc_slot_status(host);
Krishna Konda360aa422011-12-06 18:27:41 -08004859
Krishna Konda941604a2012-01-10 17:46:34 -08004860 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004861 }
San Mehat9d2bd732009-09-22 16:44:22 -07004862
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004863 if (plat->status_irq) {
4864 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07004865 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004866 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07004867 DRIVER_NAME " (slot)",
4868 host);
4869 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004870 pr_err("Unable to get slot IRQ %d (%d)\n",
4871 plat->status_irq, ret);
4872 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004873 }
4874 } else if (plat->register_status_notify) {
4875 plat->register_status_notify(msmsdcc_status_notify_cb, host);
4876 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004877 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07004878 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004879
4880 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004881
4882 ret = pm_runtime_set_active(&(pdev)->dev);
4883 if (ret < 0)
4884 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
4885 __func__, ret);
4886 /*
4887 * There is no notion of suspend/resume for SD/MMC/SDIO
4888 * cards. So host can be suspended/resumed with out
4889 * worrying about its children.
4890 */
4891 pm_suspend_ignore_children(&(pdev)->dev, true);
4892
4893 /*
4894 * MMC/SD/SDIO bus suspend/resume operations are defined
4895 * only for the slots that will be used for non-removable
4896 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
4897 * defined. Otherwise, they simply become card removal and
4898 * insertion events during suspend and resume respectively.
4899 * Hence, enable run-time PM only for slots for which bus
4900 * suspend/resume operations are defined.
4901 */
4902#ifdef CONFIG_MMC_UNSAFE_RESUME
4903 /*
4904 * If this capability is set, MMC core will enable/disable host
4905 * for every claim/release operation on a host. We use this
4906 * notification to increment/decrement runtime pm usage count.
4907 */
4908 mmc->caps |= MMC_CAP_DISABLE;
4909 pm_runtime_enable(&(pdev)->dev);
4910#else
4911 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
4912 mmc->caps |= MMC_CAP_DISABLE;
4913 pm_runtime_enable(&(pdev)->dev);
4914 }
4915#endif
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05304916#ifndef CONFIG_PM_RUNTIME
4917 mmc_set_disable_delay(mmc, MSM_MMC_DISABLE_TIMEOUT);
4918#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004919 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
4920 (unsigned long)host);
4921
San Mehat9d2bd732009-09-22 16:44:22 -07004922 mmc_add_host(mmc);
4923
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004924#ifdef CONFIG_HAS_EARLYSUSPEND
4925 host->early_suspend.suspend = msmsdcc_early_suspend;
4926 host->early_suspend.resume = msmsdcc_late_resume;
4927 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
4928 register_early_suspend(&host->early_suspend);
4929#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004930
Krishna Konda25786ec2011-07-25 16:21:36 -07004931 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
4932 " dmacrcri %d\n", mmc_hostname(mmc),
4933 (unsigned long long)core_memres->start,
4934 (unsigned int) core_irqres->start,
4935 (unsigned int) plat->status_irq, host->dma.channel,
4936 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004937
4938 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
4939 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
4940 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
4941 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
4942 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
4943 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
4944 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
4945 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
4946 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
4947 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
4948 host->eject);
4949 pr_info("%s: Power save feature enable = %d\n",
4950 mmc_hostname(mmc), msmsdcc_pwrsave);
4951
Krishna Konda25786ec2011-07-25 16:21:36 -07004952 if (host->is_dma_mode && host->dma.channel != -1
4953 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004954 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004955 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004956 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004957 mmc_hostname(mmc), host->dma.cmd_busaddr,
4958 host->dma.cmdptr_busaddr);
4959 } else if (host->is_sps_mode) {
4960 pr_info("%s: SPS-BAM data transfer mode available\n",
4961 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004962 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004963 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004964
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004965#if defined(CONFIG_DEBUG_FS)
4966 msmsdcc_dbg_createhost(host);
4967#endif
4968 if (!plat->status_irq) {
4969 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
4970 if (ret)
4971 goto platform_irq_free;
4972 }
San Mehat9d2bd732009-09-22 16:44:22 -07004973 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004974
4975 platform_irq_free:
4976 del_timer_sync(&host->req_tout_timer);
4977 pm_runtime_disable(&(pdev)->dev);
4978 pm_runtime_set_suspended(&(pdev)->dev);
4979
4980 if (plat->status_irq)
4981 free_irq(plat->status_irq, host);
4982 sdiowakeup_irq_free:
4983 wake_lock_destroy(&host->sdio_suspend_wlock);
4984 if (plat->sdiowakeup_irq)
4985 free_irq(plat->sdiowakeup_irq, host);
4986 pio_irq_free:
4987 if (plat->sdiowakeup_irq)
4988 wake_lock_destroy(&host->sdio_wlock);
4989 free_irq(core_irqres->start, host);
4990 irq_free:
4991 free_irq(core_irqres->start, host);
4992 dml_exit:
4993 if (host->is_sps_mode)
4994 msmsdcc_dml_exit(host);
4995 sps_exit:
4996 if (host->is_sps_mode)
4997 msmsdcc_sps_exit(host);
4998 vreg_deinit:
4999 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07005000 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005001 clk_disable(host->clk);
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005002 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305003 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07005004 clk_put:
5005 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005006 pclk_disable:
5007 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05305008 clk_disable_unprepare(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07005009 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005010 if (!IS_ERR(host->pclk))
5011 clk_put(host->pclk);
5012 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05305013 clk_disable_unprepare(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005014 dfab_pclk_put:
5015 if (!IS_ERR_OR_NULL(host->dfab_pclk))
5016 clk_put(host->dfab_pclk);
5017 dma_free:
5018 if (host->is_dma_mode) {
5019 if (host->dmares)
5020 dma_free_coherent(NULL,
5021 sizeof(struct msmsdcc_nc_dmadata),
5022 host->dma.nc, host->dma.nc_busaddr);
5023 }
5024 ioremap_free:
5025 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07005026 host_free:
5027 mmc_free_host(mmc);
5028 out:
5029 return ret;
5030}
5031
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005032static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07005033{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005034 struct mmc_host *mmc = mmc_get_drvdata(pdev);
5035 struct mmc_platform_data *plat;
5036 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07005037
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005038 if (!mmc)
5039 return -ENXIO;
5040
5041 if (pm_runtime_suspended(&(pdev)->dev))
5042 pm_runtime_resume(&(pdev)->dev);
5043
5044 host = mmc_priv(mmc);
5045
5046 DBG(host, "Removing SDCC device = %d\n", pdev->id);
5047 plat = host->plat;
5048
5049 if (!plat->status_irq)
5050 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
5051
5052 del_timer_sync(&host->req_tout_timer);
5053 tasklet_kill(&host->dma_tlet);
5054 tasklet_kill(&host->sps.tlet);
5055 mmc_remove_host(mmc);
5056
5057 if (plat->status_irq)
5058 free_irq(plat->status_irq, host);
5059
5060 wake_lock_destroy(&host->sdio_suspend_wlock);
5061 if (plat->sdiowakeup_irq) {
5062 wake_lock_destroy(&host->sdio_wlock);
5063 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
5064 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07005065 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005066
5067 free_irq(host->core_irqres->start, host);
5068 free_irq(host->core_irqres->start, host);
5069
5070 clk_put(host->clk);
5071 if (!IS_ERR(host->pclk))
5072 clk_put(host->pclk);
5073 if (!IS_ERR_OR_NULL(host->dfab_pclk))
5074 clk_put(host->dfab_pclk);
5075
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005076 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305077 pm_qos_remove_request(&host->pm_qos_req_dma);
5078
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005079 msmsdcc_vreg_init(host, false);
5080
5081 if (host->is_dma_mode) {
5082 if (host->dmares)
5083 dma_free_coherent(NULL,
5084 sizeof(struct msmsdcc_nc_dmadata),
5085 host->dma.nc, host->dma.nc_busaddr);
5086 }
5087
5088 if (host->is_sps_mode) {
5089 msmsdcc_dml_exit(host);
5090 msmsdcc_sps_exit(host);
5091 }
5092
5093 iounmap(host->base);
5094 mmc_free_host(mmc);
5095
5096#ifdef CONFIG_HAS_EARLYSUSPEND
5097 unregister_early_suspend(&host->early_suspend);
5098#endif
5099 pm_runtime_disable(&(pdev)->dev);
5100 pm_runtime_set_suspended(&(pdev)->dev);
5101
5102 return 0;
5103}
5104
5105#ifdef CONFIG_MSM_SDIO_AL
5106int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
5107{
5108 struct msmsdcc_host *host = mmc_priv(mmc);
5109 unsigned long flags;
5110
Asutosh Dasf5298c32012-04-03 14:51:47 +05305111 mutex_lock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005112 spin_lock_irqsave(&host->lock, flags);
5113 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
5114 enable ? "En" : "Dis");
5115
5116 if (enable) {
5117 if (!host->sdcc_irq_disabled) {
5118 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05305119 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005120 host->sdcc_irq_disabled = 1;
5121 }
5122
5123 if (host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305124 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005125 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305126 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005127 host->clks_on = 0;
5128 }
5129
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305130 if (host->plat->sdio_lpm_gpio_setup &&
5131 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005132 spin_unlock_irqrestore(&host->lock, flags);
5133 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
5134 spin_lock_irqsave(&host->lock, flags);
5135 host->sdio_gpio_lpm = 1;
5136 }
5137
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305138 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005139 msmsdcc_enable_irq_wake(host);
5140 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305141 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005142 }
5143 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305144 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005145 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305146 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005147 msmsdcc_disable_irq_wake(host);
5148 }
5149
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305150 if (host->plat->sdio_lpm_gpio_setup &&
5151 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005152 spin_unlock_irqrestore(&host->lock, flags);
5153 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
5154 spin_lock_irqsave(&host->lock, flags);
5155 host->sdio_gpio_lpm = 0;
5156 }
5157
5158 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305159 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005160 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305161 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005162 host->clks_on = 1;
5163 }
5164
5165 if (host->sdcc_irq_disabled) {
5166 writel_relaxed(host->mci_irqenable,
5167 host->base + MMCIMASK0);
5168 mb();
5169 enable_irq(host->core_irqres->start);
5170 host->sdcc_irq_disabled = 0;
5171 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005172 }
5173 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305174 mutex_unlock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005175 return 0;
5176}
5177#else
5178int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
5179{
5180 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07005181}
5182#endif
5183
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005184#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07005185static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005186msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07005187{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005188 struct mmc_host *mmc = dev_get_drvdata(dev);
5189 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07005190 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305191 unsigned long flags;
5192
San Mehat9d2bd732009-09-22 16:44:22 -07005193
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005194 if (host->plat->is_sdio_al_client)
5195 return 0;
Sahitya Tummala7661a452011-07-18 13:28:35 +05305196 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005197 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005198 host->sdcc_suspending = 1;
5199 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07005200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005201 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005202 * MMC core thinks that host is disabled by now since
5203 * runtime suspend is scheduled after msmsdcc_disable()
5204 * is called. Thus, MMC core will try to enable the host
5205 * while suspending it. This results in a synchronous
5206 * runtime resume request while in runtime suspending
5207 * context and hence inorder to complete this resume
5208 * requet, it will wait for suspend to be complete,
5209 * but runtime suspend also can not proceed further
5210 * until the host is resumed. Thus, it leads to a hang.
5211 * Hence, increase the pm usage count before suspending
5212 * the host so that any resume requests after this will
5213 * simple become pm usage counter increment operations.
5214 */
5215 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05305216 /* If there is pending detect work abort runtime suspend */
5217 if (unlikely(work_busy(&mmc->detect.work)))
5218 rc = -EAGAIN;
5219 else
5220 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005221 pm_runtime_put_noidle(dev);
5222
5223 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305224 spin_lock_irqsave(&host->lock, flags);
5225 host->sdcc_suspended = true;
5226 spin_unlock_irqrestore(&host->lock, flags);
5227 if (mmc->card && mmc_card_sdio(mmc->card) &&
5228 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005229 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305230 * If SDIO function driver doesn't want
5231 * to power off the card, atleast turn off
5232 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005233 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305234 mmc_host_clk_hold(mmc);
5235 spin_lock_irqsave(&mmc->clk_lock, flags);
5236 mmc->clk_old = mmc->ios.clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005237 mmc->ios.clock = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305238 mmc->clk_gated = true;
5239 spin_unlock_irqrestore(&mmc->clk_lock, flags);
5240 mmc_set_ios(mmc);
5241 mmc_host_clk_release(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005242 }
5243 }
5244 host->sdcc_suspending = 0;
5245 mmc->suspend_task = NULL;
5246 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
5247 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005248 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05305249 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
San Mehat9d2bd732009-09-22 16:44:22 -07005250 return rc;
5251}
5252
5253static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005254msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07005255{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005256 struct mmc_host *mmc = dev_get_drvdata(dev);
5257 struct msmsdcc_host *host = mmc_priv(mmc);
5258 unsigned long flags;
5259
5260 if (host->plat->is_sdio_al_client)
5261 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07005262
Sahitya Tummala7661a452011-07-18 13:28:35 +05305263 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005264 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305265 if (mmc->card && mmc_card_sdio(mmc->card) &&
5266 mmc_card_keep_power(mmc)) {
5267 mmc_host_clk_hold(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305268 mmc->ios.clock = host->clk_rate;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305269 mmc_set_ios(mmc);
5270 mmc_host_clk_release(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305271 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005272
5273 mmc_resume_host(mmc);
5274
5275 /*
5276 * FIXME: Clearing of flags must be handled in clients
5277 * resume handler.
5278 */
5279 spin_lock_irqsave(&host->lock, flags);
5280 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305281 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005282 spin_unlock_irqrestore(&host->lock, flags);
5283
5284 /*
5285 * After resuming the host wait for sometime so that
5286 * the SDIO work will be processed.
5287 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305288 if (mmc->card && mmc_card_sdio(mmc->card)) {
Subhash Jadavanic9b85752012-04-13 11:16:49 +05305289 if ((host->plat->mpm_sdiowakeup_int ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005290 host->plat->sdiowakeup_irq) &&
5291 wake_lock_active(&host->sdio_wlock))
5292 wake_lock_timeout(&host->sdio_wlock, 1);
5293 }
5294
5295 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005296 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05305297 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005298 return 0;
5299}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005300
5301static int msmsdcc_runtime_idle(struct device *dev)
5302{
5303 struct mmc_host *mmc = dev_get_drvdata(dev);
5304 struct msmsdcc_host *host = mmc_priv(mmc);
5305
5306 if (host->plat->is_sdio_al_client)
5307 return 0;
5308
5309 /* Idle timeout is not configurable for now */
5310 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
5311
5312 return -EAGAIN;
5313}
5314
5315static int msmsdcc_pm_suspend(struct device *dev)
5316{
5317 struct mmc_host *mmc = dev_get_drvdata(dev);
5318 struct msmsdcc_host *host = mmc_priv(mmc);
5319 int rc = 0;
5320
5321 if (host->plat->is_sdio_al_client)
5322 return 0;
5323
5324
5325 if (host->plat->status_irq)
5326 disable_irq(host->plat->status_irq);
5327
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005328 if (!pm_runtime_suspended(dev))
5329 rc = msmsdcc_runtime_suspend(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005330
5331 return rc;
5332}
5333
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305334static int msmsdcc_suspend_noirq(struct device *dev)
5335{
5336 struct mmc_host *mmc = dev_get_drvdata(dev);
5337 struct msmsdcc_host *host = mmc_priv(mmc);
5338 int rc = 0;
5339
5340 /*
5341 * After platform suspend there may be active request
5342 * which might have enabled clocks. For example, in SDIO
5343 * case, ksdioirq thread might have scheduled after sdcc
5344 * suspend but before system freeze. In that case abort
5345 * suspend and retry instead of keeping the clocks on
5346 * during suspend and not allowing TCXO.
5347 */
5348
Asutosh Dasf5298c32012-04-03 14:51:47 +05305349 if (host->clks_on && !host->plat->is_sdio_al_client) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305350 pr_warn("%s: clocks are on after suspend, aborting system "
5351 "suspend\n", mmc_hostname(mmc));
5352 rc = -EAGAIN;
5353 }
5354
5355 return rc;
5356}
5357
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005358static int msmsdcc_pm_resume(struct device *dev)
5359{
5360 struct mmc_host *mmc = dev_get_drvdata(dev);
5361 struct msmsdcc_host *host = mmc_priv(mmc);
5362 int rc = 0;
5363
5364 if (host->plat->is_sdio_al_client)
5365 return 0;
5366
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005367 if (mmc->card && mmc_card_sdio(mmc->card))
Sahitya Tummalafb486372011-09-02 19:01:49 +05305368 rc = msmsdcc_runtime_resume(dev);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005369 else
5370 host->pending_resume = true;
5371
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005372 if (host->plat->status_irq) {
5373 msmsdcc_check_status((unsigned long)host);
5374 enable_irq(host->plat->status_irq);
5375 }
5376
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005377 return rc;
5378}
5379
Daniel Walker08ecfde2010-06-23 12:32:20 -07005380#else
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005381static int msmsdcc_runtime_suspend(struct device *dev)
5382{
5383 return 0;
5384}
5385static int msmsdcc_runtime_idle(struct device *dev)
5386{
5387 return 0;
5388}
5389static int msmsdcc_pm_suspend(struct device *dev)
5390{
5391 return 0;
5392}
5393static int msmsdcc_pm_resume(struct device *dev)
5394{
5395 return 0;
5396}
5397static int msmsdcc_suspend_noirq(struct device *dev)
5398{
5399 return 0;
5400}
5401static int msmsdcc_runtime_resume(struct device *dev)
5402{
5403 return 0;
5404}
Daniel Walker08ecfde2010-06-23 12:32:20 -07005405#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005406
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005407static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
5408 .runtime_suspend = msmsdcc_runtime_suspend,
5409 .runtime_resume = msmsdcc_runtime_resume,
5410 .runtime_idle = msmsdcc_runtime_idle,
5411 .suspend = msmsdcc_pm_suspend,
5412 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305413 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005414};
5415
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305416static const struct of_device_id msmsdcc_dt_match[] = {
5417 {.compatible = "qcom,msm-sdcc"},
5418
5419};
5420MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
5421
San Mehat9d2bd732009-09-22 16:44:22 -07005422static struct platform_driver msmsdcc_driver = {
5423 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005424 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07005425 .driver = {
5426 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005427 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305428 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07005429 },
5430};
5431
5432static int __init msmsdcc_init(void)
5433{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005434#if defined(CONFIG_DEBUG_FS)
5435 int ret = 0;
5436 ret = msmsdcc_dbg_init();
5437 if (ret) {
5438 pr_err("Failed to create debug fs dir \n");
5439 return ret;
5440 }
5441#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005442 return platform_driver_register(&msmsdcc_driver);
5443}
5444
5445static void __exit msmsdcc_exit(void)
5446{
5447 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005448
5449#if defined(CONFIG_DEBUG_FS)
5450 debugfs_remove(debugfs_file);
5451 debugfs_remove(debugfs_dir);
5452#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005453}
5454
5455module_init(msmsdcc_init);
5456module_exit(msmsdcc_exit);
5457
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005458MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07005459MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005460
5461#if defined(CONFIG_DEBUG_FS)
5462
5463static int
5464msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
5465{
5466 file->private_data = inode->i_private;
5467 return 0;
5468}
5469
5470static ssize_t
5471msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
5472 size_t count, loff_t *ppos)
5473{
5474 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08005475 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005476 int max, i;
5477
5478 i = 0;
5479 max = sizeof(buf) - 1;
5480
5481 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
5482 host->curr.cmd, host->curr.data);
5483 if (host->curr.cmd) {
5484 struct mmc_command *cmd = host->curr.cmd;
5485
5486 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
5487 cmd->opcode, cmd->arg, cmd->flags);
5488 }
5489 if (host->curr.data) {
5490 struct mmc_data *data = host->curr.data;
5491 i += scnprintf(buf + i, max - i,
5492 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
5493 data->timeout_ns, data->timeout_clks,
5494 data->blksz, data->blocks, data->error,
5495 data->flags);
5496 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
5497 host->curr.xfer_size, host->curr.xfer_remain,
5498 host->curr.data_xfered, host->dma.sg);
5499 }
5500
5501 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
5502}
5503
5504static const struct file_operations msmsdcc_dbg_state_ops = {
5505 .read = msmsdcc_dbg_state_read,
5506 .open = msmsdcc_dbg_state_open,
5507};
5508
5509static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
5510{
5511 if (debugfs_dir) {
5512 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
5513 0644, debugfs_dir, host,
5514 &msmsdcc_dbg_state_ops);
5515 }
5516}
5517
5518static int __init msmsdcc_dbg_init(void)
5519{
5520 int err;
5521
5522 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
5523 if (IS_ERR(debugfs_dir)) {
5524 err = PTR_ERR(debugfs_dir);
5525 debugfs_dir = NULL;
5526 return err;
5527 }
5528
5529 return 0;
5530}
5531#endif