blob: a4af6c9bd9e2f156331ec56b6f416aec638d1a74 [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>
Steve Mucklef132c6c2012-06-06 18:30:57 -070046#include <linux/pm_qos.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>
Subhash Jadavanibcd435f2012-04-24 18:26:49 +053058#include <mach/msm_bus.h>
San Mehat9d2bd732009-09-22 16:44:22 -070059
San Mehat9d2bd732009-09-22 16:44:22 -070060#include "msm_sdcc.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070061#include "msm_sdcc_dml.h"
San Mehat9d2bd732009-09-22 16:44:22 -070062
63#define DRIVER_NAME "msm-sdcc"
64
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070065#define DBG(host, fmt, args...) \
66 pr_debug("%s: %s: " fmt "\n", mmc_hostname(host->mmc), __func__ , args)
67
68#define IRQ_DEBUG 0
69#define SPS_SDCC_PRODUCER_PIPE_INDEX 1
70#define SPS_SDCC_CONSUMER_PIPE_INDEX 2
71#define SPS_CONS_PERIPHERAL 0
72#define SPS_PROD_PERIPHERAL 1
Subhash Jadavanie6e1b822012-03-12 18:17:58 +053073/* Use SPS only if transfer size is more than this macro */
74#define SPS_MIN_XFER_SIZE MCI_FIFOSIZE
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070075
Subhash Jadavanibcd435f2012-04-24 18:26:49 +053076#define MSM_MMC_BUS_VOTING_DELAY 200 /* msecs */
77
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070078#if defined(CONFIG_DEBUG_FS)
79static void msmsdcc_dbg_createhost(struct msmsdcc_host *);
80static struct dentry *debugfs_dir;
81static struct dentry *debugfs_file;
82static int msmsdcc_dbg_init(void);
83#endif
84
Asutosh Dasaccacd42012-03-08 14:33:17 +053085static int msmsdcc_prep_xfer(struct msmsdcc_host *host, struct mmc_data
86 *data);
87
Subhash Jadavani8766e352011-11-30 11:30:32 +053088static u64 dma_mask = DMA_BIT_MASK(32);
San Mehat9d2bd732009-09-22 16:44:22 -070089static unsigned int msmsdcc_pwrsave = 1;
San Mehat9d2bd732009-09-22 16:44:22 -070090
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070091static struct mmc_command dummy52cmd;
92static struct mmc_request dummy52mrq = {
93 .cmd = &dummy52cmd,
94 .data = NULL,
95 .stop = NULL,
96};
97static struct mmc_command dummy52cmd = {
98 .opcode = SD_IO_RW_DIRECT,
99 .flags = MMC_RSP_PRESENT,
100 .data = NULL,
101 .mrq = &dummy52mrq,
102};
103/*
104 * An array holding the Tuning pattern to compare with when
105 * executing a tuning cycle.
106 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +0530107static const u32 tuning_block_64[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700108 0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
109 0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
110 0xF0FFF0FF, 0x3CCCFC0F, 0xCFCC33CC, 0xEEFFEFFF,
111 0xFDFFFDFF, 0xFFBFFFDF, 0xFFF7FFBB, 0xDE7B7FF7
112};
San Mehat9d2bd732009-09-22 16:44:22 -0700113
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +0530114static const u32 tuning_block_128[] = {
115 0xFF00FFFF, 0x0000FFFF, 0xCCCCFFFF, 0xCCCC33CC,
116 0xCC3333CC, 0xFFFFCCCC, 0xFFFFEEFF, 0xFFEEEEFF,
117 0xFFDDFFFF, 0xDDDDFFFF, 0xBBFFFFFF, 0xBBFFFFFF,
118 0xFFFFFFBB, 0xFFFFFF77, 0x77FF7777, 0xFFEEDDBB,
119 0x00FFFFFF, 0x00FFFFFF, 0xCCFFFF00, 0xCC33CCCC,
120 0x3333CCCC, 0xFFCCCCCC, 0xFFEEFFFF, 0xEEEEFFFF,
121 0xDDFFFFFF, 0xDDFFFFFF, 0xFFFFFFDD, 0xFFFFFFBB,
122 0xFFFFBBBB, 0xFFFF77FF, 0xFF7777FF, 0xEEDDBB77
123};
San Mehat865c8062009-11-13 13:42:06 -0800124
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700125#if IRQ_DEBUG == 1
126static char *irq_status_bits[] = { "cmdcrcfail", "datcrcfail", "cmdtimeout",
127 "dattimeout", "txunderrun", "rxoverrun",
128 "cmdrespend", "cmdsent", "dataend", NULL,
129 "datablkend", "cmdactive", "txactive",
130 "rxactive", "txhalfempty", "rxhalffull",
131 "txfifofull", "rxfifofull", "txfifoempty",
132 "rxfifoempty", "txdataavlbl", "rxdataavlbl",
133 "sdiointr", "progdone", "atacmdcompl",
134 "sdiointrope", "ccstimeout", NULL, NULL,
135 NULL, NULL, NULL };
136
137static void
138msmsdcc_print_status(struct msmsdcc_host *host, char *hdr, uint32_t status)
San Mehat865c8062009-11-13 13:42:06 -0800139{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700140 int i;
San Mehat8b1c2ba2009-11-16 10:17:30 -0800141
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700142 pr_debug("%s-%s ", mmc_hostname(host->mmc), hdr);
143 for (i = 0; i < 32; i++) {
144 if (status & (1 << i))
145 pr_debug("%s ", irq_status_bits[i]);
San Mehat865c8062009-11-13 13:42:06 -0800146 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700147 pr_debug("\n");
San Mehatc7fc9372009-11-22 17:19:07 -0800148}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700149#endif
San Mehat865c8062009-11-13 13:42:06 -0800150
San Mehat9d2bd732009-09-22 16:44:22 -0700151static void
152msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
153 u32 c);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530154static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530155static inline void msmsdcc_delay(struct msmsdcc_host *host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530156static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -0800157static void msmsdcc_sg_start(struct msmsdcc_host *host);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -0800158static int msmsdcc_vreg_reset(struct msmsdcc_host *host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -0700159static int msmsdcc_runtime_resume(struct device *dev);
San Mehat9d2bd732009-09-22 16:44:22 -0700160
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530161static inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530162{
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530163 unsigned short ret = NR_SG;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530164
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530165 if (is_sps_mode(host)) {
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +0530166 ret = SPS_MAX_DESCS;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530167 } else { /* DMA or PIO mode */
168 if (NR_SG > MAX_NR_SG_DMA_PIO)
169 ret = MAX_NR_SG_DMA_PIO;
170 }
171
172 return ret;
173}
174
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530175/* Prevent idle power collapse(pc) while operating in peripheral mode */
176static void msmsdcc_pm_qos_update_latency(struct msmsdcc_host *host, int vote)
177{
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -0700178 if (!host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530179 return;
180
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530181 if (vote)
182 pm_qos_update_request(&host->pm_qos_req_dma,
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -0700183 host->cpu_dma_latency);
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530184 else
185 pm_qos_update_request(&host->pm_qos_req_dma,
186 PM_QOS_DEFAULT_VALUE);
187}
188
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700189#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
190static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
191 struct msmsdcc_sps_ep_conn_data *ep);
192static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
193 struct msmsdcc_sps_ep_conn_data *ep);
194#else
195static inline int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
196 struct msmsdcc_sps_ep_conn_data *ep,
197 bool is_producer) { return 0; }
198static inline void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
199 struct msmsdcc_sps_ep_conn_data *ep) { }
200static inline int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
201 struct msmsdcc_sps_ep_conn_data *ep)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530202{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700203 return 0;
204}
205static inline int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
206 struct msmsdcc_sps_ep_conn_data *ep)
207{
208 return 0;
209}
210static inline int msmsdcc_sps_init(struct msmsdcc_host *host) { return 0; }
211static inline void msmsdcc_sps_exit(struct msmsdcc_host *host) {}
212#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530213
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700214/**
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530215 * Apply soft reset to all SDCC BAM pipes
216 *
217 * This function applies soft reset to SDCC BAM pipe.
218 *
219 * This function should be called to recover from error
220 * conditions encountered during CMD/DATA tranfsers with card.
221 *
222 * @host - Pointer to driver's host structure
223 *
224 */
225static void msmsdcc_sps_pipes_reset_and_restore(struct msmsdcc_host *host)
226{
227 int rc;
228
229 /* Reset all SDCC BAM pipes */
230 rc = msmsdcc_sps_reset_ep(host, &host->sps.prod);
231 if (rc)
232 pr_err("%s:msmsdcc_sps_reset_ep(prod) error=%d\n",
233 mmc_hostname(host->mmc), rc);
234 rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
235 if (rc)
236 pr_err("%s:msmsdcc_sps_reset_ep(cons) error=%d\n",
237 mmc_hostname(host->mmc), rc);
238
239 /* Restore all BAM pipes connections */
240 rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
241 if (rc)
242 pr_err("%s:msmsdcc_sps_restore_ep(prod) error=%d\n",
243 mmc_hostname(host->mmc), rc);
244 rc = msmsdcc_sps_restore_ep(host, &host->sps.cons);
245 if (rc)
246 pr_err("%s:msmsdcc_sps_restore_ep(cons) error=%d\n",
247 mmc_hostname(host->mmc), rc);
248}
249
250/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700251 * Apply soft reset
252 *
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530253 * This function applies soft reset to SDCC core and DML core.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700254 *
255 * This function should be called to recover from error
256 * conditions encountered with CMD/DATA tranfsers with card.
257 *
258 * Soft reset should only be used with SDCC controller v4.
259 *
260 * @host - Pointer to driver's host structure
261 *
262 */
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530263static void msmsdcc_soft_reset(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700264{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700265 /*
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530266 * Reset controller state machines without resetting
267 * configuration registers (MCI_POWER, MCI_CLK, MCI_INT_MASKn).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700268 */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530269 if (is_sw_reset_save_config(host)) {
270 ktime_t start;
271
272 writel_relaxed(readl_relaxed(host->base + MMCIPOWER)
273 | MCI_SW_RST_CFG, host->base + MMCIPOWER);
274 msmsdcc_sync_reg_wr(host);
275
276 start = ktime_get();
277 while (readl_relaxed(host->base + MMCIPOWER) & MCI_SW_RST_CFG) {
278 /*
279 * SW reset can take upto 10HCLK + 15MCLK cycles.
280 * Calculating based on min clk rates (hclk = 27MHz,
281 * mclk = 400KHz) it comes to ~40us. Let's poll for
282 * max. 1ms for reset completion.
283 */
284 if (ktime_to_us(ktime_sub(ktime_get(), start)) > 1000) {
285 pr_err("%s: %s failed\n",
286 mmc_hostname(host->mmc), __func__);
287 BUG();
288 }
289 }
290 } else {
291 writel_relaxed(0, host->base + MMCICOMMAND);
292 msmsdcc_sync_reg_wr(host);
293 writel_relaxed(0, host->base + MMCIDATACTRL);
294 msmsdcc_sync_reg_wr(host);
295 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530296}
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530297
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530298static void msmsdcc_hard_reset(struct msmsdcc_host *host)
299{
300 int ret;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530301
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530302 /*
303 * Reset SDCC controller to power on default state.
304 * Don't issue a reset request to clock control block if
305 * SDCC controller itself can support hard reset.
306 */
307 if (is_sw_hard_reset(host)) {
308 ktime_t start;
309
310 writel_relaxed(readl_relaxed(host->base + MMCIPOWER)
311 | MCI_SW_RST, host->base + MMCIPOWER);
312 msmsdcc_sync_reg_wr(host);
313
314 start = ktime_get();
315 while (readl_relaxed(host->base + MMCIPOWER) & MCI_SW_RST) {
316 /*
317 * See comment in msmsdcc_soft_reset() on choosing 1ms
318 * poll timeout.
319 */
320 if (ktime_to_us(ktime_sub(ktime_get(), start)) > 1000) {
321 pr_err("%s: %s failed\n",
322 mmc_hostname(host->mmc), __func__);
323 BUG();
324 }
325 }
326 } else {
327 ret = clk_reset(host->clk, CLK_RESET_ASSERT);
328 if (ret)
329 pr_err("%s: Clock assert failed at %u Hz" \
330 " with err %d\n", mmc_hostname(host->mmc),
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530331 host->clk_rate, ret);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530332
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530333 ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
334 if (ret)
335 pr_err("%s: Clock deassert failed at %u Hz" \
336 " with err %d\n", mmc_hostname(host->mmc),
337 host->clk_rate, ret);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530338
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530339 mb();
340 /* Give some delay for clock reset to propogate to controller */
341 msmsdcc_delay(host);
342 }
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530343}
344
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700345static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
346{
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530347 if (is_soft_reset(host)) {
348 if (is_sps_mode(host)) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530349 /* Reset DML first */
350 msmsdcc_dml_reset(host);
351 /*
352 * delay the SPS pipe reset in thread context as
353 * sps_connect/sps_disconnect APIs can be called
354 * only from non-atomic context.
355 */
356 host->sps.pipe_reset_pending = true;
357 }
358 mb();
359 msmsdcc_soft_reset(host);
360
361 pr_debug("%s: Applied soft reset to Controller\n",
362 mmc_hostname(host->mmc));
363
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530364 if (is_sps_mode(host))
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530365 msmsdcc_dml_init(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700366 } else {
367 /* Give Clock reset (hard reset) to controller */
368 u32 mci_clk = 0;
369 u32 mci_mask0 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700370
371 /* Save the controller state */
372 mci_clk = readl_relaxed(host->base + MMCICLOCK);
373 mci_mask0 = readl_relaxed(host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +0530374 host->pwr = readl_relaxed(host->base + MMCIPOWER);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700375 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700376
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530377 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700378 pr_debug("%s: Controller has been reinitialized\n",
379 mmc_hostname(host->mmc));
380
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700381 /* Restore the contoller state */
382 writel_relaxed(host->pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530383 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700384 writel_relaxed(mci_clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530385 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700386 writel_relaxed(mci_mask0, host->base + MMCIMASK0);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530387 mb(); /* no delay required after writing to MASK0 register */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700388 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530389
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700390 if (host->dummy_52_needed)
391 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700392}
393
394static int
San Mehat9d2bd732009-09-22 16:44:22 -0700395msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
396{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700397 int retval = 0;
398
San Mehat9d2bd732009-09-22 16:44:22 -0700399 BUG_ON(host->curr.data);
400
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700401 del_timer(&host->req_tout_timer);
San Mehat9d2bd732009-09-22 16:44:22 -0700402
403 if (mrq->data)
404 mrq->data->bytes_xfered = host->curr.data_xfered;
405 if (mrq->cmd->error == -ETIMEDOUT)
406 mdelay(5);
407
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530408 /* Clear current request information as current request has ended */
409 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
410
San Mehat9d2bd732009-09-22 16:44:22 -0700411 /*
412 * Need to drop the host lock here; mmc_request_done may call
413 * back into the driver...
414 */
415 spin_unlock(&host->lock);
416 mmc_request_done(host->mmc, mrq);
417 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700418
419 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700420}
421
422static void
423msmsdcc_stop_data(struct msmsdcc_host *host)
424{
San Mehat9d2bd732009-09-22 16:44:22 -0700425 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530426 host->curr.got_dataend = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +0530427 host->curr.wait_for_auto_prog_done = false;
428 host->curr.got_auto_prog_done = false;
Krishna Konda9d1679c2012-06-04 22:44:28 -0700429 writel_relaxed(0, host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530430 msmsdcc_sync_reg_wr(host); /* Allow the DPSM to be reset */
San Mehat9d2bd732009-09-22 16:44:22 -0700431}
432
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700433static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700434{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700435 return host->core_memres->start + MMCIFIFO;
436}
437
438static inline unsigned int msmsdcc_get_min_sup_clk_rate(
439 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530440
Subhash Jadavanidd432952012-03-28 11:25:56 +0530441static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700442{
443 mb();
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530444 if (!is_wait_for_reg_write(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +0530445 udelay(host->reg_write_delay);
446 else if (readl_relaxed(host->base + MCI_STATUS2) &
447 MCI_MCLK_REG_WR_ACTIVE) {
448 ktime_t start, diff;
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530449
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530450 start = ktime_get();
451 while (readl_relaxed(host->base + MCI_STATUS2) &
452 MCI_MCLK_REG_WR_ACTIVE) {
453 diff = ktime_sub(ktime_get(), start);
454 /* poll for max. 1 ms */
455 if (ktime_to_us(diff) > 1000) {
456 pr_warning("%s: previous reg. write is"
457 " still active\n",
458 mmc_hostname(host->mmc));
459 break;
460 }
461 }
462 }
San Mehat9d2bd732009-09-22 16:44:22 -0700463}
464
Subhash Jadavanidd432952012-03-28 11:25:56 +0530465static inline void msmsdcc_delay(struct msmsdcc_host *host)
466{
467 udelay(host->reg_write_delay);
468
San Mehat9d2bd732009-09-22 16:44:22 -0700469}
470
San Mehat56a8b5b2009-11-21 12:29:46 -0800471static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700472msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
473{
474 writel_relaxed(arg, host->base + MMCIARGUMENT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700475 writel_relaxed(c, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530476 /*
477 * As after sending the command, we don't write any of the
478 * controller registers and just wait for the
479 * CMD_RESPOND_END/CMD_SENT/Command failure notication
480 * from Controller.
481 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700482 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800483}
484
485static void
486msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
487{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700488 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800489
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700490 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
491 writel_relaxed((unsigned int)host->curr.xfer_size,
492 host->base + MMCIDATALENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700493 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530494 msmsdcc_sync_reg_wr(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800495
San Mehat6ac9ea62009-12-02 17:24:58 -0800496 if (host->cmd_cmd) {
497 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700498 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800499 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800500}
501
San Mehat9d2bd732009-09-22 16:44:22 -0700502static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530503msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700504{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530505 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700506 unsigned long flags;
507 struct mmc_request *mrq;
508
509 spin_lock_irqsave(&host->lock, flags);
510 mrq = host->curr.mrq;
511 BUG_ON(!mrq);
512
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530513 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700514 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700515 goto out;
516 }
517
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530518 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700519 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700520 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700521 } else {
522 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530523 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700524 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530525 mmc_hostname(host->mmc), host->dma.result);
526 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700527 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530528 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530529 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700530 host->dma.err.flush[0], host->dma.err.flush[1],
531 host->dma.err.flush[2], host->dma.err.flush[3],
532 host->dma.err.flush[4],
533 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530534 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700535 if (!mrq->data->error)
536 mrq->data->error = -EIO;
537 }
Asutosh Dasaccacd42012-03-08 14:33:17 +0530538 if (!mrq->data->host_cookie)
539 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
540 host->dma.num_ents, host->dma.dir);
San Mehat9d2bd732009-09-22 16:44:22 -0700541
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700542 if (host->curr.user_pages) {
543 struct scatterlist *sg = host->dma.sg;
544 int i;
545
546 for (i = 0; i < host->dma.num_ents; i++, sg++)
547 flush_dcache_page(sg_page(sg));
548 }
San Mehat9d2bd732009-09-22 16:44:22 -0700549
San Mehat9d2bd732009-09-22 16:44:22 -0700550 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800551 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700552
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530553 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
554 (host->curr.wait_for_auto_prog_done &&
555 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700556 /*
557 * If we've already gotten our DATAEND / DATABLKEND
558 * for this request, then complete it through here.
559 */
San Mehat9d2bd732009-09-22 16:44:22 -0700560
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700561 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700562 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700563 host->curr.xfer_remain -= host->curr.xfer_size;
564 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700565 if (host->dummy_52_needed) {
San Mehat9d2bd732009-09-22 16:44:22 -0700566 mrq->data->bytes_xfered = host->curr.data_xfered;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700567 host->dummy_52_sent = 1;
568 msmsdcc_start_command(host, &dummy52cmd,
569 MCI_CPSM_PROGENA);
570 goto out;
571 }
572 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530573 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530574 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700575 mrq->data->bytes_xfered = host->curr.data_xfered;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700576 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530577 /*
578 * Clear current request information as current
579 * request has ended
580 */
581 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
San Mehat9d2bd732009-09-22 16:44:22 -0700582 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700583
San Mehat9d2bd732009-09-22 16:44:22 -0700584 mmc_request_done(host->mmc, mrq);
585 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530586 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
587 || !mrq->sbc)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700588 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530589 }
San Mehat9d2bd732009-09-22 16:44:22 -0700590 }
591
592out:
593 spin_unlock_irqrestore(&host->lock, flags);
594 return;
595}
596
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700597#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
598/**
599 * Callback notification from SPS driver
600 *
601 * This callback function gets triggered called from
602 * SPS driver when requested SPS data transfer is
603 * completed.
604 *
605 * SPS driver invokes this callback in BAM irq context so
606 * SDCC driver schedule a tasklet for further processing
607 * this callback notification at later point of time in
608 * tasklet context and immediately returns control back
609 * to SPS driver.
610 *
611 * @nofity - Pointer to sps event notify sturcture
612 *
613 */
614static void
615msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
616{
617 struct msmsdcc_host *host =
618 (struct msmsdcc_host *)
619 ((struct sps_event_notify *)notify)->user;
620
621 host->sps.notify = *notify;
622 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
623 mmc_hostname(host->mmc), __func__, notify->event_id,
624 notify->data.transfer.iovec.addr,
625 notify->data.transfer.iovec.size,
626 notify->data.transfer.iovec.flags);
627 /* Schedule a tasklet for completing data transfer */
628 tasklet_schedule(&host->sps.tlet);
629}
630
631/**
632 * Tasklet handler for processing SPS callback event
633 *
634 * This function processing SPS event notification and
635 * checks if the SPS transfer is completed or not and
636 * then accordingly notifies status to MMC core layer.
637 *
638 * This function is called in tasklet context.
639 *
640 * @data - Pointer to sdcc driver data
641 *
642 */
643static void msmsdcc_sps_complete_tlet(unsigned long data)
644{
645 unsigned long flags;
646 int i, rc;
647 u32 data_xfered = 0;
648 struct mmc_request *mrq;
649 struct sps_iovec iovec;
650 struct sps_pipe *sps_pipe_handle;
651 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
652 struct sps_event_notify *notify = &host->sps.notify;
653
654 spin_lock_irqsave(&host->lock, flags);
655 if (host->sps.dir == DMA_FROM_DEVICE)
656 sps_pipe_handle = host->sps.prod.pipe_handle;
657 else
658 sps_pipe_handle = host->sps.cons.pipe_handle;
659 mrq = host->curr.mrq;
660
661 if (!mrq) {
662 spin_unlock_irqrestore(&host->lock, flags);
663 return;
664 }
665
666 pr_debug("%s: %s: sps event_id=%d\n",
667 mmc_hostname(host->mmc), __func__,
668 notify->event_id);
669
670 if (msmsdcc_is_dml_busy(host)) {
671 /* oops !!! this should never happen. */
672 pr_err("%s: %s: Received SPS EOT event"
673 " but DML HW is still busy !!!\n",
674 mmc_hostname(host->mmc), __func__);
675 }
676 /*
677 * Got End of transfer event!!! Check if all of the data
678 * has been transferred?
679 */
680 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
681 rc = sps_get_iovec(sps_pipe_handle, &iovec);
682 if (rc) {
683 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
684 mmc_hostname(host->mmc), __func__, rc, i);
685 break;
686 }
687 data_xfered += iovec.size;
688 }
689
690 if (data_xfered == host->curr.xfer_size) {
691 host->curr.data_xfered = host->curr.xfer_size;
692 host->curr.xfer_remain -= host->curr.xfer_size;
693 pr_debug("%s: Data xfer success. data_xfered=0x%x",
694 mmc_hostname(host->mmc),
695 host->curr.xfer_size);
696 } else {
697 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
698 " xfer_size=%d", mmc_hostname(host->mmc),
699 data_xfered, host->curr.xfer_size);
700 msmsdcc_reset_and_restore(host);
701 if (!mrq->data->error)
702 mrq->data->error = -EIO;
703 }
704
705 /* Unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +0530706 if (!mrq->data->host_cookie)
707 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
708 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700709 host->sps.sg = NULL;
710 host->sps.busy = 0;
711
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530712 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
713 (host->curr.wait_for_auto_prog_done &&
714 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700715 /*
716 * If we've already gotten our DATAEND / DATABLKEND
717 * for this request, then complete it through here.
718 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700719
720 if (!mrq->data->error) {
721 host->curr.data_xfered = host->curr.xfer_size;
722 host->curr.xfer_remain -= host->curr.xfer_size;
723 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700724 if (host->dummy_52_needed) {
725 mrq->data->bytes_xfered = host->curr.data_xfered;
726 host->dummy_52_sent = 1;
727 msmsdcc_start_command(host, &dummy52cmd,
728 MCI_CPSM_PROGENA);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700729 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700730 return;
731 }
732 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530733 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530734 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700735 mrq->data->bytes_xfered = host->curr.data_xfered;
736 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530737 /*
738 * Clear current request information as current
739 * request has ended
740 */
741 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700742 spin_unlock_irqrestore(&host->lock, flags);
743
744 mmc_request_done(host->mmc, mrq);
745 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530746 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
747 || !mrq->sbc)) {
748 msmsdcc_start_command(host, mrq->data->stop, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700749 }
750 }
751 spin_unlock_irqrestore(&host->lock, flags);
752}
753
754/**
755 * Exit from current SPS data transfer
756 *
757 * This function exits from current SPS data transfer.
758 *
759 * This function should be called when error condition
760 * is encountered during data transfer.
761 *
762 * @host - Pointer to sdcc host structure
763 *
764 */
765static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
766{
767 struct mmc_request *mrq;
768
769 mrq = host->curr.mrq;
770 BUG_ON(!mrq);
771
772 msmsdcc_reset_and_restore(host);
773 if (!mrq->data->error)
774 mrq->data->error = -EIO;
775
776 /* Unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +0530777 if (!mrq->data->host_cookie)
778 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
779 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700780
781 host->sps.sg = NULL;
782 host->sps.busy = 0;
783 if (host->curr.data)
784 msmsdcc_stop_data(host);
785
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530786 if (!mrq->data->stop || mrq->cmd->error ||
787 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700788 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530789 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
790 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700791 msmsdcc_start_command(host, mrq->data->stop, 0);
792
793}
794#else
795static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
796static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
797static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
798#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
799
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530800static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700801
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530802static void
803msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
804 unsigned int result,
805 struct msm_dmov_errdata *err)
806{
807 struct msmsdcc_dma_data *dma_data =
808 container_of(cmd, struct msmsdcc_dma_data, hdr);
809 struct msmsdcc_host *host = dma_data->host;
810
811 dma_data->result = result;
812 if (err)
813 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
814
815 tasklet_schedule(&host->dma_tlet);
816}
817
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530818static bool msmsdcc_is_dma_possible(struct msmsdcc_host *host,
819 struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700820{
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530821 bool ret = true;
822 u32 xfer_size = data->blksz * data->blocks;
San Mehat9d2bd732009-09-22 16:44:22 -0700823
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530824 if (is_sps_mode(host)) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530825 /*
826 * BAM Mode: Fall back on PIO if size is less
827 * than or equal to SPS_MIN_XFER_SIZE bytes.
828 */
829 if (xfer_size <= SPS_MIN_XFER_SIZE)
830 ret = false;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530831 } else if (is_dma_mode(host)) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530832 /*
833 * ADM Mode: Fall back on PIO if size is less than FIFO size
834 * or not integer multiple of FIFO size
835 */
836 if (xfer_size % MCI_FIFOSIZE)
837 ret = false;
838 } else {
839 /* PIO Mode */
840 ret = false;
841 }
842
843 return ret;
San Mehat9d2bd732009-09-22 16:44:22 -0700844}
845
846static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
847{
848 struct msmsdcc_nc_dmadata *nc;
849 dmov_box *box;
850 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700851 unsigned int n;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530852 int i, err = 0, box_cmd_cnt = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700853 struct scatterlist *sg = data->sg;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530854 unsigned int len, offset;
San Mehat9d2bd732009-09-22 16:44:22 -0700855
Krishna Konda25786ec2011-07-25 16:21:36 -0700856 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700857 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700858
Krishna Konda25786ec2011-07-25 16:21:36 -0700859 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
San Mehat9d2bd732009-09-22 16:44:22 -0700860
861 host->dma.sg = data->sg;
862 host->dma.num_ents = data->sg_len;
863
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530864 /* Prevent memory corruption */
865 BUG_ON(host->dma.num_ents > msmsdcc_get_nr_sg(host));
San Mehat56a8b5b2009-11-21 12:29:46 -0800866
San Mehat9d2bd732009-09-22 16:44:22 -0700867 nc = host->dma.nc;
868
San Mehat9d2bd732009-09-22 16:44:22 -0700869 if (data->flags & MMC_DATA_READ)
870 host->dma.dir = DMA_FROM_DEVICE;
871 else
872 host->dma.dir = DMA_TO_DEVICE;
873
Asutosh Dasaccacd42012-03-08 14:33:17 +0530874 if (!data->host_cookie) {
875 n = msmsdcc_prep_xfer(host, data);
876 if (unlikely(n < 0)) {
877 host->dma.sg = NULL;
878 host->dma.num_ents = 0;
879 return -ENOMEM;
880 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800881 }
San Mehat9d2bd732009-09-22 16:44:22 -0700882
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530883 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
884 host->curr.user_pages = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700885 box = &nc->cmd[0];
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530886 for (i = 0; i < host->dma.num_ents; i++) {
887 len = sg_dma_len(sg);
888 offset = 0;
889
890 do {
891 /* Check if we can do DMA */
892 if (!len || (box_cmd_cnt >= MMC_MAX_DMA_CMDS)) {
893 err = -ENOTSUPP;
894 goto unmap;
895 }
896
897 box->cmd = CMD_MODE_BOX;
898
899 if (len >= MMC_MAX_DMA_BOX_LENGTH) {
900 len = MMC_MAX_DMA_BOX_LENGTH;
901 len -= len % data->blksz;
902 }
903 rows = (len % MCI_FIFOSIZE) ?
904 (len / MCI_FIFOSIZE) + 1 :
905 (len / MCI_FIFOSIZE);
906
907 if (data->flags & MMC_DATA_READ) {
908 box->src_row_addr = msmsdcc_fifo_addr(host);
909 box->dst_row_addr = sg_dma_address(sg) + offset;
910 box->src_dst_len = (MCI_FIFOSIZE << 16) |
911 (MCI_FIFOSIZE);
912 box->row_offset = MCI_FIFOSIZE;
913 box->num_rows = rows * ((1 << 16) + 1);
914 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
915 } else {
916 box->src_row_addr = sg_dma_address(sg) + offset;
917 box->dst_row_addr = msmsdcc_fifo_addr(host);
918 box->src_dst_len = (MCI_FIFOSIZE << 16) |
919 (MCI_FIFOSIZE);
920 box->row_offset = (MCI_FIFOSIZE << 16);
921 box->num_rows = rows * ((1 << 16) + 1);
922 box->cmd |= CMD_DST_CRCI(host->dma.crci);
923 }
924
925 offset += len;
926 len = sg_dma_len(sg) - offset;
927 box++;
928 box_cmd_cnt++;
929 } while (len);
930 sg++;
931 }
932 /* Mark last command */
933 box--;
934 box->cmd |= CMD_LC;
San Mehat9d2bd732009-09-22 16:44:22 -0700935
936 /* location of command block must be 64 bit aligned */
937 BUG_ON(host->dma.cmd_busaddr & 0x07);
938
939 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
940 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
941 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
942 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
943
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530944 /* Flush all data to memory before starting dma */
945 mb();
946
947unmap:
948 if (err) {
Asutosh Dasaccacd42012-03-08 14:33:17 +0530949 if (!data->host_cookie)
950 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
951 host->dma.num_ents, host->dma.dir);
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530952 pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
953 mmc_hostname(host->mmc), err);
San Mehat9d2bd732009-09-22 16:44:22 -0700954 }
955
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530956 return err;
San Mehat9d2bd732009-09-22 16:44:22 -0700957}
958
Asutosh Dasaccacd42012-03-08 14:33:17 +0530959static int msmsdcc_prep_xfer(struct msmsdcc_host *host,
960 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -0800961{
Asutosh Dasaccacd42012-03-08 14:33:17 +0530962 int rc = 0;
963 unsigned int dir;
964
965 /* Prevent memory corruption */
966 BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
967
968 if (data->flags & MMC_DATA_READ)
969 dir = DMA_FROM_DEVICE;
970 else
971 dir = DMA_TO_DEVICE;
972
973 /* Make sg buffers DMA ready */
974 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
975 dir);
976
977 if (unlikely(rc != data->sg_len)) {
978 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
979 mmc_hostname(host->mmc), rc);
980 rc = -ENOMEM;
981 goto dma_map_err;
982 }
983
984 pr_debug("%s: %s: %s: sg_len=%d\n",
985 mmc_hostname(host->mmc), __func__,
986 dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
987 data->sg_len);
988
989 goto out;
990
991dma_map_err:
992 dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
993 data->flags);
994out:
995 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -0700996}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700997#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
998/**
999 * Submits data transfer request to SPS driver
1000 *
1001 * This function make sg (scatter gather) data buffers
1002 * DMA ready and then submits them to SPS driver for
1003 * transfer.
1004 *
1005 * @host - Pointer to sdcc host structure
1006 * @data - Pointer to mmc_data structure
1007 *
1008 * @return 0 if success else negative value
1009 */
1010static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
Asutosh Dasaccacd42012-03-08 14:33:17 +05301011 struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -07001012{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001013 int rc = 0;
1014 u32 flags;
1015 int i;
1016 u32 addr, len, data_cnt;
1017 struct scatterlist *sg = data->sg;
1018 struct sps_pipe *sps_pipe_handle;
1019
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001020 host->sps.sg = data->sg;
1021 host->sps.num_ents = data->sg_len;
1022 host->sps.xfer_req_cnt = 0;
1023 if (data->flags & MMC_DATA_READ) {
1024 host->sps.dir = DMA_FROM_DEVICE;
1025 sps_pipe_handle = host->sps.prod.pipe_handle;
1026 } else {
1027 host->sps.dir = DMA_TO_DEVICE;
1028 sps_pipe_handle = host->sps.cons.pipe_handle;
1029 }
1030
Asutosh Dasaccacd42012-03-08 14:33:17 +05301031 if (!data->host_cookie) {
1032 rc = msmsdcc_prep_xfer(host, data);
1033 if (unlikely(rc < 0)) {
1034 host->dma.sg = NULL;
1035 host->dma.num_ents = 0;
1036 goto out;
1037 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001038 }
1039
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001040 for (i = 0; i < data->sg_len; i++) {
1041 /*
1042 * Check if this is the last buffer to transfer?
1043 * If yes then set the INT and EOT flags.
1044 */
1045 len = sg_dma_len(sg);
1046 addr = sg_dma_address(sg);
1047 flags = 0;
1048 while (len > 0) {
1049 if (len > SPS_MAX_DESC_SIZE) {
1050 data_cnt = SPS_MAX_DESC_SIZE;
1051 } else {
1052 data_cnt = len;
1053 if (i == data->sg_len - 1)
1054 flags = SPS_IOVEC_FLAG_INT |
1055 SPS_IOVEC_FLAG_EOT;
1056 }
1057 rc = sps_transfer_one(sps_pipe_handle, addr,
1058 data_cnt, host, flags);
1059 if (rc) {
1060 pr_err("%s: sps_transfer_one() error! rc=%d,"
1061 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
1062 mmc_hostname(host->mmc), rc,
1063 (u32)sps_pipe_handle, (u32)sg, i);
1064 goto dma_map_err;
1065 }
1066 addr += data_cnt;
1067 len -= data_cnt;
1068 host->sps.xfer_req_cnt++;
1069 }
1070 sg++;
1071 }
1072 goto out;
1073
1074dma_map_err:
1075 /* unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +05301076 if (!data->host_cookie)
1077 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
1078 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001079out:
1080 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07001081}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001082#else
1083static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
1084 struct mmc_data *data) { return 0; }
1085#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -07001086
1087static void
San Mehat56a8b5b2009-11-21 12:29:46 -08001088msmsdcc_start_command_deferred(struct msmsdcc_host *host,
1089 struct mmc_command *cmd, u32 *c)
1090{
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301091 DBG(host, "op %02x arg %08x flags %08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001092 cmd->opcode, cmd->arg, cmd->flags);
1093
San Mehat56a8b5b2009-11-21 12:29:46 -08001094 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
1095
1096 if (cmd->flags & MMC_RSP_PRESENT) {
1097 if (cmd->flags & MMC_RSP_136)
1098 *c |= MCI_CPSM_LONGRSP;
1099 *c |= MCI_CPSM_RESPONSE;
1100 }
1101
1102 if (/*interrupt*/0)
1103 *c |= MCI_CPSM_INTERRUPT;
1104
Asutosh Das05049132012-05-09 12:38:15 +05301105 /* DAT_CMD bit should be set for all ADTC */
1106 if (mmc_cmd_type(cmd) == MMC_CMD_ADTC)
San Mehat56a8b5b2009-11-21 12:29:46 -08001107 *c |= MCI_CSPM_DATCMD;
1108
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001109 /* Check if AUTO CMD19 is required or not? */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301110 if (host->tuning_needed &&
1111 !(host->mmc->ios.timing == MMC_TIMING_MMC_HS200)) {
1112
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301113 /*
1114 * For open ended block read operation (without CMD23),
1115 * AUTO_CMD19 bit should be set while sending the READ command.
1116 * For close ended block read operation (with CMD23),
1117 * AUTO_CMD19 bit should be set while sending CMD23.
1118 */
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301119 if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
1120 host->curr.mrq->cmd->opcode ==
1121 MMC_READ_MULTIPLE_BLOCK) ||
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301122 (!host->curr.mrq->sbc &&
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301123 (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
1124 cmd->opcode == MMC_READ_MULTIPLE_BLOCK))) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301125 msmsdcc_enable_cdr_cm_sdc4_dll(host);
1126 *c |= MCI_CSPM_AUTO_CMD19;
1127 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001128 }
1129
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05301130 /* Clear CDR_EN bit for write operations */
1131 if (host->tuning_needed && cmd->mrq->data &&
1132 (cmd->mrq->data->flags & MMC_DATA_WRITE))
1133 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) &
1134 ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
1135
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301136 if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301137 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001138 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301139 }
1140
San Mehat56a8b5b2009-11-21 12:29:46 -08001141 if (cmd == cmd->mrq->stop)
1142 *c |= MCI_CSPM_MCIABORT;
1143
San Mehat56a8b5b2009-11-21 12:29:46 -08001144 if (host->curr.cmd != NULL) {
Girish K Sa3c76eb2011-10-11 11:44:09 +05301145 pr_err("%s: Overlapping command requests\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001146 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -08001147 }
1148 host->curr.cmd = cmd;
1149}
1150
1151static void
1152msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1153 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001154{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301155 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001156 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001157 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001158 unsigned int pio_irqmask = 0;
1159
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301160 BUG_ON(!data->sg);
1161 BUG_ON(!data->sg_len);
1162
San Mehat9d2bd732009-09-22 16:44:22 -07001163 host->curr.data = data;
1164 host->curr.xfer_size = data->blksz * data->blocks;
1165 host->curr.xfer_remain = host->curr.xfer_size;
1166 host->curr.data_xfered = 0;
1167 host->curr.got_dataend = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301168 host->curr.got_auto_prog_done = false;
San Mehat9d2bd732009-09-22 16:44:22 -07001169
San Mehat9d2bd732009-09-22 16:44:22 -07001170 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1171
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301172 if (host->curr.wait_for_auto_prog_done)
1173 datactrl |= MCI_AUTO_PROG_DONE;
San Mehat9d2bd732009-09-22 16:44:22 -07001174
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05301175 if (msmsdcc_is_dma_possible(host, data)) {
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301176 if (is_dma_mode(host) && !msmsdcc_config_dma(host, data)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001177 datactrl |= MCI_DPSM_DMAENABLE;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301178 } else if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001179 if (!msmsdcc_is_dml_busy(host)) {
1180 if (!msmsdcc_sps_start_xfer(host, data)) {
1181 /* Now kick start DML transfer */
1182 mb();
1183 msmsdcc_dml_start_xfer(host, data);
1184 datactrl |= MCI_DPSM_DMAENABLE;
1185 host->sps.busy = 1;
1186 }
1187 } else {
1188 /*
1189 * Can't proceed with new transfer as
1190 * previous trasnfer is already in progress.
1191 * There is no point of going into PIO mode
1192 * as well. Is this a time to do kernel panic?
1193 */
1194 pr_err("%s: %s: DML HW is busy!!!"
1195 " Can't perform new SPS transfers"
1196 " now\n", mmc_hostname(host->mmc),
1197 __func__);
1198 }
1199 }
1200 }
1201
1202 /* Is data transfer in PIO mode required? */
1203 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001204 if (data->flags & MMC_DATA_READ) {
1205 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1206 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1207 pio_irqmask |= MCI_RXDATAAVLBLMASK;
1208 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001209 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1210 MCI_TXFIFOEMPTYMASK;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001211
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001212 msmsdcc_sg_start(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001213 }
1214
1215 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301216 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
Subhash Jadavanif5277752011-10-12 16:47:52 +05301217 else if (host->curr.use_wr_data_pend)
1218 datactrl |= MCI_DATA_PEND;
San Mehat9d2bd732009-09-22 16:44:22 -07001219
San Mehat56a8b5b2009-11-21 12:29:46 -08001220 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001221 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001222 timeout = data->timeout_clks + (unsigned int)clks*2 ;
Subhash Jadavani63540362012-06-12 14:56:04 +05301223 WARN(!timeout,
1224 "%s: data timeout is zero. timeout_ns=0x%x, timeout_clks=0x%x\n",
1225 mmc_hostname(host->mmc), data->timeout_ns, data->timeout_clks);
San Mehat9d2bd732009-09-22 16:44:22 -07001226
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301227 if (is_dma_mode(host) && (datactrl & MCI_DPSM_DMAENABLE)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001228 /* Use ADM (Application Data Mover) HW for Data transfer */
1229 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001230 host->cmd_timeout = timeout;
1231 host->cmd_pio_irqmask = pio_irqmask;
1232 host->cmd_datactrl = datactrl;
1233 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001234
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001235 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1236 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001237 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001238
1239 if (cmd) {
1240 msmsdcc_start_command_deferred(host, cmd, &c);
1241 host->cmd_c = c;
1242 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001243 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1244 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1245 host->base + MMCIMASK0);
1246 mb();
1247 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001248 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001249 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001250 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001251
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001252 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001253
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001254 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1255 (~(MCI_IRQ_PIO))) | pio_irqmask,
1256 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001257 writel_relaxed(datactrl, base + MMCIDATACTRL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001258
1259 if (cmd) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05301260 /* Delay between data/command */
1261 msmsdcc_sync_reg_wr(host);
San Mehat56a8b5b2009-11-21 12:29:46 -08001262 /* Daisy-chain the command if requested */
1263 msmsdcc_start_command(host, cmd, c);
Subhash Jadavanidd432952012-03-28 11:25:56 +05301264 } else {
1265 /*
1266 * We don't need delay after writing to DATA_CTRL
1267 * register if we are not writing to CMD register
1268 * immediately after this. As we already have delay
1269 * before sending the command, we just need mb() here.
1270 */
1271 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001272 }
San Mehat9d2bd732009-09-22 16:44:22 -07001273 }
1274}
1275
1276static void
1277msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1278{
San Mehat56a8b5b2009-11-21 12:29:46 -08001279 msmsdcc_start_command_deferred(host, cmd, &c);
1280 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001281}
1282
1283static void
1284msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1285 unsigned int status)
1286{
1287 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001288 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
Subhash Jadavanib30c9822012-03-27 18:03:16 +05301289 || data->mrq->cmd->opcode == MMC_BUS_TEST_R
1290 || data->mrq->cmd->opcode ==
1291 MMC_SEND_TUNING_BLOCK_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001292 pr_err("%s: Data CRC error\n",
1293 mmc_hostname(host->mmc));
1294 pr_err("%s: opcode 0x%.8x\n", __func__,
1295 data->mrq->cmd->opcode);
1296 pr_err("%s: blksz %d, blocks %d\n", __func__,
1297 data->blksz, data->blocks);
1298 data->error = -EILSEQ;
1299 }
San Mehat9d2bd732009-09-22 16:44:22 -07001300 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001301 /* CRC is optional for the bus test commands, not all
1302 * cards respond back with CRC. However controller
1303 * waits for the CRC and times out. Hence ignore the
1304 * data timeouts during the Bustest.
1305 */
1306 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1307 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301308 pr_err("%s: CMD%d: Data timeout\n",
1309 mmc_hostname(host->mmc),
1310 data->mrq->cmd->opcode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001311 data->error = -ETIMEDOUT;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301312 msmsdcc_dump_sdcc_state(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001313 }
San Mehat9d2bd732009-09-22 16:44:22 -07001314 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001315 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001316 data->error = -EIO;
1317 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001318 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001319 data->error = -EIO;
1320 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001321 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001322 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001323 data->error = -EIO;
1324 }
San Mehat9d2bd732009-09-22 16:44:22 -07001325
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001326 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001327 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001328 host->dummy_52_needed = 0;
1329}
San Mehat9d2bd732009-09-22 16:44:22 -07001330
1331static int
1332msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1333{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001334 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001335 uint32_t *ptr = (uint32_t *) buffer;
1336 int count = 0;
1337
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301338 if (remain % 4)
1339 remain = ((remain >> 2) + 1) << 2;
1340
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001341 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1342
1343 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001344 ptr++;
1345 count += sizeof(uint32_t);
1346
1347 remain -= sizeof(uint32_t);
1348 if (remain == 0)
1349 break;
1350 }
1351 return count;
1352}
1353
1354static int
1355msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001356 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001357{
1358 void __iomem *base = host->base;
1359 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001360 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001361
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001362 while (readl_relaxed(base + MMCISTATUS) &
1363 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1364 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001365
San Mehat9d2bd732009-09-22 16:44:22 -07001366 count = min(remain, maxcnt);
1367
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301368 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1369 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001370 ptr += count;
1371 remain -= count;
1372
1373 if (remain == 0)
1374 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001375 }
1376 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001377
1378 return ptr - buffer;
1379}
1380
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001381/*
1382 * Copy up to a word (4 bytes) between a scatterlist
1383 * and a temporary bounce buffer when the word lies across
1384 * two pages. The temporary buffer can then be read to/
1385 * written from the FIFO once.
1386 */
1387static void _msmsdcc_sg_consume_word(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -07001388{
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001389 struct msmsdcc_pio_data *pio = &host->pio;
1390 unsigned int bytes_avail;
1391
1392 if (host->curr.data->flags & MMC_DATA_READ)
1393 memcpy(pio->sg_miter.addr, pio->bounce_buf,
1394 pio->bounce_buf_len);
1395 else
1396 memcpy(pio->bounce_buf, pio->sg_miter.addr,
1397 pio->bounce_buf_len);
1398
1399 while (pio->bounce_buf_len != 4) {
1400 if (!sg_miter_next(&pio->sg_miter))
1401 break;
1402 bytes_avail = min_t(unsigned int, pio->sg_miter.length,
1403 4 - pio->bounce_buf_len);
1404 if (host->curr.data->flags & MMC_DATA_READ)
1405 memcpy(pio->sg_miter.addr,
1406 &pio->bounce_buf[pio->bounce_buf_len],
1407 bytes_avail);
1408 else
1409 memcpy(&pio->bounce_buf[pio->bounce_buf_len],
1410 pio->sg_miter.addr, bytes_avail);
1411
1412 pio->sg_miter.consumed = bytes_avail;
1413 pio->bounce_buf_len += bytes_avail;
San Mehat9d2bd732009-09-22 16:44:22 -07001414 }
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001415}
1416
1417/*
1418 * Use sg_miter_next to return as many 4-byte aligned
1419 * chunks as possible, using a temporary 4 byte buffer
1420 * for alignment if necessary
1421 */
1422static int msmsdcc_sg_next(struct msmsdcc_host *host, char **buf, int *len)
1423{
1424 struct msmsdcc_pio_data *pio = &host->pio;
1425 unsigned int length, rlength;
1426 char *buffer;
1427
1428 if (!sg_miter_next(&pio->sg_miter))
1429 return 0;
1430
1431 buffer = pio->sg_miter.addr;
1432 length = pio->sg_miter.length;
1433
1434 if (length < host->curr.xfer_remain) {
1435 rlength = round_down(length, 4);
1436 if (rlength) {
1437 /*
1438 * We have a 4-byte aligned chunk.
1439 * The rounding will be reflected by
1440 * a call to msmsdcc_sg_consumed
1441 */
1442 length = rlength;
1443 goto sg_next_end;
1444 }
1445 /*
1446 * We have a length less than 4 bytes. Check to
1447 * see if more buffer is available, and combine
1448 * to make 4 bytes if possible.
1449 */
1450 pio->bounce_buf_len = length;
1451 memset(pio->bounce_buf, 0, 4);
1452
1453 /*
1454 * On a read, get 4 bytes from FIFO, and distribute
1455 * (4-bouce_buf_len) bytes into consecutive
1456 * sgl buffers when msmsdcc_sg_consumed is called
1457 */
1458 if (host->curr.data->flags & MMC_DATA_READ) {
1459 buffer = pio->bounce_buf;
1460 length = 4;
1461 goto sg_next_end;
1462 } else {
1463 _msmsdcc_sg_consume_word(host);
1464 buffer = pio->bounce_buf;
1465 length = pio->bounce_buf_len;
1466 }
1467 }
1468
1469sg_next_end:
1470 *buf = buffer;
1471 *len = length;
1472 return 1;
1473}
1474
1475/*
1476 * Update sg_miter.consumed based on how many bytes were
1477 * consumed. If the bounce buffer was used to read from FIFO,
1478 * redistribute into sgls.
1479 */
1480static void msmsdcc_sg_consumed(struct msmsdcc_host *host,
1481 unsigned int length)
1482{
1483 struct msmsdcc_pio_data *pio = &host->pio;
1484
1485 if (host->curr.data->flags & MMC_DATA_READ) {
1486 if (length > pio->sg_miter.consumed)
1487 /*
1488 * consumed 4 bytes, but sgl
1489 * describes < 4 bytes
1490 */
1491 _msmsdcc_sg_consume_word(host);
1492 else
1493 pio->sg_miter.consumed = length;
1494 } else
1495 if (length < pio->sg_miter.consumed)
1496 pio->sg_miter.consumed = length;
1497}
1498
1499static void msmsdcc_sg_start(struct msmsdcc_host *host)
1500{
1501 unsigned int sg_miter_flags = SG_MITER_ATOMIC;
1502
1503 host->pio.bounce_buf_len = 0;
1504
1505 if (host->curr.data->flags & MMC_DATA_READ)
1506 sg_miter_flags |= SG_MITER_TO_SG;
1507 else
1508 sg_miter_flags |= SG_MITER_FROM_SG;
1509
1510 sg_miter_start(&host->pio.sg_miter, host->curr.data->sg,
1511 host->curr.data->sg_len, sg_miter_flags);
1512}
1513
1514static void msmsdcc_sg_stop(struct msmsdcc_host *host)
1515{
1516 sg_miter_stop(&host->pio.sg_miter);
San Mehat9d2bd732009-09-22 16:44:22 -07001517}
1518
San Mehat1cd22962010-02-03 12:59:29 -08001519static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001520msmsdcc_pio_irq(int irq, void *dev_id)
1521{
1522 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001523 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001524 uint32_t status;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001525 unsigned long flags;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001526 unsigned int remain;
1527 char *buffer;
San Mehat9d2bd732009-09-22 16:44:22 -07001528
Murali Palnati36448a42011-09-02 15:06:18 +05301529 spin_lock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301530
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001531 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001532
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001533 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301534 (MCI_IRQ_PIO)) == 0) {
1535 spin_unlock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301536 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301537 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001538#if IRQ_DEBUG
1539 msmsdcc_print_status(host, "irq1-r", status);
1540#endif
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001541 local_irq_save(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001542
1543 do {
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001544 unsigned int len;
San Mehat9d2bd732009-09-22 16:44:22 -07001545
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001546 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1547 | MCI_RXDATAAVLBL)))
1548 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001549
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001550 if (!msmsdcc_sg_next(host, &buffer, &remain))
1551 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001552
San Mehat9d2bd732009-09-22 16:44:22 -07001553 len = 0;
1554 if (status & MCI_RXACTIVE)
1555 len = msmsdcc_pio_read(host, buffer, remain);
1556 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001557 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001558
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301559 /* len might have aligned to 32bits above */
1560 if (len > remain)
1561 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001562
San Mehat9d2bd732009-09-22 16:44:22 -07001563 host->curr.xfer_remain -= len;
1564 host->curr.data_xfered += len;
1565 remain -= len;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001566 msmsdcc_sg_consumed(host, len);
San Mehat9d2bd732009-09-22 16:44:22 -07001567
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001568 if (remain) /* Done with this page? */
1569 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001570
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001571 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001572 } while (1);
1573
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001574 msmsdcc_sg_stop(host);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001575 local_irq_restore(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001576
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001577 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1578 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1579 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1580 host->base + MMCIMASK0);
1581 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301582 /*
1583 * back to back write to MASK0 register don't need
1584 * synchronization delay.
1585 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001586 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1587 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1588 }
1589 mb();
1590 } else if (!host->curr.xfer_remain) {
1591 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1592 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1593 mb();
1594 }
San Mehat9d2bd732009-09-22 16:44:22 -07001595
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001596 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001597
1598 return IRQ_HANDLED;
1599}
1600
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001601static void
1602msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1603
1604static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1605 struct mmc_data *data)
1606{
1607 u32 loop_cnt = 0;
1608
1609 /*
1610 * For read commands with data less than fifo size, it is possible to
1611 * get DATAEND first and RXDATA_AVAIL might be set later because of
1612 * synchronization delay through the asynchronous RX FIFO. Thus, for
1613 * such cases, even after DATAEND interrupt is received software
1614 * should poll for RXDATA_AVAIL until the requested data is read out
1615 * of FIFO. This change is needed to get around this abnormal but
1616 * sometimes expected behavior of SDCC3 controller.
1617 *
1618 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1619 * after the data is loaded into RX FIFO. This would amount to less
1620 * than a microsecond and thus looping for 1000 times is good enough
1621 * for that delay.
1622 */
1623 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1624 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1625 spin_unlock(&host->lock);
1626 msmsdcc_pio_irq(1, host);
1627 spin_lock(&host->lock);
1628 }
1629 }
1630 if (loop_cnt == 1000) {
1631 pr_info("%s: Timed out while polling for Rx Data\n",
1632 mmc_hostname(host->mmc));
1633 data->error = -ETIMEDOUT;
1634 msmsdcc_reset_and_restore(host);
1635 }
1636}
1637
San Mehat9d2bd732009-09-22 16:44:22 -07001638static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1639{
1640 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001641
1642 host->curr.cmd = NULL;
subhashj8046ae12012-05-02 12:14:52 +05301643 if (mmc_resp_type(cmd))
1644 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1645 /*
1646 * Read rest of the response registers only if
1647 * long response is expected for this command
1648 */
1649 if (mmc_resp_type(cmd) & MMC_RSP_136) {
1650 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1651 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1652 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
1653 }
San Mehat9d2bd732009-09-22 16:44:22 -07001654
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001655 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301656 pr_debug("%s: CMD%d: Command timeout\n",
1657 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001658 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001659 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301660 !host->tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301661 pr_err("%s: CMD%d: Command CRC error\n",
1662 mmc_hostname(host->mmc), cmd->opcode);
1663 msmsdcc_dump_sdcc_state(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001664 cmd->error = -EILSEQ;
1665 }
1666
Subhash Jadavani8706ced2012-05-25 16:09:21 +05301667 if (!cmd->error) {
1668 if (cmd->cmd_timeout_ms > host->curr.req_tout_ms) {
1669 host->curr.req_tout_ms = cmd->cmd_timeout_ms;
1670 mod_timer(&host->req_tout_timer, (jiffies +
1671 msecs_to_jiffies(host->curr.req_tout_ms)));
1672 }
1673 }
1674
San Mehat9d2bd732009-09-22 16:44:22 -07001675 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001676 if (host->curr.data && host->dma.sg &&
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301677 is_dma_mode(host))
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001678 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001679 else if (host->curr.data && host->sps.sg &&
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301680 is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001681 /* Stop current SPS transfer */
1682 msmsdcc_sps_exit_curr_xfer(host);
1683 }
San Mehat9d2bd732009-09-22 16:44:22 -07001684 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301685 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001686 msmsdcc_stop_data(host);
1687 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301688 } else { /* host->data == NULL */
1689 if (!cmd->error && host->prog_enable) {
1690 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001691 host->prog_enable = 0;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301692 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001693 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301694 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301695 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301696 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301697 host->curr.wait_for_auto_prog_done = false;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001698 if (host->dummy_52_needed)
1699 host->dummy_52_needed = 0;
1700 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001701 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301702 msmsdcc_request_end(host, cmd->mrq);
1703 }
1704 }
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301705 } else if (cmd->data) {
Subhash Jadavanif5277752011-10-12 16:47:52 +05301706 if (cmd == host->curr.mrq->sbc)
1707 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1708 else if ((cmd->data->flags & MMC_DATA_WRITE) &&
1709 !host->curr.use_wr_data_pend)
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301710 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001711 }
1712}
1713
San Mehat9d2bd732009-09-22 16:44:22 -07001714static irqreturn_t
1715msmsdcc_irq(int irq, void *dev_id)
1716{
1717 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001718 u32 status;
1719 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001720 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001721
1722 spin_lock(&host->lock);
1723
1724 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001725 struct mmc_command *cmd;
1726 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001727
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001728 if (timer) {
1729 timer = 0;
1730 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001731 }
San Mehat9d2bd732009-09-22 16:44:22 -07001732
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05301733 if (!atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001734 pr_debug("%s: %s: SDIO async irq received\n",
1735 mmc_hostname(host->mmc), __func__);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301736
1737 /*
1738 * Only async interrupt can come when clocks are off,
1739 * disable further interrupts and enable them when
1740 * clocks are on.
1741 */
1742 if (!host->sdcc_irq_disabled) {
1743 disable_irq_nosync(irq);
1744 host->sdcc_irq_disabled = 1;
1745 }
1746
1747 /*
1748 * If mmc_card_wake_sdio_irq() is set, mmc core layer
1749 * will take care of signaling sdio irq during
1750 * mmc_sdio_resume().
1751 */
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301752 if (host->sdcc_suspended) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301753 /*
1754 * This is a wakeup interrupt so hold wakelock
1755 * until SDCC resume is handled.
1756 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001757 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301758 } else {
1759 spin_unlock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301760 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301761 spin_lock(&host->lock);
1762 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301763 ret = 1;
1764 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001765 }
1766
1767 status = readl_relaxed(host->base + MMCISTATUS);
1768
1769 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1770 (~(MCI_IRQ_PIO))) == 0)
San Mehat9d2bd732009-09-22 16:44:22 -07001771 break;
1772
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001773#if IRQ_DEBUG
1774 msmsdcc_print_status(host, "irq0-r", status);
1775#endif
1776 status &= readl_relaxed(host->base + MMCIMASK0);
1777 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301778 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301779 if (host->clk_rate <=
1780 msmsdcc_get_min_sup_clk_rate(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +05301781 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001782#if IRQ_DEBUG
1783 msmsdcc_print_status(host, "irq0-p", status);
1784#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001785
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001786 if (status & MCI_SDIOINTROPE) {
1787 if (host->sdcc_suspending)
1788 wake_lock(&host->sdio_suspend_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301789 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001790 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301791 spin_lock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001792 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001793 data = host->curr.data;
1794
1795 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001796 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1797 MCI_CMDTIMEOUT)) {
1798 if (status & MCI_CMDTIMEOUT)
1799 pr_debug("%s: dummy CMD52 timeout\n",
1800 mmc_hostname(host->mmc));
1801 if (status & MCI_CMDCRCFAIL)
1802 pr_debug("%s: dummy CMD52 CRC failed\n",
1803 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001804 host->dummy_52_sent = 0;
1805 host->dummy_52_needed = 0;
1806 if (data) {
1807 msmsdcc_stop_data(host);
1808 msmsdcc_request_end(host, data->mrq);
1809 }
1810 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001811 spin_unlock(&host->lock);
1812 return IRQ_HANDLED;
1813 }
1814 break;
1815 }
1816
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001817 /*
1818 * Check for proper command response
1819 */
1820 cmd = host->curr.cmd;
1821 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1822 MCI_CMDTIMEOUT | MCI_PROGDONE |
1823 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1824 msmsdcc_do_cmdirq(host, status);
1825 }
1826
Sathish Ambley081d7842011-11-29 11:19:41 -08001827 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001828 /* Check for data errors */
1829 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1830 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1831 msmsdcc_data_err(host, data, status);
1832 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301833 if (host->dma.sg && is_dma_mode(host))
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001834 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301835 else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001836 /* Stop current SPS transfer */
1837 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301838 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001839 msmsdcc_reset_and_restore(host);
1840 if (host->curr.data)
1841 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301842 if (!data->stop || (host->curr.mrq->sbc
1843 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001844 timer |=
1845 msmsdcc_request_end(host,
1846 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301847 else if ((host->curr.mrq->sbc
1848 && data->error) ||
1849 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001850 msmsdcc_start_command(host,
1851 data->stop,
1852 0);
1853 timer = 1;
1854 }
1855 }
1856 }
1857
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301858 /* Check for prog done */
1859 if (host->curr.wait_for_auto_prog_done &&
1860 (status & MCI_PROGDONE))
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301861 host->curr.got_auto_prog_done = true;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301862
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001863 /* Check for data done */
1864 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1865 host->curr.got_dataend = 1;
1866
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301867 if (host->curr.got_dataend &&
1868 (!host->curr.wait_for_auto_prog_done ||
1869 (host->curr.wait_for_auto_prog_done &&
1870 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001871 /*
1872 * If DMA is still in progress, we complete
1873 * via the completion handler
1874 */
1875 if (!host->dma.busy && !host->sps.busy) {
1876 /*
1877 * There appears to be an issue in the
1878 * controller where if you request a
1879 * small block transfer (< fifo size),
1880 * you may get your DATAEND/DATABLKEND
1881 * irq without the PIO data irq.
1882 *
1883 * Check to see if theres still data
1884 * to be read, and simulate a PIO irq.
1885 */
1886 if (data->flags & MMC_DATA_READ)
1887 msmsdcc_wait_for_rxdata(host,
1888 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001889 if (!data->error) {
1890 host->curr.data_xfered =
1891 host->curr.xfer_size;
1892 host->curr.xfer_remain -=
1893 host->curr.xfer_size;
1894 }
1895
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001896 if (!host->dummy_52_needed) {
1897 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301898 if (!data->stop ||
1899 (host->curr.mrq->sbc
1900 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001901 msmsdcc_request_end(
1902 host,
1903 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301904 else if ((host->curr.mrq->sbc
1905 && data->error) ||
1906 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001907 msmsdcc_start_command(
1908 host,
1909 data->stop, 0);
1910 timer = 1;
1911 }
1912 } else {
1913 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001914 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001915 &dummy52cmd,
1916 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001917 }
1918 }
1919 }
1920 }
1921
San Mehat9d2bd732009-09-22 16:44:22 -07001922 ret = 1;
1923 } while (status);
1924
1925 spin_unlock(&host->lock);
1926
San Mehat9d2bd732009-09-22 16:44:22 -07001927 return IRQ_RETVAL(ret);
1928}
1929
1930static void
Asutosh Dasaccacd42012-03-08 14:33:17 +05301931msmsdcc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
1932 bool is_first_request)
1933{
1934 struct msmsdcc_host *host = mmc_priv(mmc);
1935 struct mmc_data *data = mrq->data;
1936 int rc = 0;
1937
1938 if (unlikely(!data)) {
1939 pr_err("%s: %s cannot prepare null data\n", mmc_hostname(mmc),
1940 __func__);
1941 return;
1942 }
1943 if (unlikely(data->host_cookie)) {
1944 /* Very wrong */
1945 data->host_cookie = 0;
1946 pr_err("%s: %s Request reposted for prepare\n",
1947 mmc_hostname(mmc), __func__);
1948 return;
1949 }
1950
1951 if (!msmsdcc_is_dma_possible(host, data))
1952 return;
1953
1954 rc = msmsdcc_prep_xfer(host, data);
1955 if (unlikely(rc < 0)) {
1956 data->host_cookie = 0;
1957 return;
1958 }
1959
1960 data->host_cookie = 1;
1961}
1962
1963static void
1964msmsdcc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, int err)
1965{
1966 struct msmsdcc_host *host = mmc_priv(mmc);
1967 unsigned int dir;
1968 struct mmc_data *data = mrq->data;
1969
1970 if (unlikely(!data)) {
1971 pr_err("%s: %s cannot cleanup null data\n", mmc_hostname(mmc),
1972 __func__);
1973 return;
1974 }
1975 if (data->flags & MMC_DATA_READ)
1976 dir = DMA_FROM_DEVICE;
1977 else
1978 dir = DMA_TO_DEVICE;
1979
1980 if (data->host_cookie)
1981 dma_unmap_sg(mmc_dev(host->mmc), data->sg,
1982 data->sg_len, dir);
1983
1984 data->host_cookie = 0;
1985}
1986
1987static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001988msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1989{
Subhash Jadavanif5277752011-10-12 16:47:52 +05301990 if (mrq->data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001991 /* Queue/read data, daisy-chain command when data starts */
Subhash Jadavanif5277752011-10-12 16:47:52 +05301992 if ((mrq->data->flags & MMC_DATA_READ) ||
1993 host->curr.use_wr_data_pend)
1994 msmsdcc_start_data(host, mrq->data,
1995 mrq->sbc ? mrq->sbc : mrq->cmd,
1996 0);
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301997 else
Subhash Jadavanif5277752011-10-12 16:47:52 +05301998 msmsdcc_start_command(host,
1999 mrq->sbc ? mrq->sbc : mrq->cmd,
2000 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002001 } else {
2002 msmsdcc_start_command(host, mrq->cmd, 0);
2003 }
2004}
2005
2006static void
San Mehat9d2bd732009-09-22 16:44:22 -07002007msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
2008{
2009 struct msmsdcc_host *host = mmc_priv(mmc);
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302010 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07002011
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002012 /*
2013 * Get the SDIO AL client out of LPM.
2014 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002015 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002016 if (host->plat->is_sdio_al_client)
2017 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002018
Subhash Jadavanib5b07742011-08-29 17:48:07 +05302019 /* check if sps pipe reset is pending? */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05302020 if (is_sps_mode(host) && host->sps.pipe_reset_pending) {
Subhash Jadavanib5b07742011-08-29 17:48:07 +05302021 msmsdcc_sps_pipes_reset_and_restore(host);
2022 host->sps.pipe_reset_pending = false;
2023 }
San Mehat9d2bd732009-09-22 16:44:22 -07002024
2025 spin_lock_irqsave(&host->lock, flags);
2026
San Mehat9d2bd732009-09-22 16:44:22 -07002027 if (host->eject) {
2028 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
2029 mrq->cmd->error = 0;
2030 mrq->data->bytes_xfered = mrq->data->blksz *
2031 mrq->data->blocks;
2032 } else
2033 mrq->cmd->error = -ENOMEDIUM;
2034
2035 spin_unlock_irqrestore(&host->lock, flags);
2036 mmc_request_done(mmc, mrq);
2037 return;
2038 }
2039
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302040 /*
subhashjf181c292012-05-02 13:07:40 +05302041 * Don't start the request if SDCC is not in proper state to handle it
2042 */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302043 if (!host->pwr || !atomic_read(&host->clks_on)
2044 || host->sdcc_irq_disabled) {
subhashjf181c292012-05-02 13:07:40 +05302045 WARN(1, "%s: %s: SDCC is in bad state. don't process"
2046 " new request (CMD%d)\n", mmc_hostname(host->mmc),
2047 __func__, mrq->cmd->opcode);
2048 msmsdcc_dump_sdcc_state(host);
2049 mrq->cmd->error = -EIO;
2050 if (mrq->data) {
2051 mrq->data->error = -EIO;
2052 mrq->data->bytes_xfered = 0;
2053 }
2054 spin_unlock_irqrestore(&host->lock, flags);
2055 mmc_request_done(mmc, mrq);
2056 return;
2057 }
2058
2059 WARN(host->curr.mrq, "%s: %s: New request (CMD%d) received while"
2060 " other request (CMD%d) is in progress\n",
2061 mmc_hostname(host->mmc), __func__,
2062 mrq->cmd->opcode, host->curr.mrq->cmd->opcode);
2063
2064 /*
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302065 * Set timeout value to 10 secs (or more in case of buggy cards)
2066 */
2067 if ((mmc->card) && (mmc->card->quirks & MMC_QUIRK_INAND_DATA_TIMEOUT))
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302068 host->curr.req_tout_ms = 20000;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302069 else
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302070 host->curr.req_tout_ms = MSM_MMC_REQ_TIMEOUT;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302071 /*
2072 * Kick the software request timeout timer here with the timeout
2073 * value identified above
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302074 */
2075 mod_timer(&host->req_tout_timer,
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302076 (jiffies +
2077 msecs_to_jiffies(host->curr.req_tout_ms)));
San Mehat9d2bd732009-09-22 16:44:22 -07002078
San Mehat9d2bd732009-09-22 16:44:22 -07002079 host->curr.mrq = mrq;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302080 if (mrq->sbc) {
2081 mrq->sbc->mrq = mrq;
2082 mrq->sbc->data = mrq->data;
2083 }
2084
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302085 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05302086 if (is_auto_prog_done(host)) {
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302087 if (!mrq->stop)
2088 host->curr.wait_for_auto_prog_done = true;
2089 } else {
2090 if ((mrq->cmd->opcode == SD_IO_RW_EXTENDED) ||
2091 (mrq->cmd->opcode == 54))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002092 host->dummy_52_needed = 1;
2093 }
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302094
Subhash Jadavanif5277752011-10-12 16:47:52 +05302095 if ((mrq->cmd->opcode == MMC_WRITE_BLOCK) ||
2096 (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK))
2097 host->curr.use_wr_data_pend = true;
San Mehat9d2bd732009-09-22 16:44:22 -07002098 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302099
Subhash Jadavanif5277752011-10-12 16:47:52 +05302100 msmsdcc_request_start(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302101
San Mehat9d2bd732009-09-22 16:44:22 -07002102 spin_unlock_irqrestore(&host->lock, flags);
2103}
2104
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002105static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
2106 int min_uV, int max_uV)
2107{
2108 int rc = 0;
2109
2110 if (vreg->set_voltage_sup) {
2111 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
2112 if (rc) {
2113 pr_err("%s: regulator_set_voltage(%s) failed."
2114 " min_uV=%d, max_uV=%d, rc=%d\n",
2115 __func__, vreg->name, min_uV, max_uV, rc);
2116 }
2117 }
2118
2119 return rc;
2120}
2121
2122static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
2123 int uA_load)
2124{
2125 int rc = 0;
2126
Krishna Kondafea60182011-11-01 16:01:34 -07002127 /* regulators that do not support regulator_set_voltage also
2128 do not support regulator_set_optimum_mode */
2129 if (vreg->set_voltage_sup) {
2130 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
2131 if (rc < 0)
2132 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
2133 "uA_load=%d) failed. rc=%d\n", __func__,
2134 vreg->name, uA_load, rc);
2135 else
2136 /* regulator_set_optimum_mode() can return non zero
2137 * value even for success case.
2138 */
2139 rc = 0;
2140 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002141
2142 return rc;
2143}
2144
2145static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
2146 struct device *dev)
2147{
2148 int rc = 0;
2149
2150 /* check if regulator is already initialized? */
2151 if (vreg->reg)
2152 goto out;
2153
2154 /* Get the regulator handle */
2155 vreg->reg = regulator_get(dev, vreg->name);
2156 if (IS_ERR(vreg->reg)) {
2157 rc = PTR_ERR(vreg->reg);
2158 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
2159 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002160 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002161 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002162
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05302163 if (regulator_count_voltages(vreg->reg) > 0) {
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002164 vreg->set_voltage_sup = 1;
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05302165 /* sanity check */
2166 if (!vreg->high_vol_level || !vreg->hpm_uA) {
2167 pr_err("%s: %s invalid constraints specified\n",
2168 __func__, vreg->name);
2169 rc = -EINVAL;
2170 }
2171 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002172
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002173out:
2174 return rc;
2175}
2176
2177static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
2178{
2179 if (vreg->reg)
2180 regulator_put(vreg->reg);
2181}
2182
2183/* This init function should be called only once for each SDCC slot */
2184static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
2185{
2186 int rc = 0;
2187 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302188 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vdd_io_reg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002189 struct device *dev = mmc_dev(host->mmc);
2190
2191 curr_slot = host->plat->vreg_data;
2192 if (!curr_slot)
2193 goto out;
2194
2195 curr_vdd_reg = curr_slot->vdd_data;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302196 curr_vdd_io_reg = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002197
2198 if (is_init) {
2199 /*
2200 * Get the regulator handle from voltage regulator framework
2201 * and then try to set the voltage level for the regulator
2202 */
2203 if (curr_vdd_reg) {
2204 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
2205 if (rc)
2206 goto out;
2207 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302208 if (curr_vdd_io_reg) {
2209 rc = msmsdcc_vreg_init_reg(curr_vdd_io_reg, dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002210 if (rc)
2211 goto vdd_reg_deinit;
2212 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002213 rc = msmsdcc_vreg_reset(host);
2214 if (rc)
2215 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
2216 host->pdev_id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002217 goto out;
2218 } else {
2219 /* Deregister all regulators from regulator framework */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302220 goto vdd_io_reg_deinit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002221 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302222vdd_io_reg_deinit:
2223 if (curr_vdd_io_reg)
2224 msmsdcc_vreg_deinit_reg(curr_vdd_io_reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002225vdd_reg_deinit:
2226 if (curr_vdd_reg)
2227 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2228out:
2229 return rc;
2230}
2231
2232static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2233{
2234 int rc = 0;
2235
Subhash Jadavanicc922692011-08-01 23:05:01 +05302236 /* Put regulator in HPM (high power mode) */
2237 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2238 if (rc < 0)
2239 goto out;
2240
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002241 if (!vreg->is_enabled) {
2242 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302243 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2244 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002245 if (rc)
2246 goto out;
2247
2248 rc = regulator_enable(vreg->reg);
2249 if (rc) {
2250 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2251 __func__, vreg->name, rc);
2252 goto out;
2253 }
2254 vreg->is_enabled = true;
2255 }
2256
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002257out:
2258 return rc;
2259}
2260
Krishna Konda3c4142d2012-06-27 11:01:56 -07002261static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg, bool is_init)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002262{
2263 int rc = 0;
2264
2265 /* Never disable regulator marked as always_on */
2266 if (vreg->is_enabled && !vreg->always_on) {
2267 rc = regulator_disable(vreg->reg);
2268 if (rc) {
2269 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2270 __func__, vreg->name, rc);
2271 goto out;
2272 }
2273 vreg->is_enabled = false;
2274
2275 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2276 if (rc < 0)
2277 goto out;
2278
2279 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302280 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002281 if (rc)
2282 goto out;
Krishna Konda3c4142d2012-06-27 11:01:56 -07002283 } else if (vreg->is_enabled && vreg->always_on) {
2284 if (!is_init && vreg->lpm_sup) {
2285 /* Put always_on regulator in LPM (low power mode) */
2286 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2287 if (rc < 0)
2288 goto out;
2289 } else if (is_init && vreg->reset_at_init) {
2290 /**
2291 * The regulator might not actually be disabled if it
2292 * is shared and in use by other drivers.
2293 */
2294 rc = regulator_disable(vreg->reg);
2295 if (rc) {
2296 pr_err("%s: regulator_disable(%s) failed at " \
2297 "bootup. rc=%d\n", __func__,
2298 vreg->name, rc);
2299 goto out;
2300 }
2301 vreg->is_enabled = false;
2302 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002303 }
2304out:
2305 return rc;
2306}
2307
Krishna Konda3c4142d2012-06-27 11:01:56 -07002308static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable,
2309 bool is_init)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002310{
2311 int rc = 0, i;
2312 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302313 struct msm_mmc_reg_data *vreg_table[2];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002314
2315 curr_slot = host->plat->vreg_data;
2316 if (!curr_slot)
2317 goto out;
2318
Subhash Jadavani937c7502012-06-01 15:34:46 +05302319 vreg_table[0] = curr_slot->vdd_data;
2320 vreg_table[1] = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002321
2322 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2323 if (vreg_table[i]) {
2324 if (enable)
2325 rc = msmsdcc_vreg_enable(vreg_table[i]);
2326 else
Krishna Konda3c4142d2012-06-27 11:01:56 -07002327 rc = msmsdcc_vreg_disable(vreg_table[i],
2328 is_init);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002329 if (rc)
2330 goto out;
2331 }
2332 }
2333out:
2334 return rc;
2335}
2336
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002337/*
2338 * Reset vreg by ensuring it is off during probe. A call
2339 * to enable vreg is needed to balance disable vreg
2340 */
2341static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2342{
2343 int rc;
2344
Krishna Konda3c4142d2012-06-27 11:01:56 -07002345 rc = msmsdcc_setup_vreg(host, 1, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002346 if (rc)
2347 return rc;
Krishna Konda3c4142d2012-06-27 11:01:56 -07002348 rc = msmsdcc_setup_vreg(host, 0, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002349 return rc;
2350}
2351
Subhash Jadavani937c7502012-06-01 15:34:46 +05302352enum vdd_io_level {
2353 /* set vdd_io_data->low_vol_level */
2354 VDD_IO_LOW,
2355 /* set vdd_io_data->high_vol_level */
2356 VDD_IO_HIGH,
2357 /*
2358 * set whatever there in voltage_level (third argument) of
2359 * msmsdcc_set_vdd_io_vol() function.
2360 */
2361 VDD_IO_SET_LEVEL,
2362};
2363
2364static int msmsdcc_set_vdd_io_vol(struct msmsdcc_host *host,
2365 enum vdd_io_level level,
2366 unsigned int voltage_level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002367{
2368 int rc = 0;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302369 int set_level;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002370
2371 if (host->plat->vreg_data) {
Subhash Jadavani937c7502012-06-01 15:34:46 +05302372 struct msm_mmc_reg_data *vdd_io_reg =
2373 host->plat->vreg_data->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002374
Subhash Jadavani937c7502012-06-01 15:34:46 +05302375 if (vdd_io_reg && vdd_io_reg->is_enabled) {
2376 switch (level) {
2377 case VDD_IO_LOW:
2378 set_level = vdd_io_reg->low_vol_level;
2379 break;
2380 case VDD_IO_HIGH:
2381 set_level = vdd_io_reg->high_vol_level;
2382 break;
2383 case VDD_IO_SET_LEVEL:
2384 set_level = voltage_level;
2385 break;
2386 default:
2387 pr_err("%s: %s: invalid argument level = %d",
2388 mmc_hostname(host->mmc), __func__,
2389 level);
2390 rc = -EINVAL;
2391 goto out;
2392 }
2393 rc = msmsdcc_vreg_set_voltage(vdd_io_reg,
2394 set_level, set_level);
2395 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002396 }
2397
Subhash Jadavani937c7502012-06-01 15:34:46 +05302398out:
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302399 return rc;
2400}
2401
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002402static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2403{
2404 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2405 return 1;
2406 return 0;
2407}
2408
Asutosh Dasf5298c32012-04-03 14:51:47 +05302409/*
2410 * Any function calling msmsdcc_setup_clocks must
2411 * acquire clk_mutex. May sleep.
2412 */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302413static int msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002414{
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302415 int rc = 0;
2416
2417 if (enable && !atomic_read(&host->clks_on)) {
2418 if (!IS_ERR_OR_NULL(host->bus_clk)) {
2419 rc = clk_prepare_enable(host->bus_clk);
2420 if (rc) {
2421 pr_err("%s: %s: failed to enable the bus-clock with error %d\n",
2422 mmc_hostname(host->mmc), __func__, rc);
2423 goto out;
2424 }
2425 }
2426 if (!IS_ERR(host->pclk)) {
2427 rc = clk_prepare_enable(host->pclk);
2428 if (rc) {
2429 pr_err("%s: %s: failed to enable the pclk with error %d\n",
2430 mmc_hostname(host->mmc), __func__, rc);
2431 goto disable_bus;
2432 }
2433 }
2434 rc = clk_prepare_enable(host->clk);
2435 if (rc) {
2436 pr_err("%s: %s: failed to enable the host-clk with error %d\n",
2437 mmc_hostname(host->mmc), __func__, rc);
2438 goto disable_pclk;
2439 }
Subhash Jadavanidd432952012-03-28 11:25:56 +05302440 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302441 msmsdcc_delay(host);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302442 atomic_set(&host->clks_on, 1);
2443 } else if (!enable && atomic_read(&host->clks_on)) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05302444 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302445 msmsdcc_delay(host);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302446 clk_disable_unprepare(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002447 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302448 clk_disable_unprepare(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05302449 if (!IS_ERR_OR_NULL(host->bus_clk))
2450 clk_disable_unprepare(host->bus_clk);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302451 atomic_set(&host->clks_on, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002452 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302453 goto out;
2454
2455disable_pclk:
2456 if (!IS_ERR_OR_NULL(host->pclk))
2457 clk_disable_unprepare(host->pclk);
2458disable_bus:
2459 if (!IS_ERR_OR_NULL(host->bus_clk))
2460 clk_disable_unprepare(host->bus_clk);
2461out:
2462 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002463}
2464
2465static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2466 unsigned int req_clk)
2467{
2468 unsigned int sel_clk = -1;
2469
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302470 if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
2471 sel_clk = msmsdcc_get_min_sup_clk_rate(host);
2472 goto out;
2473 }
2474
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002475 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2476 unsigned char cnt;
2477
2478 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2479 if (host->plat->sup_clk_table[cnt] > req_clk)
2480 break;
2481 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2482 sel_clk = host->plat->sup_clk_table[cnt];
2483 break;
2484 } else
2485 sel_clk = host->plat->sup_clk_table[cnt];
2486 }
2487 } else {
2488 if ((req_clk < host->plat->msmsdcc_fmax) &&
2489 (req_clk > host->plat->msmsdcc_fmid))
2490 sel_clk = host->plat->msmsdcc_fmid;
2491 else
2492 sel_clk = req_clk;
2493 }
2494
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302495out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002496 return sel_clk;
2497}
2498
2499static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2500 struct msmsdcc_host *host)
2501{
2502 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2503 return host->plat->sup_clk_table[0];
2504 else
2505 return host->plat->msmsdcc_fmin;
2506}
2507
2508static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2509 struct msmsdcc_host *host)
2510{
2511 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2512 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2513 else
2514 return host->plat->msmsdcc_fmax;
2515}
2516
2517static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302518{
2519 struct msm_mmc_gpio_data *curr;
2520 int i, rc = 0;
2521
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002522 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302523 for (i = 0; i < curr->size; i++) {
2524 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002525 if (curr->gpio[i].is_always_on &&
2526 curr->gpio[i].is_enabled)
2527 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302528 rc = gpio_request(curr->gpio[i].no,
2529 curr->gpio[i].name);
2530 if (rc) {
2531 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2532 mmc_hostname(host->mmc),
2533 curr->gpio[i].no,
2534 curr->gpio[i].name, rc);
2535 goto free_gpios;
2536 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002537 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302538 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002539 if (curr->gpio[i].is_always_on)
2540 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302541 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002542 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302543 }
2544 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002545 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302546
2547free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002548 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302549 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002550 curr->gpio[i].is_enabled = false;
2551 }
2552out:
2553 return rc;
2554}
2555
2556static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2557{
2558 struct msm_mmc_pad_data *curr;
2559 int i;
2560
2561 curr = host->plat->pin_data->pad_data;
2562 for (i = 0; i < curr->drv->size; i++) {
2563 if (enable)
2564 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2565 curr->drv->on[i].val);
2566 else
2567 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2568 curr->drv->off[i].val);
2569 }
2570
2571 for (i = 0; i < curr->pull->size; i++) {
2572 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002573 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002574 curr->pull->on[i].val);
2575 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002576 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002577 curr->pull->off[i].val);
2578 }
2579
2580 return 0;
2581}
2582
2583static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2584{
2585 int rc = 0;
2586
2587 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2588 return 0;
2589
2590 if (host->plat->pin_data->is_gpio)
2591 rc = msmsdcc_setup_gpio(host, enable);
2592 else
2593 rc = msmsdcc_setup_pad(host, enable);
2594
2595 if (!rc)
2596 host->plat->pin_data->cfg_sts = enable;
2597
2598 return rc;
2599}
2600
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302601static int msmsdcc_cfg_mpm_sdiowakeup(struct msmsdcc_host *host,
2602 unsigned mode)
2603{
2604 int ret = 0;
2605 unsigned int pin = host->plat->mpm_sdiowakeup_int;
2606
2607 if (!pin)
2608 return 0;
2609
2610 switch (mode) {
2611 case SDC_DAT1_DISABLE:
2612 ret = msm_mpm_enable_pin(pin, 0);
2613 break;
2614 case SDC_DAT1_ENABLE:
2615 ret = msm_mpm_set_pin_type(pin, IRQ_TYPE_LEVEL_LOW);
2616 ret = msm_mpm_enable_pin(pin, 1);
2617 break;
2618 case SDC_DAT1_ENWAKE:
2619 ret = msm_mpm_set_pin_wake(pin, 1);
2620 break;
2621 case SDC_DAT1_DISWAKE:
2622 ret = msm_mpm_set_pin_wake(pin, 0);
2623 break;
2624 default:
2625 ret = -EINVAL;
2626 break;
2627 }
2628
2629 return ret;
2630}
2631
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302632static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2633{
2634 u32 pwr = 0;
2635 int ret = 0;
2636 struct mmc_host *mmc = host->mmc;
2637
2638 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2639 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2640 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
Krishna Konda3c4142d2012-06-27 11:01:56 -07002641 ret = msmsdcc_setup_vreg(host, !!ios->vdd, false);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302642
2643 if (ret) {
2644 pr_err("%s: Failed to setup voltage regulators\n",
2645 mmc_hostname(host->mmc));
2646 goto out;
2647 }
2648
2649 switch (ios->power_mode) {
2650 case MMC_POWER_OFF:
2651 pwr = MCI_PWR_OFF;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302652 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302653 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05302654 * If VDD IO rail is always on, set low voltage for VDD
2655 * IO rail when slot is not in use (like when card is not
2656 * present or during system suspend).
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302657 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302658 msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302659 msmsdcc_setup_pins(host, false);
2660 break;
2661 case MMC_POWER_UP:
2662 /* writing PWR_UP bit is redundant */
2663 pwr = MCI_PWR_UP;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302664 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302665
Subhash Jadavani937c7502012-06-01 15:34:46 +05302666 msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302667 msmsdcc_setup_pins(host, true);
2668 break;
2669 case MMC_POWER_ON:
2670 pwr = MCI_PWR_ON;
2671 break;
2672 }
2673
2674out:
2675 return pwr;
2676}
2677
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002678static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2679{
2680 unsigned int wakeup_irq;
2681
2682 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2683 host->plat->sdiowakeup_irq :
2684 host->core_irqres->start;
2685
2686 if (!host->irq_wake_enabled) {
2687 enable_irq_wake(wakeup_irq);
2688 host->irq_wake_enabled = true;
2689 }
2690}
2691
2692static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2693{
2694 unsigned int wakeup_irq;
2695
2696 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2697 host->plat->sdiowakeup_irq :
2698 host->core_irqres->start;
2699
2700 if (host->irq_wake_enabled) {
2701 disable_irq_wake(wakeup_irq);
2702 host->irq_wake_enabled = false;
2703 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302704}
2705
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05302706/* Returns required bandwidth in Bytes per Sec */
2707static unsigned int msmsdcc_get_bw_required(struct msmsdcc_host *host,
2708 struct mmc_ios *ios)
2709{
2710 unsigned int bw;
2711
2712 bw = host->clk_rate;
2713 /*
2714 * For DDR mode, SDCC controller clock will be at
2715 * the double rate than the actual clock that goes to card.
2716 */
2717 if (ios->bus_width == MMC_BUS_WIDTH_4)
2718 bw /= 2;
2719 else if (ios->bus_width == MMC_BUS_WIDTH_1)
2720 bw /= 8;
2721
2722 return bw;
2723}
2724
2725static int msmsdcc_msm_bus_get_vote_for_bw(struct msmsdcc_host *host,
2726 unsigned int bw)
2727{
2728 unsigned int *table = host->plat->msm_bus_voting_data->bw_vecs;
2729 unsigned int size = host->plat->msm_bus_voting_data->bw_vecs_size;
2730 int i;
2731
2732 if (host->msm_bus_vote.is_max_bw_needed && bw)
2733 return host->msm_bus_vote.max_bw_vote;
2734
2735 for (i = 0; i < size; i++) {
2736 if (bw <= table[i])
2737 break;
2738 }
2739
2740 if (i && (i == size))
2741 i--;
2742
2743 return i;
2744}
2745
2746static int msmsdcc_msm_bus_register(struct msmsdcc_host *host)
2747{
2748 int rc = 0;
2749 struct msm_bus_scale_pdata *use_cases;
2750
2751 if (host->plat->msm_bus_voting_data &&
2752 host->plat->msm_bus_voting_data->use_cases &&
2753 host->plat->msm_bus_voting_data->bw_vecs &&
2754 host->plat->msm_bus_voting_data->bw_vecs_size) {
2755 use_cases = host->plat->msm_bus_voting_data->use_cases;
2756 host->msm_bus_vote.client_handle =
2757 msm_bus_scale_register_client(use_cases);
2758 } else {
2759 return 0;
2760 }
2761
2762 if (!host->msm_bus_vote.client_handle) {
2763 pr_err("%s: msm_bus_scale_register_client() failed\n",
2764 mmc_hostname(host->mmc));
2765 rc = -EFAULT;
2766 } else {
2767 /* cache the vote index for minimum and maximum bandwidth */
2768 host->msm_bus_vote.min_bw_vote =
2769 msmsdcc_msm_bus_get_vote_for_bw(host, 0);
2770 host->msm_bus_vote.max_bw_vote =
2771 msmsdcc_msm_bus_get_vote_for_bw(host, UINT_MAX);
2772 }
2773
2774 return rc;
2775}
2776
2777static void msmsdcc_msm_bus_unregister(struct msmsdcc_host *host)
2778{
2779 if (host->msm_bus_vote.client_handle)
2780 msm_bus_scale_unregister_client(
2781 host->msm_bus_vote.client_handle);
2782}
2783
2784/*
2785 * This function must be called with host lock acquired.
2786 * Caller of this function should also ensure that msm bus client
2787 * handle is not null.
2788 */
2789static inline int msmsdcc_msm_bus_set_vote(struct msmsdcc_host *host,
2790 int vote,
2791 unsigned long flags)
2792{
2793 int rc = 0;
2794
2795 if (vote != host->msm_bus_vote.curr_vote) {
2796 spin_unlock_irqrestore(&host->lock, flags);
2797 rc = msm_bus_scale_client_update_request(
2798 host->msm_bus_vote.client_handle, vote);
2799 if (rc)
2800 pr_err("%s: msm_bus_scale_client_update_request() failed."
2801 " bus_client_handle=0x%x, vote=%d, err=%d\n",
2802 mmc_hostname(host->mmc),
2803 host->msm_bus_vote.client_handle, vote, rc);
2804 spin_lock_irqsave(&host->lock, flags);
2805 if (!rc)
2806 host->msm_bus_vote.curr_vote = vote;
2807 }
2808
2809 return rc;
2810}
2811
2812/*
2813 * Internal work. Work to set 0 bandwidth for msm bus.
2814 */
2815static void msmsdcc_msm_bus_work(struct work_struct *work)
2816{
2817 struct msmsdcc_host *host = container_of(work,
2818 struct msmsdcc_host,
2819 msm_bus_vote.vote_work.work);
2820 unsigned long flags;
2821
2822 if (!host->msm_bus_vote.client_handle)
2823 return;
2824
2825 spin_lock_irqsave(&host->lock, flags);
2826 /* don't vote for 0 bandwidth if any request is in progress */
2827 if (!host->curr.mrq)
2828 msmsdcc_msm_bus_set_vote(host,
2829 host->msm_bus_vote.min_bw_vote, flags);
2830 else
2831 pr_warning("%s: %s: SDCC transfer in progress. skipping"
2832 " bus voting to 0 bandwidth\n",
2833 mmc_hostname(host->mmc), __func__);
2834 spin_unlock_irqrestore(&host->lock, flags);
2835}
2836
2837/*
2838 * This function cancels any scheduled delayed work
2839 * and sets the bus vote based on ios argument.
2840 * If "ios" argument is NULL, bandwidth required is 0 else
2841 * calculate the bandwidth based on ios parameters.
2842 */
2843static void msmsdcc_msm_bus_cancel_work_and_set_vote(
2844 struct msmsdcc_host *host,
2845 struct mmc_ios *ios)
2846{
2847 unsigned long flags;
2848 unsigned int bw;
2849 int vote;
2850
2851 if (!host->msm_bus_vote.client_handle)
2852 return;
2853
2854 bw = ios ? msmsdcc_get_bw_required(host, ios) : 0;
2855
2856 cancel_delayed_work_sync(&host->msm_bus_vote.vote_work);
2857 spin_lock_irqsave(&host->lock, flags);
2858 vote = msmsdcc_msm_bus_get_vote_for_bw(host, bw);
2859 msmsdcc_msm_bus_set_vote(host, vote, flags);
2860 spin_unlock_irqrestore(&host->lock, flags);
2861}
2862
2863/* This function queues a work which will set the bandwidth requiement to 0 */
2864static void msmsdcc_msm_bus_queue_work(struct msmsdcc_host *host)
2865{
2866 unsigned long flags;
2867
2868 if (!host->msm_bus_vote.client_handle)
2869 return;
2870
2871 spin_lock_irqsave(&host->lock, flags);
2872 if (host->msm_bus_vote.min_bw_vote != host->msm_bus_vote.curr_vote)
2873 queue_delayed_work(system_nrt_wq,
2874 &host->msm_bus_vote.vote_work,
2875 msecs_to_jiffies(MSM_MMC_BUS_VOTING_DELAY));
2876 spin_unlock_irqrestore(&host->lock, flags);
2877}
2878
San Mehat9d2bd732009-09-22 16:44:22 -07002879static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302880msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
2881{
2882 struct mmc_host *mmc = host->mmc;
2883
2884 /*
2885 * SDIO_AL clients has different mechanism of handling LPM through
2886 * sdio_al driver itself. The sdio wakeup interrupt is configured as
2887 * part of that. Here, we are interested only in clients like WLAN.
2888 */
2889 if (!(mmc->card && mmc_card_sdio(mmc->card))
2890 || host->plat->is_sdio_al_client)
2891 goto out;
2892
2893 if (!host->sdcc_suspended) {
2894 /*
2895 * When MSM is not in power collapse and we
2896 * are disabling clocks, enable bit 22 in MASK0
2897 * to handle asynchronous SDIO interrupts.
2898 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302899 if (enable_wakeup_irq) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302900 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302901 mb();
2902 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302903 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302904 msmsdcc_sync_reg_wr(host);
2905 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302906 goto out;
2907 } else if (!mmc_card_wake_sdio_irq(mmc)) {
2908 /*
2909 * Wakeup MSM only if SDIO function drivers set
2910 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
2911 */
2912 goto out;
2913 }
2914
2915 if (enable_wakeup_irq) {
2916 if (!host->plat->sdiowakeup_irq) {
2917 /*
2918 * When there is no gpio line that can be configured
2919 * as wakeup interrupt handle it by configuring
2920 * asynchronous sdio interrupts and DAT1 line.
2921 */
2922 writel_relaxed(MCI_SDIOINTMASK,
2923 host->base + MMCIMASK0);
2924 mb();
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302925 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302926 /* configure sdcc core interrupt as wakeup interrupt */
2927 msmsdcc_enable_irq_wake(host);
2928 } else {
2929 /* Let gpio line handle wakeup interrupt */
2930 writel_relaxed(0, host->base + MMCIMASK0);
2931 mb();
2932 if (host->sdio_wakeupirq_disabled) {
2933 host->sdio_wakeupirq_disabled = 0;
2934 /* configure gpio line as wakeup interrupt */
2935 msmsdcc_enable_irq_wake(host);
2936 enable_irq(host->plat->sdiowakeup_irq);
2937 }
2938 }
2939 } else {
2940 if (!host->plat->sdiowakeup_irq) {
2941 /*
2942 * We may not have cleared bit 22 in the interrupt
2943 * handler as the clocks might be off at that time.
2944 */
2945 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302946 msmsdcc_sync_reg_wr(host);
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302947 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302948 msmsdcc_disable_irq_wake(host);
2949 } else if (!host->sdio_wakeupirq_disabled) {
2950 disable_irq_nosync(host->plat->sdiowakeup_irq);
2951 msmsdcc_disable_irq_wake(host);
2952 host->sdio_wakeupirq_disabled = 1;
2953 }
2954 }
2955out:
2956 return;
San Mehat9d2bd732009-09-22 16:44:22 -07002957}
2958
2959static void
2960msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2961{
2962 struct msmsdcc_host *host = mmc_priv(mmc);
2963 u32 clk = 0, pwr = 0;
2964 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002965 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002966 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002967
Sahitya Tummala7a892482011-01-18 11:22:49 +05302968
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302969 /*
2970 * Disable SDCC core interrupt until set_ios is completed.
2971 * This avoids any race conditions with interrupt raised
2972 * when turning on/off the clocks. One possible
2973 * scenario is SDIO operational interrupt while the clock
2974 * is turned off.
Asutosh Dasf5298c32012-04-03 14:51:47 +05302975 * host->lock is being released intermittently below.
2976 * Thus, prevent concurrent access to host.
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302977 */
2978
Asutosh Dasf5298c32012-04-03 14:51:47 +05302979 mutex_lock(&host->clk_mutex);
2980 DBG(host, "ios->clock = %u\n", ios->clock);
San Mehat9d2bd732009-09-22 16:44:22 -07002981 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302982 if (!host->sdcc_irq_disabled) {
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05302983 disable_irq_nosync(host->core_irqres->start);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302984 host->sdcc_irq_disabled = 1;
2985 }
San Mehatd0719e52009-12-03 10:58:54 -08002986 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002987
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05302988 /* Make sure sdcc core irq is synchronized */
2989 synchronize_irq(host->core_irqres->start);
2990
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302991 pwr = msmsdcc_setup_pwr(host, ios);
2992
2993 spin_lock_irqsave(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002994 if (ios->clock) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302995 spin_unlock_irqrestore(&host->lock, flags);
2996 rc = msmsdcc_setup_clocks(host, true);
2997 if (rc)
2998 goto out;
2999 spin_lock_irqsave(&host->lock, flags);
3000 writel_relaxed(host->mci_irqenable, host->base + MMCIMASK0);
3001 mb();
3002 msmsdcc_cfg_sdio_wakeup(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003003 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303004
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003005 /*
3006 * For DDR50 mode, controller needs clock rate to be
3007 * double than what is required on the SD card CLK pin.
3008 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05303009 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003010 /*
3011 * Make sure that we don't double the clock if
3012 * doubled clock rate is already set
3013 */
3014 if (!host->ddr_doubled_clk_rate ||
3015 (host->ddr_doubled_clk_rate &&
3016 (host->ddr_doubled_clk_rate != ios->clock))) {
3017 host->ddr_doubled_clk_rate =
3018 msmsdcc_get_sup_clk_rate(
3019 host, (ios->clock * 2));
3020 clock = host->ddr_doubled_clk_rate;
3021 }
3022 } else {
3023 host->ddr_doubled_clk_rate = 0;
3024 }
3025
3026 if (clock != host->clk_rate) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05303027 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003028 rc = clk_set_rate(host->clk, clock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303029 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003030 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303031 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003032 mmc_hostname(mmc), clock);
3033 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303034 host->reg_write_delay =
3035 (1 + ((3 * USEC_PER_SEC) /
3036 (host->clk_rate ? host->clk_rate :
3037 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003038 }
3039 /*
3040 * give atleast 2 MCLK cycles delay for clocks
3041 * and SDCC core to stabilize
3042 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05303043 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003044 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003045 clk |= MCI_CLK_ENABLE;
3046 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003047 if (ios->bus_width == MMC_BUS_WIDTH_8)
3048 clk |= MCI_CLK_WIDEBUS_8;
3049 else if (ios->bus_width == MMC_BUS_WIDTH_4)
3050 clk |= MCI_CLK_WIDEBUS_4;
3051 else
3052 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07003053
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003054 if (msmsdcc_is_pwrsave(host))
3055 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07003056
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003057 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07003058
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003059 host->tuning_needed = 0;
3060 /*
3061 * Select the controller timing mode according
3062 * to current bus speed mode
3063 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303064 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
3065 (ios->timing == MMC_TIMING_MMC_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003066 clk |= (4 << 14);
3067 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05303068 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003069 clk |= (3 << 14);
3070 } else {
3071 clk |= (2 << 14); /* feedback clock */
San Mehat9d2bd732009-09-22 16:44:22 -07003072 }
3073
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003074 /* Select free running MCLK as input clock of cm_dll_sdc4 */
3075 clk |= (2 << 23);
San Mehat9d2bd732009-09-22 16:44:22 -07003076
Subhash Jadavani00083572012-02-15 16:18:01 +05303077 /* Clear IO_PAD_PWR_SWITCH while powering off the card */
3078 if (!ios->vdd)
3079 host->io_pad_pwr_switch = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07003080
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003081 if (host->io_pad_pwr_switch)
3082 clk |= IO_PAD_PWR_SWITCH;
3083
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303084 /* Don't write into registers if clocks are disabled */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303085 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303086 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
3087 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303088 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003089 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303090 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
3091 host->pwr = pwr;
3092 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303093 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003094 }
San Mehat9d2bd732009-09-22 16:44:22 -07003095 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003096
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303097 if (!(clk & MCI_CLK_ENABLE) && atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303098 msmsdcc_cfg_sdio_wakeup(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303099 spin_unlock_irqrestore(&host->lock, flags);
3100 /*
3101 * May get a wake-up interrupt the instant we disable the
3102 * clocks. This would disable the wake-up interrupt.
3103 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003104 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303105 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003106 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303107
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303108 if (host->tuning_in_progress)
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303109 WARN(!atomic_read(&host->clks_on),
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303110 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303111
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303112 /* Let interrupts be disabled if the host is powered off */
3113 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
3114 enable_irq(host->core_irqres->start);
3115 host->sdcc_irq_disabled = 0;
3116 }
San Mehat4adbbcc2009-11-08 13:00:37 -08003117 spin_unlock_irqrestore(&host->lock, flags);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303118out:
Asutosh Dasf5298c32012-04-03 14:51:47 +05303119 mutex_unlock(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07003120}
3121
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003122int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
3123{
3124 struct msmsdcc_host *host = mmc_priv(mmc);
3125 u32 clk;
3126
3127 clk = readl_relaxed(host->base + MMCICLOCK);
3128 pr_debug("Changing to pwr_save=%d", pwrsave);
3129 if (pwrsave && msmsdcc_is_pwrsave(host))
3130 clk |= MCI_CLK_PWRSAVE;
3131 else
3132 clk &= ~MCI_CLK_PWRSAVE;
3133 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303134 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003135
3136 return 0;
3137}
3138
3139static int msmsdcc_get_ro(struct mmc_host *mmc)
3140{
3141 int status = -ENOSYS;
3142 struct msmsdcc_host *host = mmc_priv(mmc);
3143
3144 if (host->plat->wpswitch) {
3145 status = host->plat->wpswitch(mmc_dev(mmc));
3146 } else if (host->plat->wpswitch_gpio) {
3147 status = gpio_request(host->plat->wpswitch_gpio,
3148 "SD_WP_Switch");
3149 if (status) {
3150 pr_err("%s: %s: Failed to request GPIO %d\n",
3151 mmc_hostname(mmc), __func__,
3152 host->plat->wpswitch_gpio);
3153 } else {
3154 status = gpio_direction_input(
3155 host->plat->wpswitch_gpio);
3156 if (!status) {
3157 /*
3158 * Wait for atleast 300ms as debounce
3159 * time for GPIO input to stabilize.
3160 */
3161 msleep(300);
3162 status = gpio_get_value_cansleep(
3163 host->plat->wpswitch_gpio);
Sujit Reddy Thumma8f912ea2012-06-22 16:18:43 +05303164 status ^= !host->plat->is_wpswitch_active_low;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003165 }
3166 gpio_free(host->plat->wpswitch_gpio);
3167 }
3168 }
3169
3170 if (status < 0)
3171 status = -ENOSYS;
3172 pr_debug("%s: Card read-only status %d\n", __func__, status);
3173
3174 return status;
San Mehat9d2bd732009-09-22 16:44:22 -07003175}
3176
3177static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
3178{
3179 struct msmsdcc_host *host = mmc_priv(mmc);
3180 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003181
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303182 /*
3183 * We may come here with clocks turned off in that case don't
3184 * attempt to write into MASK0 register. While turning on the
3185 * clocks mci_irqenable will be written to MASK0 register.
3186 */
San Mehat9d2bd732009-09-22 16:44:22 -07003187
3188 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003189 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003190 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303191 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303192 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003193 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303194 mb();
3195 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003196 } else {
3197 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303198 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303199 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003200 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303201 mb();
3202 }
San Mehat9d2bd732009-09-22 16:44:22 -07003203 }
3204 spin_unlock_irqrestore(&host->lock, flags);
3205}
3206
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003207#ifdef CONFIG_PM_RUNTIME
subhashj245831e2012-04-30 18:46:17 +05303208static void msmsdcc_print_rpm_info(struct msmsdcc_host *host)
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003209{
subhashj245831e2012-04-30 18:46:17 +05303210 struct device *dev = mmc_dev(host->mmc);
3211
3212 pr_info("%s: RPM: runtime_status=%d, usage_count=%d,"
3213 " is_suspended=%d, disable_depth=%d, runtime_error=%d,"
3214 " request_pending=%d, request=%d\n",
3215 mmc_hostname(host->mmc), dev->power.runtime_status,
3216 atomic_read(&dev->power.usage_count),
3217 dev->power.is_suspended, dev->power.disable_depth,
3218 dev->power.runtime_error, dev->power.request_pending,
3219 dev->power.request);
3220}
3221
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003222static int msmsdcc_enable(struct mmc_host *mmc)
3223{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003224 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003225 struct device *dev = mmc->parent;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003226 struct msmsdcc_host *host = mmc_priv(mmc);
3227
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303228 msmsdcc_pm_qos_update_latency(host, 1);
3229
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003230 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303231 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003232
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003233 if (host->sdcc_suspended && host->pending_resume &&
3234 !pm_runtime_suspended(dev)) {
3235 host->pending_resume = false;
3236 pm_runtime_get_noresume(dev);
3237 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303238 goto skip_get_sync;
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003239 }
3240
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303241 if (dev->power.runtime_status == RPM_SUSPENDING) {
3242 if (mmc->suspend_task == current) {
3243 pm_runtime_get_noresume(dev);
3244 goto out;
3245 }
Sujit Reddy Thumma112bd752012-06-20 12:29:45 +05303246 } else if (dev->power.runtime_status == RPM_RESUMING) {
3247 pm_runtime_get_noresume(dev);
3248 goto out;
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303249 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003250
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303251 rc = pm_runtime_get_sync(dev);
3252
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303253skip_get_sync:
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303254 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003255 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3256 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303257 msmsdcc_print_rpm_info(host);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303258 return rc;
3259 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303260out:
3261 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303262 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003263}
3264
Steve Mucklef132c6c2012-06-06 18:30:57 -07003265static int msmsdcc_disable(struct mmc_host *mmc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003266{
3267 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303268 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003269
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303270 msmsdcc_pm_qos_update_latency(host, 0);
3271
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303272 if (mmc->card && mmc_card_sdio(mmc->card)) {
3273 rc = 0;
3274 goto out;
3275 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303276
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303277 if (host->plat->disable_runtime_pm)
3278 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003279
3280 rc = pm_runtime_put_sync(mmc->parent);
3281
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003282 /*
3283 * Ignore -EAGAIN as that is not fatal, it means that
3284 * either runtime usage count is non-zero or the runtime
3285 * pm itself is disabled or not in proper state to process
3286 * idle notification.
3287 */
3288 if (rc < 0 && (rc != -EAGAIN)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003289 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3290 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303291 msmsdcc_print_rpm_info(host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003292 return rc;
3293 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303294
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303295out:
3296 msmsdcc_msm_bus_queue_work(host);
3297 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003298}
3299#else
subhashj245831e2012-04-30 18:46:17 +05303300static void msmsdcc_print_rpm_info(struct msmsdcc_host *host) {}
3301
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303302static int msmsdcc_enable(struct mmc_host *mmc)
3303{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003304 struct device *dev = mmc->parent;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303305 struct msmsdcc_host *host = mmc_priv(mmc);
3306 unsigned long flags;
Sujit Reddy Thumma7f5051c2012-05-04 10:14:07 +05303307 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303308
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303309 msmsdcc_pm_qos_update_latency(host, 1);
3310
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303311 if (mmc->card && mmc_card_sdio(mmc->card)) {
3312 rc = 0;
3313 goto out;
3314 }
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003315
3316 if (host->sdcc_suspended && host->pending_resume) {
3317 host->pending_resume = false;
3318 rc = msmsdcc_runtime_resume(dev);
3319 goto out;
3320 }
3321
Asutosh Dasf5298c32012-04-03 14:51:47 +05303322 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303323 rc = msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303324 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303325
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003326out:
3327 if (rc < 0) {
3328 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3329 __func__, rc);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303330 msmsdcc_pm_qos_update_latency(host, 0);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003331 return rc;
3332 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303333 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303334 return 0;
3335}
3336
Steve Mucklef132c6c2012-06-06 18:30:57 -07003337static int msmsdcc_disable(struct mmc_host *mmc)
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303338{
3339 struct msmsdcc_host *host = mmc_priv(mmc);
3340 unsigned long flags;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303341 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303342
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303343 msmsdcc_pm_qos_update_latency(host, 0);
3344
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303345 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303346 goto out;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303347
Asutosh Dasf5298c32012-04-03 14:51:47 +05303348 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303349 rc = msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303350 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303351
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303352 if (rc) {
3353 msmsdcc_pm_qos_update_latency(host, 1);
3354 return rc;
3355 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303356out:
3357 msmsdcc_msm_bus_queue_work(host);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303358 return rc;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303359}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003360#endif
3361
Subhash Jadavani937c7502012-06-01 15:34:46 +05303362static int msmsdcc_switch_io_voltage(struct mmc_host *mmc,
3363 struct mmc_ios *ios)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003364{
3365 struct msmsdcc_host *host = mmc_priv(mmc);
3366 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303367 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003368
Subhash Jadavani00083572012-02-15 16:18:01 +05303369 spin_lock_irqsave(&host->lock, flags);
3370 host->io_pad_pwr_switch = 0;
3371 spin_unlock_irqrestore(&host->lock, flags);
3372
Subhash Jadavani937c7502012-06-01 15:34:46 +05303373 switch (ios->signal_voltage) {
3374 case MMC_SIGNAL_VOLTAGE_330:
3375 /* Set VDD IO to high voltage range (2.7v - 3.6v) */
3376 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303377 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303378 case MMC_SIGNAL_VOLTAGE_180:
3379 break;
3380 case MMC_SIGNAL_VOLTAGE_120:
3381 /*
3382 * For eMMC cards, VDD_IO voltage range must be changed
3383 * only if it operates in HS200 SDR 1.2V mode or in
3384 * DDR 1.2V mode.
3385 */
3386 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_SET_LEVEL, 1200000);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003387 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303388 default:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003389 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303390 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003391 goto out;
3392 }
San Mehat9d2bd732009-09-22 16:44:22 -07003393
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003394 /*
3395 * If we are here means voltage switch from high voltage to
3396 * low voltage is required
3397 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303398 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003399
3400 /*
3401 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
3402 * register until they become all zeros.
3403 */
3404 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303405 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003406 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
3407 mmc_hostname(mmc), __func__);
3408 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07003409 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003410
3411 /* Stop SD CLK output. */
3412 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3413 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303414 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003415 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003416
3417 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05303418 * Switch VDD Io from high voltage range (2.7v - 3.6v) to
3419 * low voltage range (1.7v - 1.95v).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003420 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303421 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303422 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003423 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003424
3425 spin_lock_irqsave(&host->lock, flags);
3426 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3427 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303428 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003429 host->io_pad_pwr_switch = 1;
3430 spin_unlock_irqrestore(&host->lock, flags);
3431
3432 /* Wait 5 ms for the voltage regulater in the card to become stable. */
3433 usleep_range(5000, 5500);
3434
3435 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303436 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003437 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3438 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303439 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003440 spin_unlock_irqrestore(&host->lock, flags);
3441
3442 /*
3443 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
3444 * don't become all ones within 1 ms then a Voltage Switch
3445 * sequence has failed and a power cycle to the card is required.
3446 * Otherwise Voltage Switch sequence is completed successfully.
3447 */
3448 usleep_range(1000, 1500);
3449
3450 spin_lock_irqsave(&host->lock, flags);
3451 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
3452 != (0xF << 1)) {
3453 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
3454 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303455 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003456 goto out_unlock;
3457 }
3458
3459out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303460 /* Enable PWRSAVE */
3461 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3462 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303463 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003464 spin_unlock_irqrestore(&host->lock, flags);
3465out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303466 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003467}
3468
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303469static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003470{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003471 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003472
3473 /* Program the MCLK value to MCLK_FREQ bit field */
3474 if (host->clk_rate <= 112000000)
3475 mclk_freq = 0;
3476 else if (host->clk_rate <= 125000000)
3477 mclk_freq = 1;
3478 else if (host->clk_rate <= 137000000)
3479 mclk_freq = 2;
3480 else if (host->clk_rate <= 150000000)
3481 mclk_freq = 3;
3482 else if (host->clk_rate <= 162000000)
3483 mclk_freq = 4;
3484 else if (host->clk_rate <= 175000000)
3485 mclk_freq = 5;
3486 else if (host->clk_rate <= 187000000)
3487 mclk_freq = 6;
3488 else if (host->clk_rate <= 200000000)
3489 mclk_freq = 7;
3490
3491 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3492 & ~(7 << 24)) | (mclk_freq << 24)),
3493 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003494}
3495
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303496/* Initialize the DLL (Programmable Delay Line ) */
3497static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003498{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003499 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303500 unsigned long flags;
3501 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003502
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303503 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003504 /*
3505 * Make sure that clock is always enabled when DLL
3506 * tuning is in progress. Keeping PWRSAVE ON may
3507 * turn off the clock. So let's disable the PWRSAVE
3508 * here and re-enable it once tuning is completed.
3509 */
3510 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3511 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303512 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303513
3514 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3515 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3516 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3517
3518 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3519 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3520 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3521
3522 msmsdcc_cm_sdc4_dll_set_freq(host);
3523
3524 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3525 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3526 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3527
3528 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3529 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3530 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3531
3532 /* Set DLL_EN bit to 1. */
3533 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3534 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3535
3536 /* Set CK_OUT_EN bit to 1. */
3537 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3538 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3539
3540 wait_cnt = 50;
3541 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3542 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3543 /* max. wait for 50us sec for LOCK bit to be set */
3544 if (--wait_cnt == 0) {
3545 pr_err("%s: %s: DLL failed to LOCK\n",
3546 mmc_hostname(host->mmc), __func__);
3547 rc = -ETIMEDOUT;
3548 goto out;
3549 }
3550 /* wait for 1us before polling again */
3551 udelay(1);
3552 }
3553
3554out:
3555 /* re-enable PWRSAVE */
3556 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3557 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303558 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303559 spin_unlock_irqrestore(&host->lock, flags);
3560
3561 return rc;
3562}
3563
3564static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3565 u8 poll)
3566{
3567 int rc = 0;
3568 u32 wait_cnt = 50;
3569 u8 ck_out_en = 0;
3570
3571 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3572 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3573 MCI_CK_OUT_EN);
3574
3575 while (ck_out_en != poll) {
3576 if (--wait_cnt == 0) {
3577 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3578 mmc_hostname(host->mmc), __func__, poll);
3579 rc = -ETIMEDOUT;
3580 goto out;
3581 }
3582 udelay(1);
3583
3584 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3585 MCI_CK_OUT_EN);
3586 }
3587out:
3588 return rc;
3589}
3590
3591/*
3592 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3593 * calibration sequence. This function should be called before
3594 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3595 * commands (CMD17/CMD18).
3596 *
3597 * This function gets called when host spinlock acquired.
3598 */
3599static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3600{
3601 int rc = 0;
3602 u32 config;
3603
3604 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3605 config |= MCI_CDR_EN;
3606 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3607 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3608
3609 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3610 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3611 if (rc)
3612 goto err_out;
3613
3614 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3615 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3616 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3617
3618 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3619 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3620 if (rc)
3621 goto err_out;
3622
3623 goto out;
3624
3625err_out:
3626 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3627out:
3628 return rc;
3629}
3630
3631static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3632 u8 phase)
3633{
3634 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303635 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3636 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3637 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303638 unsigned long flags;
3639 u32 config;
3640
3641 spin_lock_irqsave(&host->lock, flags);
3642
3643 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3644 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3645 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3646 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3647
3648 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3649 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3650 if (rc)
3651 goto err_out;
3652
3653 /*
3654 * Write the selected DLL clock output phase (0 ... 15)
3655 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
3656 */
3657 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3658 & ~(0xF << 20))
3659 | (grey_coded_phase_table[phase] << 20)),
3660 host->base + MCI_DLL_CONFIG);
3661
3662 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3663 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3664 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3665
3666 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3667 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3668 if (rc)
3669 goto err_out;
3670
3671 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3672 config |= MCI_CDR_EN;
3673 config &= ~MCI_CDR_EXT_EN;
3674 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3675 goto out;
3676
3677err_out:
3678 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3679 mmc_hostname(host->mmc), __func__, phase);
3680out:
3681 spin_unlock_irqrestore(&host->lock, flags);
3682 return rc;
3683}
3684
3685/*
3686 * Find out the greatest range of consecuitive selected
3687 * DLL clock output phases that can be used as sampling
3688 * setting for SD3.0 UHS-I card read operation (in SDR104
3689 * timing mode) or for eMMC4.5 card read operation (in HS200
3690 * timing mode).
3691 * Select the 3/4 of the range and configure the DLL with the
3692 * selected DLL clock output phase.
3693*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303694static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303695 u8 *phase_table, u8 total_phases)
3696{
Subhash Jadavani6159c622012-03-15 19:05:55 +05303697 #define MAX_PHASES 16
Subhash Jadavani34187042012-03-02 10:59:49 +05303698 int ret;
Subhash Jadavani6159c622012-03-15 19:05:55 +05303699 u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
3700 u8 phases_per_row[MAX_PHASES] = {0};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303701 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303702 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3703 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303704
Subhash Jadavani6159c622012-03-15 19:05:55 +05303705 if (!total_phases || (total_phases > MAX_PHASES)) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303706 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3707 mmc_hostname(host->mmc), __func__, total_phases);
3708 return -EINVAL;
3709 }
3710
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303711 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303712 ranges[row_index][col_index] = phase_table[cnt];
3713 phases_per_row[row_index] += 1;
3714 col_index++;
3715
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303716 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303717 continue;
3718 /* check if next phase in phase_table is consecutive or not */
3719 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3720 row_index++;
3721 col_index = 0;
3722 }
3723 }
3724
Subhash Jadavani6159c622012-03-15 19:05:55 +05303725 if (row_index >= MAX_PHASES)
3726 return -EINVAL;
3727
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303728 /* Check if phase-0 is present in first valid window? */
3729 if (!ranges[0][0]) {
3730 phase_0_found = true;
3731 phase_0_raw_index = 0;
3732 /* Check if cycle exist between 2 valid windows */
3733 for (cnt = 1; cnt <= row_index; cnt++) {
3734 if (phases_per_row[cnt]) {
Subhash Jadavani6159c622012-03-15 19:05:55 +05303735 for (i = 0; i < phases_per_row[cnt]; i++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303736 if (ranges[cnt][i] == 15) {
3737 phase_15_found = true;
3738 phase_15_raw_index = cnt;
3739 break;
3740 }
3741 }
3742 }
3743 }
3744 }
3745
3746 /* If 2 valid windows form cycle then merge them as single window */
3747 if (phase_0_found && phase_15_found) {
3748 /* number of phases in raw where phase 0 is present */
3749 u8 phases_0 = phases_per_row[phase_0_raw_index];
3750 /* number of phases in raw where phase 15 is present */
3751 u8 phases_15 = phases_per_row[phase_15_raw_index];
3752
Subhash Jadavani6159c622012-03-15 19:05:55 +05303753 if (phases_0 + phases_15 >= MAX_PHASES)
3754 /*
3755 * If there are more than 1 phase windows then total
3756 * number of phases in both the windows should not be
3757 * more than or equal to MAX_PHASES.
3758 */
3759 return -EINVAL;
3760
3761 /* Merge 2 cyclic windows */
3762 i = phases_15;
3763 for (cnt = 0; cnt < phases_0; cnt++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303764 ranges[phase_15_raw_index][i] =
3765 ranges[phase_0_raw_index][cnt];
Subhash Jadavani6159c622012-03-15 19:05:55 +05303766 if (++i >= MAX_PHASES)
3767 break;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303768 }
Subhash Jadavani6159c622012-03-15 19:05:55 +05303769
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303770 phases_per_row[phase_0_raw_index] = 0;
3771 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
3772 }
3773
3774 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303775 if (phases_per_row[cnt] > curr_max) {
3776 curr_max = phases_per_row[cnt];
3777 selected_row_index = cnt;
3778 }
3779 }
3780
Subhash Jadavani6159c622012-03-15 19:05:55 +05303781 i = ((curr_max * 3) / 4);
3782 if (i)
3783 i--;
3784
Subhash Jadavani34187042012-03-02 10:59:49 +05303785 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303786
Subhash Jadavani6159c622012-03-15 19:05:55 +05303787 if (ret >= MAX_PHASES) {
3788 ret = -EINVAL;
3789 pr_err("%s: %s: invalid phase selected=%d\n",
3790 mmc_hostname(host->mmc), __func__, ret);
3791 }
3792
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303793 return ret;
3794}
3795
Girish K Sa3f41692012-02-29 12:00:09 +05303796static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303797{
3798 int rc = 0;
3799 struct msmsdcc_host *host = mmc_priv(mmc);
3800 unsigned long flags;
3801 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303802 const u32 *tuning_block_pattern = tuning_block_64;
3803 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303804
3805 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
3806
3807 /* Tuning is only required for SDR104 modes */
3808 if (!host->tuning_needed) {
3809 rc = 0;
3810 goto exit;
3811 }
3812
3813 spin_lock_irqsave(&host->lock, flags);
3814 WARN(!host->pwr, "SDCC power is turned off\n");
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303815 WARN(!atomic_read(&host->clks_on), "SDCC clocks are turned off\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303816 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
3817
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303818 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303819 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
3820 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
3821 tuning_block_pattern = tuning_block_128;
3822 size = sizeof(tuning_block_128);
3823 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303824 spin_unlock_irqrestore(&host->lock, flags);
3825
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003826 /* first of all reset the tuning block */
3827 rc = msmsdcc_init_cm_sdc4_dll(host);
3828 if (rc)
3829 goto out;
3830
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303831 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003832 if (!data_buf) {
3833 rc = -ENOMEM;
3834 goto out;
3835 }
3836
3837 phase = 0;
3838 do {
3839 struct mmc_command cmd = {0};
3840 struct mmc_data data = {0};
3841 struct mmc_request mrq = {
3842 .cmd = &cmd,
3843 .data = &data
3844 };
3845 struct scatterlist sg;
3846
3847 /* set the phase in delay line hw block */
3848 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3849 if (rc)
3850 goto kfree;
3851
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303852 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003853 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
3854
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303855 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003856 data.blocks = 1;
3857 data.flags = MMC_DATA_READ;
3858 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
3859
3860 data.sg = &sg;
3861 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303862 sg_init_one(&sg, data_buf, size);
3863 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003864 mmc_wait_for_req(mmc, &mrq);
3865
3866 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303867 !memcmp(data_buf, tuning_block_pattern, size)) {
3868 /* tuning is successful at this tuning point */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003869 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303870 pr_debug("%s: %s: found good phase = %d\n",
3871 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003872 }
3873 } while (++phase < 16);
3874
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003875 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303876 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303877 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05303878 if (rc < 0)
3879 goto kfree;
3880 else
3881 phase = (u8)rc;
3882
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003883 /*
3884 * Finally set the selected phase in delay
3885 * line hw block.
3886 */
3887 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3888 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303889 goto kfree;
3890 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
3891 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003892 } else {
3893 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303894 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003895 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303896 msmsdcc_dump_sdcc_state(host);
3897 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003898 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003899
3900kfree:
3901 kfree(data_buf);
3902out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303903 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303904 host->tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303905 spin_unlock_irqrestore(&host->lock, flags);
3906exit:
3907 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003908 return rc;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003909}
3910
San Mehat9d2bd732009-09-22 16:44:22 -07003911static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003912 .enable = msmsdcc_enable,
3913 .disable = msmsdcc_disable,
Asutosh Dasaccacd42012-03-08 14:33:17 +05303914 .pre_req = msmsdcc_pre_req,
3915 .post_req = msmsdcc_post_req,
San Mehat9d2bd732009-09-22 16:44:22 -07003916 .request = msmsdcc_request,
3917 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003918 .get_ro = msmsdcc_get_ro,
San Mehat9d2bd732009-09-22 16:44:22 -07003919 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Subhash Jadavani937c7502012-06-01 15:34:46 +05303920 .start_signal_voltage_switch = msmsdcc_switch_io_voltage,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003921 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07003922};
3923
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003924static unsigned int
3925msmsdcc_slot_status(struct msmsdcc_host *host)
3926{
3927 int status;
3928 unsigned int gpio_no = host->plat->status_gpio;
3929
3930 status = gpio_request(gpio_no, "SD_HW_Detect");
3931 if (status) {
3932 pr_err("%s: %s: Failed to request GPIO %d\n",
3933 mmc_hostname(host->mmc), __func__, gpio_no);
3934 } else {
3935 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003936 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08003937 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003938 if (host->plat->is_status_gpio_active_low)
3939 status = !status;
3940 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003941 gpio_free(gpio_no);
3942 }
3943 return status;
3944}
3945
San Mehat9d2bd732009-09-22 16:44:22 -07003946static void
3947msmsdcc_check_status(unsigned long data)
3948{
3949 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3950 unsigned int status;
3951
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003952 if (host->plat->status || host->plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08003953 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003954 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003955 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003956 status = msmsdcc_slot_status(host);
3957
Krishna Konda941604a2012-01-10 17:46:34 -08003958 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08003959
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003960 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08003961 if (host->plat->status)
3962 pr_info("%s: Slot status change detected "
3963 "(%d -> %d)\n",
3964 mmc_hostname(host->mmc),
3965 host->oldstat, status);
3966 else if (host->plat->is_status_gpio_active_low)
3967 pr_info("%s: Slot status change detected "
3968 "(%d -> %d) and the card detect GPIO"
3969 " is ACTIVE_LOW\n",
3970 mmc_hostname(host->mmc),
3971 host->oldstat, status);
3972 else
3973 pr_info("%s: Slot status change detected "
3974 "(%d -> %d) and the card detect GPIO"
3975 " is ACTIVE_HIGH\n",
3976 mmc_hostname(host->mmc),
3977 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07003978 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003979 }
3980 host->oldstat = status;
3981 } else {
3982 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07003983 }
San Mehat9d2bd732009-09-22 16:44:22 -07003984}
3985
3986static irqreturn_t
3987msmsdcc_platform_status_irq(int irq, void *dev_id)
3988{
3989 struct msmsdcc_host *host = dev_id;
3990
Girish K Sa3c76eb2011-10-11 11:44:09 +05303991 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07003992 msmsdcc_check_status((unsigned long) host);
3993 return IRQ_HANDLED;
3994}
3995
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003996static irqreturn_t
3997msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
3998{
3999 struct msmsdcc_host *host = dev_id;
4000
4001 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
4002 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304003 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004004 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304005 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004006 wake_lock(&host->sdio_wlock);
4007 msmsdcc_disable_irq_wake(host);
4008 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304009 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004010 }
4011 if (host->plat->is_sdio_al_client) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004012 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304013 spin_unlock(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304014 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304015 goto out_unlocked;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004016 }
4017 spin_unlock(&host->lock);
4018
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304019out_unlocked:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004020 return IRQ_HANDLED;
4021}
4022
San Mehat9d2bd732009-09-22 16:44:22 -07004023static void
4024msmsdcc_status_notify_cb(int card_present, void *dev_id)
4025{
4026 struct msmsdcc_host *host = dev_id;
4027
Girish K Sa3c76eb2011-10-11 11:44:09 +05304028 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07004029 card_present);
4030 msmsdcc_check_status((unsigned long) host);
4031}
4032
San Mehat9d2bd732009-09-22 16:44:22 -07004033static int
4034msmsdcc_init_dma(struct msmsdcc_host *host)
4035{
4036 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
4037 host->dma.host = host;
4038 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004039 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004040
4041 if (!host->dmares)
4042 return -ENODEV;
4043
4044 host->dma.nc = dma_alloc_coherent(NULL,
4045 sizeof(struct msmsdcc_nc_dmadata),
4046 &host->dma.nc_busaddr,
4047 GFP_KERNEL);
4048 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004049 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07004050 return -ENOMEM;
4051 }
4052 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
4053 host->dma.cmd_busaddr = host->dma.nc_busaddr;
4054 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
4055 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
4056 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07004057 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07004058
4059 return 0;
4060}
4061
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004062#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
4063/**
4064 * Allocate and Connect a SDCC peripheral's SPS endpoint
4065 *
4066 * This function allocates endpoint context and
4067 * connect it with memory endpoint by calling
4068 * appropriate SPS driver APIs.
4069 *
4070 * Also registers a SPS callback function with
4071 * SPS driver
4072 *
4073 * This function should only be called once typically
4074 * during driver probe.
4075 *
4076 * @host - Pointer to sdcc host structure
4077 * @ep - Pointer to sps endpoint data structure
4078 * @is_produce - 1 means Producer endpoint
4079 * 0 means Consumer endpoint
4080 *
4081 * @return - 0 if successful else negative value.
4082 *
4083 */
4084static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
4085 struct msmsdcc_sps_ep_conn_data *ep,
4086 bool is_producer)
4087{
4088 int rc = 0;
4089 struct sps_pipe *sps_pipe_handle;
4090 struct sps_connect *sps_config = &ep->config;
4091 struct sps_register_event *sps_event = &ep->event;
4092
4093 /* Allocate endpoint context */
4094 sps_pipe_handle = sps_alloc_endpoint();
4095 if (!sps_pipe_handle) {
4096 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
4097 mmc_hostname(host->mmc), is_producer);
4098 rc = -ENOMEM;
4099 goto out;
4100 }
4101
4102 /* Get default connection configuration for an endpoint */
4103 rc = sps_get_config(sps_pipe_handle, sps_config);
4104 if (rc) {
4105 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
4106 " rc=%d", mmc_hostname(host->mmc),
4107 (u32)sps_pipe_handle, rc);
4108 goto get_config_err;
4109 }
4110
4111 /* Modify the default connection configuration */
4112 if (is_producer) {
4113 /*
4114 * For SDCC producer transfer, source should be
4115 * SDCC peripheral where as destination should
4116 * be system memory.
4117 */
4118 sps_config->source = host->sps.bam_handle;
4119 sps_config->destination = SPS_DEV_HANDLE_MEM;
4120 /* Producer pipe will handle this connection */
4121 sps_config->mode = SPS_MODE_SRC;
4122 sps_config->options =
4123 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4124 } else {
4125 /*
4126 * For SDCC consumer transfer, source should be
4127 * system memory where as destination should
4128 * SDCC peripheral
4129 */
4130 sps_config->source = SPS_DEV_HANDLE_MEM;
4131 sps_config->destination = host->sps.bam_handle;
4132 sps_config->mode = SPS_MODE_DEST;
4133 sps_config->options =
4134 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4135 }
4136
4137 /* Producer pipe index */
4138 sps_config->src_pipe_index = host->sps.src_pipe_index;
4139 /* Consumer pipe index */
4140 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
4141 /*
4142 * This event thresold value is only significant for BAM-to-BAM
4143 * transfer. It's ignored for BAM-to-System mode transfer.
4144 */
4145 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304146
4147 /* Allocate maximum descriptor fifo size */
4148 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
4149 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004150 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
4151 sps_config->desc.size,
4152 &sps_config->desc.phys_base,
4153 GFP_KERNEL);
4154
Pratibhasagar V00b94332011-10-18 14:57:27 +05304155 if (!sps_config->desc.base) {
4156 rc = -ENOMEM;
4157 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
4158 , mmc_hostname(host->mmc));
4159 goto get_config_err;
4160 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004161 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
4162
4163 /* Establish connection between peripheral and memory endpoint */
4164 rc = sps_connect(sps_pipe_handle, sps_config);
4165 if (rc) {
4166 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4167 " rc=%d", mmc_hostname(host->mmc),
4168 (u32)sps_pipe_handle, rc);
4169 goto sps_connect_err;
4170 }
4171
4172 sps_event->mode = SPS_TRIGGER_CALLBACK;
4173 sps_event->options = SPS_O_EOT;
4174 sps_event->callback = msmsdcc_sps_complete_cb;
4175 sps_event->xfer_done = NULL;
4176 sps_event->user = (void *)host;
4177
4178 /* Register callback event for EOT (End of transfer) event. */
4179 rc = sps_register_event(sps_pipe_handle, sps_event);
4180 if (rc) {
4181 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4182 " rc=%d", mmc_hostname(host->mmc),
4183 (u32)sps_pipe_handle, rc);
4184 goto reg_event_err;
4185 }
4186 /* Now save the sps pipe handle */
4187 ep->pipe_handle = sps_pipe_handle;
4188 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
4189 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
4190 __func__, is_producer ? "READ" : "WRITE",
4191 (u32)sps_pipe_handle, sps_config->desc.phys_base);
4192 goto out;
4193
4194reg_event_err:
4195 sps_disconnect(sps_pipe_handle);
4196sps_connect_err:
4197 dma_free_coherent(mmc_dev(host->mmc),
4198 sps_config->desc.size,
4199 sps_config->desc.base,
4200 sps_config->desc.phys_base);
4201get_config_err:
4202 sps_free_endpoint(sps_pipe_handle);
4203out:
4204 return rc;
4205}
4206
4207/**
4208 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
4209 *
4210 * This function disconnect endpoint and deallocates
4211 * endpoint context.
4212 *
4213 * This function should only be called once typically
4214 * during driver remove.
4215 *
4216 * @host - Pointer to sdcc host structure
4217 * @ep - Pointer to sps endpoint data structure
4218 *
4219 */
4220static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
4221 struct msmsdcc_sps_ep_conn_data *ep)
4222{
4223 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4224 struct sps_connect *sps_config = &ep->config;
4225 struct sps_register_event *sps_event = &ep->event;
4226
4227 sps_event->xfer_done = NULL;
4228 sps_event->callback = NULL;
4229 sps_register_event(sps_pipe_handle, sps_event);
4230 sps_disconnect(sps_pipe_handle);
4231 dma_free_coherent(mmc_dev(host->mmc),
4232 sps_config->desc.size,
4233 sps_config->desc.base,
4234 sps_config->desc.phys_base);
4235 sps_free_endpoint(sps_pipe_handle);
4236}
4237
4238/**
4239 * Reset SDCC peripheral's SPS endpoint
4240 *
4241 * This function disconnects an endpoint.
4242 *
4243 * This function should be called for reseting
4244 * SPS endpoint when data transfer error is
4245 * encountered during data transfer. This
4246 * can be considered as soft reset to endpoint.
4247 *
4248 * This function should only be called if
4249 * msmsdcc_sps_init() is already called.
4250 *
4251 * @host - Pointer to sdcc host structure
4252 * @ep - Pointer to sps endpoint data structure
4253 *
4254 * @return - 0 if successful else negative value.
4255 */
4256static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
4257 struct msmsdcc_sps_ep_conn_data *ep)
4258{
4259 int rc = 0;
4260 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4261
4262 rc = sps_disconnect(sps_pipe_handle);
4263 if (rc) {
4264 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
4265 " rc=%d", mmc_hostname(host->mmc), __func__,
4266 (u32)sps_pipe_handle, rc);
4267 goto out;
4268 }
4269 out:
4270 return rc;
4271}
4272
4273/**
4274 * Restore SDCC peripheral's SPS endpoint
4275 *
4276 * This function connects an endpoint.
4277 *
4278 * This function should be called for restoring
4279 * SPS endpoint after data transfer error is
4280 * encountered during data transfer. This
4281 * can be considered as soft reset to endpoint.
4282 *
4283 * This function should only be called if
4284 * msmsdcc_sps_reset_ep() is called before.
4285 *
4286 * @host - Pointer to sdcc host structure
4287 * @ep - Pointer to sps endpoint data structure
4288 *
4289 * @return - 0 if successful else negative value.
4290 */
4291static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
4292 struct msmsdcc_sps_ep_conn_data *ep)
4293{
4294 int rc = 0;
4295 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4296 struct sps_connect *sps_config = &ep->config;
4297 struct sps_register_event *sps_event = &ep->event;
4298
4299 /* Establish connection between peripheral and memory endpoint */
4300 rc = sps_connect(sps_pipe_handle, sps_config);
4301 if (rc) {
4302 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
4303 " rc=%d", mmc_hostname(host->mmc), __func__,
4304 (u32)sps_pipe_handle, rc);
4305 goto out;
4306 }
4307
4308 /* Register callback event for EOT (End of transfer) event. */
4309 rc = sps_register_event(sps_pipe_handle, sps_event);
4310 if (rc) {
4311 pr_err("%s: %s: sps_register_event() failed!!!"
4312 " pipe_handle=0x%x, rc=%d",
4313 mmc_hostname(host->mmc), __func__,
4314 (u32)sps_pipe_handle, rc);
4315 goto reg_event_err;
4316 }
4317 goto out;
4318
4319reg_event_err:
4320 sps_disconnect(sps_pipe_handle);
4321out:
4322 return rc;
4323}
4324
4325/**
4326 * Initialize SPS HW connected with SDCC core
4327 *
4328 * This function register BAM HW resources with
4329 * SPS driver and then initialize 2 SPS endpoints
4330 *
4331 * This function should only be called once typically
4332 * during driver probe.
4333 *
4334 * @host - Pointer to sdcc host structure
4335 *
4336 * @return - 0 if successful else negative value.
4337 *
4338 */
4339static int msmsdcc_sps_init(struct msmsdcc_host *host)
4340{
4341 int rc = 0;
4342 struct sps_bam_props bam = {0};
4343
4344 host->bam_base = ioremap(host->bam_memres->start,
4345 resource_size(host->bam_memres));
4346 if (!host->bam_base) {
4347 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
4348 " size=0x%x", mmc_hostname(host->mmc),
4349 host->bam_memres->start,
4350 (host->bam_memres->end -
4351 host->bam_memres->start));
4352 rc = -ENOMEM;
4353 goto out;
4354 }
4355
4356 bam.phys_addr = host->bam_memres->start;
4357 bam.virt_addr = host->bam_base;
4358 /*
4359 * This event thresold value is only significant for BAM-to-BAM
4360 * transfer. It's ignored for BAM-to-System mode transfer.
4361 */
4362 bam.event_threshold = 0x10; /* Pipe event threshold */
4363 /*
4364 * This threshold controls when the BAM publish
4365 * the descriptor size on the sideband interface.
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304366 * SPS HW will be used for data transfer size even
4367 * less than SDCC FIFO size. So let's set BAM summing
4368 * thresold to SPS_MIN_XFER_SIZE bytes.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004369 */
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304370 bam.summing_threshold = SPS_MIN_XFER_SIZE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004371 /* SPS driver wll handle the SDCC BAM IRQ */
4372 bam.irq = (u32)host->bam_irqres->start;
4373 bam.manage = SPS_BAM_MGR_LOCAL;
4374
4375 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
4376 (u32)bam.phys_addr);
4377 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
4378 (u32)bam.virt_addr);
4379
4380 /* Register SDCC Peripheral BAM device to SPS driver */
4381 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
4382 if (rc) {
4383 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
4384 mmc_hostname(host->mmc), rc);
4385 goto reg_bam_err;
4386 }
4387 pr_info("%s: BAM device registered. bam_handle=0x%x",
4388 mmc_hostname(host->mmc), host->sps.bam_handle);
4389
4390 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
4391 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
4392
4393 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
4394 SPS_PROD_PERIPHERAL);
4395 if (rc)
4396 goto sps_reset_err;
4397 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
4398 SPS_CONS_PERIPHERAL);
4399 if (rc)
4400 goto cons_conn_err;
4401
4402 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
4403 mmc_hostname(host->mmc),
4404 (unsigned long long)host->bam_memres->start,
4405 (unsigned int)host->bam_irqres->start);
4406 goto out;
4407
4408cons_conn_err:
4409 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4410sps_reset_err:
4411 sps_deregister_bam_device(host->sps.bam_handle);
4412reg_bam_err:
4413 iounmap(host->bam_base);
4414out:
4415 return rc;
4416}
4417
4418/**
4419 * De-initialize SPS HW connected with SDCC core
4420 *
4421 * This function deinitialize SPS endpoints and then
4422 * deregisters BAM resources from SPS driver.
4423 *
4424 * This function should only be called once typically
4425 * during driver remove.
4426 *
4427 * @host - Pointer to sdcc host structure
4428 *
4429 */
4430static void msmsdcc_sps_exit(struct msmsdcc_host *host)
4431{
4432 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
4433 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4434 sps_deregister_bam_device(host->sps.bam_handle);
4435 iounmap(host->bam_base);
4436}
4437#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
4438
4439static ssize_t
4440show_polling(struct device *dev, struct device_attribute *attr, char *buf)
4441{
4442 struct mmc_host *mmc = dev_get_drvdata(dev);
4443 struct msmsdcc_host *host = mmc_priv(mmc);
4444 int poll;
4445 unsigned long flags;
4446
4447 spin_lock_irqsave(&host->lock, flags);
4448 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
4449 spin_unlock_irqrestore(&host->lock, flags);
4450
4451 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
4452}
4453
4454static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05304455store_polling(struct device *dev, struct device_attribute *attr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004456 const char *buf, size_t count)
4457{
4458 struct mmc_host *mmc = dev_get_drvdata(dev);
4459 struct msmsdcc_host *host = mmc_priv(mmc);
4460 int value;
4461 unsigned long flags;
4462
4463 sscanf(buf, "%d", &value);
4464
4465 spin_lock_irqsave(&host->lock, flags);
4466 if (value) {
4467 mmc->caps |= MMC_CAP_NEEDS_POLL;
4468 mmc_detect_change(host->mmc, 0);
4469 } else {
4470 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4471 }
4472#ifdef CONFIG_HAS_EARLYSUSPEND
4473 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
4474#endif
4475 spin_unlock_irqrestore(&host->lock, flags);
4476 return count;
4477}
4478
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304479static ssize_t
4480show_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
4481 char *buf)
4482{
4483 struct mmc_host *mmc = dev_get_drvdata(dev);
4484 struct msmsdcc_host *host = mmc_priv(mmc);
4485
4486 return snprintf(buf, PAGE_SIZE, "%u\n",
4487 host->msm_bus_vote.is_max_bw_needed);
4488}
4489
4490static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05304491store_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304492 const char *buf, size_t count)
4493{
4494 struct mmc_host *mmc = dev_get_drvdata(dev);
4495 struct msmsdcc_host *host = mmc_priv(mmc);
4496 uint32_t value;
4497 unsigned long flags;
4498
4499 if (!kstrtou32(buf, 0, &value)) {
4500 spin_lock_irqsave(&host->lock, flags);
4501 host->msm_bus_vote.is_max_bw_needed = !!value;
4502 spin_unlock_irqrestore(&host->lock, flags);
4503 }
4504
4505 return count;
4506}
4507
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004508#ifdef CONFIG_HAS_EARLYSUSPEND
4509static void msmsdcc_early_suspend(struct early_suspend *h)
4510{
4511 struct msmsdcc_host *host =
4512 container_of(h, struct msmsdcc_host, early_suspend);
4513 unsigned long flags;
4514
4515 spin_lock_irqsave(&host->lock, flags);
4516 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
4517 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4518 spin_unlock_irqrestore(&host->lock, flags);
4519};
4520static void msmsdcc_late_resume(struct early_suspend *h)
4521{
4522 struct msmsdcc_host *host =
4523 container_of(h, struct msmsdcc_host, early_suspend);
4524 unsigned long flags;
4525
4526 if (host->polling_enabled) {
4527 spin_lock_irqsave(&host->lock, flags);
4528 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
4529 mmc_detect_change(host->mmc, 0);
4530 spin_unlock_irqrestore(&host->lock, flags);
4531 }
4532};
4533#endif
4534
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304535static void msmsdcc_print_regs(const char *name, void __iomem *base,
4536 u32 phys_base, unsigned int no_of_regs)
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304537{
4538 unsigned int i;
4539
4540 if (!base)
4541 return;
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304542
4543 pr_info("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
4544 " =====\n", name, phys_base, (u32)base);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304545 for (i = 0; i < no_of_regs; i = i + 4) {
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304546 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
4547 (u32)readl_relaxed(base + i*4),
4548 (u32)readl_relaxed(base + ((i+1)*4)),
4549 (u32)readl_relaxed(base + ((i+2)*4)),
4550 (u32)readl_relaxed(base + ((i+3)*4)));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304551 }
4552}
4553
4554static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
4555{
4556 /* Dump current state of SDCC clocks, power and irq */
4557 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304558 (host->pwr ? "ON" : "OFF"));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304559 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304560 mmc_hostname(host->mmc),
4561 (atomic_read(&host->clks_on) ? "ON" : "OFF"),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304562 (u32)clk_get_rate(host->clk));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304563 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
4564 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
4565
4566 /* Now dump SDCC registers. Don't print FIFO registers */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304567 if (atomic_read(&host->clks_on))
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304568 msmsdcc_print_regs("SDCC-CORE", host->base,
4569 host->core_memres->start, 28);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304570
4571 if (host->curr.data) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304572 if (!msmsdcc_is_dma_possible(host, host->curr.data))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304573 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304574 else if (is_dma_mode(host))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304575 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
4576 mmc_hostname(host->mmc), host->dma.busy,
4577 host->dma.channel, host->dma.crci);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304578 else if (is_sps_mode(host)) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304579 if (host->sps.busy && atomic_read(&host->clks_on))
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304580 msmsdcc_print_regs("SDCC-DML", host->dml_base,
4581 host->dml_memres->start,
4582 16);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304583 pr_info("%s: SPS mode: busy=%d\n",
4584 mmc_hostname(host->mmc), host->sps.busy);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304585 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304586
4587 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
4588 mmc_hostname(host->mmc), host->curr.xfer_size,
4589 host->curr.data_xfered, host->curr.xfer_remain);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304590 }
4591
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304592 pr_info("%s: got_dataend=%d, prog_enable=%d,"
Subhash Jadavani8706ced2012-05-25 16:09:21 +05304593 " wait_for_auto_prog_done=%d, got_auto_prog_done=%d,"
4594 " req_tout_ms=%d\n", mmc_hostname(host->mmc),
4595 host->curr.got_dataend, host->prog_enable,
4596 host->curr.wait_for_auto_prog_done,
4597 host->curr.got_auto_prog_done, host->curr.req_tout_ms);
subhashj245831e2012-04-30 18:46:17 +05304598 msmsdcc_print_rpm_info(host);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304599}
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304600
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004601static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
4602{
4603 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4604 struct mmc_request *mrq;
4605 unsigned long flags;
4606
4607 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004608 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004609 pr_info("%s: %s: dummy CMD52 timeout\n",
4610 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004611 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004612 }
4613
4614 mrq = host->curr.mrq;
4615
4616 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304617 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
4618 mrq->cmd->opcode);
4619 msmsdcc_dump_sdcc_state(host);
4620
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004621 if (!mrq->cmd->error)
4622 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304623 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004624 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004625 if (mrq->data && !mrq->data->error)
4626 mrq->data->error = -ETIMEDOUT;
4627 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304628 if (host->dma.sg && is_dma_mode(host)) {
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07004629 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304630 } else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004631 /* Stop current SPS transfer */
4632 msmsdcc_sps_exit_curr_xfer(host);
4633 } else {
4634 msmsdcc_reset_and_restore(host);
4635 msmsdcc_stop_data(host);
4636 if (mrq->data && mrq->data->stop)
4637 msmsdcc_start_command(host,
4638 mrq->data->stop, 0);
4639 else
4640 msmsdcc_request_end(host, mrq);
4641 }
4642 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304643 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05304644 host->curr.wait_for_auto_prog_done = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004645 msmsdcc_reset_and_restore(host);
4646 msmsdcc_request_end(host, mrq);
4647 }
4648 }
4649 spin_unlock_irqrestore(&host->lock, flags);
4650}
4651
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05304652#define MAX_PROP_SIZE 32
4653static int msmsdcc_dt_parse_vreg_info(struct device *dev,
4654 struct msm_mmc_reg_data **vreg_data, const char *vreg_name)
4655{
4656 int len, ret = 0;
4657 const __be32 *prop;
4658 char prop_name[MAX_PROP_SIZE];
4659 struct msm_mmc_reg_data *vreg;
4660 struct device_node *np = dev->of_node;
4661
4662 snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", vreg_name);
4663 if (of_parse_phandle(np, prop_name, 0)) {
4664 vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
4665 if (!vreg) {
4666 dev_err(dev, "No memory for vreg: %s\n", vreg_name);
4667 ret = -ENOMEM;
4668 goto err;
4669 }
4670
4671 vreg->name = vreg_name;
4672
4673 snprintf(prop_name, MAX_PROP_SIZE,
4674 "qcom,sdcc-%s-always_on", vreg_name);
4675 if (of_get_property(np, prop_name, NULL))
4676 vreg->always_on = true;
4677
4678 snprintf(prop_name, MAX_PROP_SIZE,
4679 "qcom,sdcc-%s-lpm_sup", vreg_name);
4680 if (of_get_property(np, prop_name, NULL))
4681 vreg->lpm_sup = true;
4682
4683 snprintf(prop_name, MAX_PROP_SIZE,
4684 "qcom,sdcc-%s-voltage_level", vreg_name);
4685 prop = of_get_property(np, prop_name, &len);
4686 if (!prop || (len != (2 * sizeof(__be32)))) {
4687 dev_warn(dev, "%s %s property\n",
4688 prop ? "invalid format" : "no", prop_name);
4689 } else {
4690 vreg->low_vol_level = be32_to_cpup(&prop[0]);
4691 vreg->high_vol_level = be32_to_cpup(&prop[1]);
4692 }
4693
4694 snprintf(prop_name, MAX_PROP_SIZE,
4695 "qcom,sdcc-%s-current_level", vreg_name);
4696 prop = of_get_property(np, prop_name, &len);
4697 if (!prop || (len != (2 * sizeof(__be32)))) {
4698 dev_warn(dev, "%s %s property\n",
4699 prop ? "invalid format" : "no", prop_name);
4700 } else {
4701 vreg->lpm_uA = be32_to_cpup(&prop[0]);
4702 vreg->hpm_uA = be32_to_cpup(&prop[1]);
4703 }
4704
4705 *vreg_data = vreg;
4706 dev_dbg(dev, "%s: %s %s vol=[%d %d]uV, curr=[%d %d]uA\n",
4707 vreg->name, vreg->always_on ? "always_on," : "",
4708 vreg->lpm_sup ? "lpm_sup," : "", vreg->low_vol_level,
4709 vreg->high_vol_level, vreg->lpm_uA, vreg->hpm_uA);
4710 }
4711
4712err:
4713 return ret;
4714}
4715
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304716static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
4717{
4718 int i, ret;
4719 struct mmc_platform_data *pdata;
4720 struct device_node *np = dev->of_node;
Devin Kim9ccbff52012-07-16 20:55:14 -07004721 u32 bus_width = 0, current_limit = 0;
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05304722 u32 *clk_table, *sup_voltages;
Devin Kim9ccbff52012-07-16 20:55:14 -07004723 int clk_table_len, sup_volt_len, len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304724
4725 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
4726 if (!pdata) {
4727 dev_err(dev, "could not allocate memory for platform data\n");
4728 goto err;
4729 }
4730
4731 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
4732 if (bus_width == 8) {
4733 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
4734 } else if (bus_width == 4) {
4735 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
4736 } else {
4737 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
4738 pdata->mmc_bus_width = 0;
4739 }
4740
4741 if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
4742 size_t sz;
4743 sz = sup_volt_len / sizeof(*sup_voltages);
4744 if (sz > 0) {
4745 sup_voltages = devm_kzalloc(dev,
4746 sz * sizeof(*sup_voltages), GFP_KERNEL);
4747 if (!sup_voltages) {
4748 dev_err(dev, "No memory for supported voltage\n");
4749 goto err;
4750 }
4751
4752 ret = of_property_read_u32_array(np,
4753 "qcom,sdcc-sup-voltages", sup_voltages, sz);
4754 if (ret < 0) {
4755 dev_err(dev, "error while reading voltage"
4756 "ranges %d\n", ret);
4757 goto err;
4758 }
4759 } else {
4760 dev_err(dev, "No supported voltages\n");
4761 goto err;
4762 }
4763 for (i = 0; i < sz; i += 2) {
4764 u32 mask;
4765
4766 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
4767 sup_voltages[i + 1]);
4768 if (!mask)
4769 dev_err(dev, "Invalide voltage range %d\n", i);
4770 pdata->ocr_mask |= mask;
4771 }
4772 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
4773 } else {
4774 dev_err(dev, "Supported voltage range not specified\n");
4775 }
4776
4777 if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
4778 size_t sz;
4779 sz = clk_table_len / sizeof(*clk_table);
4780
4781 if (sz > 0) {
4782 clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
4783 GFP_KERNEL);
4784 if (!clk_table) {
4785 dev_err(dev, "No memory for clock table\n");
4786 goto err;
4787 }
4788
4789 ret = of_property_read_u32_array(np,
4790 "qcom,sdcc-clk-rates", clk_table, sz);
4791 if (ret < 0) {
4792 dev_err(dev, "error while reading clk"
4793 "table %d\n", ret);
4794 goto err;
4795 }
4796 } else {
4797 dev_err(dev, "clk_table not specified\n");
4798 goto err;
4799 }
4800 pdata->sup_clk_table = clk_table;
4801 pdata->sup_clk_cnt = sz;
4802 } else {
4803 dev_err(dev, "Supported clock rates not specified\n");
4804 }
4805
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05304806 pdata->vreg_data = devm_kzalloc(dev,
4807 sizeof(struct msm_mmc_slot_reg_data), GFP_KERNEL);
4808 if (!pdata->vreg_data) {
4809 dev_err(dev, "could not allocate memory for vreg_data\n");
4810 goto err;
4811 }
4812
4813 if (msmsdcc_dt_parse_vreg_info(dev,
4814 &pdata->vreg_data->vdd_data, "vdd"))
4815 goto err;
4816
4817 if (msmsdcc_dt_parse_vreg_info(dev,
4818 &pdata->vreg_data->vdd_io_data, "vdd-io"))
4819 goto err;
4820
Devin Kim9ccbff52012-07-16 20:55:14 -07004821 len = of_property_count_strings(np, "qcom,sdcc-bus-speed-mode");
4822
4823 for (i = 0; i < len; i++) {
4824 const char *name = NULL;
4825
4826 of_property_read_string_index(np,
4827 "qcom,sdcc-bus-speed-mode", i, &name);
4828 if (!name)
4829 continue;
4830
4831 if (!strncmp(name, "SDR12", sizeof("SDR12")))
4832 pdata->uhs_caps |= MMC_CAP_UHS_SDR12;
4833 else if (!strncmp(name, "SDR25", sizeof("SDR25")))
4834 pdata->uhs_caps |= MMC_CAP_UHS_SDR25;
4835 else if (!strncmp(name, "SDR50", sizeof("SDR50")))
4836 pdata->uhs_caps |= MMC_CAP_UHS_SDR50;
4837 else if (!strncmp(name, "DDR50", sizeof("DDR50")))
4838 pdata->uhs_caps |= MMC_CAP_UHS_DDR50;
4839 else if (!strncmp(name, "SDR104", sizeof("SDR104")))
4840 pdata->uhs_caps |= MMC_CAP_UHS_SDR104;
4841 else if (!strncmp(name, "HS200_1p8v", sizeof("HS200_1p8v")))
4842 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_8V_SDR;
4843 else if (!strncmp(name, "HS200_1p2v", sizeof("HS200_1p2v")))
4844 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_2V_SDR;
4845 else if (!strncmp(name, "DDR_1p8v", sizeof("DDR_1p8v")))
4846 pdata->uhs_caps |= MMC_CAP_1_8V_DDR
4847 | MMC_CAP_UHS_DDR50;
4848 else if (!strncmp(name, "DDR_1p2v", sizeof("DDR_1p2v")))
4849 pdata->uhs_caps |= MMC_CAP_1_2V_DDR
4850 | MMC_CAP_UHS_DDR50;
4851 }
4852
4853 of_property_read_u32(np, "qcom,sdcc-current-limit", &current_limit);
4854 if (current_limit == 800)
4855 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_800;
4856 else if (current_limit == 600)
4857 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_600;
4858 else if (current_limit == 400)
4859 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_400;
4860 else if (current_limit == 200)
4861 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_200;
4862
4863 if (of_get_property(np, "qcom,sdcc-xpc", NULL))
4864 pdata->xpc_cap = true;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304865 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
4866 pdata->nonremovable = true;
4867 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
4868 pdata->disable_cmd23 = true;
4869
4870 return pdata;
4871err:
4872 return NULL;
4873}
4874
San Mehat9d2bd732009-09-22 16:44:22 -07004875static int
4876msmsdcc_probe(struct platform_device *pdev)
4877{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304878 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07004879 struct msmsdcc_host *host;
4880 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004881 unsigned long flags;
4882 struct resource *core_irqres = NULL;
4883 struct resource *bam_irqres = NULL;
4884 struct resource *core_memres = NULL;
4885 struct resource *dml_memres = NULL;
4886 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07004887 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07004888 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05304889 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004890 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07004891
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304892 if (pdev->dev.of_node) {
4893 plat = msmsdcc_populate_pdata(&pdev->dev);
4894 of_property_read_u32((&pdev->dev)->of_node,
4895 "cell-index", &pdev->id);
4896 } else {
4897 plat = pdev->dev.platform_data;
4898 }
San Mehat9d2bd732009-09-22 16:44:22 -07004899
4900 /* must have platform data */
4901 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004902 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004903 ret = -EINVAL;
4904 goto out;
4905 }
4906
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004907 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07004908 return -EINVAL;
4909
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304910 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
4911 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
4912 return -EINVAL;
4913 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004914
San Mehat9d2bd732009-09-22 16:44:22 -07004915 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004916 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004917 return -ENXIO;
4918 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304919 if (pdev->dev.of_node) {
4920 /*
4921 * Device tree iomem resources are only accessible by index.
4922 * index = 0 -> SDCC register interface
4923 * index = 1 -> DML register interface
4924 * index = 2 -> BAM register interface
4925 * IRQ resources:
4926 * index = 0 -> SDCC IRQ
4927 * index = 1 -> BAM IRQ
4928 */
4929 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
4930 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
4931 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
4932 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
4933 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
4934 } else {
4935 for (i = 0; i < pdev->num_resources; i++) {
4936 if (pdev->resource[i].flags & IORESOURCE_MEM) {
4937 if (!strncmp(pdev->resource[i].name,
4938 "sdcc_dml_addr",
4939 sizeof("sdcc_dml_addr")))
4940 dml_memres = &pdev->resource[i];
4941 else if (!strncmp(pdev->resource[i].name,
4942 "sdcc_bam_addr",
4943 sizeof("sdcc_bam_addr")))
4944 bam_memres = &pdev->resource[i];
4945 else
4946 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07004947
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304948 }
4949 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
4950 if (!strncmp(pdev->resource[i].name,
4951 "sdcc_bam_irq",
4952 sizeof("sdcc_bam_irq")))
4953 bam_irqres = &pdev->resource[i];
4954 else
4955 core_irqres = &pdev->resource[i];
4956 }
4957 if (pdev->resource[i].flags & IORESOURCE_DMA) {
4958 if (!strncmp(pdev->resource[i].name,
4959 "sdcc_dma_chnl",
4960 sizeof("sdcc_dma_chnl")))
4961 dmares = &pdev->resource[i];
4962 else if (!strncmp(pdev->resource[i].name,
4963 "sdcc_dma_crci",
4964 sizeof("sdcc_dma_crci")))
4965 dma_crci_res = &pdev->resource[i];
4966 }
Krishna Konda25786ec2011-07-25 16:21:36 -07004967 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004968 }
San Mehat9d2bd732009-09-22 16:44:22 -07004969
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004970 if (!core_irqres || !core_memres) {
4971 pr_err("%s: Invalid sdcc core resource\n", __func__);
4972 return -ENXIO;
4973 }
4974
4975 /*
4976 * Both BAM and DML memory resource should be preset.
4977 * BAM IRQ resource should also be present.
4978 */
4979 if ((bam_memres && !dml_memres) ||
4980 (!bam_memres && dml_memres) ||
4981 ((bam_memres && dml_memres) && !bam_irqres)) {
4982 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004983 return -ENXIO;
4984 }
4985
4986 /*
4987 * Setup our host structure
4988 */
San Mehat9d2bd732009-09-22 16:44:22 -07004989 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
4990 if (!mmc) {
4991 ret = -ENOMEM;
4992 goto out;
4993 }
4994
4995 host = mmc_priv(mmc);
4996 host->pdev_id = pdev->id;
4997 host->plat = plat;
4998 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08004999 host->curr.cmd = NULL;
Sahitya Tummala19207f02011-05-02 18:10:01 +05305000
Sahitya Tummalad9df3272011-08-19 16:50:46 +05305001 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305002 set_hw_caps(host, MSMSDCC_SPS_BAM_SUP);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005003 else if (dmares)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305004 set_hw_caps(host, MSMSDCC_DMA_SUP);
San Mehat9d2bd732009-09-22 16:44:22 -07005005
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005006 host->base = ioremap(core_memres->start,
5007 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07005008 if (!host->base) {
5009 ret = -ENOMEM;
Sahitya Tummaladce7c752011-05-02 18:06:05 +05305010 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005011 }
5012
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005013 host->core_irqres = core_irqres;
5014 host->bam_irqres = bam_irqres;
5015 host->core_memres = core_memres;
5016 host->dml_memres = dml_memres;
5017 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07005018 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07005019 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07005020 spin_lock_init(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305021 mutex_init(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07005022
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005023#ifdef CONFIG_MMC_EMBEDDED_SDIO
5024 if (plat->embedded_sdio)
5025 mmc_set_embedded_sdio_data(mmc,
5026 &plat->embedded_sdio->cis,
5027 &plat->embedded_sdio->cccr,
5028 plat->embedded_sdio->funcs,
5029 plat->embedded_sdio->num_funcs);
5030#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005031
Sahitya Tummala62612cf2010-12-08 15:03:03 +05305032 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
5033 (unsigned long)host);
5034
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005035 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
5036 (unsigned long)host);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305037 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005038 /* Setup DMA */
Subhash Jadavani190657c2011-05-02 18:10:40 +05305039 ret = msmsdcc_init_dma(host);
5040 if (ret)
5041 goto ioremap_free;
5042 } else {
5043 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07005044 host->dma.crci = -1;
Subhash Jadavani190657c2011-05-02 18:10:40 +05305045 }
San Mehat9d2bd732009-09-22 16:44:22 -07005046
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005047 /*
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305048 * Setup SDCC bus voter clock.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005049 */
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305050 host->bus_clk = clk_get(&pdev->dev, "bus_clk");
5051 if (!IS_ERR_OR_NULL(host->bus_clk)) {
5052 /* Vote for max. clk rate for max. performance */
5053 ret = clk_set_rate(host->bus_clk, INT_MAX);
5054 if (ret)
5055 goto bus_clk_put;
5056 ret = clk_prepare_enable(host->bus_clk);
5057 if (ret)
5058 goto bus_clk_put;
San Mehat9d2bd732009-09-22 16:44:22 -07005059 }
5060
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005061 /*
5062 * Setup main peripheral bus clock
5063 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07005064 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005065 if (!IS_ERR(host->pclk)) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305066 ret = clk_prepare_enable(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005067 if (ret)
5068 goto pclk_put;
5069
5070 host->pclk_rate = clk_get_rate(host->pclk);
5071 }
5072
5073 /*
5074 * Setup SDC MMC clock
5075 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07005076 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07005077 if (IS_ERR(host->clk)) {
5078 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005079 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07005080 }
5081
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005082 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
Sahitya Tummala514d9ed2011-05-02 18:07:01 +05305083 if (ret) {
5084 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
5085 goto clk_put;
5086 }
5087
Asutosh Dasf5298c32012-04-03 14:51:47 +05305088 ret = clk_prepare_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07005089 if (ret)
5090 goto clk_put;
5091
San Mehat9d2bd732009-09-22 16:44:22 -07005092 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05305093 if (!host->clk_rate)
5094 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05305095
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305096 set_default_hw_caps(host);
5097
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05305098 /*
5099 * Set the register write delay according to min. clock frequency
5100 * supported and update later when the host->clk_rate changes.
5101 */
5102 host->reg_write_delay =
5103 (1 + ((3 * USEC_PER_SEC) /
5104 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005105
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305106 atomic_set(&host->clks_on, 1);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05305107 /* Apply Hard reset to SDCC to put it in power on default state */
5108 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005109
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005110#define MSM_MMC_DEFAULT_CPUDMA_LATENCY 200 /* usecs */
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305111 /* pm qos request to prevent apps idle power collapse */
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005112 if (host->plat->cpu_dma_latency)
5113 host->cpu_dma_latency = host->plat->cpu_dma_latency;
5114 else
5115 host->cpu_dma_latency = MSM_MMC_DEFAULT_CPUDMA_LATENCY;
5116 pm_qos_add_request(&host->pm_qos_req_dma,
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305117 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
5118
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305119 ret = msmsdcc_msm_bus_register(host);
5120 if (ret)
5121 goto pm_qos_remove;
5122
5123 if (host->msm_bus_vote.client_handle)
5124 INIT_DELAYED_WORK(&host->msm_bus_vote.vote_work,
5125 msmsdcc_msm_bus_work);
5126
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005127 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07005128 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005129 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07005130 goto clk_disable;
5131 }
5132
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005133
5134 /* Clocks has to be running before accessing SPS/DML HW blocks */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305135 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005136 /* Initialize SPS */
5137 ret = msmsdcc_sps_init(host);
5138 if (ret)
5139 goto vreg_deinit;
5140 /* Initialize DML */
5141 ret = msmsdcc_dml_init(host);
5142 if (ret)
5143 goto sps_exit;
5144 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05305145 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07005146
San Mehat9d2bd732009-09-22 16:44:22 -07005147 /*
5148 * Setup MMC host structure
5149 */
5150 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005151 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
5152 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005153 mmc->ocr_avail = plat->ocr_mask;
Sujit Reddy Thumma0e05f022012-06-11 19:44:18 +05305154 mmc->clkgate_delay = MSM_MMC_CLK_GATE_DELAY;
5155
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005156 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
5157 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07005158 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05305159 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
San Mehat9d2bd732009-09-22 16:44:22 -07005160
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05305161 /*
5162 * If we send the CMD23 before multi block write/read command
5163 * then we need not to send CMD12 at the end of the transfer.
5164 * If we don't send the CMD12 then only way to detect the PROG_DONE
5165 * status is to use the AUTO_PROG_DONE status provided by SDCC4
5166 * controller. So let's enable the CMD23 for SDCC4 only.
5167 */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305168 if (!plat->disable_cmd23 && is_auto_prog_done(host))
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05305169 mmc->caps |= MMC_CAP_CMD23;
San Mehat9d2bd732009-09-22 16:44:22 -07005170
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005171 mmc->caps |= plat->uhs_caps;
Devin Kim9ccbff52012-07-16 20:55:14 -07005172 mmc->caps2 |= plat->uhs_caps2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005173 /*
5174 * XPC controls the maximum current in the default speed mode of SDXC
5175 * card. XPC=0 means 100mA (max.) but speed class is not supported.
5176 * XPC=1 means 150mA (max.) and speed class is supported.
5177 */
5178 if (plat->xpc_cap)
5179 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
5180 MMC_CAP_SET_XPC_180);
5181
Maya Erez25e22612012-05-20 08:45:01 +03005182 mmc->caps2 |= MMC_CAP2_PACKED_WR;
Maya Erez8afe8d22012-05-20 15:11:52 +03005183 mmc->caps2 |= MMC_CAP2_PACKED_WR_CONTROL;
Subhash Jadavani6bb34a82012-04-18 13:18:40 +05305184 mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
Yaniv Gardi14098552012-06-04 10:56:03 +03005185 mmc->caps2 |= MMC_CAP2_SANITIZE;
5186
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005187 if (plat->nonremovable)
5188 mmc->caps |= MMC_CAP_NONREMOVABLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005189 mmc->caps |= MMC_CAP_SDIO_IRQ;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005190
Konstantin Dorfman9db69fc2012-06-01 14:04:45 +03005191 mmc->caps2 |= MMC_CAP2_INIT_BKOPS | MMC_CAP2_BKOPS;
5192
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005193 if (plat->is_sdio_al_client)
5194 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07005195
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305196 mmc->max_segs = msmsdcc_get_nr_sg(host);
5197 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
5198 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07005199
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305200 mmc->max_req_size = MMC_MAX_REQ_SIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07005201 mmc->max_seg_size = mmc->max_req_size;
5202
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005203 writel_relaxed(0, host->base + MMCIMASK0);
5204 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05305205 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005206
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005207 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
5208 mb();
5209 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07005210
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005211 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
5212 DRIVER_NAME " (cmd)", host);
5213 if (ret)
5214 goto dml_exit;
5215
5216 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
5217 DRIVER_NAME " (pio)", host);
5218 if (ret)
5219 goto irq_free;
5220
5221 /*
5222 * Enable SDCC IRQ only when host is powered on. Otherwise, this
5223 * IRQ is un-necessarily being monitored by MPM (Modem power
5224 * management block) during idle-power collapse. The MPM will be
5225 * configured to monitor the DATA1 GPIO line with level-low trigger
5226 * and thus depending on the GPIO status, it prevents TCXO shutdown
5227 * during idle-power collapse.
5228 */
5229 disable_irq(core_irqres->start);
5230 host->sdcc_irq_disabled = 1;
5231
5232 if (plat->sdiowakeup_irq) {
5233 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5234 mmc_hostname(mmc));
5235 ret = request_irq(plat->sdiowakeup_irq,
5236 msmsdcc_platform_sdiowakeup_irq,
5237 IRQF_SHARED | IRQF_TRIGGER_LOW,
5238 DRIVER_NAME "sdiowakeup", host);
5239 if (ret) {
5240 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
5241 plat->sdiowakeup_irq, ret);
5242 goto pio_irq_free;
5243 } else {
5244 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305245 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005246 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305247 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005248 }
5249 spin_unlock_irqrestore(&host->lock, flags);
5250 }
5251 }
5252
Subhash Jadavanic9b85752012-04-13 11:16:49 +05305253 if (host->plat->mpm_sdiowakeup_int) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005254 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5255 mmc_hostname(mmc));
5256 }
5257
5258 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
5259 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005260 /*
5261 * Setup card detect change
5262 */
5263
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005264 if (plat->status || plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08005265 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005266 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08005267 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005268 host->oldstat = msmsdcc_slot_status(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005269
Krishna Konda941604a2012-01-10 17:46:34 -08005270 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005271 }
San Mehat9d2bd732009-09-22 16:44:22 -07005272
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005273 if (plat->status_irq) {
5274 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07005275 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005276 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07005277 DRIVER_NAME " (slot)",
5278 host);
5279 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005280 pr_err("Unable to get slot IRQ %d (%d)\n",
5281 plat->status_irq, ret);
5282 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005283 }
5284 } else if (plat->register_status_notify) {
5285 plat->register_status_notify(msmsdcc_status_notify_cb, host);
5286 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005287 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07005288 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005289
5290 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005291
5292 ret = pm_runtime_set_active(&(pdev)->dev);
5293 if (ret < 0)
5294 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
5295 __func__, ret);
5296 /*
5297 * There is no notion of suspend/resume for SD/MMC/SDIO
5298 * cards. So host can be suspended/resumed with out
5299 * worrying about its children.
5300 */
5301 pm_suspend_ignore_children(&(pdev)->dev, true);
5302
5303 /*
5304 * MMC/SD/SDIO bus suspend/resume operations are defined
5305 * only for the slots that will be used for non-removable
5306 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
5307 * defined. Otherwise, they simply become card removal and
5308 * insertion events during suspend and resume respectively.
5309 * Hence, enable run-time PM only for slots for which bus
5310 * suspend/resume operations are defined.
5311 */
5312#ifdef CONFIG_MMC_UNSAFE_RESUME
5313 /*
5314 * If this capability is set, MMC core will enable/disable host
5315 * for every claim/release operation on a host. We use this
5316 * notification to increment/decrement runtime pm usage count.
5317 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005318 pm_runtime_enable(&(pdev)->dev);
5319#else
5320 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005321 pm_runtime_enable(&(pdev)->dev);
5322 }
5323#endif
5324 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
5325 (unsigned long)host);
5326
San Mehat9d2bd732009-09-22 16:44:22 -07005327 mmc_add_host(mmc);
5328
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005329#ifdef CONFIG_HAS_EARLYSUSPEND
5330 host->early_suspend.suspend = msmsdcc_early_suspend;
5331 host->early_suspend.resume = msmsdcc_late_resume;
5332 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
5333 register_early_suspend(&host->early_suspend);
5334#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005335
Krishna Konda25786ec2011-07-25 16:21:36 -07005336 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
5337 " dmacrcri %d\n", mmc_hostname(mmc),
5338 (unsigned long long)core_memres->start,
5339 (unsigned int) core_irqres->start,
5340 (unsigned int) plat->status_irq, host->dma.channel,
5341 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005342
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305343 pr_info("%s: Controller capabilities: 0x%.8x\n",
5344 mmc_hostname(mmc), host->hw_caps);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005345 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
5346 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
5347 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
5348 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
5349 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
5350 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
5351 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
5352 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
5353 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
5354 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
5355 host->eject);
5356 pr_info("%s: Power save feature enable = %d\n",
5357 mmc_hostname(mmc), msmsdcc_pwrsave);
5358
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305359 if (is_dma_mode(host) && host->dma.channel != -1
Krishna Konda25786ec2011-07-25 16:21:36 -07005360 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005361 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005362 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005363 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005364 mmc_hostname(mmc), host->dma.cmd_busaddr,
5365 host->dma.cmdptr_busaddr);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305366 } else if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005367 pr_info("%s: SPS-BAM data transfer mode available\n",
5368 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005369 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005370 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005371
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005372#if defined(CONFIG_DEBUG_FS)
5373 msmsdcc_dbg_createhost(host);
5374#endif
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305375
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305376 host->max_bus_bw.show = show_sdcc_to_mem_max_bus_bw;
5377 host->max_bus_bw.store = store_sdcc_to_mem_max_bus_bw;
5378 sysfs_attr_init(&host->max_bus_bw.attr);
5379 host->max_bus_bw.attr.name = "max_bus_bw";
5380 host->max_bus_bw.attr.mode = S_IRUGO | S_IWUSR;
5381 ret = device_create_file(&pdev->dev, &host->max_bus_bw);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305382 if (ret)
5383 goto platform_irq_free;
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305384
5385 if (!plat->status_irq) {
5386 host->polling.show = show_polling;
5387 host->polling.store = store_polling;
5388 sysfs_attr_init(&host->polling.attr);
5389 host->polling.attr.name = "polling";
5390 host->polling.attr.mode = S_IRUGO | S_IWUSR;
5391 ret = device_create_file(&pdev->dev, &host->polling);
5392 if (ret)
5393 goto remove_max_bus_bw_file;
5394 }
San Mehat9d2bd732009-09-22 16:44:22 -07005395 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005396
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305397 remove_max_bus_bw_file:
5398 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005399 platform_irq_free:
5400 del_timer_sync(&host->req_tout_timer);
5401 pm_runtime_disable(&(pdev)->dev);
5402 pm_runtime_set_suspended(&(pdev)->dev);
5403
5404 if (plat->status_irq)
5405 free_irq(plat->status_irq, host);
5406 sdiowakeup_irq_free:
5407 wake_lock_destroy(&host->sdio_suspend_wlock);
5408 if (plat->sdiowakeup_irq)
5409 free_irq(plat->sdiowakeup_irq, host);
5410 pio_irq_free:
5411 if (plat->sdiowakeup_irq)
5412 wake_lock_destroy(&host->sdio_wlock);
5413 free_irq(core_irqres->start, host);
5414 irq_free:
5415 free_irq(core_irqres->start, host);
5416 dml_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305417 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005418 msmsdcc_dml_exit(host);
5419 sps_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305420 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005421 msmsdcc_sps_exit(host);
5422 vreg_deinit:
5423 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07005424 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005425 clk_disable(host->clk);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305426 msmsdcc_msm_bus_unregister(host);
5427 pm_qos_remove:
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005428 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305429 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07005430 clk_put:
5431 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005432 pclk_disable:
5433 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05305434 clk_disable_unprepare(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07005435 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005436 if (!IS_ERR(host->pclk))
5437 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305438 if (!IS_ERR_OR_NULL(host->bus_clk))
5439 clk_disable_unprepare(host->bus_clk);
5440 bus_clk_put:
5441 if (!IS_ERR_OR_NULL(host->bus_clk))
5442 clk_put(host->bus_clk);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305443 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005444 if (host->dmares)
5445 dma_free_coherent(NULL,
5446 sizeof(struct msmsdcc_nc_dmadata),
5447 host->dma.nc, host->dma.nc_busaddr);
5448 }
5449 ioremap_free:
Sahitya Tummaladce7c752011-05-02 18:06:05 +05305450 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07005451 host_free:
5452 mmc_free_host(mmc);
5453 out:
5454 return ret;
5455}
5456
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005457static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07005458{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005459 struct mmc_host *mmc = mmc_get_drvdata(pdev);
5460 struct mmc_platform_data *plat;
5461 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07005462
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005463 if (!mmc)
5464 return -ENXIO;
5465
5466 if (pm_runtime_suspended(&(pdev)->dev))
5467 pm_runtime_resume(&(pdev)->dev);
5468
5469 host = mmc_priv(mmc);
5470
5471 DBG(host, "Removing SDCC device = %d\n", pdev->id);
5472 plat = host->plat;
5473
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305474 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005475 if (!plat->status_irq)
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305476 device_remove_file(&pdev->dev, &host->polling);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005477
5478 del_timer_sync(&host->req_tout_timer);
5479 tasklet_kill(&host->dma_tlet);
5480 tasklet_kill(&host->sps.tlet);
5481 mmc_remove_host(mmc);
5482
5483 if (plat->status_irq)
5484 free_irq(plat->status_irq, host);
5485
5486 wake_lock_destroy(&host->sdio_suspend_wlock);
5487 if (plat->sdiowakeup_irq) {
5488 wake_lock_destroy(&host->sdio_wlock);
5489 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
5490 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07005491 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005492
5493 free_irq(host->core_irqres->start, host);
5494 free_irq(host->core_irqres->start, host);
5495
5496 clk_put(host->clk);
5497 if (!IS_ERR(host->pclk))
5498 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305499 if (!IS_ERR_OR_NULL(host->bus_clk))
5500 clk_put(host->bus_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005501
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005502 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305503 pm_qos_remove_request(&host->pm_qos_req_dma);
5504
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305505 if (host->msm_bus_vote.client_handle) {
5506 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
5507 msmsdcc_msm_bus_unregister(host);
5508 }
5509
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005510 msmsdcc_vreg_init(host, false);
5511
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305512 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005513 if (host->dmares)
5514 dma_free_coherent(NULL,
5515 sizeof(struct msmsdcc_nc_dmadata),
5516 host->dma.nc, host->dma.nc_busaddr);
5517 }
5518
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305519 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005520 msmsdcc_dml_exit(host);
5521 msmsdcc_sps_exit(host);
5522 }
5523
5524 iounmap(host->base);
5525 mmc_free_host(mmc);
5526
5527#ifdef CONFIG_HAS_EARLYSUSPEND
5528 unregister_early_suspend(&host->early_suspend);
5529#endif
5530 pm_runtime_disable(&(pdev)->dev);
5531 pm_runtime_set_suspended(&(pdev)->dev);
5532
5533 return 0;
5534}
5535
5536#ifdef CONFIG_MSM_SDIO_AL
5537int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
5538{
5539 struct msmsdcc_host *host = mmc_priv(mmc);
5540 unsigned long flags;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305541 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005542
Asutosh Dasf5298c32012-04-03 14:51:47 +05305543 mutex_lock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005544 spin_lock_irqsave(&host->lock, flags);
5545 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
5546 enable ? "En" : "Dis");
5547
5548 if (enable) {
5549 if (!host->sdcc_irq_disabled) {
5550 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05305551 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005552 host->sdcc_irq_disabled = 1;
5553 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305554 rc = msmsdcc_setup_clocks(host, false);
5555 if (rc)
5556 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005557
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305558 if (host->plat->sdio_lpm_gpio_setup &&
5559 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005560 spin_unlock_irqrestore(&host->lock, flags);
5561 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
5562 spin_lock_irqsave(&host->lock, flags);
5563 host->sdio_gpio_lpm = 1;
5564 }
5565
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305566 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005567 msmsdcc_enable_irq_wake(host);
5568 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305569 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005570 }
5571 } else {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305572 rc = msmsdcc_setup_clocks(host, true);
5573 if (rc)
5574 goto out;
5575
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305576 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005577 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305578 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005579 msmsdcc_disable_irq_wake(host);
5580 }
5581
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305582 if (host->plat->sdio_lpm_gpio_setup &&
5583 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005584 spin_unlock_irqrestore(&host->lock, flags);
5585 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
5586 spin_lock_irqsave(&host->lock, flags);
5587 host->sdio_gpio_lpm = 0;
5588 }
5589
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305590 if (host->sdcc_irq_disabled && atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005591 writel_relaxed(host->mci_irqenable,
5592 host->base + MMCIMASK0);
5593 mb();
5594 enable_irq(host->core_irqres->start);
5595 host->sdcc_irq_disabled = 0;
5596 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005597 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305598out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005599 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305600 mutex_unlock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305601 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005602}
5603#else
5604int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
5605{
5606 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07005607}
5608#endif
5609
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005610#ifdef CONFIG_PM
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05305611#ifdef CONFIG_MMC_CLKGATE
5612static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
5613{
5614 struct mmc_host *mmc = host->mmc;
5615 unsigned long flags;
5616
5617 mmc_host_clk_hold(mmc);
5618 spin_lock_irqsave(&mmc->clk_lock, flags);
5619 mmc->clk_old = mmc->ios.clock;
5620 mmc->ios.clock = 0;
5621 mmc->clk_gated = true;
5622 spin_unlock_irqrestore(&mmc->clk_lock, flags);
5623 mmc_set_ios(mmc);
5624 mmc_host_clk_release(mmc);
5625}
5626
5627static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
5628{
5629 struct mmc_host *mmc = host->mmc;
5630
5631 mmc_host_clk_hold(mmc);
5632 mmc->ios.clock = host->clk_rate;
5633 mmc_set_ios(mmc);
5634 mmc_host_clk_release(mmc);
5635}
5636#else
5637static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
5638{
5639 struct mmc_host *mmc = host->mmc;
5640
5641 mmc->ios.clock = 0;
5642 mmc_set_ios(mmc);
5643}
5644
5645static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
5646{
5647 struct mmc_host *mmc = host->mmc;
5648
5649 mmc->ios.clock = host->clk_rate;
5650 mmc_set_ios(mmc);
5651}
5652#endif
5653
San Mehat9d2bd732009-09-22 16:44:22 -07005654static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005655msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07005656{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005657 struct mmc_host *mmc = dev_get_drvdata(dev);
5658 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07005659 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305660 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07005661
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305662 if (host->plat->is_sdio_al_client) {
5663 rc = 0;
5664 goto out;
San Mehat9d2bd732009-09-22 16:44:22 -07005665 }
San Mehat9d2bd732009-09-22 16:44:22 -07005666
Sahitya Tummala7661a452011-07-18 13:28:35 +05305667 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005668 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005669 host->sdcc_suspending = 1;
5670 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07005671
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005672 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005673 * MMC core thinks that host is disabled by now since
5674 * runtime suspend is scheduled after msmsdcc_disable()
5675 * is called. Thus, MMC core will try to enable the host
5676 * while suspending it. This results in a synchronous
5677 * runtime resume request while in runtime suspending
5678 * context and hence inorder to complete this resume
5679 * requet, it will wait for suspend to be complete,
5680 * but runtime suspend also can not proceed further
5681 * until the host is resumed. Thus, it leads to a hang.
5682 * Hence, increase the pm usage count before suspending
5683 * the host so that any resume requests after this will
5684 * simple become pm usage counter increment operations.
5685 */
5686 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05305687 /* If there is pending detect work abort runtime suspend */
5688 if (unlikely(work_busy(&mmc->detect.work)))
5689 rc = -EAGAIN;
5690 else
5691 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005692 pm_runtime_put_noidle(dev);
5693
5694 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305695 spin_lock_irqsave(&host->lock, flags);
5696 host->sdcc_suspended = true;
5697 spin_unlock_irqrestore(&host->lock, flags);
5698 if (mmc->card && mmc_card_sdio(mmc->card) &&
5699 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005700 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305701 * If SDIO function driver doesn't want
5702 * to power off the card, atleast turn off
5703 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005704 */
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05305705 msmsdcc_gate_clock(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005706 }
5707 }
5708 host->sdcc_suspending = 0;
5709 mmc->suspend_task = NULL;
5710 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
5711 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005712 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05305713 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305714out:
5715 /* set bus bandwidth to 0 immediately */
5716 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
San Mehat9d2bd732009-09-22 16:44:22 -07005717 return rc;
5718}
5719
5720static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005721msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07005722{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005723 struct mmc_host *mmc = dev_get_drvdata(dev);
5724 struct msmsdcc_host *host = mmc_priv(mmc);
5725 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07005726
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005727 if (host->plat->is_sdio_al_client)
5728 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07005729
Sahitya Tummala7661a452011-07-18 13:28:35 +05305730 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005731 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305732 if (mmc->card && mmc_card_sdio(mmc->card) &&
5733 mmc_card_keep_power(mmc)) {
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05305734 msmsdcc_ungate_clock(host);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305735 }
San Mehat9d2bd732009-09-22 16:44:22 -07005736
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005737 mmc_resume_host(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07005738
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005739 /*
5740 * FIXME: Clearing of flags must be handled in clients
5741 * resume handler.
5742 */
5743 spin_lock_irqsave(&host->lock, flags);
5744 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305745 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005746 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07005747
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005748 /*
5749 * After resuming the host wait for sometime so that
5750 * the SDIO work will be processed.
5751 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305752 if (mmc->card && mmc_card_sdio(mmc->card)) {
Subhash Jadavanic9b85752012-04-13 11:16:49 +05305753 if ((host->plat->mpm_sdiowakeup_int ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005754 host->plat->sdiowakeup_irq) &&
5755 wake_lock_active(&host->sdio_wlock))
5756 wake_lock_timeout(&host->sdio_wlock, 1);
5757 }
5758
5759 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005760 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05305761 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005762 return 0;
5763}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005764
5765static int msmsdcc_runtime_idle(struct device *dev)
5766{
5767 struct mmc_host *mmc = dev_get_drvdata(dev);
5768 struct msmsdcc_host *host = mmc_priv(mmc);
5769
5770 if (host->plat->is_sdio_al_client)
5771 return 0;
5772
5773 /* Idle timeout is not configurable for now */
5774 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
5775
5776 return -EAGAIN;
5777}
5778
5779static int msmsdcc_pm_suspend(struct device *dev)
5780{
5781 struct mmc_host *mmc = dev_get_drvdata(dev);
5782 struct msmsdcc_host *host = mmc_priv(mmc);
5783 int rc = 0;
5784
5785 if (host->plat->is_sdio_al_client)
5786 return 0;
5787
5788
5789 if (host->plat->status_irq)
5790 disable_irq(host->plat->status_irq);
5791
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005792 if (!pm_runtime_suspended(dev))
5793 rc = msmsdcc_runtime_suspend(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005794
5795 return rc;
5796}
5797
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305798static int msmsdcc_suspend_noirq(struct device *dev)
5799{
5800 struct mmc_host *mmc = dev_get_drvdata(dev);
5801 struct msmsdcc_host *host = mmc_priv(mmc);
5802 int rc = 0;
5803
5804 /*
5805 * After platform suspend there may be active request
5806 * which might have enabled clocks. For example, in SDIO
5807 * case, ksdioirq thread might have scheduled after sdcc
5808 * suspend but before system freeze. In that case abort
5809 * suspend and retry instead of keeping the clocks on
5810 * during suspend and not allowing TCXO.
5811 */
5812
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305813 if (atomic_read(&host->clks_on) && !host->plat->is_sdio_al_client) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305814 pr_warn("%s: clocks are on after suspend, aborting system "
5815 "suspend\n", mmc_hostname(mmc));
5816 rc = -EAGAIN;
5817 }
5818
5819 return rc;
5820}
5821
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005822static int msmsdcc_pm_resume(struct device *dev)
5823{
5824 struct mmc_host *mmc = dev_get_drvdata(dev);
5825 struct msmsdcc_host *host = mmc_priv(mmc);
5826 int rc = 0;
5827
5828 if (host->plat->is_sdio_al_client)
5829 return 0;
5830
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005831 if (mmc->card && mmc_card_sdio(mmc->card))
Sahitya Tummalafb486372011-09-02 19:01:49 +05305832 rc = msmsdcc_runtime_resume(dev);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005833 else
5834 host->pending_resume = true;
5835
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005836 if (host->plat->status_irq) {
5837 msmsdcc_check_status((unsigned long)host);
5838 enable_irq(host->plat->status_irq);
5839 }
5840
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005841 return rc;
5842}
5843
Daniel Walker08ecfde2010-06-23 12:32:20 -07005844#else
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005845static int msmsdcc_runtime_suspend(struct device *dev)
5846{
5847 return 0;
5848}
5849static int msmsdcc_runtime_idle(struct device *dev)
5850{
5851 return 0;
5852}
5853static int msmsdcc_pm_suspend(struct device *dev)
5854{
5855 return 0;
5856}
5857static int msmsdcc_pm_resume(struct device *dev)
5858{
5859 return 0;
5860}
5861static int msmsdcc_suspend_noirq(struct device *dev)
5862{
5863 return 0;
5864}
5865static int msmsdcc_runtime_resume(struct device *dev)
5866{
5867 return 0;
5868}
Daniel Walker08ecfde2010-06-23 12:32:20 -07005869#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005870
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005871static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
5872 .runtime_suspend = msmsdcc_runtime_suspend,
5873 .runtime_resume = msmsdcc_runtime_resume,
5874 .runtime_idle = msmsdcc_runtime_idle,
5875 .suspend = msmsdcc_pm_suspend,
5876 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305877 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005878};
5879
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305880static const struct of_device_id msmsdcc_dt_match[] = {
5881 {.compatible = "qcom,msm-sdcc"},
5882
5883};
5884MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
5885
San Mehat9d2bd732009-09-22 16:44:22 -07005886static struct platform_driver msmsdcc_driver = {
5887 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005888 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07005889 .driver = {
5890 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005891 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305892 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07005893 },
5894};
5895
5896static int __init msmsdcc_init(void)
5897{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005898#if defined(CONFIG_DEBUG_FS)
5899 int ret = 0;
5900 ret = msmsdcc_dbg_init();
5901 if (ret) {
5902 pr_err("Failed to create debug fs dir \n");
5903 return ret;
5904 }
5905#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005906 return platform_driver_register(&msmsdcc_driver);
5907}
San Mehat9d2bd732009-09-22 16:44:22 -07005908
San Mehat9d2bd732009-09-22 16:44:22 -07005909static void __exit msmsdcc_exit(void)
5910{
5911 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005912
5913#if defined(CONFIG_DEBUG_FS)
5914 debugfs_remove(debugfs_file);
5915 debugfs_remove(debugfs_dir);
5916#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005917}
5918
5919module_init(msmsdcc_init);
5920module_exit(msmsdcc_exit);
5921
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005922MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07005923MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005924
5925#if defined(CONFIG_DEBUG_FS)
5926
5927static int
5928msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
5929{
5930 file->private_data = inode->i_private;
5931 return 0;
5932}
5933
5934static ssize_t
5935msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
5936 size_t count, loff_t *ppos)
5937{
5938 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08005939 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005940 int max, i;
5941
5942 i = 0;
5943 max = sizeof(buf) - 1;
5944
5945 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
5946 host->curr.cmd, host->curr.data);
5947 if (host->curr.cmd) {
5948 struct mmc_command *cmd = host->curr.cmd;
5949
5950 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
5951 cmd->opcode, cmd->arg, cmd->flags);
5952 }
5953 if (host->curr.data) {
5954 struct mmc_data *data = host->curr.data;
5955 i += scnprintf(buf + i, max - i,
5956 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
5957 data->timeout_ns, data->timeout_clks,
5958 data->blksz, data->blocks, data->error,
5959 data->flags);
5960 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
5961 host->curr.xfer_size, host->curr.xfer_remain,
5962 host->curr.data_xfered, host->dma.sg);
5963 }
5964
5965 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
5966}
5967
5968static const struct file_operations msmsdcc_dbg_state_ops = {
5969 .read = msmsdcc_dbg_state_read,
5970 .open = msmsdcc_dbg_state_open,
5971};
5972
5973static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
5974{
5975 if (debugfs_dir) {
5976 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
5977 0644, debugfs_dir, host,
5978 &msmsdcc_dbg_state_ops);
5979 }
5980}
5981
5982static int __init msmsdcc_dbg_init(void)
5983{
5984 int err;
5985
5986 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
5987 if (IS_ERR(debugfs_dir)) {
5988 err = PTR_ERR(debugfs_dir);
5989 debugfs_dir = NULL;
5990 return err;
5991 }
5992
5993 return 0;
5994}
5995#endif