blob: 23cb03d10258b788f463cb24e70fdd5af98a5b72 [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>
Sujit Reddy Thumma38459152012-06-26 00:07:59 +053023#include <linux/of_gpio.h>
San Mehat9d2bd732009-09-22 16:44:22 -070024#include <linux/device.h>
25#include <linux/interrupt.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070026#include <linux/irq.h>
San Mehat9d2bd732009-09-22 16:44:22 -070027#include <linux/delay.h>
28#include <linux/err.h>
29#include <linux/highmem.h>
30#include <linux/log2.h>
31#include <linux/mmc/host.h>
32#include <linux/mmc/card.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070033#include <linux/mmc/mmc.h>
San Mehatb3fa5792009-11-02 18:46:09 -080034#include <linux/mmc/sdio.h>
San Mehat9d2bd732009-09-22 16:44:22 -070035#include <linux/clk.h>
36#include <linux/scatterlist.h>
37#include <linux/platform_device.h>
38#include <linux/dma-mapping.h>
39#include <linux/debugfs.h>
40#include <linux/io.h>
41#include <linux/memory.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070042#include <linux/pm_runtime.h>
43#include <linux/wakelock.h>
Sahitya Tummala7a892482011-01-18 11:22:49 +053044#include <linux/gpio.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070045#include <linux/regulator/consumer.h>
46#include <linux/slab.h>
Steve Mucklef132c6c2012-06-06 18:30:57 -070047#include <linux/pm_qos.h>
San Mehat9d2bd732009-09-22 16:44:22 -070048
49#include <asm/cacheflush.h>
50#include <asm/div64.h>
51#include <asm/sizes.h>
52
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070053#include <asm/mach/mmc.h>
San Mehat9d2bd732009-09-22 16:44:22 -070054#include <mach/msm_iomap.h>
Sahitya Tummalab08bb352010-12-08 15:03:05 +053055#include <mach/clk.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070056#include <mach/dma.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070057#include <mach/sdio_al.h>
Subhash Jadavanic9b85752012-04-13 11:16:49 +053058#include <mach/mpm.h>
Subhash Jadavanibcd435f2012-04-24 18:26:49 +053059#include <mach/msm_bus.h>
San Mehat9d2bd732009-09-22 16:44:22 -070060
San Mehat9d2bd732009-09-22 16:44:22 -070061#include "msm_sdcc.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070062#include "msm_sdcc_dml.h"
San Mehat9d2bd732009-09-22 16:44:22 -070063
64#define DRIVER_NAME "msm-sdcc"
65
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070066#define DBG(host, fmt, args...) \
67 pr_debug("%s: %s: " fmt "\n", mmc_hostname(host->mmc), __func__ , args)
68
69#define IRQ_DEBUG 0
70#define SPS_SDCC_PRODUCER_PIPE_INDEX 1
71#define SPS_SDCC_CONSUMER_PIPE_INDEX 2
72#define SPS_CONS_PERIPHERAL 0
73#define SPS_PROD_PERIPHERAL 1
Subhash Jadavanie6e1b822012-03-12 18:17:58 +053074/* Use SPS only if transfer size is more than this macro */
75#define SPS_MIN_XFER_SIZE MCI_FIFOSIZE
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070076
Subhash Jadavanibcd435f2012-04-24 18:26:49 +053077#define MSM_MMC_BUS_VOTING_DELAY 200 /* msecs */
78
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070079#if defined(CONFIG_DEBUG_FS)
80static void msmsdcc_dbg_createhost(struct msmsdcc_host *);
81static struct dentry *debugfs_dir;
82static struct dentry *debugfs_file;
83static int msmsdcc_dbg_init(void);
84#endif
85
Asutosh Dasaccacd42012-03-08 14:33:17 +053086static int msmsdcc_prep_xfer(struct msmsdcc_host *host, struct mmc_data
87 *data);
88
Subhash Jadavani8766e352011-11-30 11:30:32 +053089static u64 dma_mask = DMA_BIT_MASK(32);
San Mehat9d2bd732009-09-22 16:44:22 -070090static unsigned int msmsdcc_pwrsave = 1;
San Mehat9d2bd732009-09-22 16:44:22 -070091
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070092static struct mmc_command dummy52cmd;
93static struct mmc_request dummy52mrq = {
94 .cmd = &dummy52cmd,
95 .data = NULL,
96 .stop = NULL,
97};
98static struct mmc_command dummy52cmd = {
99 .opcode = SD_IO_RW_DIRECT,
100 .flags = MMC_RSP_PRESENT,
101 .data = NULL,
102 .mrq = &dummy52mrq,
103};
104/*
105 * An array holding the Tuning pattern to compare with when
106 * executing a tuning cycle.
107 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +0530108static const u32 tuning_block_64[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700109 0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
110 0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
111 0xF0FFF0FF, 0x3CCCFC0F, 0xCFCC33CC, 0xEEFFEFFF,
112 0xFDFFFDFF, 0xFFBFFFDF, 0xFFF7FFBB, 0xDE7B7FF7
113};
San Mehat9d2bd732009-09-22 16:44:22 -0700114
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +0530115static const u32 tuning_block_128[] = {
116 0xFF00FFFF, 0x0000FFFF, 0xCCCCFFFF, 0xCCCC33CC,
117 0xCC3333CC, 0xFFFFCCCC, 0xFFFFEEFF, 0xFFEEEEFF,
118 0xFFDDFFFF, 0xDDDDFFFF, 0xBBFFFFFF, 0xBBFFFFFF,
119 0xFFFFFFBB, 0xFFFFFF77, 0x77FF7777, 0xFFEEDDBB,
120 0x00FFFFFF, 0x00FFFFFF, 0xCCFFFF00, 0xCC33CCCC,
121 0x3333CCCC, 0xFFCCCCCC, 0xFFEEFFFF, 0xEEEEFFFF,
122 0xDDFFFFFF, 0xDDFFFFFF, 0xFFFFFFDD, 0xFFFFFFBB,
123 0xFFFFBBBB, 0xFFFF77FF, 0xFF7777FF, 0xEEDDBB77
124};
San Mehat865c8062009-11-13 13:42:06 -0800125
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700126#if IRQ_DEBUG == 1
127static char *irq_status_bits[] = { "cmdcrcfail", "datcrcfail", "cmdtimeout",
128 "dattimeout", "txunderrun", "rxoverrun",
129 "cmdrespend", "cmdsent", "dataend", NULL,
130 "datablkend", "cmdactive", "txactive",
131 "rxactive", "txhalfempty", "rxhalffull",
132 "txfifofull", "rxfifofull", "txfifoempty",
133 "rxfifoempty", "txdataavlbl", "rxdataavlbl",
134 "sdiointr", "progdone", "atacmdcompl",
135 "sdiointrope", "ccstimeout", NULL, NULL,
136 NULL, NULL, NULL };
137
138static void
139msmsdcc_print_status(struct msmsdcc_host *host, char *hdr, uint32_t status)
San Mehat865c8062009-11-13 13:42:06 -0800140{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700141 int i;
San Mehat8b1c2ba2009-11-16 10:17:30 -0800142
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700143 pr_debug("%s-%s ", mmc_hostname(host->mmc), hdr);
144 for (i = 0; i < 32; i++) {
145 if (status & (1 << i))
146 pr_debug("%s ", irq_status_bits[i]);
San Mehat865c8062009-11-13 13:42:06 -0800147 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700148 pr_debug("\n");
San Mehatc7fc9372009-11-22 17:19:07 -0800149}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700150#endif
San Mehat865c8062009-11-13 13:42:06 -0800151
San Mehat9d2bd732009-09-22 16:44:22 -0700152static void
153msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
154 u32 c);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530155static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530156static inline void msmsdcc_delay(struct msmsdcc_host *host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530157static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -0800158static void msmsdcc_sg_start(struct msmsdcc_host *host);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -0800159static int msmsdcc_vreg_reset(struct msmsdcc_host *host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -0700160static int msmsdcc_runtime_resume(struct device *dev);
San Mehat9d2bd732009-09-22 16:44:22 -0700161
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530162static inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530163{
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530164 unsigned short ret = NR_SG;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530165
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530166 if (is_sps_mode(host)) {
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +0530167 ret = SPS_MAX_DESCS;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530168 } else { /* DMA or PIO mode */
169 if (NR_SG > MAX_NR_SG_DMA_PIO)
170 ret = MAX_NR_SG_DMA_PIO;
171 }
172
173 return ret;
174}
175
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530176/* Prevent idle power collapse(pc) while operating in peripheral mode */
177static void msmsdcc_pm_qos_update_latency(struct msmsdcc_host *host, int vote)
178{
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -0700179 if (!host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530180 return;
181
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530182 if (vote)
183 pm_qos_update_request(&host->pm_qos_req_dma,
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -0700184 host->cpu_dma_latency);
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530185 else
186 pm_qos_update_request(&host->pm_qos_req_dma,
187 PM_QOS_DEFAULT_VALUE);
188}
189
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700190#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
191static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
192 struct msmsdcc_sps_ep_conn_data *ep);
193static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
194 struct msmsdcc_sps_ep_conn_data *ep);
195#else
196static inline int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
197 struct msmsdcc_sps_ep_conn_data *ep,
198 bool is_producer) { return 0; }
199static inline void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
200 struct msmsdcc_sps_ep_conn_data *ep) { }
201static inline int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
202 struct msmsdcc_sps_ep_conn_data *ep)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530203{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700204 return 0;
205}
206static inline int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
207 struct msmsdcc_sps_ep_conn_data *ep)
208{
209 return 0;
210}
211static inline int msmsdcc_sps_init(struct msmsdcc_host *host) { return 0; }
212static inline void msmsdcc_sps_exit(struct msmsdcc_host *host) {}
213#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530214
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700215/**
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530216 * Apply soft reset to all SDCC BAM pipes
217 *
218 * This function applies soft reset to SDCC BAM pipe.
219 *
220 * This function should be called to recover from error
221 * conditions encountered during CMD/DATA tranfsers with card.
222 *
223 * @host - Pointer to driver's host structure
224 *
225 */
226static void msmsdcc_sps_pipes_reset_and_restore(struct msmsdcc_host *host)
227{
228 int rc;
229
230 /* Reset all SDCC BAM pipes */
231 rc = msmsdcc_sps_reset_ep(host, &host->sps.prod);
232 if (rc)
233 pr_err("%s:msmsdcc_sps_reset_ep(prod) error=%d\n",
234 mmc_hostname(host->mmc), rc);
235 rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
236 if (rc)
237 pr_err("%s:msmsdcc_sps_reset_ep(cons) error=%d\n",
238 mmc_hostname(host->mmc), rc);
239
Krishna Konda5af8f972012-05-14 16:15:24 -0700240 if (host->sps.reset_device) {
241 rc = sps_device_reset(host->sps.bam_handle);
242 if (rc)
243 pr_err("%s: sps_device_reset error=%d\n",
244 mmc_hostname(host->mmc), rc);
245 host->sps.reset_device = false;
246 }
247
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530248 /* Restore all BAM pipes connections */
249 rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
250 if (rc)
251 pr_err("%s:msmsdcc_sps_restore_ep(prod) error=%d\n",
252 mmc_hostname(host->mmc), rc);
253 rc = msmsdcc_sps_restore_ep(host, &host->sps.cons);
254 if (rc)
255 pr_err("%s:msmsdcc_sps_restore_ep(cons) error=%d\n",
256 mmc_hostname(host->mmc), rc);
257}
258
259/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700260 * Apply soft reset
261 *
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530262 * This function applies soft reset to SDCC core and DML core.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700263 *
264 * This function should be called to recover from error
265 * conditions encountered with CMD/DATA tranfsers with card.
266 *
267 * Soft reset should only be used with SDCC controller v4.
268 *
269 * @host - Pointer to driver's host structure
270 *
271 */
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530272static void msmsdcc_soft_reset(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700273{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700274 /*
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530275 * Reset controller state machines without resetting
276 * configuration registers (MCI_POWER, MCI_CLK, MCI_INT_MASKn).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700277 */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530278 if (is_sw_reset_save_config(host)) {
279 ktime_t start;
280
281 writel_relaxed(readl_relaxed(host->base + MMCIPOWER)
282 | MCI_SW_RST_CFG, host->base + MMCIPOWER);
283 msmsdcc_sync_reg_wr(host);
284
285 start = ktime_get();
286 while (readl_relaxed(host->base + MMCIPOWER) & MCI_SW_RST_CFG) {
287 /*
288 * SW reset can take upto 10HCLK + 15MCLK cycles.
289 * Calculating based on min clk rates (hclk = 27MHz,
290 * mclk = 400KHz) it comes to ~40us. Let's poll for
291 * max. 1ms for reset completion.
292 */
293 if (ktime_to_us(ktime_sub(ktime_get(), start)) > 1000) {
294 pr_err("%s: %s failed\n",
295 mmc_hostname(host->mmc), __func__);
296 BUG();
297 }
298 }
299 } else {
300 writel_relaxed(0, host->base + MMCICOMMAND);
301 msmsdcc_sync_reg_wr(host);
302 writel_relaxed(0, host->base + MMCIDATACTRL);
303 msmsdcc_sync_reg_wr(host);
304 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530305}
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530306
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530307static void msmsdcc_hard_reset(struct msmsdcc_host *host)
308{
309 int ret;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530310
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530311 /*
312 * Reset SDCC controller to power on default state.
313 * Don't issue a reset request to clock control block if
314 * SDCC controller itself can support hard reset.
315 */
316 if (is_sw_hard_reset(host)) {
317 ktime_t start;
318
319 writel_relaxed(readl_relaxed(host->base + MMCIPOWER)
320 | MCI_SW_RST, host->base + MMCIPOWER);
321 msmsdcc_sync_reg_wr(host);
322
323 start = ktime_get();
324 while (readl_relaxed(host->base + MMCIPOWER) & MCI_SW_RST) {
325 /*
326 * See comment in msmsdcc_soft_reset() on choosing 1ms
327 * poll timeout.
328 */
329 if (ktime_to_us(ktime_sub(ktime_get(), start)) > 1000) {
330 pr_err("%s: %s failed\n",
331 mmc_hostname(host->mmc), __func__);
332 BUG();
333 }
334 }
335 } else {
336 ret = clk_reset(host->clk, CLK_RESET_ASSERT);
337 if (ret)
338 pr_err("%s: Clock assert failed at %u Hz" \
339 " with err %d\n", mmc_hostname(host->mmc),
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530340 host->clk_rate, ret);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530341
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530342 ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
343 if (ret)
344 pr_err("%s: Clock deassert failed at %u Hz" \
345 " with err %d\n", mmc_hostname(host->mmc),
346 host->clk_rate, ret);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530347
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530348 mb();
349 /* Give some delay for clock reset to propogate to controller */
350 msmsdcc_delay(host);
351 }
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530352}
353
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700354static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
355{
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530356 if (is_soft_reset(host)) {
357 if (is_sps_mode(host)) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530358 /* Reset DML first */
359 msmsdcc_dml_reset(host);
360 /*
361 * delay the SPS pipe reset in thread context as
362 * sps_connect/sps_disconnect APIs can be called
363 * only from non-atomic context.
364 */
365 host->sps.pipe_reset_pending = true;
366 }
367 mb();
368 msmsdcc_soft_reset(host);
369
370 pr_debug("%s: Applied soft reset to Controller\n",
371 mmc_hostname(host->mmc));
372
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530373 if (is_sps_mode(host))
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530374 msmsdcc_dml_init(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700375 } else {
376 /* Give Clock reset (hard reset) to controller */
377 u32 mci_clk = 0;
378 u32 mci_mask0 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700379
380 /* Save the controller state */
381 mci_clk = readl_relaxed(host->base + MMCICLOCK);
382 mci_mask0 = readl_relaxed(host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +0530383 host->pwr = readl_relaxed(host->base + MMCIPOWER);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700384 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700385
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530386 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700387 pr_debug("%s: Controller has been reinitialized\n",
388 mmc_hostname(host->mmc));
389
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700390 /* Restore the contoller state */
391 writel_relaxed(host->pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530392 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700393 writel_relaxed(mci_clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530394 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700395 writel_relaxed(mci_mask0, host->base + MMCIMASK0);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530396 mb(); /* no delay required after writing to MASK0 register */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700397 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530398
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700399 if (host->dummy_52_needed)
400 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700401}
402
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530403static void msmsdcc_reset_dpsm(struct msmsdcc_host *host)
404{
405 struct mmc_request *mrq = host->curr.mrq;
406
407 if (!mrq || !mrq->cmd || (!mrq->data && !host->pending_dpsm_reset))
408 goto out;
409
410 /*
411 * For CMD24, if auto prog done is not supported defer
412 * dpsm reset until prog done is received. Otherwise,
413 * we poll here unnecessarily as TXACTIVE will not be
414 * deasserted until DAT0 goes high.
415 */
416 if ((mrq->cmd->opcode == MMC_WRITE_BLOCK) && !is_auto_prog_done(host)) {
417 host->pending_dpsm_reset = true;
418 goto out;
419 }
420
421 /* Make sure h/w (TX/RX) is inactive before resetting DPSM */
422 if (is_wait_for_tx_rx_active(host)) {
423 ktime_t start = ktime_get();
424
425 while (readl_relaxed(host->base + MMCISTATUS) &
426 (MCI_TXACTIVE | MCI_RXACTIVE)) {
427 /*
428 * TX/RX active bits may be asserted for 4HCLK + 4MCLK
429 * cycles (~11us) after data transfer due to clock mux
430 * switching delays. Let's poll for 1ms and panic if
431 * still active.
432 */
433 if (ktime_to_us(ktime_sub(ktime_get(), start)) > 1000) {
434 pr_err("%s: %s still active\n",
435 mmc_hostname(host->mmc),
436 readl_relaxed(host->base + MMCISTATUS)
437 & MCI_TXACTIVE ? "TX" : "RX");
438 msmsdcc_dump_sdcc_state(host);
439 BUG();
440 }
441 }
442 }
443
444 writel_relaxed(0, host->base + MMCIDATACTRL);
445 msmsdcc_sync_reg_wr(host); /* Allow the DPSM to be reset */
446 host->pending_dpsm_reset = false;
447out:
448 return;
449}
450
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700451static int
San Mehat9d2bd732009-09-22 16:44:22 -0700452msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
453{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700454 int retval = 0;
455
San Mehat9d2bd732009-09-22 16:44:22 -0700456 BUG_ON(host->curr.data);
457
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700458 del_timer(&host->req_tout_timer);
San Mehat9d2bd732009-09-22 16:44:22 -0700459
460 if (mrq->data)
461 mrq->data->bytes_xfered = host->curr.data_xfered;
462 if (mrq->cmd->error == -ETIMEDOUT)
463 mdelay(5);
464
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530465 msmsdcc_reset_dpsm(host);
466
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530467 /* Clear current request information as current request has ended */
468 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
469
San Mehat9d2bd732009-09-22 16:44:22 -0700470 /*
471 * Need to drop the host lock here; mmc_request_done may call
472 * back into the driver...
473 */
474 spin_unlock(&host->lock);
475 mmc_request_done(host->mmc, mrq);
476 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700477
478 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700479}
480
481static void
482msmsdcc_stop_data(struct msmsdcc_host *host)
483{
San Mehat9d2bd732009-09-22 16:44:22 -0700484 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530485 host->curr.got_dataend = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +0530486 host->curr.wait_for_auto_prog_done = false;
487 host->curr.got_auto_prog_done = false;
San Mehat9d2bd732009-09-22 16:44:22 -0700488}
489
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700490static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700491{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700492 return host->core_memres->start + MMCIFIFO;
493}
494
495static inline unsigned int msmsdcc_get_min_sup_clk_rate(
496 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530497
Subhash Jadavanidd432952012-03-28 11:25:56 +0530498static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700499{
500 mb();
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530501 if (!is_wait_for_reg_write(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +0530502 udelay(host->reg_write_delay);
503 else if (readl_relaxed(host->base + MCI_STATUS2) &
504 MCI_MCLK_REG_WR_ACTIVE) {
505 ktime_t start, diff;
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530506
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530507 start = ktime_get();
508 while (readl_relaxed(host->base + MCI_STATUS2) &
509 MCI_MCLK_REG_WR_ACTIVE) {
510 diff = ktime_sub(ktime_get(), start);
511 /* poll for max. 1 ms */
512 if (ktime_to_us(diff) > 1000) {
513 pr_warning("%s: previous reg. write is"
514 " still active\n",
515 mmc_hostname(host->mmc));
516 break;
517 }
518 }
519 }
San Mehat9d2bd732009-09-22 16:44:22 -0700520}
521
Subhash Jadavanidd432952012-03-28 11:25:56 +0530522static inline void msmsdcc_delay(struct msmsdcc_host *host)
523{
524 udelay(host->reg_write_delay);
525
San Mehat9d2bd732009-09-22 16:44:22 -0700526}
527
San Mehat56a8b5b2009-11-21 12:29:46 -0800528static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700529msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
530{
531 writel_relaxed(arg, host->base + MMCIARGUMENT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700532 writel_relaxed(c, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530533 /*
534 * As after sending the command, we don't write any of the
535 * controller registers and just wait for the
536 * CMD_RESPOND_END/CMD_SENT/Command failure notication
537 * from Controller.
538 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700539 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800540}
541
542static void
543msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
544{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700545 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800546
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700547 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
548 writel_relaxed((unsigned int)host->curr.xfer_size,
549 host->base + MMCIDATALENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700550 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530551 msmsdcc_sync_reg_wr(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800552
San Mehat6ac9ea62009-12-02 17:24:58 -0800553 if (host->cmd_cmd) {
554 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700555 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800556 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800557}
558
San Mehat9d2bd732009-09-22 16:44:22 -0700559static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530560msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700561{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530562 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700563 unsigned long flags;
564 struct mmc_request *mrq;
565
566 spin_lock_irqsave(&host->lock, flags);
567 mrq = host->curr.mrq;
568 BUG_ON(!mrq);
569
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530570 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700571 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700572 goto out;
573 }
574
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530575 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700576 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700577 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700578 } else {
579 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530580 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700581 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530582 mmc_hostname(host->mmc), host->dma.result);
583 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700584 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530585 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530586 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700587 host->dma.err.flush[0], host->dma.err.flush[1],
588 host->dma.err.flush[2], host->dma.err.flush[3],
589 host->dma.err.flush[4],
590 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530591 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700592 if (!mrq->data->error)
593 mrq->data->error = -EIO;
594 }
Asutosh Dasaccacd42012-03-08 14:33:17 +0530595 if (!mrq->data->host_cookie)
596 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
597 host->dma.num_ents, host->dma.dir);
San Mehat9d2bd732009-09-22 16:44:22 -0700598
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700599 if (host->curr.user_pages) {
600 struct scatterlist *sg = host->dma.sg;
601 int i;
602
603 for (i = 0; i < host->dma.num_ents; i++, sg++)
604 flush_dcache_page(sg_page(sg));
605 }
San Mehat9d2bd732009-09-22 16:44:22 -0700606
San Mehat9d2bd732009-09-22 16:44:22 -0700607 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800608 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700609
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530610 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
611 (host->curr.wait_for_auto_prog_done &&
612 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700613 /*
614 * If we've already gotten our DATAEND / DATABLKEND
615 * for this request, then complete it through here.
616 */
San Mehat9d2bd732009-09-22 16:44:22 -0700617
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700618 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700619 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700620 host->curr.xfer_remain -= host->curr.xfer_size;
621 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700622 if (host->dummy_52_needed) {
San Mehat9d2bd732009-09-22 16:44:22 -0700623 mrq->data->bytes_xfered = host->curr.data_xfered;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700624 host->dummy_52_sent = 1;
625 msmsdcc_start_command(host, &dummy52cmd,
626 MCI_CPSM_PROGENA);
627 goto out;
628 }
629 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530630 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530631 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700632 mrq->data->bytes_xfered = host->curr.data_xfered;
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530633 msmsdcc_reset_dpsm(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700634 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530635 /*
636 * Clear current request information as current
637 * request has ended
638 */
639 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
San Mehat9d2bd732009-09-22 16:44:22 -0700640 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700641
San Mehat9d2bd732009-09-22 16:44:22 -0700642 mmc_request_done(host->mmc, mrq);
643 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530644 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
645 || !mrq->sbc)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700646 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530647 }
San Mehat9d2bd732009-09-22 16:44:22 -0700648 }
649
650out:
651 spin_unlock_irqrestore(&host->lock, flags);
652 return;
653}
654
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700655#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
656/**
657 * Callback notification from SPS driver
658 *
659 * This callback function gets triggered called from
660 * SPS driver when requested SPS data transfer is
661 * completed.
662 *
663 * SPS driver invokes this callback in BAM irq context so
664 * SDCC driver schedule a tasklet for further processing
665 * this callback notification at later point of time in
666 * tasklet context and immediately returns control back
667 * to SPS driver.
668 *
669 * @nofity - Pointer to sps event notify sturcture
670 *
671 */
672static void
673msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
674{
675 struct msmsdcc_host *host =
676 (struct msmsdcc_host *)
677 ((struct sps_event_notify *)notify)->user;
678
679 host->sps.notify = *notify;
680 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
681 mmc_hostname(host->mmc), __func__, notify->event_id,
682 notify->data.transfer.iovec.addr,
683 notify->data.transfer.iovec.size,
684 notify->data.transfer.iovec.flags);
685 /* Schedule a tasklet for completing data transfer */
686 tasklet_schedule(&host->sps.tlet);
687}
688
689/**
690 * Tasklet handler for processing SPS callback event
691 *
692 * This function processing SPS event notification and
693 * checks if the SPS transfer is completed or not and
694 * then accordingly notifies status to MMC core layer.
695 *
696 * This function is called in tasklet context.
697 *
698 * @data - Pointer to sdcc driver data
699 *
700 */
701static void msmsdcc_sps_complete_tlet(unsigned long data)
702{
703 unsigned long flags;
704 int i, rc;
705 u32 data_xfered = 0;
706 struct mmc_request *mrq;
707 struct sps_iovec iovec;
708 struct sps_pipe *sps_pipe_handle;
709 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
710 struct sps_event_notify *notify = &host->sps.notify;
711
712 spin_lock_irqsave(&host->lock, flags);
713 if (host->sps.dir == DMA_FROM_DEVICE)
714 sps_pipe_handle = host->sps.prod.pipe_handle;
715 else
716 sps_pipe_handle = host->sps.cons.pipe_handle;
717 mrq = host->curr.mrq;
718
719 if (!mrq) {
720 spin_unlock_irqrestore(&host->lock, flags);
721 return;
722 }
723
724 pr_debug("%s: %s: sps event_id=%d\n",
725 mmc_hostname(host->mmc), __func__,
726 notify->event_id);
727
728 if (msmsdcc_is_dml_busy(host)) {
729 /* oops !!! this should never happen. */
730 pr_err("%s: %s: Received SPS EOT event"
731 " but DML HW is still busy !!!\n",
732 mmc_hostname(host->mmc), __func__);
733 }
734 /*
735 * Got End of transfer event!!! Check if all of the data
736 * has been transferred?
737 */
738 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
739 rc = sps_get_iovec(sps_pipe_handle, &iovec);
740 if (rc) {
741 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
742 mmc_hostname(host->mmc), __func__, rc, i);
743 break;
744 }
745 data_xfered += iovec.size;
746 }
747
748 if (data_xfered == host->curr.xfer_size) {
749 host->curr.data_xfered = host->curr.xfer_size;
750 host->curr.xfer_remain -= host->curr.xfer_size;
751 pr_debug("%s: Data xfer success. data_xfered=0x%x",
752 mmc_hostname(host->mmc),
753 host->curr.xfer_size);
754 } else {
755 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
756 " xfer_size=%d", mmc_hostname(host->mmc),
757 data_xfered, host->curr.xfer_size);
758 msmsdcc_reset_and_restore(host);
759 if (!mrq->data->error)
760 mrq->data->error = -EIO;
761 }
762
763 /* Unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +0530764 if (!mrq->data->host_cookie)
765 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
766 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700767 host->sps.sg = NULL;
768 host->sps.busy = 0;
769
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530770 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
771 (host->curr.wait_for_auto_prog_done &&
772 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700773 /*
774 * If we've already gotten our DATAEND / DATABLKEND
775 * for this request, then complete it through here.
776 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700777
778 if (!mrq->data->error) {
779 host->curr.data_xfered = host->curr.xfer_size;
780 host->curr.xfer_remain -= host->curr.xfer_size;
781 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700782 if (host->dummy_52_needed) {
783 mrq->data->bytes_xfered = host->curr.data_xfered;
784 host->dummy_52_sent = 1;
785 msmsdcc_start_command(host, &dummy52cmd,
786 MCI_CPSM_PROGENA);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700787 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700788 return;
789 }
790 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530791 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530792 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700793 mrq->data->bytes_xfered = host->curr.data_xfered;
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530794 msmsdcc_reset_dpsm(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700795 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530796 /*
797 * Clear current request information as current
798 * request has ended
799 */
800 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700801 spin_unlock_irqrestore(&host->lock, flags);
802
803 mmc_request_done(host->mmc, mrq);
804 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530805 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
806 || !mrq->sbc)) {
807 msmsdcc_start_command(host, mrq->data->stop, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700808 }
809 }
810 spin_unlock_irqrestore(&host->lock, flags);
811}
812
813/**
814 * Exit from current SPS data transfer
815 *
816 * This function exits from current SPS data transfer.
817 *
818 * This function should be called when error condition
819 * is encountered during data transfer.
820 *
821 * @host - Pointer to sdcc host structure
822 *
823 */
824static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
825{
826 struct mmc_request *mrq;
827
828 mrq = host->curr.mrq;
829 BUG_ON(!mrq);
830
831 msmsdcc_reset_and_restore(host);
832 if (!mrq->data->error)
833 mrq->data->error = -EIO;
834
835 /* Unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +0530836 if (!mrq->data->host_cookie)
837 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
838 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700839
840 host->sps.sg = NULL;
841 host->sps.busy = 0;
842 if (host->curr.data)
843 msmsdcc_stop_data(host);
844
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530845 if (!mrq->data->stop || mrq->cmd->error ||
846 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700847 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530848 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
849 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700850 msmsdcc_start_command(host, mrq->data->stop, 0);
851
852}
853#else
854static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
855static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
856static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
857#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
858
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530859static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700860
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530861static void
862msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
863 unsigned int result,
864 struct msm_dmov_errdata *err)
865{
866 struct msmsdcc_dma_data *dma_data =
867 container_of(cmd, struct msmsdcc_dma_data, hdr);
868 struct msmsdcc_host *host = dma_data->host;
869
870 dma_data->result = result;
871 if (err)
872 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
873
874 tasklet_schedule(&host->dma_tlet);
875}
876
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530877static bool msmsdcc_is_dma_possible(struct msmsdcc_host *host,
878 struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700879{
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530880 bool ret = true;
881 u32 xfer_size = data->blksz * data->blocks;
San Mehat9d2bd732009-09-22 16:44:22 -0700882
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530883 if (is_sps_mode(host)) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530884 /*
885 * BAM Mode: Fall back on PIO if size is less
886 * than or equal to SPS_MIN_XFER_SIZE bytes.
887 */
888 if (xfer_size <= SPS_MIN_XFER_SIZE)
889 ret = false;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530890 } else if (is_dma_mode(host)) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530891 /*
892 * ADM Mode: Fall back on PIO if size is less than FIFO size
893 * or not integer multiple of FIFO size
894 */
895 if (xfer_size % MCI_FIFOSIZE)
896 ret = false;
897 } else {
898 /* PIO Mode */
899 ret = false;
900 }
901
902 return ret;
San Mehat9d2bd732009-09-22 16:44:22 -0700903}
904
905static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
906{
907 struct msmsdcc_nc_dmadata *nc;
908 dmov_box *box;
909 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700910 unsigned int n;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530911 int i, err = 0, box_cmd_cnt = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700912 struct scatterlist *sg = data->sg;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530913 unsigned int len, offset;
San Mehat9d2bd732009-09-22 16:44:22 -0700914
Krishna Konda25786ec2011-07-25 16:21:36 -0700915 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700916 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700917
Krishna Konda25786ec2011-07-25 16:21:36 -0700918 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
San Mehat9d2bd732009-09-22 16:44:22 -0700919
920 host->dma.sg = data->sg;
921 host->dma.num_ents = data->sg_len;
922
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530923 /* Prevent memory corruption */
924 BUG_ON(host->dma.num_ents > msmsdcc_get_nr_sg(host));
San Mehat56a8b5b2009-11-21 12:29:46 -0800925
San Mehat9d2bd732009-09-22 16:44:22 -0700926 nc = host->dma.nc;
927
San Mehat9d2bd732009-09-22 16:44:22 -0700928 if (data->flags & MMC_DATA_READ)
929 host->dma.dir = DMA_FROM_DEVICE;
930 else
931 host->dma.dir = DMA_TO_DEVICE;
932
Asutosh Dasaccacd42012-03-08 14:33:17 +0530933 if (!data->host_cookie) {
934 n = msmsdcc_prep_xfer(host, data);
935 if (unlikely(n < 0)) {
936 host->dma.sg = NULL;
937 host->dma.num_ents = 0;
938 return -ENOMEM;
939 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800940 }
San Mehat9d2bd732009-09-22 16:44:22 -0700941
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530942 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
943 host->curr.user_pages = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700944 box = &nc->cmd[0];
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530945 for (i = 0; i < host->dma.num_ents; i++) {
946 len = sg_dma_len(sg);
947 offset = 0;
948
949 do {
950 /* Check if we can do DMA */
951 if (!len || (box_cmd_cnt >= MMC_MAX_DMA_CMDS)) {
952 err = -ENOTSUPP;
953 goto unmap;
954 }
955
956 box->cmd = CMD_MODE_BOX;
957
958 if (len >= MMC_MAX_DMA_BOX_LENGTH) {
959 len = MMC_MAX_DMA_BOX_LENGTH;
960 len -= len % data->blksz;
961 }
962 rows = (len % MCI_FIFOSIZE) ?
963 (len / MCI_FIFOSIZE) + 1 :
964 (len / MCI_FIFOSIZE);
965
966 if (data->flags & MMC_DATA_READ) {
967 box->src_row_addr = msmsdcc_fifo_addr(host);
968 box->dst_row_addr = sg_dma_address(sg) + offset;
969 box->src_dst_len = (MCI_FIFOSIZE << 16) |
970 (MCI_FIFOSIZE);
971 box->row_offset = MCI_FIFOSIZE;
972 box->num_rows = rows * ((1 << 16) + 1);
973 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
974 } else {
975 box->src_row_addr = sg_dma_address(sg) + offset;
976 box->dst_row_addr = msmsdcc_fifo_addr(host);
977 box->src_dst_len = (MCI_FIFOSIZE << 16) |
978 (MCI_FIFOSIZE);
979 box->row_offset = (MCI_FIFOSIZE << 16);
980 box->num_rows = rows * ((1 << 16) + 1);
981 box->cmd |= CMD_DST_CRCI(host->dma.crci);
982 }
983
984 offset += len;
985 len = sg_dma_len(sg) - offset;
986 box++;
987 box_cmd_cnt++;
988 } while (len);
989 sg++;
990 }
991 /* Mark last command */
992 box--;
993 box->cmd |= CMD_LC;
San Mehat9d2bd732009-09-22 16:44:22 -0700994
995 /* location of command block must be 64 bit aligned */
996 BUG_ON(host->dma.cmd_busaddr & 0x07);
997
998 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
999 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
1000 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
1001 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
1002
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05301003 /* Flush all data to memory before starting dma */
1004 mb();
1005
1006unmap:
1007 if (err) {
Asutosh Dasaccacd42012-03-08 14:33:17 +05301008 if (!data->host_cookie)
1009 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
1010 host->dma.num_ents, host->dma.dir);
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05301011 pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
1012 mmc_hostname(host->mmc), err);
San Mehat9d2bd732009-09-22 16:44:22 -07001013 }
1014
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05301015 return err;
San Mehat9d2bd732009-09-22 16:44:22 -07001016}
1017
Asutosh Dasaccacd42012-03-08 14:33:17 +05301018static int msmsdcc_prep_xfer(struct msmsdcc_host *host,
1019 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -08001020{
Asutosh Dasaccacd42012-03-08 14:33:17 +05301021 int rc = 0;
1022 unsigned int dir;
1023
1024 /* Prevent memory corruption */
1025 BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
1026
1027 if (data->flags & MMC_DATA_READ)
1028 dir = DMA_FROM_DEVICE;
1029 else
1030 dir = DMA_TO_DEVICE;
1031
1032 /* Make sg buffers DMA ready */
1033 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
1034 dir);
1035
1036 if (unlikely(rc != data->sg_len)) {
1037 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
1038 mmc_hostname(host->mmc), rc);
1039 rc = -ENOMEM;
1040 goto dma_map_err;
1041 }
1042
1043 pr_debug("%s: %s: %s: sg_len=%d\n",
1044 mmc_hostname(host->mmc), __func__,
1045 dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
1046 data->sg_len);
1047
1048 goto out;
1049
1050dma_map_err:
1051 dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
1052 data->flags);
1053out:
1054 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07001055}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001056#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
1057/**
1058 * Submits data transfer request to SPS driver
1059 *
1060 * This function make sg (scatter gather) data buffers
1061 * DMA ready and then submits them to SPS driver for
1062 * transfer.
1063 *
1064 * @host - Pointer to sdcc host structure
1065 * @data - Pointer to mmc_data structure
1066 *
1067 * @return 0 if success else negative value
1068 */
1069static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
Asutosh Dasaccacd42012-03-08 14:33:17 +05301070 struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -07001071{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001072 int rc = 0;
1073 u32 flags;
1074 int i;
1075 u32 addr, len, data_cnt;
1076 struct scatterlist *sg = data->sg;
1077 struct sps_pipe *sps_pipe_handle;
1078
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001079 host->sps.sg = data->sg;
1080 host->sps.num_ents = data->sg_len;
1081 host->sps.xfer_req_cnt = 0;
1082 if (data->flags & MMC_DATA_READ) {
1083 host->sps.dir = DMA_FROM_DEVICE;
1084 sps_pipe_handle = host->sps.prod.pipe_handle;
1085 } else {
1086 host->sps.dir = DMA_TO_DEVICE;
1087 sps_pipe_handle = host->sps.cons.pipe_handle;
1088 }
1089
Asutosh Dasaccacd42012-03-08 14:33:17 +05301090 if (!data->host_cookie) {
1091 rc = msmsdcc_prep_xfer(host, data);
1092 if (unlikely(rc < 0)) {
1093 host->dma.sg = NULL;
1094 host->dma.num_ents = 0;
1095 goto out;
1096 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001097 }
1098
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001099 for (i = 0; i < data->sg_len; i++) {
1100 /*
1101 * Check if this is the last buffer to transfer?
1102 * If yes then set the INT and EOT flags.
1103 */
1104 len = sg_dma_len(sg);
1105 addr = sg_dma_address(sg);
1106 flags = 0;
1107 while (len > 0) {
1108 if (len > SPS_MAX_DESC_SIZE) {
1109 data_cnt = SPS_MAX_DESC_SIZE;
1110 } else {
1111 data_cnt = len;
1112 if (i == data->sg_len - 1)
1113 flags = SPS_IOVEC_FLAG_INT |
1114 SPS_IOVEC_FLAG_EOT;
1115 }
1116 rc = sps_transfer_one(sps_pipe_handle, addr,
1117 data_cnt, host, flags);
1118 if (rc) {
1119 pr_err("%s: sps_transfer_one() error! rc=%d,"
1120 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
1121 mmc_hostname(host->mmc), rc,
1122 (u32)sps_pipe_handle, (u32)sg, i);
1123 goto dma_map_err;
1124 }
1125 addr += data_cnt;
1126 len -= data_cnt;
1127 host->sps.xfer_req_cnt++;
1128 }
1129 sg++;
1130 }
1131 goto out;
1132
1133dma_map_err:
1134 /* unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +05301135 if (!data->host_cookie)
1136 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
1137 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001138out:
1139 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07001140}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001141#else
1142static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
1143 struct mmc_data *data) { return 0; }
1144#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -07001145
1146static void
San Mehat56a8b5b2009-11-21 12:29:46 -08001147msmsdcc_start_command_deferred(struct msmsdcc_host *host,
1148 struct mmc_command *cmd, u32 *c)
1149{
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301150 DBG(host, "op %02x arg %08x flags %08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001151 cmd->opcode, cmd->arg, cmd->flags);
1152
San Mehat56a8b5b2009-11-21 12:29:46 -08001153 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
1154
1155 if (cmd->flags & MMC_RSP_PRESENT) {
1156 if (cmd->flags & MMC_RSP_136)
1157 *c |= MCI_CPSM_LONGRSP;
1158 *c |= MCI_CPSM_RESPONSE;
1159 }
1160
1161 if (/*interrupt*/0)
1162 *c |= MCI_CPSM_INTERRUPT;
1163
Asutosh Das05049132012-05-09 12:38:15 +05301164 /* DAT_CMD bit should be set for all ADTC */
1165 if (mmc_cmd_type(cmd) == MMC_CMD_ADTC)
San Mehat56a8b5b2009-11-21 12:29:46 -08001166 *c |= MCI_CSPM_DATCMD;
1167
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001168 /* Check if AUTO CMD19 is required or not? */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301169 if (host->tuning_needed &&
1170 !(host->mmc->ios.timing == MMC_TIMING_MMC_HS200)) {
1171
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301172 /*
1173 * For open ended block read operation (without CMD23),
1174 * AUTO_CMD19 bit should be set while sending the READ command.
1175 * For close ended block read operation (with CMD23),
1176 * AUTO_CMD19 bit should be set while sending CMD23.
1177 */
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301178 if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
1179 host->curr.mrq->cmd->opcode ==
1180 MMC_READ_MULTIPLE_BLOCK) ||
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301181 (!host->curr.mrq->sbc &&
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301182 (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
1183 cmd->opcode == MMC_READ_MULTIPLE_BLOCK))) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301184 msmsdcc_enable_cdr_cm_sdc4_dll(host);
1185 *c |= MCI_CSPM_AUTO_CMD19;
1186 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001187 }
1188
Subhash Jadavanif97d2992012-07-13 14:47:47 +05301189 if (cmd->mrq->data && (cmd->mrq->data->flags & MMC_DATA_READ))
1190 writel_relaxed((readl_relaxed(host->base +
1191 MCI_DLL_CONFIG) | MCI_CDR_EN),
1192 host->base + MCI_DLL_CONFIG);
1193 else
1194 /* Clear CDR_EN bit for non read operations */
1195 writel_relaxed((readl_relaxed(host->base +
1196 MCI_DLL_CONFIG) & ~MCI_CDR_EN),
1197 host->base + MCI_DLL_CONFIG);
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05301198
Sujit Reddy Thumma02868752012-06-25 17:22:56 +05301199 if (((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) ||
1200 (cmd->opcode == MMC_SEND_STATUS &&
1201 !(cmd->flags & MMC_CMD_ADTC))) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301202 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001203 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301204 }
1205
San Mehat56a8b5b2009-11-21 12:29:46 -08001206 if (cmd == cmd->mrq->stop)
1207 *c |= MCI_CSPM_MCIABORT;
1208
San Mehat56a8b5b2009-11-21 12:29:46 -08001209 if (host->curr.cmd != NULL) {
Girish K Sa3c76eb2011-10-11 11:44:09 +05301210 pr_err("%s: Overlapping command requests\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001211 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -08001212 }
1213 host->curr.cmd = cmd;
1214}
1215
1216static void
1217msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1218 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001219{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301220 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001221 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001222 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001223 unsigned int pio_irqmask = 0;
1224
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301225 BUG_ON(!data->sg);
1226 BUG_ON(!data->sg_len);
1227
San Mehat9d2bd732009-09-22 16:44:22 -07001228 host->curr.data = data;
1229 host->curr.xfer_size = data->blksz * data->blocks;
1230 host->curr.xfer_remain = host->curr.xfer_size;
1231 host->curr.data_xfered = 0;
1232 host->curr.got_dataend = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301233 host->curr.got_auto_prog_done = false;
San Mehat9d2bd732009-09-22 16:44:22 -07001234
San Mehat9d2bd732009-09-22 16:44:22 -07001235 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1236
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301237 if (host->curr.wait_for_auto_prog_done)
1238 datactrl |= MCI_AUTO_PROG_DONE;
San Mehat9d2bd732009-09-22 16:44:22 -07001239
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05301240 if (msmsdcc_is_dma_possible(host, data)) {
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301241 if (is_dma_mode(host) && !msmsdcc_config_dma(host, data)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001242 datactrl |= MCI_DPSM_DMAENABLE;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301243 } else if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001244 if (!msmsdcc_is_dml_busy(host)) {
1245 if (!msmsdcc_sps_start_xfer(host, data)) {
1246 /* Now kick start DML transfer */
1247 mb();
1248 msmsdcc_dml_start_xfer(host, data);
1249 datactrl |= MCI_DPSM_DMAENABLE;
1250 host->sps.busy = 1;
1251 }
1252 } else {
1253 /*
1254 * Can't proceed with new transfer as
1255 * previous trasnfer is already in progress.
1256 * There is no point of going into PIO mode
1257 * as well. Is this a time to do kernel panic?
1258 */
1259 pr_err("%s: %s: DML HW is busy!!!"
1260 " Can't perform new SPS transfers"
1261 " now\n", mmc_hostname(host->mmc),
1262 __func__);
1263 }
1264 }
1265 }
1266
1267 /* Is data transfer in PIO mode required? */
1268 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001269 if (data->flags & MMC_DATA_READ) {
1270 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1271 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1272 pio_irqmask |= MCI_RXDATAAVLBLMASK;
1273 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001274 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1275 MCI_TXFIFOEMPTYMASK;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001276
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001277 msmsdcc_sg_start(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001278 }
1279
1280 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301281 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
Subhash Jadavanif5277752011-10-12 16:47:52 +05301282 else if (host->curr.use_wr_data_pend)
1283 datactrl |= MCI_DATA_PEND;
San Mehat9d2bd732009-09-22 16:44:22 -07001284
San Mehat56a8b5b2009-11-21 12:29:46 -08001285 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001286 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001287 timeout = data->timeout_clks + (unsigned int)clks*2 ;
Subhash Jadavani63540362012-06-12 14:56:04 +05301288 WARN(!timeout,
1289 "%s: data timeout is zero. timeout_ns=0x%x, timeout_clks=0x%x\n",
1290 mmc_hostname(host->mmc), data->timeout_ns, data->timeout_clks);
San Mehat9d2bd732009-09-22 16:44:22 -07001291
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301292 if (is_dma_mode(host) && (datactrl & MCI_DPSM_DMAENABLE)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001293 /* Use ADM (Application Data Mover) HW for Data transfer */
1294 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001295 host->cmd_timeout = timeout;
1296 host->cmd_pio_irqmask = pio_irqmask;
1297 host->cmd_datactrl = datactrl;
1298 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001299
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001300 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1301 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001302 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001303
1304 if (cmd) {
1305 msmsdcc_start_command_deferred(host, cmd, &c);
1306 host->cmd_c = c;
1307 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001308 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1309 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1310 host->base + MMCIMASK0);
1311 mb();
1312 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001313 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001314 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001315 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001316
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001317 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001318
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001319 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1320 (~(MCI_IRQ_PIO))) | pio_irqmask,
1321 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001322 writel_relaxed(datactrl, base + MMCIDATACTRL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001323
1324 if (cmd) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05301325 /* Delay between data/command */
1326 msmsdcc_sync_reg_wr(host);
San Mehat56a8b5b2009-11-21 12:29:46 -08001327 /* Daisy-chain the command if requested */
1328 msmsdcc_start_command(host, cmd, c);
Subhash Jadavanidd432952012-03-28 11:25:56 +05301329 } else {
1330 /*
1331 * We don't need delay after writing to DATA_CTRL
1332 * register if we are not writing to CMD register
1333 * immediately after this. As we already have delay
1334 * before sending the command, we just need mb() here.
1335 */
1336 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001337 }
San Mehat9d2bd732009-09-22 16:44:22 -07001338 }
1339}
1340
1341static void
1342msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1343{
San Mehat56a8b5b2009-11-21 12:29:46 -08001344 msmsdcc_start_command_deferred(host, cmd, &c);
1345 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001346}
1347
1348static void
1349msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1350 unsigned int status)
1351{
1352 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001353 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
Subhash Jadavanib30c9822012-03-27 18:03:16 +05301354 || data->mrq->cmd->opcode == MMC_BUS_TEST_R
1355 || data->mrq->cmd->opcode ==
1356 MMC_SEND_TUNING_BLOCK_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001357 pr_err("%s: Data CRC error\n",
1358 mmc_hostname(host->mmc));
1359 pr_err("%s: opcode 0x%.8x\n", __func__,
1360 data->mrq->cmd->opcode);
1361 pr_err("%s: blksz %d, blocks %d\n", __func__,
1362 data->blksz, data->blocks);
1363 data->error = -EILSEQ;
1364 }
San Mehat9d2bd732009-09-22 16:44:22 -07001365 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001366 /* CRC is optional for the bus test commands, not all
1367 * cards respond back with CRC. However controller
1368 * waits for the CRC and times out. Hence ignore the
1369 * data timeouts during the Bustest.
1370 */
1371 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1372 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301373 pr_err("%s: CMD%d: Data timeout\n",
1374 mmc_hostname(host->mmc),
1375 data->mrq->cmd->opcode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001376 data->error = -ETIMEDOUT;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301377 msmsdcc_dump_sdcc_state(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001378 }
San Mehat9d2bd732009-09-22 16:44:22 -07001379 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001380 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001381 data->error = -EIO;
1382 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001383 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001384 data->error = -EIO;
1385 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001386 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001387 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001388 data->error = -EIO;
1389 }
San Mehat9d2bd732009-09-22 16:44:22 -07001390
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001391 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001392 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001393 host->dummy_52_needed = 0;
1394}
San Mehat9d2bd732009-09-22 16:44:22 -07001395
1396static int
1397msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1398{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001399 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001400 uint32_t *ptr = (uint32_t *) buffer;
1401 int count = 0;
1402
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301403 if (remain % 4)
1404 remain = ((remain >> 2) + 1) << 2;
1405
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001406 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1407
1408 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001409 ptr++;
1410 count += sizeof(uint32_t);
1411
1412 remain -= sizeof(uint32_t);
1413 if (remain == 0)
1414 break;
1415 }
1416 return count;
1417}
1418
1419static int
1420msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001421 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001422{
1423 void __iomem *base = host->base;
1424 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001425 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001426
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001427 while (readl_relaxed(base + MMCISTATUS) &
1428 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1429 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001430
San Mehat9d2bd732009-09-22 16:44:22 -07001431 count = min(remain, maxcnt);
1432
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301433 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1434 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001435 ptr += count;
1436 remain -= count;
1437
1438 if (remain == 0)
1439 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001440 }
1441 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001442
1443 return ptr - buffer;
1444}
1445
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001446/*
1447 * Copy up to a word (4 bytes) between a scatterlist
1448 * and a temporary bounce buffer when the word lies across
1449 * two pages. The temporary buffer can then be read to/
1450 * written from the FIFO once.
1451 */
1452static void _msmsdcc_sg_consume_word(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -07001453{
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001454 struct msmsdcc_pio_data *pio = &host->pio;
1455 unsigned int bytes_avail;
1456
1457 if (host->curr.data->flags & MMC_DATA_READ)
1458 memcpy(pio->sg_miter.addr, pio->bounce_buf,
1459 pio->bounce_buf_len);
1460 else
1461 memcpy(pio->bounce_buf, pio->sg_miter.addr,
1462 pio->bounce_buf_len);
1463
1464 while (pio->bounce_buf_len != 4) {
1465 if (!sg_miter_next(&pio->sg_miter))
1466 break;
1467 bytes_avail = min_t(unsigned int, pio->sg_miter.length,
1468 4 - pio->bounce_buf_len);
1469 if (host->curr.data->flags & MMC_DATA_READ)
1470 memcpy(pio->sg_miter.addr,
1471 &pio->bounce_buf[pio->bounce_buf_len],
1472 bytes_avail);
1473 else
1474 memcpy(&pio->bounce_buf[pio->bounce_buf_len],
1475 pio->sg_miter.addr, bytes_avail);
1476
1477 pio->sg_miter.consumed = bytes_avail;
1478 pio->bounce_buf_len += bytes_avail;
San Mehat9d2bd732009-09-22 16:44:22 -07001479 }
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001480}
1481
1482/*
1483 * Use sg_miter_next to return as many 4-byte aligned
1484 * chunks as possible, using a temporary 4 byte buffer
1485 * for alignment if necessary
1486 */
1487static int msmsdcc_sg_next(struct msmsdcc_host *host, char **buf, int *len)
1488{
1489 struct msmsdcc_pio_data *pio = &host->pio;
1490 unsigned int length, rlength;
1491 char *buffer;
1492
1493 if (!sg_miter_next(&pio->sg_miter))
1494 return 0;
1495
1496 buffer = pio->sg_miter.addr;
1497 length = pio->sg_miter.length;
1498
1499 if (length < host->curr.xfer_remain) {
1500 rlength = round_down(length, 4);
1501 if (rlength) {
1502 /*
1503 * We have a 4-byte aligned chunk.
1504 * The rounding will be reflected by
1505 * a call to msmsdcc_sg_consumed
1506 */
1507 length = rlength;
1508 goto sg_next_end;
1509 }
1510 /*
1511 * We have a length less than 4 bytes. Check to
1512 * see if more buffer is available, and combine
1513 * to make 4 bytes if possible.
1514 */
1515 pio->bounce_buf_len = length;
1516 memset(pio->bounce_buf, 0, 4);
1517
1518 /*
1519 * On a read, get 4 bytes from FIFO, and distribute
1520 * (4-bouce_buf_len) bytes into consecutive
1521 * sgl buffers when msmsdcc_sg_consumed is called
1522 */
1523 if (host->curr.data->flags & MMC_DATA_READ) {
1524 buffer = pio->bounce_buf;
1525 length = 4;
1526 goto sg_next_end;
1527 } else {
1528 _msmsdcc_sg_consume_word(host);
1529 buffer = pio->bounce_buf;
1530 length = pio->bounce_buf_len;
1531 }
1532 }
1533
1534sg_next_end:
1535 *buf = buffer;
1536 *len = length;
1537 return 1;
1538}
1539
1540/*
1541 * Update sg_miter.consumed based on how many bytes were
1542 * consumed. If the bounce buffer was used to read from FIFO,
1543 * redistribute into sgls.
1544 */
1545static void msmsdcc_sg_consumed(struct msmsdcc_host *host,
1546 unsigned int length)
1547{
1548 struct msmsdcc_pio_data *pio = &host->pio;
1549
1550 if (host->curr.data->flags & MMC_DATA_READ) {
1551 if (length > pio->sg_miter.consumed)
1552 /*
1553 * consumed 4 bytes, but sgl
1554 * describes < 4 bytes
1555 */
1556 _msmsdcc_sg_consume_word(host);
1557 else
1558 pio->sg_miter.consumed = length;
1559 } else
1560 if (length < pio->sg_miter.consumed)
1561 pio->sg_miter.consumed = length;
1562}
1563
1564static void msmsdcc_sg_start(struct msmsdcc_host *host)
1565{
1566 unsigned int sg_miter_flags = SG_MITER_ATOMIC;
1567
1568 host->pio.bounce_buf_len = 0;
1569
1570 if (host->curr.data->flags & MMC_DATA_READ)
1571 sg_miter_flags |= SG_MITER_TO_SG;
1572 else
1573 sg_miter_flags |= SG_MITER_FROM_SG;
1574
1575 sg_miter_start(&host->pio.sg_miter, host->curr.data->sg,
1576 host->curr.data->sg_len, sg_miter_flags);
1577}
1578
1579static void msmsdcc_sg_stop(struct msmsdcc_host *host)
1580{
1581 sg_miter_stop(&host->pio.sg_miter);
San Mehat9d2bd732009-09-22 16:44:22 -07001582}
1583
San Mehat1cd22962010-02-03 12:59:29 -08001584static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001585msmsdcc_pio_irq(int irq, void *dev_id)
1586{
1587 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001588 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001589 uint32_t status;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001590 unsigned long flags;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001591 unsigned int remain;
1592 char *buffer;
San Mehat9d2bd732009-09-22 16:44:22 -07001593
Murali Palnati36448a42011-09-02 15:06:18 +05301594 spin_lock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301595
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001596 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001597
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001598 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301599 (MCI_IRQ_PIO)) == 0) {
1600 spin_unlock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301601 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301602 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001603#if IRQ_DEBUG
1604 msmsdcc_print_status(host, "irq1-r", status);
1605#endif
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001606 local_irq_save(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001607
1608 do {
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001609 unsigned int len;
San Mehat9d2bd732009-09-22 16:44:22 -07001610
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001611 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1612 | MCI_RXDATAAVLBL)))
1613 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001614
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001615 if (!msmsdcc_sg_next(host, &buffer, &remain))
1616 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001617
San Mehat9d2bd732009-09-22 16:44:22 -07001618 len = 0;
1619 if (status & MCI_RXACTIVE)
1620 len = msmsdcc_pio_read(host, buffer, remain);
1621 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001622 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001623
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301624 /* len might have aligned to 32bits above */
1625 if (len > remain)
1626 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001627
San Mehat9d2bd732009-09-22 16:44:22 -07001628 host->curr.xfer_remain -= len;
1629 host->curr.data_xfered += len;
1630 remain -= len;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001631 msmsdcc_sg_consumed(host, len);
San Mehat9d2bd732009-09-22 16:44:22 -07001632
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001633 if (remain) /* Done with this page? */
1634 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001635
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001636 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001637 } while (1);
1638
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001639 msmsdcc_sg_stop(host);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001640 local_irq_restore(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001641
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001642 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1643 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1644 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1645 host->base + MMCIMASK0);
1646 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301647 /*
1648 * back to back write to MASK0 register don't need
1649 * synchronization delay.
1650 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001651 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1652 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1653 }
1654 mb();
1655 } else if (!host->curr.xfer_remain) {
1656 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1657 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1658 mb();
1659 }
San Mehat9d2bd732009-09-22 16:44:22 -07001660
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001661 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001662
1663 return IRQ_HANDLED;
1664}
1665
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001666static void
1667msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1668
1669static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1670 struct mmc_data *data)
1671{
1672 u32 loop_cnt = 0;
1673
1674 /*
1675 * For read commands with data less than fifo size, it is possible to
1676 * get DATAEND first and RXDATA_AVAIL might be set later because of
1677 * synchronization delay through the asynchronous RX FIFO. Thus, for
1678 * such cases, even after DATAEND interrupt is received software
1679 * should poll for RXDATA_AVAIL until the requested data is read out
1680 * of FIFO. This change is needed to get around this abnormal but
1681 * sometimes expected behavior of SDCC3 controller.
1682 *
1683 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1684 * after the data is loaded into RX FIFO. This would amount to less
1685 * than a microsecond and thus looping for 1000 times is good enough
1686 * for that delay.
1687 */
1688 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1689 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1690 spin_unlock(&host->lock);
1691 msmsdcc_pio_irq(1, host);
1692 spin_lock(&host->lock);
1693 }
1694 }
1695 if (loop_cnt == 1000) {
1696 pr_info("%s: Timed out while polling for Rx Data\n",
1697 mmc_hostname(host->mmc));
1698 data->error = -ETIMEDOUT;
1699 msmsdcc_reset_and_restore(host);
1700 }
1701}
1702
San Mehat9d2bd732009-09-22 16:44:22 -07001703static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1704{
1705 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001706
1707 host->curr.cmd = NULL;
subhashj8046ae12012-05-02 12:14:52 +05301708 if (mmc_resp_type(cmd))
1709 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1710 /*
1711 * Read rest of the response registers only if
1712 * long response is expected for this command
1713 */
1714 if (mmc_resp_type(cmd) & MMC_RSP_136) {
1715 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1716 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1717 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
1718 }
San Mehat9d2bd732009-09-22 16:44:22 -07001719
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001720 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301721 pr_debug("%s: CMD%d: Command timeout\n",
1722 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001723 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001724 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301725 !host->tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301726 pr_err("%s: CMD%d: Command CRC error\n",
1727 mmc_hostname(host->mmc), cmd->opcode);
1728 msmsdcc_dump_sdcc_state(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001729 cmd->error = -EILSEQ;
1730 }
1731
Subhash Jadavani8706ced2012-05-25 16:09:21 +05301732 if (!cmd->error) {
1733 if (cmd->cmd_timeout_ms > host->curr.req_tout_ms) {
1734 host->curr.req_tout_ms = cmd->cmd_timeout_ms;
1735 mod_timer(&host->req_tout_timer, (jiffies +
1736 msecs_to_jiffies(host->curr.req_tout_ms)));
1737 }
1738 }
1739
San Mehat9d2bd732009-09-22 16:44:22 -07001740 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001741 if (host->curr.data && host->dma.sg &&
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301742 is_dma_mode(host))
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001743 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001744 else if (host->curr.data && host->sps.sg &&
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301745 is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001746 /* Stop current SPS transfer */
1747 msmsdcc_sps_exit_curr_xfer(host);
1748 }
San Mehat9d2bd732009-09-22 16:44:22 -07001749 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301750 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001751 msmsdcc_stop_data(host);
1752 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301753 } else { /* host->data == NULL */
1754 if (!cmd->error && host->prog_enable) {
1755 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001756 host->prog_enable = 0;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301757 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001758 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301759 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301760 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301761 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301762 host->curr.wait_for_auto_prog_done = false;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001763 if (host->dummy_52_needed)
1764 host->dummy_52_needed = 0;
1765 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001766 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301767 msmsdcc_request_end(host, cmd->mrq);
1768 }
1769 }
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301770 } else if (cmd->data) {
Subhash Jadavanif5277752011-10-12 16:47:52 +05301771 if (cmd == host->curr.mrq->sbc)
1772 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1773 else if ((cmd->data->flags & MMC_DATA_WRITE) &&
1774 !host->curr.use_wr_data_pend)
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301775 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001776 }
1777}
1778
San Mehat9d2bd732009-09-22 16:44:22 -07001779static irqreturn_t
1780msmsdcc_irq(int irq, void *dev_id)
1781{
1782 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001783 u32 status;
1784 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001785 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001786
1787 spin_lock(&host->lock);
1788
1789 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001790 struct mmc_command *cmd;
1791 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001792
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001793 if (timer) {
1794 timer = 0;
1795 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001796 }
San Mehat9d2bd732009-09-22 16:44:22 -07001797
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05301798 if (!atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001799 pr_debug("%s: %s: SDIO async irq received\n",
1800 mmc_hostname(host->mmc), __func__);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301801
1802 /*
1803 * Only async interrupt can come when clocks are off,
1804 * disable further interrupts and enable them when
1805 * clocks are on.
1806 */
1807 if (!host->sdcc_irq_disabled) {
1808 disable_irq_nosync(irq);
1809 host->sdcc_irq_disabled = 1;
1810 }
1811
1812 /*
1813 * If mmc_card_wake_sdio_irq() is set, mmc core layer
1814 * will take care of signaling sdio irq during
1815 * mmc_sdio_resume().
1816 */
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301817 if (host->sdcc_suspended) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301818 /*
1819 * This is a wakeup interrupt so hold wakelock
1820 * until SDCC resume is handled.
1821 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001822 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301823 } else {
1824 spin_unlock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301825 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301826 spin_lock(&host->lock);
1827 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301828 ret = 1;
1829 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001830 }
1831
1832 status = readl_relaxed(host->base + MMCISTATUS);
1833
1834 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1835 (~(MCI_IRQ_PIO))) == 0)
San Mehat9d2bd732009-09-22 16:44:22 -07001836 break;
1837
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001838#if IRQ_DEBUG
1839 msmsdcc_print_status(host, "irq0-r", status);
1840#endif
1841 status &= readl_relaxed(host->base + MMCIMASK0);
1842 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301843 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301844 if (host->clk_rate <=
1845 msmsdcc_get_min_sup_clk_rate(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +05301846 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001847#if IRQ_DEBUG
1848 msmsdcc_print_status(host, "irq0-p", status);
1849#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001850
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001851 if (status & MCI_SDIOINTROPE) {
1852 if (host->sdcc_suspending)
1853 wake_lock(&host->sdio_suspend_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301854 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001855 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301856 spin_lock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001857 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001858 data = host->curr.data;
1859
1860 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001861 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1862 MCI_CMDTIMEOUT)) {
1863 if (status & MCI_CMDTIMEOUT)
1864 pr_debug("%s: dummy CMD52 timeout\n",
1865 mmc_hostname(host->mmc));
1866 if (status & MCI_CMDCRCFAIL)
1867 pr_debug("%s: dummy CMD52 CRC failed\n",
1868 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001869 host->dummy_52_sent = 0;
1870 host->dummy_52_needed = 0;
1871 if (data) {
1872 msmsdcc_stop_data(host);
1873 msmsdcc_request_end(host, data->mrq);
1874 }
1875 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001876 spin_unlock(&host->lock);
1877 return IRQ_HANDLED;
1878 }
1879 break;
1880 }
1881
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001882 /*
1883 * Check for proper command response
1884 */
1885 cmd = host->curr.cmd;
1886 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1887 MCI_CMDTIMEOUT | MCI_PROGDONE |
1888 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1889 msmsdcc_do_cmdirq(host, status);
1890 }
1891
Sathish Ambley081d7842011-11-29 11:19:41 -08001892 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001893 /* Check for data errors */
1894 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1895 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1896 msmsdcc_data_err(host, data, status);
1897 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301898 if (host->dma.sg && is_dma_mode(host))
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001899 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301900 else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001901 /* Stop current SPS transfer */
1902 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301903 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001904 msmsdcc_reset_and_restore(host);
1905 if (host->curr.data)
1906 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301907 if (!data->stop || (host->curr.mrq->sbc
1908 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001909 timer |=
1910 msmsdcc_request_end(host,
1911 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301912 else if ((host->curr.mrq->sbc
1913 && data->error) ||
1914 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001915 msmsdcc_start_command(host,
1916 data->stop,
1917 0);
1918 timer = 1;
1919 }
1920 }
1921 }
1922
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301923 /* Check for prog done */
1924 if (host->curr.wait_for_auto_prog_done &&
1925 (status & MCI_PROGDONE))
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301926 host->curr.got_auto_prog_done = true;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301927
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001928 /* Check for data done */
1929 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1930 host->curr.got_dataend = 1;
1931
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301932 if (host->curr.got_dataend &&
1933 (!host->curr.wait_for_auto_prog_done ||
1934 (host->curr.wait_for_auto_prog_done &&
1935 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001936 /*
1937 * If DMA is still in progress, we complete
1938 * via the completion handler
1939 */
1940 if (!host->dma.busy && !host->sps.busy) {
1941 /*
1942 * There appears to be an issue in the
1943 * controller where if you request a
1944 * small block transfer (< fifo size),
1945 * you may get your DATAEND/DATABLKEND
1946 * irq without the PIO data irq.
1947 *
1948 * Check to see if theres still data
1949 * to be read, and simulate a PIO irq.
1950 */
1951 if (data->flags & MMC_DATA_READ)
1952 msmsdcc_wait_for_rxdata(host,
1953 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001954 if (!data->error) {
1955 host->curr.data_xfered =
1956 host->curr.xfer_size;
1957 host->curr.xfer_remain -=
1958 host->curr.xfer_size;
1959 }
1960
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001961 if (!host->dummy_52_needed) {
1962 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301963 if (!data->stop ||
1964 (host->curr.mrq->sbc
1965 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001966 msmsdcc_request_end(
1967 host,
1968 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301969 else if ((host->curr.mrq->sbc
1970 && data->error) ||
1971 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001972 msmsdcc_start_command(
1973 host,
1974 data->stop, 0);
1975 timer = 1;
1976 }
1977 } else {
1978 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001979 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001980 &dummy52cmd,
1981 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001982 }
1983 }
1984 }
1985 }
1986
San Mehat9d2bd732009-09-22 16:44:22 -07001987 ret = 1;
1988 } while (status);
1989
1990 spin_unlock(&host->lock);
1991
San Mehat9d2bd732009-09-22 16:44:22 -07001992 return IRQ_RETVAL(ret);
1993}
1994
1995static void
Asutosh Dasaccacd42012-03-08 14:33:17 +05301996msmsdcc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
1997 bool is_first_request)
1998{
1999 struct msmsdcc_host *host = mmc_priv(mmc);
2000 struct mmc_data *data = mrq->data;
2001 int rc = 0;
2002
2003 if (unlikely(!data)) {
2004 pr_err("%s: %s cannot prepare null data\n", mmc_hostname(mmc),
2005 __func__);
2006 return;
2007 }
2008 if (unlikely(data->host_cookie)) {
2009 /* Very wrong */
2010 data->host_cookie = 0;
2011 pr_err("%s: %s Request reposted for prepare\n",
2012 mmc_hostname(mmc), __func__);
2013 return;
2014 }
2015
2016 if (!msmsdcc_is_dma_possible(host, data))
2017 return;
2018
2019 rc = msmsdcc_prep_xfer(host, data);
2020 if (unlikely(rc < 0)) {
2021 data->host_cookie = 0;
2022 return;
2023 }
2024
2025 data->host_cookie = 1;
2026}
2027
2028static void
2029msmsdcc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, int err)
2030{
2031 struct msmsdcc_host *host = mmc_priv(mmc);
2032 unsigned int dir;
2033 struct mmc_data *data = mrq->data;
2034
2035 if (unlikely(!data)) {
2036 pr_err("%s: %s cannot cleanup null data\n", mmc_hostname(mmc),
2037 __func__);
2038 return;
2039 }
2040 if (data->flags & MMC_DATA_READ)
2041 dir = DMA_FROM_DEVICE;
2042 else
2043 dir = DMA_TO_DEVICE;
2044
2045 if (data->host_cookie)
2046 dma_unmap_sg(mmc_dev(host->mmc), data->sg,
2047 data->sg_len, dir);
2048
2049 data->host_cookie = 0;
2050}
2051
2052static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002053msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
2054{
Subhash Jadavanif5277752011-10-12 16:47:52 +05302055 if (mrq->data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002056 /* Queue/read data, daisy-chain command when data starts */
Subhash Jadavanif5277752011-10-12 16:47:52 +05302057 if ((mrq->data->flags & MMC_DATA_READ) ||
2058 host->curr.use_wr_data_pend)
2059 msmsdcc_start_data(host, mrq->data,
2060 mrq->sbc ? mrq->sbc : mrq->cmd,
2061 0);
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302062 else
Subhash Jadavanif5277752011-10-12 16:47:52 +05302063 msmsdcc_start_command(host,
2064 mrq->sbc ? mrq->sbc : mrq->cmd,
2065 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002066 } else {
2067 msmsdcc_start_command(host, mrq->cmd, 0);
2068 }
2069}
2070
2071static void
San Mehat9d2bd732009-09-22 16:44:22 -07002072msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
2073{
2074 struct msmsdcc_host *host = mmc_priv(mmc);
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302075 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07002076
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002077 /*
2078 * Get the SDIO AL client out of LPM.
2079 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002080 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002081 if (host->plat->is_sdio_al_client)
2082 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002083
Subhash Jadavanib5b07742011-08-29 17:48:07 +05302084 /* check if sps pipe reset is pending? */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05302085 if (is_sps_mode(host) && host->sps.pipe_reset_pending) {
Subhash Jadavanib5b07742011-08-29 17:48:07 +05302086 msmsdcc_sps_pipes_reset_and_restore(host);
2087 host->sps.pipe_reset_pending = false;
2088 }
San Mehat9d2bd732009-09-22 16:44:22 -07002089
2090 spin_lock_irqsave(&host->lock, flags);
2091
San Mehat9d2bd732009-09-22 16:44:22 -07002092 if (host->eject) {
2093 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
2094 mrq->cmd->error = 0;
2095 mrq->data->bytes_xfered = mrq->data->blksz *
2096 mrq->data->blocks;
2097 } else
2098 mrq->cmd->error = -ENOMEDIUM;
2099
2100 spin_unlock_irqrestore(&host->lock, flags);
2101 mmc_request_done(mmc, mrq);
2102 return;
2103 }
2104
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302105 /*
subhashjf181c292012-05-02 13:07:40 +05302106 * Don't start the request if SDCC is not in proper state to handle it
2107 */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302108 if (!host->pwr || !atomic_read(&host->clks_on)
2109 || host->sdcc_irq_disabled) {
subhashjf181c292012-05-02 13:07:40 +05302110 WARN(1, "%s: %s: SDCC is in bad state. don't process"
2111 " new request (CMD%d)\n", mmc_hostname(host->mmc),
2112 __func__, mrq->cmd->opcode);
2113 msmsdcc_dump_sdcc_state(host);
2114 mrq->cmd->error = -EIO;
2115 if (mrq->data) {
2116 mrq->data->error = -EIO;
2117 mrq->data->bytes_xfered = 0;
2118 }
2119 spin_unlock_irqrestore(&host->lock, flags);
2120 mmc_request_done(mmc, mrq);
2121 return;
2122 }
2123
2124 WARN(host->curr.mrq, "%s: %s: New request (CMD%d) received while"
2125 " other request (CMD%d) is in progress\n",
2126 mmc_hostname(host->mmc), __func__,
2127 mrq->cmd->opcode, host->curr.mrq->cmd->opcode);
2128
2129 /*
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302130 * Set timeout value to 10 secs (or more in case of buggy cards)
2131 */
2132 if ((mmc->card) && (mmc->card->quirks & MMC_QUIRK_INAND_DATA_TIMEOUT))
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302133 host->curr.req_tout_ms = 20000;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302134 else
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302135 host->curr.req_tout_ms = MSM_MMC_REQ_TIMEOUT;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302136 /*
2137 * Kick the software request timeout timer here with the timeout
2138 * value identified above
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302139 */
2140 mod_timer(&host->req_tout_timer,
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302141 (jiffies +
2142 msecs_to_jiffies(host->curr.req_tout_ms)));
San Mehat9d2bd732009-09-22 16:44:22 -07002143
San Mehat9d2bd732009-09-22 16:44:22 -07002144 host->curr.mrq = mrq;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302145 if (mrq->sbc) {
2146 mrq->sbc->mrq = mrq;
2147 mrq->sbc->data = mrq->data;
2148 }
2149
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302150 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05302151 if (is_auto_prog_done(host)) {
Sujit Reddy Thummab8e83692012-07-17 15:08:13 +05302152 /*
2153 * Auto-prog done will be enabled for following cases:
2154 * mrq->sbc | mrq->stop
2155 * _____________|________________
2156 * True | Don't care
2157 * False | False (CMD24, ACMD25 use case)
2158 */
2159 if (mrq->sbc || !mrq->stop)
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302160 host->curr.wait_for_auto_prog_done = true;
2161 } else {
2162 if ((mrq->cmd->opcode == SD_IO_RW_EXTENDED) ||
2163 (mrq->cmd->opcode == 54))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002164 host->dummy_52_needed = 1;
2165 }
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302166
Subhash Jadavanif5277752011-10-12 16:47:52 +05302167 if ((mrq->cmd->opcode == MMC_WRITE_BLOCK) ||
2168 (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK))
2169 host->curr.use_wr_data_pend = true;
San Mehat9d2bd732009-09-22 16:44:22 -07002170 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302171
Subhash Jadavanif5277752011-10-12 16:47:52 +05302172 msmsdcc_request_start(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302173
San Mehat9d2bd732009-09-22 16:44:22 -07002174 spin_unlock_irqrestore(&host->lock, flags);
2175}
2176
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002177static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
2178 int min_uV, int max_uV)
2179{
2180 int rc = 0;
2181
2182 if (vreg->set_voltage_sup) {
2183 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
2184 if (rc) {
2185 pr_err("%s: regulator_set_voltage(%s) failed."
2186 " min_uV=%d, max_uV=%d, rc=%d\n",
2187 __func__, vreg->name, min_uV, max_uV, rc);
2188 }
2189 }
2190
2191 return rc;
2192}
2193
2194static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
2195 int uA_load)
2196{
2197 int rc = 0;
2198
Krishna Kondafea60182011-11-01 16:01:34 -07002199 /* regulators that do not support regulator_set_voltage also
2200 do not support regulator_set_optimum_mode */
2201 if (vreg->set_voltage_sup) {
2202 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
2203 if (rc < 0)
2204 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
2205 "uA_load=%d) failed. rc=%d\n", __func__,
2206 vreg->name, uA_load, rc);
2207 else
2208 /* regulator_set_optimum_mode() can return non zero
2209 * value even for success case.
2210 */
2211 rc = 0;
2212 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002213
2214 return rc;
2215}
2216
2217static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
2218 struct device *dev)
2219{
2220 int rc = 0;
2221
2222 /* check if regulator is already initialized? */
2223 if (vreg->reg)
2224 goto out;
2225
2226 /* Get the regulator handle */
2227 vreg->reg = regulator_get(dev, vreg->name);
2228 if (IS_ERR(vreg->reg)) {
2229 rc = PTR_ERR(vreg->reg);
2230 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
2231 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002232 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002233 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002234
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05302235 if (regulator_count_voltages(vreg->reg) > 0) {
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002236 vreg->set_voltage_sup = 1;
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05302237 /* sanity check */
2238 if (!vreg->high_vol_level || !vreg->hpm_uA) {
2239 pr_err("%s: %s invalid constraints specified\n",
2240 __func__, vreg->name);
2241 rc = -EINVAL;
2242 }
2243 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002244
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002245out:
2246 return rc;
2247}
2248
2249static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
2250{
2251 if (vreg->reg)
2252 regulator_put(vreg->reg);
2253}
2254
2255/* This init function should be called only once for each SDCC slot */
2256static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
2257{
2258 int rc = 0;
2259 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302260 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vdd_io_reg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002261 struct device *dev = mmc_dev(host->mmc);
2262
2263 curr_slot = host->plat->vreg_data;
2264 if (!curr_slot)
2265 goto out;
2266
2267 curr_vdd_reg = curr_slot->vdd_data;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302268 curr_vdd_io_reg = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002269
2270 if (is_init) {
2271 /*
2272 * Get the regulator handle from voltage regulator framework
2273 * and then try to set the voltage level for the regulator
2274 */
2275 if (curr_vdd_reg) {
2276 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
2277 if (rc)
2278 goto out;
2279 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302280 if (curr_vdd_io_reg) {
2281 rc = msmsdcc_vreg_init_reg(curr_vdd_io_reg, dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002282 if (rc)
2283 goto vdd_reg_deinit;
2284 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002285 rc = msmsdcc_vreg_reset(host);
2286 if (rc)
2287 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
2288 host->pdev_id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002289 goto out;
2290 } else {
2291 /* Deregister all regulators from regulator framework */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302292 goto vdd_io_reg_deinit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002293 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302294vdd_io_reg_deinit:
2295 if (curr_vdd_io_reg)
2296 msmsdcc_vreg_deinit_reg(curr_vdd_io_reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002297vdd_reg_deinit:
2298 if (curr_vdd_reg)
2299 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2300out:
2301 return rc;
2302}
2303
2304static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2305{
2306 int rc = 0;
2307
Subhash Jadavanicc922692011-08-01 23:05:01 +05302308 /* Put regulator in HPM (high power mode) */
2309 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2310 if (rc < 0)
2311 goto out;
2312
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002313 if (!vreg->is_enabled) {
2314 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302315 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2316 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002317 if (rc)
2318 goto out;
2319
2320 rc = regulator_enable(vreg->reg);
2321 if (rc) {
2322 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2323 __func__, vreg->name, rc);
2324 goto out;
2325 }
2326 vreg->is_enabled = true;
2327 }
2328
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002329out:
2330 return rc;
2331}
2332
Krishna Konda3c4142d2012-06-27 11:01:56 -07002333static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg, bool is_init)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002334{
2335 int rc = 0;
2336
2337 /* Never disable regulator marked as always_on */
2338 if (vreg->is_enabled && !vreg->always_on) {
2339 rc = regulator_disable(vreg->reg);
2340 if (rc) {
2341 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2342 __func__, vreg->name, rc);
2343 goto out;
2344 }
2345 vreg->is_enabled = false;
2346
2347 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2348 if (rc < 0)
2349 goto out;
2350
2351 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302352 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002353 if (rc)
2354 goto out;
Krishna Konda3c4142d2012-06-27 11:01:56 -07002355 } else if (vreg->is_enabled && vreg->always_on) {
2356 if (!is_init && vreg->lpm_sup) {
2357 /* Put always_on regulator in LPM (low power mode) */
2358 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2359 if (rc < 0)
2360 goto out;
2361 } else if (is_init && vreg->reset_at_init) {
2362 /**
2363 * The regulator might not actually be disabled if it
2364 * is shared and in use by other drivers.
2365 */
2366 rc = regulator_disable(vreg->reg);
2367 if (rc) {
2368 pr_err("%s: regulator_disable(%s) failed at " \
2369 "bootup. rc=%d\n", __func__,
2370 vreg->name, rc);
2371 goto out;
2372 }
2373 vreg->is_enabled = false;
2374 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002375 }
2376out:
2377 return rc;
2378}
2379
Krishna Konda3c4142d2012-06-27 11:01:56 -07002380static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable,
2381 bool is_init)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002382{
2383 int rc = 0, i;
2384 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302385 struct msm_mmc_reg_data *vreg_table[2];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002386
2387 curr_slot = host->plat->vreg_data;
2388 if (!curr_slot)
2389 goto out;
2390
Subhash Jadavani937c7502012-06-01 15:34:46 +05302391 vreg_table[0] = curr_slot->vdd_data;
2392 vreg_table[1] = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002393
2394 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2395 if (vreg_table[i]) {
2396 if (enable)
2397 rc = msmsdcc_vreg_enable(vreg_table[i]);
2398 else
Krishna Konda3c4142d2012-06-27 11:01:56 -07002399 rc = msmsdcc_vreg_disable(vreg_table[i],
2400 is_init);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002401 if (rc)
2402 goto out;
2403 }
2404 }
2405out:
2406 return rc;
2407}
2408
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002409/*
2410 * Reset vreg by ensuring it is off during probe. A call
2411 * to enable vreg is needed to balance disable vreg
2412 */
2413static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2414{
2415 int rc;
2416
Krishna Konda3c4142d2012-06-27 11:01:56 -07002417 rc = msmsdcc_setup_vreg(host, 1, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002418 if (rc)
2419 return rc;
Krishna Konda3c4142d2012-06-27 11:01:56 -07002420 rc = msmsdcc_setup_vreg(host, 0, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002421 return rc;
2422}
2423
Subhash Jadavani937c7502012-06-01 15:34:46 +05302424enum vdd_io_level {
2425 /* set vdd_io_data->low_vol_level */
2426 VDD_IO_LOW,
2427 /* set vdd_io_data->high_vol_level */
2428 VDD_IO_HIGH,
2429 /*
2430 * set whatever there in voltage_level (third argument) of
2431 * msmsdcc_set_vdd_io_vol() function.
2432 */
2433 VDD_IO_SET_LEVEL,
2434};
2435
2436static int msmsdcc_set_vdd_io_vol(struct msmsdcc_host *host,
2437 enum vdd_io_level level,
2438 unsigned int voltage_level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002439{
2440 int rc = 0;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302441 int set_level;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002442
2443 if (host->plat->vreg_data) {
Subhash Jadavani937c7502012-06-01 15:34:46 +05302444 struct msm_mmc_reg_data *vdd_io_reg =
2445 host->plat->vreg_data->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002446
Subhash Jadavani937c7502012-06-01 15:34:46 +05302447 if (vdd_io_reg && vdd_io_reg->is_enabled) {
2448 switch (level) {
2449 case VDD_IO_LOW:
2450 set_level = vdd_io_reg->low_vol_level;
2451 break;
2452 case VDD_IO_HIGH:
2453 set_level = vdd_io_reg->high_vol_level;
2454 break;
2455 case VDD_IO_SET_LEVEL:
2456 set_level = voltage_level;
2457 break;
2458 default:
2459 pr_err("%s: %s: invalid argument level = %d",
2460 mmc_hostname(host->mmc), __func__,
2461 level);
2462 rc = -EINVAL;
2463 goto out;
2464 }
2465 rc = msmsdcc_vreg_set_voltage(vdd_io_reg,
2466 set_level, set_level);
2467 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002468 }
2469
Subhash Jadavani937c7502012-06-01 15:34:46 +05302470out:
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302471 return rc;
2472}
2473
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002474static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2475{
2476 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2477 return 1;
2478 return 0;
2479}
2480
Asutosh Dasf5298c32012-04-03 14:51:47 +05302481/*
2482 * Any function calling msmsdcc_setup_clocks must
2483 * acquire clk_mutex. May sleep.
2484 */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302485static int msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002486{
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302487 int rc = 0;
2488
2489 if (enable && !atomic_read(&host->clks_on)) {
2490 if (!IS_ERR_OR_NULL(host->bus_clk)) {
2491 rc = clk_prepare_enable(host->bus_clk);
2492 if (rc) {
2493 pr_err("%s: %s: failed to enable the bus-clock with error %d\n",
2494 mmc_hostname(host->mmc), __func__, rc);
2495 goto out;
2496 }
2497 }
2498 if (!IS_ERR(host->pclk)) {
2499 rc = clk_prepare_enable(host->pclk);
2500 if (rc) {
2501 pr_err("%s: %s: failed to enable the pclk with error %d\n",
2502 mmc_hostname(host->mmc), __func__, rc);
2503 goto disable_bus;
2504 }
2505 }
2506 rc = clk_prepare_enable(host->clk);
2507 if (rc) {
2508 pr_err("%s: %s: failed to enable the host-clk with error %d\n",
2509 mmc_hostname(host->mmc), __func__, rc);
2510 goto disable_pclk;
2511 }
Subhash Jadavanidd432952012-03-28 11:25:56 +05302512 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302513 msmsdcc_delay(host);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302514 atomic_set(&host->clks_on, 1);
2515 } else if (!enable && atomic_read(&host->clks_on)) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05302516 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302517 msmsdcc_delay(host);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302518 clk_disable_unprepare(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002519 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302520 clk_disable_unprepare(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05302521 if (!IS_ERR_OR_NULL(host->bus_clk))
2522 clk_disable_unprepare(host->bus_clk);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302523 atomic_set(&host->clks_on, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002524 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302525 goto out;
2526
2527disable_pclk:
2528 if (!IS_ERR_OR_NULL(host->pclk))
2529 clk_disable_unprepare(host->pclk);
2530disable_bus:
2531 if (!IS_ERR_OR_NULL(host->bus_clk))
2532 clk_disable_unprepare(host->bus_clk);
2533out:
2534 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002535}
2536
2537static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2538 unsigned int req_clk)
2539{
2540 unsigned int sel_clk = -1;
2541
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302542 if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
2543 sel_clk = msmsdcc_get_min_sup_clk_rate(host);
2544 goto out;
2545 }
2546
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002547 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2548 unsigned char cnt;
2549
2550 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2551 if (host->plat->sup_clk_table[cnt] > req_clk)
2552 break;
2553 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2554 sel_clk = host->plat->sup_clk_table[cnt];
2555 break;
2556 } else
2557 sel_clk = host->plat->sup_clk_table[cnt];
2558 }
2559 } else {
2560 if ((req_clk < host->plat->msmsdcc_fmax) &&
2561 (req_clk > host->plat->msmsdcc_fmid))
2562 sel_clk = host->plat->msmsdcc_fmid;
2563 else
2564 sel_clk = req_clk;
2565 }
2566
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302567out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002568 return sel_clk;
2569}
2570
2571static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2572 struct msmsdcc_host *host)
2573{
2574 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2575 return host->plat->sup_clk_table[0];
2576 else
2577 return host->plat->msmsdcc_fmin;
2578}
2579
2580static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2581 struct msmsdcc_host *host)
2582{
2583 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2584 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2585 else
2586 return host->plat->msmsdcc_fmax;
2587}
2588
2589static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302590{
2591 struct msm_mmc_gpio_data *curr;
2592 int i, rc = 0;
2593
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002594 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302595 for (i = 0; i < curr->size; i++) {
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05302596 if (!gpio_is_valid(curr->gpio[i].no)) {
2597 rc = -EINVAL;
2598 pr_err("%s: Invalid gpio = %d\n",
2599 mmc_hostname(host->mmc), curr->gpio[i].no);
2600 goto free_gpios;
2601 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302602 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002603 if (curr->gpio[i].is_always_on &&
2604 curr->gpio[i].is_enabled)
2605 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302606 rc = gpio_request(curr->gpio[i].no,
2607 curr->gpio[i].name);
2608 if (rc) {
2609 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2610 mmc_hostname(host->mmc),
2611 curr->gpio[i].no,
2612 curr->gpio[i].name, rc);
2613 goto free_gpios;
2614 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002615 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302616 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002617 if (curr->gpio[i].is_always_on)
2618 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302619 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002620 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302621 }
2622 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002623 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302624
2625free_gpios:
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05302626 for (i--; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302627 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002628 curr->gpio[i].is_enabled = false;
2629 }
2630out:
2631 return rc;
2632}
2633
2634static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2635{
2636 struct msm_mmc_pad_data *curr;
2637 int i;
2638
2639 curr = host->plat->pin_data->pad_data;
2640 for (i = 0; i < curr->drv->size; i++) {
2641 if (enable)
2642 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2643 curr->drv->on[i].val);
2644 else
2645 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2646 curr->drv->off[i].val);
2647 }
2648
2649 for (i = 0; i < curr->pull->size; i++) {
2650 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002651 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002652 curr->pull->on[i].val);
2653 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002654 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002655 curr->pull->off[i].val);
2656 }
2657
2658 return 0;
2659}
2660
2661static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2662{
2663 int rc = 0;
2664
2665 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2666 return 0;
2667
2668 if (host->plat->pin_data->is_gpio)
2669 rc = msmsdcc_setup_gpio(host, enable);
2670 else
2671 rc = msmsdcc_setup_pad(host, enable);
2672
2673 if (!rc)
2674 host->plat->pin_data->cfg_sts = enable;
2675
2676 return rc;
2677}
2678
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302679static int msmsdcc_cfg_mpm_sdiowakeup(struct msmsdcc_host *host,
2680 unsigned mode)
2681{
2682 int ret = 0;
2683 unsigned int pin = host->plat->mpm_sdiowakeup_int;
2684
2685 if (!pin)
2686 return 0;
2687
2688 switch (mode) {
2689 case SDC_DAT1_DISABLE:
2690 ret = msm_mpm_enable_pin(pin, 0);
2691 break;
2692 case SDC_DAT1_ENABLE:
2693 ret = msm_mpm_set_pin_type(pin, IRQ_TYPE_LEVEL_LOW);
2694 ret = msm_mpm_enable_pin(pin, 1);
2695 break;
2696 case SDC_DAT1_ENWAKE:
2697 ret = msm_mpm_set_pin_wake(pin, 1);
2698 break;
2699 case SDC_DAT1_DISWAKE:
2700 ret = msm_mpm_set_pin_wake(pin, 0);
2701 break;
2702 default:
2703 ret = -EINVAL;
2704 break;
2705 }
2706
2707 return ret;
2708}
2709
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302710static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2711{
2712 u32 pwr = 0;
2713 int ret = 0;
2714 struct mmc_host *mmc = host->mmc;
2715
2716 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2717 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2718 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
Krishna Konda3c4142d2012-06-27 11:01:56 -07002719 ret = msmsdcc_setup_vreg(host, !!ios->vdd, false);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302720
2721 if (ret) {
2722 pr_err("%s: Failed to setup voltage regulators\n",
2723 mmc_hostname(host->mmc));
2724 goto out;
2725 }
2726
2727 switch (ios->power_mode) {
2728 case MMC_POWER_OFF:
2729 pwr = MCI_PWR_OFF;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302730 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302731 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05302732 * If VDD IO rail is always on, set low voltage for VDD
2733 * IO rail when slot is not in use (like when card is not
2734 * present or during system suspend).
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302735 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302736 msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302737 msmsdcc_setup_pins(host, false);
2738 break;
2739 case MMC_POWER_UP:
2740 /* writing PWR_UP bit is redundant */
2741 pwr = MCI_PWR_UP;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302742 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302743
Subhash Jadavani937c7502012-06-01 15:34:46 +05302744 msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302745 msmsdcc_setup_pins(host, true);
2746 break;
2747 case MMC_POWER_ON:
2748 pwr = MCI_PWR_ON;
2749 break;
2750 }
2751
2752out:
2753 return pwr;
2754}
2755
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002756static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2757{
2758 unsigned int wakeup_irq;
2759
2760 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2761 host->plat->sdiowakeup_irq :
2762 host->core_irqres->start;
2763
2764 if (!host->irq_wake_enabled) {
2765 enable_irq_wake(wakeup_irq);
2766 host->irq_wake_enabled = true;
2767 }
2768}
2769
2770static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2771{
2772 unsigned int wakeup_irq;
2773
2774 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2775 host->plat->sdiowakeup_irq :
2776 host->core_irqres->start;
2777
2778 if (host->irq_wake_enabled) {
2779 disable_irq_wake(wakeup_irq);
2780 host->irq_wake_enabled = false;
2781 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302782}
2783
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05302784/* Returns required bandwidth in Bytes per Sec */
2785static unsigned int msmsdcc_get_bw_required(struct msmsdcc_host *host,
2786 struct mmc_ios *ios)
2787{
2788 unsigned int bw;
2789
2790 bw = host->clk_rate;
2791 /*
2792 * For DDR mode, SDCC controller clock will be at
2793 * the double rate than the actual clock that goes to card.
2794 */
2795 if (ios->bus_width == MMC_BUS_WIDTH_4)
2796 bw /= 2;
2797 else if (ios->bus_width == MMC_BUS_WIDTH_1)
2798 bw /= 8;
2799
2800 return bw;
2801}
2802
2803static int msmsdcc_msm_bus_get_vote_for_bw(struct msmsdcc_host *host,
2804 unsigned int bw)
2805{
2806 unsigned int *table = host->plat->msm_bus_voting_data->bw_vecs;
2807 unsigned int size = host->plat->msm_bus_voting_data->bw_vecs_size;
2808 int i;
2809
2810 if (host->msm_bus_vote.is_max_bw_needed && bw)
2811 return host->msm_bus_vote.max_bw_vote;
2812
2813 for (i = 0; i < size; i++) {
2814 if (bw <= table[i])
2815 break;
2816 }
2817
2818 if (i && (i == size))
2819 i--;
2820
2821 return i;
2822}
2823
2824static int msmsdcc_msm_bus_register(struct msmsdcc_host *host)
2825{
2826 int rc = 0;
2827 struct msm_bus_scale_pdata *use_cases;
2828
2829 if (host->plat->msm_bus_voting_data &&
2830 host->plat->msm_bus_voting_data->use_cases &&
2831 host->plat->msm_bus_voting_data->bw_vecs &&
2832 host->plat->msm_bus_voting_data->bw_vecs_size) {
2833 use_cases = host->plat->msm_bus_voting_data->use_cases;
2834 host->msm_bus_vote.client_handle =
2835 msm_bus_scale_register_client(use_cases);
2836 } else {
2837 return 0;
2838 }
2839
2840 if (!host->msm_bus_vote.client_handle) {
2841 pr_err("%s: msm_bus_scale_register_client() failed\n",
2842 mmc_hostname(host->mmc));
2843 rc = -EFAULT;
2844 } else {
2845 /* cache the vote index for minimum and maximum bandwidth */
2846 host->msm_bus_vote.min_bw_vote =
2847 msmsdcc_msm_bus_get_vote_for_bw(host, 0);
2848 host->msm_bus_vote.max_bw_vote =
2849 msmsdcc_msm_bus_get_vote_for_bw(host, UINT_MAX);
2850 }
2851
2852 return rc;
2853}
2854
2855static void msmsdcc_msm_bus_unregister(struct msmsdcc_host *host)
2856{
2857 if (host->msm_bus_vote.client_handle)
2858 msm_bus_scale_unregister_client(
2859 host->msm_bus_vote.client_handle);
2860}
2861
2862/*
2863 * This function must be called with host lock acquired.
2864 * Caller of this function should also ensure that msm bus client
2865 * handle is not null.
2866 */
2867static inline int msmsdcc_msm_bus_set_vote(struct msmsdcc_host *host,
2868 int vote,
2869 unsigned long flags)
2870{
2871 int rc = 0;
2872
2873 if (vote != host->msm_bus_vote.curr_vote) {
2874 spin_unlock_irqrestore(&host->lock, flags);
2875 rc = msm_bus_scale_client_update_request(
2876 host->msm_bus_vote.client_handle, vote);
2877 if (rc)
2878 pr_err("%s: msm_bus_scale_client_update_request() failed."
2879 " bus_client_handle=0x%x, vote=%d, err=%d\n",
2880 mmc_hostname(host->mmc),
2881 host->msm_bus_vote.client_handle, vote, rc);
2882 spin_lock_irqsave(&host->lock, flags);
2883 if (!rc)
2884 host->msm_bus_vote.curr_vote = vote;
2885 }
2886
2887 return rc;
2888}
2889
2890/*
2891 * Internal work. Work to set 0 bandwidth for msm bus.
2892 */
2893static void msmsdcc_msm_bus_work(struct work_struct *work)
2894{
2895 struct msmsdcc_host *host = container_of(work,
2896 struct msmsdcc_host,
2897 msm_bus_vote.vote_work.work);
2898 unsigned long flags;
2899
2900 if (!host->msm_bus_vote.client_handle)
2901 return;
2902
2903 spin_lock_irqsave(&host->lock, flags);
2904 /* don't vote for 0 bandwidth if any request is in progress */
2905 if (!host->curr.mrq)
2906 msmsdcc_msm_bus_set_vote(host,
2907 host->msm_bus_vote.min_bw_vote, flags);
2908 else
2909 pr_warning("%s: %s: SDCC transfer in progress. skipping"
2910 " bus voting to 0 bandwidth\n",
2911 mmc_hostname(host->mmc), __func__);
2912 spin_unlock_irqrestore(&host->lock, flags);
2913}
2914
2915/*
2916 * This function cancels any scheduled delayed work
2917 * and sets the bus vote based on ios argument.
2918 * If "ios" argument is NULL, bandwidth required is 0 else
2919 * calculate the bandwidth based on ios parameters.
2920 */
2921static void msmsdcc_msm_bus_cancel_work_and_set_vote(
2922 struct msmsdcc_host *host,
2923 struct mmc_ios *ios)
2924{
2925 unsigned long flags;
2926 unsigned int bw;
2927 int vote;
2928
2929 if (!host->msm_bus_vote.client_handle)
2930 return;
2931
2932 bw = ios ? msmsdcc_get_bw_required(host, ios) : 0;
2933
2934 cancel_delayed_work_sync(&host->msm_bus_vote.vote_work);
2935 spin_lock_irqsave(&host->lock, flags);
2936 vote = msmsdcc_msm_bus_get_vote_for_bw(host, bw);
2937 msmsdcc_msm_bus_set_vote(host, vote, flags);
2938 spin_unlock_irqrestore(&host->lock, flags);
2939}
2940
2941/* This function queues a work which will set the bandwidth requiement to 0 */
2942static void msmsdcc_msm_bus_queue_work(struct msmsdcc_host *host)
2943{
2944 unsigned long flags;
2945
2946 if (!host->msm_bus_vote.client_handle)
2947 return;
2948
2949 spin_lock_irqsave(&host->lock, flags);
2950 if (host->msm_bus_vote.min_bw_vote != host->msm_bus_vote.curr_vote)
2951 queue_delayed_work(system_nrt_wq,
2952 &host->msm_bus_vote.vote_work,
2953 msecs_to_jiffies(MSM_MMC_BUS_VOTING_DELAY));
2954 spin_unlock_irqrestore(&host->lock, flags);
2955}
2956
San Mehat9d2bd732009-09-22 16:44:22 -07002957static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302958msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
2959{
2960 struct mmc_host *mmc = host->mmc;
2961
2962 /*
2963 * SDIO_AL clients has different mechanism of handling LPM through
2964 * sdio_al driver itself. The sdio wakeup interrupt is configured as
2965 * part of that. Here, we are interested only in clients like WLAN.
2966 */
2967 if (!(mmc->card && mmc_card_sdio(mmc->card))
2968 || host->plat->is_sdio_al_client)
2969 goto out;
2970
2971 if (!host->sdcc_suspended) {
2972 /*
2973 * When MSM is not in power collapse and we
2974 * are disabling clocks, enable bit 22 in MASK0
2975 * to handle asynchronous SDIO interrupts.
2976 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302977 if (enable_wakeup_irq) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302978 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302979 mb();
2980 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302981 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302982 msmsdcc_sync_reg_wr(host);
2983 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302984 goto out;
2985 } else if (!mmc_card_wake_sdio_irq(mmc)) {
2986 /*
2987 * Wakeup MSM only if SDIO function drivers set
2988 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
2989 */
2990 goto out;
2991 }
2992
2993 if (enable_wakeup_irq) {
2994 if (!host->plat->sdiowakeup_irq) {
2995 /*
2996 * When there is no gpio line that can be configured
2997 * as wakeup interrupt handle it by configuring
2998 * asynchronous sdio interrupts and DAT1 line.
2999 */
3000 writel_relaxed(MCI_SDIOINTMASK,
3001 host->base + MMCIMASK0);
3002 mb();
Subhash Jadavanic9b85752012-04-13 11:16:49 +05303003 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303004 /* configure sdcc core interrupt as wakeup interrupt */
3005 msmsdcc_enable_irq_wake(host);
3006 } else {
3007 /* Let gpio line handle wakeup interrupt */
3008 writel_relaxed(0, host->base + MMCIMASK0);
3009 mb();
3010 if (host->sdio_wakeupirq_disabled) {
3011 host->sdio_wakeupirq_disabled = 0;
3012 /* configure gpio line as wakeup interrupt */
3013 msmsdcc_enable_irq_wake(host);
3014 enable_irq(host->plat->sdiowakeup_irq);
3015 }
3016 }
3017 } else {
3018 if (!host->plat->sdiowakeup_irq) {
3019 /*
3020 * We may not have cleared bit 22 in the interrupt
3021 * handler as the clocks might be off at that time.
3022 */
3023 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303024 msmsdcc_sync_reg_wr(host);
Subhash Jadavanic9b85752012-04-13 11:16:49 +05303025 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303026 msmsdcc_disable_irq_wake(host);
3027 } else if (!host->sdio_wakeupirq_disabled) {
3028 disable_irq_nosync(host->plat->sdiowakeup_irq);
3029 msmsdcc_disable_irq_wake(host);
3030 host->sdio_wakeupirq_disabled = 1;
3031 }
3032 }
3033out:
3034 return;
San Mehat9d2bd732009-09-22 16:44:22 -07003035}
3036
3037static void
3038msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
3039{
3040 struct msmsdcc_host *host = mmc_priv(mmc);
3041 u32 clk = 0, pwr = 0;
3042 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08003043 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003044 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07003045
Sahitya Tummala7a892482011-01-18 11:22:49 +05303046
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303047 /*
3048 * Disable SDCC core interrupt until set_ios is completed.
3049 * This avoids any race conditions with interrupt raised
3050 * when turning on/off the clocks. One possible
3051 * scenario is SDIO operational interrupt while the clock
3052 * is turned off.
Asutosh Dasf5298c32012-04-03 14:51:47 +05303053 * host->lock is being released intermittently below.
3054 * Thus, prevent concurrent access to host.
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303055 */
3056
Asutosh Dasf5298c32012-04-03 14:51:47 +05303057 mutex_lock(&host->clk_mutex);
3058 DBG(host, "ios->clock = %u\n", ios->clock);
San Mehat9d2bd732009-09-22 16:44:22 -07003059 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303060 if (!host->sdcc_irq_disabled) {
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05303061 disable_irq_nosync(host->core_irqres->start);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303062 host->sdcc_irq_disabled = 1;
3063 }
San Mehatd0719e52009-12-03 10:58:54 -08003064 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07003065
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05303066 /* Make sure sdcc core irq is synchronized */
3067 synchronize_irq(host->core_irqres->start);
3068
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303069 pwr = msmsdcc_setup_pwr(host, ios);
3070
3071 spin_lock_irqsave(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07003072 if (ios->clock) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303073 spin_unlock_irqrestore(&host->lock, flags);
3074 rc = msmsdcc_setup_clocks(host, true);
3075 if (rc)
3076 goto out;
3077 spin_lock_irqsave(&host->lock, flags);
3078 writel_relaxed(host->mci_irqenable, host->base + MMCIMASK0);
3079 mb();
3080 msmsdcc_cfg_sdio_wakeup(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003081 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303082
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003083 /*
3084 * For DDR50 mode, controller needs clock rate to be
3085 * double than what is required on the SD card CLK pin.
3086 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05303087 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003088 /*
3089 * Make sure that we don't double the clock if
3090 * doubled clock rate is already set
3091 */
3092 if (!host->ddr_doubled_clk_rate ||
3093 (host->ddr_doubled_clk_rate &&
3094 (host->ddr_doubled_clk_rate != ios->clock))) {
3095 host->ddr_doubled_clk_rate =
3096 msmsdcc_get_sup_clk_rate(
3097 host, (ios->clock * 2));
3098 clock = host->ddr_doubled_clk_rate;
3099 }
3100 } else {
3101 host->ddr_doubled_clk_rate = 0;
3102 }
3103
3104 if (clock != host->clk_rate) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05303105 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003106 rc = clk_set_rate(host->clk, clock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303107 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003108 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303109 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003110 mmc_hostname(mmc), clock);
3111 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303112 host->reg_write_delay =
3113 (1 + ((3 * USEC_PER_SEC) /
3114 (host->clk_rate ? host->clk_rate :
3115 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003116 }
3117 /*
3118 * give atleast 2 MCLK cycles delay for clocks
3119 * and SDCC core to stabilize
3120 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05303121 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003122 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003123 clk |= MCI_CLK_ENABLE;
3124 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003125 if (ios->bus_width == MMC_BUS_WIDTH_8)
3126 clk |= MCI_CLK_WIDEBUS_8;
3127 else if (ios->bus_width == MMC_BUS_WIDTH_4)
3128 clk |= MCI_CLK_WIDEBUS_4;
3129 else
3130 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07003131
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003132 if (msmsdcc_is_pwrsave(host))
3133 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07003134
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003135 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07003136
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003137 host->tuning_needed = 0;
3138 /*
3139 * Select the controller timing mode according
3140 * to current bus speed mode
3141 */
Subhash Jadavanif97d2992012-07-13 14:47:47 +05303142 if (host->clk_rate > (100 * 1000 * 1000) &&
3143 (ios->timing == MMC_TIMING_UHS_SDR104 ||
3144 ios->timing == MMC_TIMING_MMC_HS200)) {
3145 /* Card clock frequency must be > 100MHz to enable tuning */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003146 clk |= (4 << 14);
3147 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05303148 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003149 clk |= (3 << 14);
3150 } else {
3151 clk |= (2 << 14); /* feedback clock */
San Mehat9d2bd732009-09-22 16:44:22 -07003152 }
3153
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003154 /* Select free running MCLK as input clock of cm_dll_sdc4 */
3155 clk |= (2 << 23);
San Mehat9d2bd732009-09-22 16:44:22 -07003156
Subhash Jadavani00083572012-02-15 16:18:01 +05303157 /* Clear IO_PAD_PWR_SWITCH while powering off the card */
3158 if (!ios->vdd)
3159 host->io_pad_pwr_switch = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07003160
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003161 if (host->io_pad_pwr_switch)
3162 clk |= IO_PAD_PWR_SWITCH;
3163
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303164 /* Don't write into registers if clocks are disabled */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303165 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303166 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
3167 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303168 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003169 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303170 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
3171 host->pwr = pwr;
3172 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303173 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003174 }
San Mehat9d2bd732009-09-22 16:44:22 -07003175 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003176
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303177 if (!(clk & MCI_CLK_ENABLE) && atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303178 msmsdcc_cfg_sdio_wakeup(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303179 spin_unlock_irqrestore(&host->lock, flags);
3180 /*
3181 * May get a wake-up interrupt the instant we disable the
3182 * clocks. This would disable the wake-up interrupt.
3183 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003184 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303185 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003186 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303187
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303188 if (host->tuning_in_progress)
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303189 WARN(!atomic_read(&host->clks_on),
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303190 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303191
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303192 /* Let interrupts be disabled if the host is powered off */
3193 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
3194 enable_irq(host->core_irqres->start);
3195 host->sdcc_irq_disabled = 0;
3196 }
San Mehat4adbbcc2009-11-08 13:00:37 -08003197 spin_unlock_irqrestore(&host->lock, flags);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303198out:
Asutosh Dasf5298c32012-04-03 14:51:47 +05303199 mutex_unlock(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07003200}
3201
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003202int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
3203{
3204 struct msmsdcc_host *host = mmc_priv(mmc);
3205 u32 clk;
3206
3207 clk = readl_relaxed(host->base + MMCICLOCK);
3208 pr_debug("Changing to pwr_save=%d", pwrsave);
3209 if (pwrsave && msmsdcc_is_pwrsave(host))
3210 clk |= MCI_CLK_PWRSAVE;
3211 else
3212 clk &= ~MCI_CLK_PWRSAVE;
3213 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303214 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003215
3216 return 0;
3217}
3218
3219static int msmsdcc_get_ro(struct mmc_host *mmc)
3220{
3221 int status = -ENOSYS;
3222 struct msmsdcc_host *host = mmc_priv(mmc);
3223
3224 if (host->plat->wpswitch) {
3225 status = host->plat->wpswitch(mmc_dev(mmc));
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05303226 } else if (gpio_is_valid(host->plat->wpswitch_gpio)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003227 status = gpio_request(host->plat->wpswitch_gpio,
3228 "SD_WP_Switch");
3229 if (status) {
3230 pr_err("%s: %s: Failed to request GPIO %d\n",
3231 mmc_hostname(mmc), __func__,
3232 host->plat->wpswitch_gpio);
3233 } else {
3234 status = gpio_direction_input(
3235 host->plat->wpswitch_gpio);
3236 if (!status) {
3237 /*
3238 * Wait for atleast 300ms as debounce
3239 * time for GPIO input to stabilize.
3240 */
3241 msleep(300);
3242 status = gpio_get_value_cansleep(
3243 host->plat->wpswitch_gpio);
Sujit Reddy Thumma8f912ea2012-06-22 16:18:43 +05303244 status ^= !host->plat->is_wpswitch_active_low;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003245 }
3246 gpio_free(host->plat->wpswitch_gpio);
3247 }
3248 }
3249
3250 if (status < 0)
3251 status = -ENOSYS;
3252 pr_debug("%s: Card read-only status %d\n", __func__, status);
3253
3254 return status;
San Mehat9d2bd732009-09-22 16:44:22 -07003255}
3256
3257static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
3258{
3259 struct msmsdcc_host *host = mmc_priv(mmc);
3260 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003261
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303262 /*
3263 * We may come here with clocks turned off in that case don't
3264 * attempt to write into MASK0 register. While turning on the
3265 * clocks mci_irqenable will be written to MASK0 register.
3266 */
San Mehat9d2bd732009-09-22 16:44:22 -07003267
3268 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003269 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003270 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303271 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303272 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003273 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303274 mb();
3275 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003276 } else {
3277 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303278 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303279 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003280 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303281 mb();
3282 }
San Mehat9d2bd732009-09-22 16:44:22 -07003283 }
3284 spin_unlock_irqrestore(&host->lock, flags);
3285}
3286
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003287#ifdef CONFIG_PM_RUNTIME
subhashj245831e2012-04-30 18:46:17 +05303288static void msmsdcc_print_rpm_info(struct msmsdcc_host *host)
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003289{
subhashj245831e2012-04-30 18:46:17 +05303290 struct device *dev = mmc_dev(host->mmc);
3291
3292 pr_info("%s: RPM: runtime_status=%d, usage_count=%d,"
3293 " is_suspended=%d, disable_depth=%d, runtime_error=%d,"
3294 " request_pending=%d, request=%d\n",
3295 mmc_hostname(host->mmc), dev->power.runtime_status,
3296 atomic_read(&dev->power.usage_count),
3297 dev->power.is_suspended, dev->power.disable_depth,
3298 dev->power.runtime_error, dev->power.request_pending,
3299 dev->power.request);
3300}
3301
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003302static int msmsdcc_enable(struct mmc_host *mmc)
3303{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003304 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003305 struct device *dev = mmc->parent;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003306 struct msmsdcc_host *host = mmc_priv(mmc);
3307
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303308 msmsdcc_pm_qos_update_latency(host, 1);
3309
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003310 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303311 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003312
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003313 if (host->sdcc_suspended && host->pending_resume &&
3314 !pm_runtime_suspended(dev)) {
3315 host->pending_resume = false;
3316 pm_runtime_get_noresume(dev);
3317 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303318 goto skip_get_sync;
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003319 }
3320
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303321 if (dev->power.runtime_status == RPM_SUSPENDING) {
3322 if (mmc->suspend_task == current) {
3323 pm_runtime_get_noresume(dev);
3324 goto out;
3325 }
Sujit Reddy Thumma112bd752012-06-20 12:29:45 +05303326 } else if (dev->power.runtime_status == RPM_RESUMING) {
3327 pm_runtime_get_noresume(dev);
3328 goto out;
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303329 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003330
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303331 rc = pm_runtime_get_sync(dev);
3332
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303333skip_get_sync:
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303334 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003335 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3336 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303337 msmsdcc_print_rpm_info(host);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303338 return rc;
3339 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303340out:
3341 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303342 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003343}
3344
Steve Mucklef132c6c2012-06-06 18:30:57 -07003345static int msmsdcc_disable(struct mmc_host *mmc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003346{
3347 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303348 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003349
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303350 msmsdcc_pm_qos_update_latency(host, 0);
3351
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303352 if (mmc->card && mmc_card_sdio(mmc->card)) {
3353 rc = 0;
3354 goto out;
3355 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303356
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303357 if (host->plat->disable_runtime_pm)
3358 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003359
3360 rc = pm_runtime_put_sync(mmc->parent);
3361
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003362 /*
3363 * Ignore -EAGAIN as that is not fatal, it means that
3364 * either runtime usage count is non-zero or the runtime
3365 * pm itself is disabled or not in proper state to process
3366 * idle notification.
3367 */
3368 if (rc < 0 && (rc != -EAGAIN)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003369 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3370 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303371 msmsdcc_print_rpm_info(host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003372 return rc;
3373 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303374
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303375out:
3376 msmsdcc_msm_bus_queue_work(host);
3377 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003378}
3379#else
subhashj245831e2012-04-30 18:46:17 +05303380static void msmsdcc_print_rpm_info(struct msmsdcc_host *host) {}
3381
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303382static int msmsdcc_enable(struct mmc_host *mmc)
3383{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003384 struct device *dev = mmc->parent;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303385 struct msmsdcc_host *host = mmc_priv(mmc);
3386 unsigned long flags;
Sujit Reddy Thumma7f5051c2012-05-04 10:14:07 +05303387 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303388
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303389 msmsdcc_pm_qos_update_latency(host, 1);
3390
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303391 if (mmc->card && mmc_card_sdio(mmc->card)) {
3392 rc = 0;
3393 goto out;
3394 }
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003395
3396 if (host->sdcc_suspended && host->pending_resume) {
3397 host->pending_resume = false;
3398 rc = msmsdcc_runtime_resume(dev);
3399 goto out;
3400 }
3401
Asutosh Dasf5298c32012-04-03 14:51:47 +05303402 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303403 rc = msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303404 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303405
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003406out:
3407 if (rc < 0) {
3408 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3409 __func__, rc);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303410 msmsdcc_pm_qos_update_latency(host, 0);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003411 return rc;
3412 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303413 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303414 return 0;
3415}
3416
Steve Mucklef132c6c2012-06-06 18:30:57 -07003417static int msmsdcc_disable(struct mmc_host *mmc)
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303418{
3419 struct msmsdcc_host *host = mmc_priv(mmc);
3420 unsigned long flags;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303421 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303422
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303423 msmsdcc_pm_qos_update_latency(host, 0);
3424
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303425 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303426 goto out;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303427
Asutosh Dasf5298c32012-04-03 14:51:47 +05303428 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303429 rc = msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303430 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303431
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303432 if (rc) {
3433 msmsdcc_pm_qos_update_latency(host, 1);
3434 return rc;
3435 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303436out:
3437 msmsdcc_msm_bus_queue_work(host);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303438 return rc;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303439}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003440#endif
3441
Subhash Jadavani937c7502012-06-01 15:34:46 +05303442static int msmsdcc_switch_io_voltage(struct mmc_host *mmc,
3443 struct mmc_ios *ios)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003444{
3445 struct msmsdcc_host *host = mmc_priv(mmc);
3446 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303447 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003448
Subhash Jadavani00083572012-02-15 16:18:01 +05303449 spin_lock_irqsave(&host->lock, flags);
3450 host->io_pad_pwr_switch = 0;
3451 spin_unlock_irqrestore(&host->lock, flags);
3452
Subhash Jadavani937c7502012-06-01 15:34:46 +05303453 switch (ios->signal_voltage) {
3454 case MMC_SIGNAL_VOLTAGE_330:
3455 /* Set VDD IO to high voltage range (2.7v - 3.6v) */
3456 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303457 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303458 case MMC_SIGNAL_VOLTAGE_180:
3459 break;
3460 case MMC_SIGNAL_VOLTAGE_120:
3461 /*
3462 * For eMMC cards, VDD_IO voltage range must be changed
3463 * only if it operates in HS200 SDR 1.2V mode or in
3464 * DDR 1.2V mode.
3465 */
3466 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_SET_LEVEL, 1200000);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003467 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303468 default:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003469 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303470 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003471 goto out;
3472 }
San Mehat9d2bd732009-09-22 16:44:22 -07003473
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003474 /*
3475 * If we are here means voltage switch from high voltage to
3476 * low voltage is required
3477 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303478 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003479
3480 /*
3481 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
3482 * register until they become all zeros.
3483 */
3484 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303485 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003486 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
3487 mmc_hostname(mmc), __func__);
3488 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07003489 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003490
3491 /* Stop SD CLK output. */
3492 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3493 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303494 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003495 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003496
3497 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05303498 * Switch VDD Io from high voltage range (2.7v - 3.6v) to
3499 * low voltage range (1.7v - 1.95v).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003500 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303501 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303502 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003503 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003504
3505 spin_lock_irqsave(&host->lock, flags);
3506 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3507 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303508 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003509 host->io_pad_pwr_switch = 1;
3510 spin_unlock_irqrestore(&host->lock, flags);
3511
3512 /* Wait 5 ms for the voltage regulater in the card to become stable. */
3513 usleep_range(5000, 5500);
3514
3515 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303516 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003517 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3518 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303519 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003520 spin_unlock_irqrestore(&host->lock, flags);
3521
3522 /*
3523 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
3524 * don't become all ones within 1 ms then a Voltage Switch
3525 * sequence has failed and a power cycle to the card is required.
3526 * Otherwise Voltage Switch sequence is completed successfully.
3527 */
3528 usleep_range(1000, 1500);
3529
3530 spin_lock_irqsave(&host->lock, flags);
3531 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
3532 != (0xF << 1)) {
3533 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
3534 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303535 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003536 goto out_unlock;
3537 }
3538
3539out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303540 /* Enable PWRSAVE */
3541 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3542 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303543 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003544 spin_unlock_irqrestore(&host->lock, flags);
3545out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303546 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003547}
3548
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303549static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003550{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003551 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003552
3553 /* Program the MCLK value to MCLK_FREQ bit field */
3554 if (host->clk_rate <= 112000000)
3555 mclk_freq = 0;
3556 else if (host->clk_rate <= 125000000)
3557 mclk_freq = 1;
3558 else if (host->clk_rate <= 137000000)
3559 mclk_freq = 2;
3560 else if (host->clk_rate <= 150000000)
3561 mclk_freq = 3;
3562 else if (host->clk_rate <= 162000000)
3563 mclk_freq = 4;
3564 else if (host->clk_rate <= 175000000)
3565 mclk_freq = 5;
3566 else if (host->clk_rate <= 187000000)
3567 mclk_freq = 6;
3568 else if (host->clk_rate <= 200000000)
3569 mclk_freq = 7;
3570
3571 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3572 & ~(7 << 24)) | (mclk_freq << 24)),
3573 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003574}
3575
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303576/* Initialize the DLL (Programmable Delay Line ) */
3577static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003578{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003579 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303580 unsigned long flags;
3581 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003582
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303583 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003584 /*
3585 * Make sure that clock is always enabled when DLL
3586 * tuning is in progress. Keeping PWRSAVE ON may
3587 * turn off the clock. So let's disable the PWRSAVE
3588 * here and re-enable it once tuning is completed.
3589 */
3590 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3591 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303592 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303593
3594 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3595 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3596 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3597
3598 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3599 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3600 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3601
3602 msmsdcc_cm_sdc4_dll_set_freq(host);
3603
3604 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3605 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3606 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3607
3608 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3609 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3610 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3611
3612 /* Set DLL_EN bit to 1. */
3613 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3614 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3615
3616 /* Set CK_OUT_EN bit to 1. */
3617 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3618 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3619
3620 wait_cnt = 50;
3621 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3622 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3623 /* max. wait for 50us sec for LOCK bit to be set */
3624 if (--wait_cnt == 0) {
3625 pr_err("%s: %s: DLL failed to LOCK\n",
3626 mmc_hostname(host->mmc), __func__);
3627 rc = -ETIMEDOUT;
3628 goto out;
3629 }
3630 /* wait for 1us before polling again */
3631 udelay(1);
3632 }
3633
3634out:
3635 /* re-enable PWRSAVE */
3636 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3637 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303638 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303639 spin_unlock_irqrestore(&host->lock, flags);
3640
3641 return rc;
3642}
3643
3644static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3645 u8 poll)
3646{
3647 int rc = 0;
3648 u32 wait_cnt = 50;
3649 u8 ck_out_en = 0;
3650
3651 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3652 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3653 MCI_CK_OUT_EN);
3654
3655 while (ck_out_en != poll) {
3656 if (--wait_cnt == 0) {
3657 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3658 mmc_hostname(host->mmc), __func__, poll);
3659 rc = -ETIMEDOUT;
3660 goto out;
3661 }
3662 udelay(1);
3663
3664 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3665 MCI_CK_OUT_EN);
3666 }
3667out:
3668 return rc;
3669}
3670
3671/*
3672 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3673 * calibration sequence. This function should be called before
3674 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3675 * commands (CMD17/CMD18).
3676 *
3677 * This function gets called when host spinlock acquired.
3678 */
3679static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3680{
3681 int rc = 0;
3682 u32 config;
3683
3684 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3685 config |= MCI_CDR_EN;
3686 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3687 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3688
3689 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3690 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3691 if (rc)
3692 goto err_out;
3693
3694 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3695 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3696 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3697
3698 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3699 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3700 if (rc)
3701 goto err_out;
3702
3703 goto out;
3704
3705err_out:
3706 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3707out:
3708 return rc;
3709}
3710
3711static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3712 u8 phase)
3713{
3714 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303715 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3716 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3717 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303718 unsigned long flags;
3719 u32 config;
3720
3721 spin_lock_irqsave(&host->lock, flags);
3722
3723 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3724 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3725 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3726 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3727
3728 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3729 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3730 if (rc)
3731 goto err_out;
3732
3733 /*
3734 * Write the selected DLL clock output phase (0 ... 15)
3735 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
3736 */
3737 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3738 & ~(0xF << 20))
3739 | (grey_coded_phase_table[phase] << 20)),
3740 host->base + MCI_DLL_CONFIG);
3741
3742 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3743 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3744 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3745
3746 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3747 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3748 if (rc)
3749 goto err_out;
3750
3751 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3752 config |= MCI_CDR_EN;
3753 config &= ~MCI_CDR_EXT_EN;
3754 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3755 goto out;
3756
3757err_out:
3758 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3759 mmc_hostname(host->mmc), __func__, phase);
3760out:
3761 spin_unlock_irqrestore(&host->lock, flags);
3762 return rc;
3763}
3764
3765/*
3766 * Find out the greatest range of consecuitive selected
3767 * DLL clock output phases that can be used as sampling
3768 * setting for SD3.0 UHS-I card read operation (in SDR104
3769 * timing mode) or for eMMC4.5 card read operation (in HS200
3770 * timing mode).
3771 * Select the 3/4 of the range and configure the DLL with the
3772 * selected DLL clock output phase.
3773*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303774static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303775 u8 *phase_table, u8 total_phases)
3776{
Subhash Jadavani6159c622012-03-15 19:05:55 +05303777 #define MAX_PHASES 16
Subhash Jadavani34187042012-03-02 10:59:49 +05303778 int ret;
Subhash Jadavani6159c622012-03-15 19:05:55 +05303779 u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
3780 u8 phases_per_row[MAX_PHASES] = {0};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303781 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303782 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3783 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303784
Subhash Jadavani6159c622012-03-15 19:05:55 +05303785 if (!total_phases || (total_phases > MAX_PHASES)) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303786 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3787 mmc_hostname(host->mmc), __func__, total_phases);
3788 return -EINVAL;
3789 }
3790
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303791 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303792 ranges[row_index][col_index] = phase_table[cnt];
3793 phases_per_row[row_index] += 1;
3794 col_index++;
3795
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303796 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303797 continue;
3798 /* check if next phase in phase_table is consecutive or not */
3799 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3800 row_index++;
3801 col_index = 0;
3802 }
3803 }
3804
Subhash Jadavani6159c622012-03-15 19:05:55 +05303805 if (row_index >= MAX_PHASES)
3806 return -EINVAL;
3807
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303808 /* Check if phase-0 is present in first valid window? */
3809 if (!ranges[0][0]) {
3810 phase_0_found = true;
3811 phase_0_raw_index = 0;
3812 /* Check if cycle exist between 2 valid windows */
3813 for (cnt = 1; cnt <= row_index; cnt++) {
3814 if (phases_per_row[cnt]) {
Subhash Jadavani6159c622012-03-15 19:05:55 +05303815 for (i = 0; i < phases_per_row[cnt]; i++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303816 if (ranges[cnt][i] == 15) {
3817 phase_15_found = true;
3818 phase_15_raw_index = cnt;
3819 break;
3820 }
3821 }
3822 }
3823 }
3824 }
3825
3826 /* If 2 valid windows form cycle then merge them as single window */
3827 if (phase_0_found && phase_15_found) {
3828 /* number of phases in raw where phase 0 is present */
3829 u8 phases_0 = phases_per_row[phase_0_raw_index];
3830 /* number of phases in raw where phase 15 is present */
3831 u8 phases_15 = phases_per_row[phase_15_raw_index];
3832
Subhash Jadavani6159c622012-03-15 19:05:55 +05303833 if (phases_0 + phases_15 >= MAX_PHASES)
3834 /*
3835 * If there are more than 1 phase windows then total
3836 * number of phases in both the windows should not be
3837 * more than or equal to MAX_PHASES.
3838 */
3839 return -EINVAL;
3840
3841 /* Merge 2 cyclic windows */
3842 i = phases_15;
3843 for (cnt = 0; cnt < phases_0; cnt++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303844 ranges[phase_15_raw_index][i] =
3845 ranges[phase_0_raw_index][cnt];
Subhash Jadavani6159c622012-03-15 19:05:55 +05303846 if (++i >= MAX_PHASES)
3847 break;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303848 }
Subhash Jadavani6159c622012-03-15 19:05:55 +05303849
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303850 phases_per_row[phase_0_raw_index] = 0;
3851 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
3852 }
3853
3854 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303855 if (phases_per_row[cnt] > curr_max) {
3856 curr_max = phases_per_row[cnt];
3857 selected_row_index = cnt;
3858 }
3859 }
3860
Subhash Jadavani6159c622012-03-15 19:05:55 +05303861 i = ((curr_max * 3) / 4);
3862 if (i)
3863 i--;
3864
Subhash Jadavani34187042012-03-02 10:59:49 +05303865 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303866
Subhash Jadavani6159c622012-03-15 19:05:55 +05303867 if (ret >= MAX_PHASES) {
3868 ret = -EINVAL;
3869 pr_err("%s: %s: invalid phase selected=%d\n",
3870 mmc_hostname(host->mmc), __func__, ret);
3871 }
3872
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303873 return ret;
3874}
3875
Girish K Sa3f41692012-02-29 12:00:09 +05303876static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303877{
3878 int rc = 0;
3879 struct msmsdcc_host *host = mmc_priv(mmc);
3880 unsigned long flags;
3881 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303882 const u32 *tuning_block_pattern = tuning_block_64;
3883 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303884
3885 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
3886
3887 /* Tuning is only required for SDR104 modes */
3888 if (!host->tuning_needed) {
3889 rc = 0;
3890 goto exit;
3891 }
3892
3893 spin_lock_irqsave(&host->lock, flags);
3894 WARN(!host->pwr, "SDCC power is turned off\n");
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303895 WARN(!atomic_read(&host->clks_on), "SDCC clocks are turned off\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303896 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
3897
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303898 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303899 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
3900 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
3901 tuning_block_pattern = tuning_block_128;
3902 size = sizeof(tuning_block_128);
3903 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303904 spin_unlock_irqrestore(&host->lock, flags);
3905
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003906 /* first of all reset the tuning block */
3907 rc = msmsdcc_init_cm_sdc4_dll(host);
3908 if (rc)
3909 goto out;
3910
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303911 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003912 if (!data_buf) {
3913 rc = -ENOMEM;
3914 goto out;
3915 }
3916
3917 phase = 0;
3918 do {
3919 struct mmc_command cmd = {0};
3920 struct mmc_data data = {0};
3921 struct mmc_request mrq = {
3922 .cmd = &cmd,
3923 .data = &data
3924 };
3925 struct scatterlist sg;
3926
3927 /* set the phase in delay line hw block */
3928 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3929 if (rc)
3930 goto kfree;
3931
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303932 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003933 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
3934
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303935 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003936 data.blocks = 1;
3937 data.flags = MMC_DATA_READ;
3938 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
3939
3940 data.sg = &sg;
3941 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303942 sg_init_one(&sg, data_buf, size);
3943 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003944 mmc_wait_for_req(mmc, &mrq);
3945
3946 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303947 !memcmp(data_buf, tuning_block_pattern, size)) {
3948 /* tuning is successful at this tuning point */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003949 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303950 pr_debug("%s: %s: found good phase = %d\n",
3951 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003952 }
3953 } while (++phase < 16);
3954
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003955 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303956 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303957 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05303958 if (rc < 0)
3959 goto kfree;
3960 else
3961 phase = (u8)rc;
3962
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003963 /*
3964 * Finally set the selected phase in delay
3965 * line hw block.
3966 */
3967 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3968 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303969 goto kfree;
3970 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
3971 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003972 } else {
3973 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303974 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003975 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303976 msmsdcc_dump_sdcc_state(host);
3977 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003978 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003979
3980kfree:
3981 kfree(data_buf);
3982out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303983 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303984 host->tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303985 spin_unlock_irqrestore(&host->lock, flags);
3986exit:
3987 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003988 return rc;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003989}
3990
San Mehat9d2bd732009-09-22 16:44:22 -07003991static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003992 .enable = msmsdcc_enable,
3993 .disable = msmsdcc_disable,
Asutosh Dasaccacd42012-03-08 14:33:17 +05303994 .pre_req = msmsdcc_pre_req,
3995 .post_req = msmsdcc_post_req,
San Mehat9d2bd732009-09-22 16:44:22 -07003996 .request = msmsdcc_request,
3997 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003998 .get_ro = msmsdcc_get_ro,
San Mehat9d2bd732009-09-22 16:44:22 -07003999 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Subhash Jadavani937c7502012-06-01 15:34:46 +05304000 .start_signal_voltage_switch = msmsdcc_switch_io_voltage,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004001 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07004002};
4003
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004004static unsigned int
4005msmsdcc_slot_status(struct msmsdcc_host *host)
4006{
4007 int status;
4008 unsigned int gpio_no = host->plat->status_gpio;
4009
4010 status = gpio_request(gpio_no, "SD_HW_Detect");
4011 if (status) {
4012 pr_err("%s: %s: Failed to request GPIO %d\n",
4013 mmc_hostname(host->mmc), __func__, gpio_no);
4014 } else {
4015 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08004016 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08004017 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08004018 if (host->plat->is_status_gpio_active_low)
4019 status = !status;
4020 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004021 gpio_free(gpio_no);
4022 }
4023 return status;
4024}
4025
San Mehat9d2bd732009-09-22 16:44:22 -07004026static void
4027msmsdcc_check_status(unsigned long data)
4028{
4029 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4030 unsigned int status;
4031
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05304032 if (host->plat->status || gpio_is_valid(host->plat->status_gpio)) {
Krishna Konda941604a2012-01-10 17:46:34 -08004033 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004034 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004035 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004036 status = msmsdcc_slot_status(host);
4037
Krishna Konda941604a2012-01-10 17:46:34 -08004038 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08004039
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004040 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08004041 if (host->plat->status)
4042 pr_info("%s: Slot status change detected "
4043 "(%d -> %d)\n",
4044 mmc_hostname(host->mmc),
4045 host->oldstat, status);
4046 else if (host->plat->is_status_gpio_active_low)
4047 pr_info("%s: Slot status change detected "
4048 "(%d -> %d) and the card detect GPIO"
4049 " is ACTIVE_LOW\n",
4050 mmc_hostname(host->mmc),
4051 host->oldstat, status);
4052 else
4053 pr_info("%s: Slot status change detected "
4054 "(%d -> %d) and the card detect GPIO"
4055 " is ACTIVE_HIGH\n",
4056 mmc_hostname(host->mmc),
4057 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07004058 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004059 }
4060 host->oldstat = status;
4061 } else {
4062 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07004063 }
San Mehat9d2bd732009-09-22 16:44:22 -07004064}
4065
4066static irqreturn_t
4067msmsdcc_platform_status_irq(int irq, void *dev_id)
4068{
4069 struct msmsdcc_host *host = dev_id;
4070
Girish K Sa3c76eb2011-10-11 11:44:09 +05304071 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07004072 msmsdcc_check_status((unsigned long) host);
4073 return IRQ_HANDLED;
4074}
4075
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004076static irqreturn_t
4077msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
4078{
4079 struct msmsdcc_host *host = dev_id;
4080
4081 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
4082 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304083 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004084 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304085 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004086 wake_lock(&host->sdio_wlock);
4087 msmsdcc_disable_irq_wake(host);
4088 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304089 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004090 }
4091 if (host->plat->is_sdio_al_client) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004092 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304093 spin_unlock(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304094 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304095 goto out_unlocked;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004096 }
4097 spin_unlock(&host->lock);
4098
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304099out_unlocked:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004100 return IRQ_HANDLED;
4101}
4102
San Mehat9d2bd732009-09-22 16:44:22 -07004103static void
4104msmsdcc_status_notify_cb(int card_present, void *dev_id)
4105{
4106 struct msmsdcc_host *host = dev_id;
4107
Girish K Sa3c76eb2011-10-11 11:44:09 +05304108 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07004109 card_present);
4110 msmsdcc_check_status((unsigned long) host);
4111}
4112
San Mehat9d2bd732009-09-22 16:44:22 -07004113static int
4114msmsdcc_init_dma(struct msmsdcc_host *host)
4115{
4116 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
4117 host->dma.host = host;
4118 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004119 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004120
4121 if (!host->dmares)
4122 return -ENODEV;
4123
4124 host->dma.nc = dma_alloc_coherent(NULL,
4125 sizeof(struct msmsdcc_nc_dmadata),
4126 &host->dma.nc_busaddr,
4127 GFP_KERNEL);
4128 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004129 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07004130 return -ENOMEM;
4131 }
4132 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
4133 host->dma.cmd_busaddr = host->dma.nc_busaddr;
4134 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
4135 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
4136 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07004137 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07004138
4139 return 0;
4140}
4141
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004142#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
4143/**
4144 * Allocate and Connect a SDCC peripheral's SPS endpoint
4145 *
4146 * This function allocates endpoint context and
4147 * connect it with memory endpoint by calling
4148 * appropriate SPS driver APIs.
4149 *
4150 * Also registers a SPS callback function with
4151 * SPS driver
4152 *
4153 * This function should only be called once typically
4154 * during driver probe.
4155 *
4156 * @host - Pointer to sdcc host structure
4157 * @ep - Pointer to sps endpoint data structure
4158 * @is_produce - 1 means Producer endpoint
4159 * 0 means Consumer endpoint
4160 *
4161 * @return - 0 if successful else negative value.
4162 *
4163 */
4164static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
4165 struct msmsdcc_sps_ep_conn_data *ep,
4166 bool is_producer)
4167{
4168 int rc = 0;
4169 struct sps_pipe *sps_pipe_handle;
4170 struct sps_connect *sps_config = &ep->config;
4171 struct sps_register_event *sps_event = &ep->event;
4172
4173 /* Allocate endpoint context */
4174 sps_pipe_handle = sps_alloc_endpoint();
4175 if (!sps_pipe_handle) {
4176 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
4177 mmc_hostname(host->mmc), is_producer);
4178 rc = -ENOMEM;
4179 goto out;
4180 }
4181
4182 /* Get default connection configuration for an endpoint */
4183 rc = sps_get_config(sps_pipe_handle, sps_config);
4184 if (rc) {
4185 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
4186 " rc=%d", mmc_hostname(host->mmc),
4187 (u32)sps_pipe_handle, rc);
4188 goto get_config_err;
4189 }
4190
4191 /* Modify the default connection configuration */
4192 if (is_producer) {
4193 /*
4194 * For SDCC producer transfer, source should be
4195 * SDCC peripheral where as destination should
4196 * be system memory.
4197 */
4198 sps_config->source = host->sps.bam_handle;
4199 sps_config->destination = SPS_DEV_HANDLE_MEM;
4200 /* Producer pipe will handle this connection */
4201 sps_config->mode = SPS_MODE_SRC;
4202 sps_config->options =
4203 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4204 } else {
4205 /*
4206 * For SDCC consumer transfer, source should be
4207 * system memory where as destination should
4208 * SDCC peripheral
4209 */
4210 sps_config->source = SPS_DEV_HANDLE_MEM;
4211 sps_config->destination = host->sps.bam_handle;
4212 sps_config->mode = SPS_MODE_DEST;
4213 sps_config->options =
4214 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4215 }
4216
4217 /* Producer pipe index */
4218 sps_config->src_pipe_index = host->sps.src_pipe_index;
4219 /* Consumer pipe index */
4220 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
4221 /*
4222 * This event thresold value is only significant for BAM-to-BAM
4223 * transfer. It's ignored for BAM-to-System mode transfer.
4224 */
4225 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304226
4227 /* Allocate maximum descriptor fifo size */
4228 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
4229 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004230 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
4231 sps_config->desc.size,
4232 &sps_config->desc.phys_base,
4233 GFP_KERNEL);
4234
Pratibhasagar V00b94332011-10-18 14:57:27 +05304235 if (!sps_config->desc.base) {
4236 rc = -ENOMEM;
4237 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
4238 , mmc_hostname(host->mmc));
4239 goto get_config_err;
4240 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004241 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
4242
4243 /* Establish connection between peripheral and memory endpoint */
4244 rc = sps_connect(sps_pipe_handle, sps_config);
4245 if (rc) {
4246 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4247 " rc=%d", mmc_hostname(host->mmc),
4248 (u32)sps_pipe_handle, rc);
4249 goto sps_connect_err;
4250 }
4251
4252 sps_event->mode = SPS_TRIGGER_CALLBACK;
4253 sps_event->options = SPS_O_EOT;
4254 sps_event->callback = msmsdcc_sps_complete_cb;
4255 sps_event->xfer_done = NULL;
4256 sps_event->user = (void *)host;
4257
4258 /* Register callback event for EOT (End of transfer) event. */
4259 rc = sps_register_event(sps_pipe_handle, sps_event);
4260 if (rc) {
4261 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4262 " rc=%d", mmc_hostname(host->mmc),
4263 (u32)sps_pipe_handle, rc);
4264 goto reg_event_err;
4265 }
4266 /* Now save the sps pipe handle */
4267 ep->pipe_handle = sps_pipe_handle;
4268 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
4269 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
4270 __func__, is_producer ? "READ" : "WRITE",
4271 (u32)sps_pipe_handle, sps_config->desc.phys_base);
4272 goto out;
4273
4274reg_event_err:
4275 sps_disconnect(sps_pipe_handle);
4276sps_connect_err:
4277 dma_free_coherent(mmc_dev(host->mmc),
4278 sps_config->desc.size,
4279 sps_config->desc.base,
4280 sps_config->desc.phys_base);
4281get_config_err:
4282 sps_free_endpoint(sps_pipe_handle);
4283out:
4284 return rc;
4285}
4286
4287/**
4288 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
4289 *
4290 * This function disconnect endpoint and deallocates
4291 * endpoint context.
4292 *
4293 * This function should only be called once typically
4294 * during driver remove.
4295 *
4296 * @host - Pointer to sdcc host structure
4297 * @ep - Pointer to sps endpoint data structure
4298 *
4299 */
4300static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
4301 struct msmsdcc_sps_ep_conn_data *ep)
4302{
4303 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4304 struct sps_connect *sps_config = &ep->config;
4305 struct sps_register_event *sps_event = &ep->event;
4306
4307 sps_event->xfer_done = NULL;
4308 sps_event->callback = NULL;
4309 sps_register_event(sps_pipe_handle, sps_event);
4310 sps_disconnect(sps_pipe_handle);
4311 dma_free_coherent(mmc_dev(host->mmc),
4312 sps_config->desc.size,
4313 sps_config->desc.base,
4314 sps_config->desc.phys_base);
4315 sps_free_endpoint(sps_pipe_handle);
4316}
4317
4318/**
4319 * Reset SDCC peripheral's SPS endpoint
4320 *
4321 * This function disconnects an endpoint.
4322 *
4323 * This function should be called for reseting
4324 * SPS endpoint when data transfer error is
4325 * encountered during data transfer. This
4326 * can be considered as soft reset to endpoint.
4327 *
4328 * This function should only be called if
4329 * msmsdcc_sps_init() is already called.
4330 *
4331 * @host - Pointer to sdcc host structure
4332 * @ep - Pointer to sps endpoint data structure
4333 *
4334 * @return - 0 if successful else negative value.
4335 */
4336static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
4337 struct msmsdcc_sps_ep_conn_data *ep)
4338{
4339 int rc = 0;
4340 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4341
4342 rc = sps_disconnect(sps_pipe_handle);
4343 if (rc) {
4344 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
4345 " rc=%d", mmc_hostname(host->mmc), __func__,
4346 (u32)sps_pipe_handle, rc);
4347 goto out;
4348 }
4349 out:
4350 return rc;
4351}
4352
4353/**
4354 * Restore SDCC peripheral's SPS endpoint
4355 *
4356 * This function connects an endpoint.
4357 *
4358 * This function should be called for restoring
4359 * SPS endpoint after data transfer error is
4360 * encountered during data transfer. This
4361 * can be considered as soft reset to endpoint.
4362 *
4363 * This function should only be called if
4364 * msmsdcc_sps_reset_ep() is called before.
4365 *
4366 * @host - Pointer to sdcc host structure
4367 * @ep - Pointer to sps endpoint data structure
4368 *
4369 * @return - 0 if successful else negative value.
4370 */
4371static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
4372 struct msmsdcc_sps_ep_conn_data *ep)
4373{
4374 int rc = 0;
4375 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4376 struct sps_connect *sps_config = &ep->config;
4377 struct sps_register_event *sps_event = &ep->event;
4378
4379 /* Establish connection between peripheral and memory endpoint */
4380 rc = sps_connect(sps_pipe_handle, sps_config);
4381 if (rc) {
4382 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
4383 " rc=%d", mmc_hostname(host->mmc), __func__,
4384 (u32)sps_pipe_handle, rc);
4385 goto out;
4386 }
4387
4388 /* Register callback event for EOT (End of transfer) event. */
4389 rc = sps_register_event(sps_pipe_handle, sps_event);
4390 if (rc) {
4391 pr_err("%s: %s: sps_register_event() failed!!!"
4392 " pipe_handle=0x%x, rc=%d",
4393 mmc_hostname(host->mmc), __func__,
4394 (u32)sps_pipe_handle, rc);
4395 goto reg_event_err;
4396 }
4397 goto out;
4398
4399reg_event_err:
4400 sps_disconnect(sps_pipe_handle);
4401out:
4402 return rc;
4403}
4404
4405/**
Krishna Konda5af8f972012-05-14 16:15:24 -07004406 * Handle BAM device's global error condition
4407 *
4408 * This is an error handler for the SDCC bam device
4409 *
4410 * This function is registered as a callback with SPS-BAM
4411 * driver and will called in case there are an errors for
4412 * the SDCC BAM deivce. Any error conditions in the BAM
4413 * device are global and will be result in this function
4414 * being called once per device.
4415 *
4416 * This function will be called from the sps driver's
4417 * interrupt context.
4418 *
4419 * @sps_cb_case - indicates what error it is
4420 * @user - Pointer to sdcc host structure
4421 */
4422static void
4423msmsdcc_sps_bam_global_irq_cb(enum sps_callback_case sps_cb_case, void *user)
4424{
4425 struct msmsdcc_host *host = (struct msmsdcc_host *)user;
4426 struct mmc_request *mrq;
4427 unsigned long flags;
4428 int32_t error = 0;
4429
4430 BUG_ON(!host);
4431 BUG_ON(!is_sps_mode(host));
4432
4433 if (sps_cb_case == SPS_CALLBACK_BAM_ERROR_IRQ) {
4434 /**
4435 * Reset the all endpoints along with reseting the sps device.
4436 */
4437 host->sps.pipe_reset_pending = true;
4438 host->sps.reset_device = true;
4439
4440 pr_err("%s: BAM Global ERROR IRQ happened\n",
4441 mmc_hostname(host->mmc));
4442 error = EAGAIN;
4443 } else if (sps_cb_case == SPS_CALLBACK_BAM_HRESP_ERR_IRQ) {
4444 /**
4445 * This means that there was an AHB access error and
4446 * the address we are trying to read/write is something
4447 * we dont have priviliges to do so.
4448 */
4449 pr_err("%s: BAM HRESP_ERR_IRQ happened\n",
4450 mmc_hostname(host->mmc));
4451 error = EACCES;
4452 } else {
4453 /**
4454 * This should not have happened ideally. If this happens
4455 * there is some seriously wrong.
4456 */
4457 pr_err("%s: BAM global IRQ callback received, type:%d\n",
4458 mmc_hostname(host->mmc), (u32) sps_cb_case);
4459 error = EIO;
4460 }
4461
4462 spin_lock_irqsave(&host->lock, flags);
4463
4464 mrq = host->curr.mrq;
4465
4466 if (mrq && mrq->cmd) {
4467 msmsdcc_dump_sdcc_state(host);
4468
4469 if (!mrq->cmd->error)
4470 mrq->cmd->error = -error;
4471 if (host->curr.data) {
4472 if (mrq->data && !mrq->data->error)
4473 mrq->data->error = -error;
4474 host->curr.data_xfered = 0;
4475 if (host->sps.sg && is_sps_mode(host)) {
4476 /* Stop current SPS transfer */
4477 msmsdcc_sps_exit_curr_xfer(host);
4478 } else {
4479 /* this condition should not have happened */
4480 pr_err("%s: something is seriously wrong. "\
4481 "Funtion: %s, line: %d\n",
4482 mmc_hostname(host->mmc),
4483 __func__, __LINE__);
4484 }
4485 } else {
4486 /* this condition should not have happened */
4487 pr_err("%s: something is seriously wrong. Funtion: "\
4488 "%s, line: %d\n", mmc_hostname(host->mmc),
4489 __func__, __LINE__);
4490 }
4491 }
4492 spin_unlock_irqrestore(&host->lock, flags);
4493}
4494
4495/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004496 * Initialize SPS HW connected with SDCC core
4497 *
4498 * This function register BAM HW resources with
4499 * SPS driver and then initialize 2 SPS endpoints
4500 *
4501 * This function should only be called once typically
4502 * during driver probe.
4503 *
4504 * @host - Pointer to sdcc host structure
4505 *
4506 * @return - 0 if successful else negative value.
4507 *
4508 */
4509static int msmsdcc_sps_init(struct msmsdcc_host *host)
4510{
4511 int rc = 0;
4512 struct sps_bam_props bam = {0};
4513
4514 host->bam_base = ioremap(host->bam_memres->start,
4515 resource_size(host->bam_memres));
4516 if (!host->bam_base) {
4517 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
4518 " size=0x%x", mmc_hostname(host->mmc),
4519 host->bam_memres->start,
4520 (host->bam_memres->end -
4521 host->bam_memres->start));
4522 rc = -ENOMEM;
4523 goto out;
4524 }
4525
4526 bam.phys_addr = host->bam_memres->start;
4527 bam.virt_addr = host->bam_base;
4528 /*
4529 * This event thresold value is only significant for BAM-to-BAM
4530 * transfer. It's ignored for BAM-to-System mode transfer.
4531 */
4532 bam.event_threshold = 0x10; /* Pipe event threshold */
4533 /*
4534 * This threshold controls when the BAM publish
4535 * the descriptor size on the sideband interface.
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304536 * SPS HW will be used for data transfer size even
4537 * less than SDCC FIFO size. So let's set BAM summing
4538 * thresold to SPS_MIN_XFER_SIZE bytes.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004539 */
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304540 bam.summing_threshold = SPS_MIN_XFER_SIZE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004541 /* SPS driver wll handle the SDCC BAM IRQ */
4542 bam.irq = (u32)host->bam_irqres->start;
4543 bam.manage = SPS_BAM_MGR_LOCAL;
Krishna Konda5af8f972012-05-14 16:15:24 -07004544 bam.callback = msmsdcc_sps_bam_global_irq_cb;
4545 bam.user = (void *)host;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004546
4547 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
4548 (u32)bam.phys_addr);
4549 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
4550 (u32)bam.virt_addr);
4551
4552 /* Register SDCC Peripheral BAM device to SPS driver */
4553 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
4554 if (rc) {
4555 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
4556 mmc_hostname(host->mmc), rc);
4557 goto reg_bam_err;
4558 }
4559 pr_info("%s: BAM device registered. bam_handle=0x%x",
4560 mmc_hostname(host->mmc), host->sps.bam_handle);
4561
4562 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
4563 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
4564
4565 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
4566 SPS_PROD_PERIPHERAL);
4567 if (rc)
4568 goto sps_reset_err;
4569 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
4570 SPS_CONS_PERIPHERAL);
4571 if (rc)
4572 goto cons_conn_err;
4573
4574 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
4575 mmc_hostname(host->mmc),
4576 (unsigned long long)host->bam_memres->start,
4577 (unsigned int)host->bam_irqres->start);
4578 goto out;
4579
4580cons_conn_err:
4581 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4582sps_reset_err:
4583 sps_deregister_bam_device(host->sps.bam_handle);
4584reg_bam_err:
4585 iounmap(host->bam_base);
4586out:
4587 return rc;
4588}
4589
4590/**
4591 * De-initialize SPS HW connected with SDCC core
4592 *
4593 * This function deinitialize SPS endpoints and then
4594 * deregisters BAM resources from SPS driver.
4595 *
4596 * This function should only be called once typically
4597 * during driver remove.
4598 *
4599 * @host - Pointer to sdcc host structure
4600 *
4601 */
4602static void msmsdcc_sps_exit(struct msmsdcc_host *host)
4603{
4604 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
4605 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4606 sps_deregister_bam_device(host->sps.bam_handle);
4607 iounmap(host->bam_base);
4608}
4609#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
4610
4611static ssize_t
4612show_polling(struct device *dev, struct device_attribute *attr, char *buf)
4613{
4614 struct mmc_host *mmc = dev_get_drvdata(dev);
4615 struct msmsdcc_host *host = mmc_priv(mmc);
4616 int poll;
4617 unsigned long flags;
4618
4619 spin_lock_irqsave(&host->lock, flags);
4620 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
4621 spin_unlock_irqrestore(&host->lock, flags);
4622
4623 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
4624}
4625
4626static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05304627store_polling(struct device *dev, struct device_attribute *attr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004628 const char *buf, size_t count)
4629{
4630 struct mmc_host *mmc = dev_get_drvdata(dev);
4631 struct msmsdcc_host *host = mmc_priv(mmc);
4632 int value;
4633 unsigned long flags;
4634
4635 sscanf(buf, "%d", &value);
4636
4637 spin_lock_irqsave(&host->lock, flags);
4638 if (value) {
4639 mmc->caps |= MMC_CAP_NEEDS_POLL;
4640 mmc_detect_change(host->mmc, 0);
4641 } else {
4642 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4643 }
4644#ifdef CONFIG_HAS_EARLYSUSPEND
4645 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
4646#endif
4647 spin_unlock_irqrestore(&host->lock, flags);
4648 return count;
4649}
4650
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304651static ssize_t
4652show_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
4653 char *buf)
4654{
4655 struct mmc_host *mmc = dev_get_drvdata(dev);
4656 struct msmsdcc_host *host = mmc_priv(mmc);
4657
4658 return snprintf(buf, PAGE_SIZE, "%u\n",
4659 host->msm_bus_vote.is_max_bw_needed);
4660}
4661
4662static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05304663store_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304664 const char *buf, size_t count)
4665{
4666 struct mmc_host *mmc = dev_get_drvdata(dev);
4667 struct msmsdcc_host *host = mmc_priv(mmc);
4668 uint32_t value;
4669 unsigned long flags;
4670
4671 if (!kstrtou32(buf, 0, &value)) {
4672 spin_lock_irqsave(&host->lock, flags);
4673 host->msm_bus_vote.is_max_bw_needed = !!value;
4674 spin_unlock_irqrestore(&host->lock, flags);
4675 }
4676
4677 return count;
4678}
4679
Pratibhasagar V13d1d032012-07-09 20:12:38 +05304680static ssize_t
4681show_idle_timeout(struct device *dev, struct device_attribute *attr,
4682 char *buf)
4683{
4684 struct mmc_host *mmc = dev_get_drvdata(dev);
4685 struct msmsdcc_host *host = mmc_priv(mmc);
4686
4687 return snprintf(buf, PAGE_SIZE, "%u (Min 5 sec)\n",
4688 host->idle_tout_ms / 1000);
4689}
4690
4691static ssize_t
4692store_idle_timeout(struct device *dev, struct device_attribute *attr,
4693 const char *buf, size_t count)
4694{
4695 struct mmc_host *mmc = dev_get_drvdata(dev);
4696 struct msmsdcc_host *host = mmc_priv(mmc);
4697 unsigned int long flags;
4698 int timeout; /* in secs */
4699
4700 if (!kstrtou32(buf, 0, &timeout)
4701 && (timeout > MSM_MMC_DEFAULT_IDLE_TIMEOUT / 1000)) {
4702 spin_lock_irqsave(&host->lock, flags);
4703 host->idle_tout_ms = timeout * 1000;
4704 spin_unlock_irqrestore(&host->lock, flags);
4705 }
4706 return count;
4707}
4708
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004709#ifdef CONFIG_HAS_EARLYSUSPEND
4710static void msmsdcc_early_suspend(struct early_suspend *h)
4711{
4712 struct msmsdcc_host *host =
4713 container_of(h, struct msmsdcc_host, early_suspend);
4714 unsigned long flags;
4715
4716 spin_lock_irqsave(&host->lock, flags);
4717 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
4718 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4719 spin_unlock_irqrestore(&host->lock, flags);
4720};
4721static void msmsdcc_late_resume(struct early_suspend *h)
4722{
4723 struct msmsdcc_host *host =
4724 container_of(h, struct msmsdcc_host, early_suspend);
4725 unsigned long flags;
4726
4727 if (host->polling_enabled) {
4728 spin_lock_irqsave(&host->lock, flags);
4729 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
4730 mmc_detect_change(host->mmc, 0);
4731 spin_unlock_irqrestore(&host->lock, flags);
4732 }
4733};
4734#endif
4735
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304736static void msmsdcc_print_regs(const char *name, void __iomem *base,
4737 u32 phys_base, unsigned int no_of_regs)
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304738{
4739 unsigned int i;
4740
4741 if (!base)
4742 return;
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304743
4744 pr_info("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
4745 " =====\n", name, phys_base, (u32)base);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304746 for (i = 0; i < no_of_regs; i = i + 4) {
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304747 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
4748 (u32)readl_relaxed(base + i*4),
4749 (u32)readl_relaxed(base + ((i+1)*4)),
4750 (u32)readl_relaxed(base + ((i+2)*4)),
4751 (u32)readl_relaxed(base + ((i+3)*4)));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304752 }
4753}
4754
4755static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
4756{
4757 /* Dump current state of SDCC clocks, power and irq */
4758 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304759 (host->pwr ? "ON" : "OFF"));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304760 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304761 mmc_hostname(host->mmc),
4762 (atomic_read(&host->clks_on) ? "ON" : "OFF"),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304763 (u32)clk_get_rate(host->clk));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304764 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
4765 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
4766
4767 /* Now dump SDCC registers. Don't print FIFO registers */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304768 if (atomic_read(&host->clks_on))
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304769 msmsdcc_print_regs("SDCC-CORE", host->base,
4770 host->core_memres->start, 28);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304771
4772 if (host->curr.data) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304773 if (!msmsdcc_is_dma_possible(host, host->curr.data))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304774 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304775 else if (is_dma_mode(host))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304776 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
4777 mmc_hostname(host->mmc), host->dma.busy,
4778 host->dma.channel, host->dma.crci);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304779 else if (is_sps_mode(host)) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304780 if (host->sps.busy && atomic_read(&host->clks_on))
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304781 msmsdcc_print_regs("SDCC-DML", host->dml_base,
4782 host->dml_memres->start,
4783 16);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304784 pr_info("%s: SPS mode: busy=%d\n",
4785 mmc_hostname(host->mmc), host->sps.busy);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304786 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304787
4788 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
4789 mmc_hostname(host->mmc), host->curr.xfer_size,
4790 host->curr.data_xfered, host->curr.xfer_remain);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304791 }
4792
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304793 pr_info("%s: got_dataend=%d, prog_enable=%d,"
Subhash Jadavani8706ced2012-05-25 16:09:21 +05304794 " wait_for_auto_prog_done=%d, got_auto_prog_done=%d,"
4795 " req_tout_ms=%d\n", mmc_hostname(host->mmc),
4796 host->curr.got_dataend, host->prog_enable,
4797 host->curr.wait_for_auto_prog_done,
4798 host->curr.got_auto_prog_done, host->curr.req_tout_ms);
subhashj245831e2012-04-30 18:46:17 +05304799 msmsdcc_print_rpm_info(host);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304800}
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304801
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004802static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
4803{
4804 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4805 struct mmc_request *mrq;
4806 unsigned long flags;
4807
4808 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004809 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004810 pr_info("%s: %s: dummy CMD52 timeout\n",
4811 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004812 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004813 }
4814
4815 mrq = host->curr.mrq;
4816
4817 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304818 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
4819 mrq->cmd->opcode);
4820 msmsdcc_dump_sdcc_state(host);
4821
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004822 if (!mrq->cmd->error)
4823 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304824 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004825 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004826 if (mrq->data && !mrq->data->error)
4827 mrq->data->error = -ETIMEDOUT;
4828 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304829 if (host->dma.sg && is_dma_mode(host)) {
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07004830 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304831 } else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004832 /* Stop current SPS transfer */
4833 msmsdcc_sps_exit_curr_xfer(host);
4834 } else {
4835 msmsdcc_reset_and_restore(host);
4836 msmsdcc_stop_data(host);
4837 if (mrq->data && mrq->data->stop)
4838 msmsdcc_start_command(host,
4839 mrq->data->stop, 0);
4840 else
4841 msmsdcc_request_end(host, mrq);
4842 }
4843 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304844 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05304845 host->curr.wait_for_auto_prog_done = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004846 msmsdcc_reset_and_restore(host);
4847 msmsdcc_request_end(host, mrq);
4848 }
4849 }
4850 spin_unlock_irqrestore(&host->lock, flags);
4851}
4852
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05304853/*
4854 * msmsdcc_dt_get_array - Wrapper fn to read an array of 32 bit integers
4855 *
4856 * @dev: device node from which the property value is to be read.
4857 * @prop_name: name of the property to be searched.
4858 * @out_array: filled array returned to caller
4859 * @len: filled array size returned to caller
4860 * @size: expected size of the array
4861 *
4862 * If expected "size" doesn't match with "len" an error is returned. If
4863 * expected size is zero, the length of actual array is returned provided
4864 * return value is zero.
4865 *
4866 * RETURNS:
4867 * zero on success, negative error if failed.
4868 */
4869static int msmsdcc_dt_get_array(struct device *dev, const char *prop_name,
4870 u32 **out_array, int *len, int size)
4871{
4872 int ret = 0;
4873 u32 *array = NULL;
4874 struct device_node *np = dev->of_node;
4875
4876 if (of_get_property(np, prop_name, len)) {
4877 size_t sz;
4878 sz = *len = *len / sizeof(*array);
4879
4880 if (sz > 0 && !(size > 0 && (sz != size))) {
4881 array = devm_kzalloc(dev, sz * sizeof(*array),
4882 GFP_KERNEL);
4883 if (!array) {
4884 dev_err(dev, "%s: no memory\n", prop_name);
4885 ret = -ENOMEM;
4886 goto out;
4887 }
4888
4889 ret = of_property_read_u32_array(np, prop_name,
4890 array, sz);
4891 if (ret < 0) {
4892 dev_err(dev, "%s: error reading array %d\n",
4893 prop_name, ret);
4894 goto out;
4895 }
4896 } else {
4897 dev_err(dev, "%s invalid size\n", prop_name);
4898 ret = -EINVAL;
4899 goto out;
4900 }
4901 } else {
4902 dev_err(dev, "%s not specified\n", prop_name);
4903 ret = -EINVAL;
4904 goto out;
4905 }
4906 *out_array = array;
4907out:
4908 if (ret)
4909 *len = 0;
4910 return ret;
4911}
4912
4913static int msmsdcc_dt_get_pad_pull_info(struct device *dev, int id,
4914 struct msm_mmc_pad_pull_data **pad_pull_data)
4915{
4916 int ret = 0, base = 0, len, i;
4917 u32 *tmp;
4918 struct msm_mmc_pad_pull_data *pull_data;
4919 struct msm_mmc_pad_pull *pull;
4920
4921 switch (id) {
4922 case 1:
4923 base = TLMM_PULL_SDC1_CLK;
4924 break;
4925 case 2:
4926 base = TLMM_PULL_SDC2_CLK;
4927 break;
4928 case 3:
4929 base = TLMM_PULL_SDC3_CLK;
4930 break;
4931 case 4:
4932 base = TLMM_PULL_SDC4_CLK;
4933 break;
4934 default:
4935 dev_err(dev, "%s: Invalid slot id\n", __func__);
4936 ret = -EINVAL;
4937 goto err;
4938 }
4939
4940 pull_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_pull_data),
4941 GFP_KERNEL);
4942 if (!pull_data) {
4943 dev_err(dev, "No memory msm_mmc_pad_pull_data\n");
4944 ret = -ENOMEM;
4945 goto err;
4946 }
4947 pull_data->size = 3; /* array size for clk, cmd, data */
4948
4949 /* Allocate on, off configs for clk, cmd, data */
4950 pull = devm_kzalloc(dev, 2 * pull_data->size *\
4951 sizeof(struct msm_mmc_pad_pull), GFP_KERNEL);
4952 if (!pull) {
4953 dev_err(dev, "No memory for msm_mmc_pad_pull\n");
4954 ret = -ENOMEM;
4955 goto err;
4956 }
4957 pull_data->on = pull;
4958 pull_data->off = pull + pull_data->size;
4959
4960 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-pull-on",
4961 &tmp, &len, pull_data->size);
4962 if (!ret) {
4963 for (i = 0; i < len; i++) {
4964 pull_data->on[i].no = base + i;
4965 pull_data->on[i].val = tmp[i];
4966 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
4967 i, pull_data->on[i].val);
4968 }
4969 } else {
4970 goto err;
4971 }
4972
4973 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-pull-off",
4974 &tmp, &len, pull_data->size);
4975 if (!ret) {
4976 for (i = 0; i < len; i++) {
4977 pull_data->off[i].no = base + i;
4978 pull_data->off[i].val = tmp[i];
4979 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
4980 i, pull_data->off[i].val);
4981 }
4982 } else {
4983 goto err;
4984 }
4985
4986 *pad_pull_data = pull_data;
4987err:
4988 return ret;
4989}
4990
4991static int msmsdcc_dt_get_pad_drv_info(struct device *dev, int id,
4992 struct msm_mmc_pad_drv_data **pad_drv_data)
4993{
4994 int ret = 0, base = 0, len, i;
4995 u32 *tmp;
4996 struct msm_mmc_pad_drv_data *drv_data;
4997 struct msm_mmc_pad_drv *drv;
4998
4999 switch (id) {
5000 case 1:
5001 base = TLMM_HDRV_SDC1_CLK;
5002 break;
5003 case 2:
5004 base = TLMM_HDRV_SDC2_CLK;
5005 break;
5006 case 3:
5007 base = TLMM_HDRV_SDC3_CLK;
5008 break;
5009 case 4:
5010 base = TLMM_HDRV_SDC4_CLK;
5011 break;
5012 default:
5013 dev_err(dev, "%s: Invalid slot id\n", __func__);
5014 ret = -EINVAL;
5015 goto err;
5016 }
5017
5018 drv_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_drv_data),
5019 GFP_KERNEL);
5020 if (!drv_data) {
5021 dev_err(dev, "No memory for msm_mmc_pad_drv_data\n");
5022 ret = -ENOMEM;
5023 goto err;
5024 }
5025 drv_data->size = 3; /* array size for clk, cmd, data */
5026
5027 /* Allocate on, off configs for clk, cmd, data */
5028 drv = devm_kzalloc(dev, 2 * drv_data->size *\
5029 sizeof(struct msm_mmc_pad_drv), GFP_KERNEL);
5030 if (!drv) {
5031 dev_err(dev, "No memory msm_mmc_pad_drv\n");
5032 ret = -ENOMEM;
5033 goto err;
5034 }
5035 drv_data->on = drv;
5036 drv_data->off = drv + drv_data->size;
5037
5038 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-drv-on",
5039 &tmp, &len, drv_data->size);
5040 if (!ret) {
5041 for (i = 0; i < len; i++) {
5042 drv_data->on[i].no = base + i;
5043 drv_data->on[i].val = tmp[i];
5044 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5045 i, drv_data->on[i].val);
5046 }
5047 } else {
5048 goto err;
5049 }
5050
5051 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-drv-off",
5052 &tmp, &len, drv_data->size);
5053 if (!ret) {
5054 for (i = 0; i < len; i++) {
5055 drv_data->off[i].no = base + i;
5056 drv_data->off[i].val = tmp[i];
5057 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5058 i, drv_data->off[i].val);
5059 }
5060 } else {
5061 goto err;
5062 }
5063
5064 *pad_drv_data = drv_data;
5065err:
5066 return ret;
5067}
5068
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305069static void msmsdcc_dt_get_cd_wp_gpio(struct device *dev,
5070 struct mmc_platform_data *pdata)
5071{
5072 enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
5073 struct device_node *np = dev->of_node;
5074
5075 pdata->status_gpio = of_get_named_gpio_flags(np,
5076 "cd-gpios", 0, &flags);
5077 if (gpio_is_valid(pdata->status_gpio)) {
5078 pdata->status_irq = gpio_to_irq(pdata->status_gpio);
5079 pdata->is_status_gpio_active_low = flags & OF_GPIO_ACTIVE_LOW;
5080 }
5081
5082 pdata->wpswitch_gpio = of_get_named_gpio_flags(np,
5083 "wp-gpios", 0, &flags);
5084 if (gpio_is_valid(pdata->wpswitch_gpio))
5085 pdata->is_wpswitch_active_low = flags & OF_GPIO_ACTIVE_LOW;
5086}
5087
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305088static int msmsdcc_dt_parse_gpio_info(struct device *dev,
5089 struct mmc_platform_data *pdata)
5090{
5091 int ret = 0, id = 0, cnt, i;
5092 struct msm_mmc_pin_data *pin_data;
5093 struct device_node *np = dev->of_node;
5094
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305095 msmsdcc_dt_get_cd_wp_gpio(dev, pdata);
5096
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305097 pin_data = devm_kzalloc(dev, sizeof(*pin_data), GFP_KERNEL);
5098 if (!pin_data) {
5099 dev_err(dev, "No memory for pin_data\n");
5100 ret = -ENOMEM;
5101 goto err;
5102 }
5103
5104 cnt = of_gpio_count(np);
5105 if (cnt > 0) {
5106 pin_data->is_gpio = true;
5107
5108 pin_data->gpio_data = devm_kzalloc(dev,
5109 sizeof(struct msm_mmc_gpio_data), GFP_KERNEL);
5110 if (!pin_data->gpio_data) {
5111 dev_err(dev, "No memory for gpio_data\n");
5112 ret = -ENOMEM;
5113 goto err;
5114 }
5115 pin_data->gpio_data->size = cnt;
5116 pin_data->gpio_data->gpio = devm_kzalloc(dev,
5117 cnt * sizeof(struct msm_mmc_gpio), GFP_KERNEL);
5118 if (!pin_data->gpio_data->gpio) {
5119 dev_err(dev, "No memory for gpio\n");
5120 ret = -ENOMEM;
5121 goto err;
5122 }
5123
5124 for (i = 0; i < cnt; i++) {
5125 const char *name = NULL;
5126 char result[32];
5127 pin_data->gpio_data->gpio[i].no = of_get_gpio(np, i);
5128 of_property_read_string_index(np,
5129 "qcom,sdcc-gpio-names", i, &name);
5130
5131 snprintf(result, 32, "%s-%s",
5132 dev_name(dev), name ? name : "?");
5133 pin_data->gpio_data->gpio[i].name = result;
5134 dev_dbg(dev, "%s: gpio[%s] = %d\n", __func__,
5135 pin_data->gpio_data->gpio[i].name,
5136 pin_data->gpio_data->gpio[i].no);
5137 }
5138 } else {
5139 pin_data->pad_data = devm_kzalloc(dev,
5140 sizeof(struct msm_mmc_pad_data), GFP_KERNEL);
5141 if (!pin_data->pad_data) {
5142 dev_err(dev, "No memory for pin_data->pad_data\n");
5143 ret = -ENOMEM;
5144 goto err;
5145 }
5146
5147 of_property_read_u32(np, "cell-index", &id);
5148
5149 ret = msmsdcc_dt_get_pad_pull_info(dev, id,
5150 &pin_data->pad_data->pull);
5151 if (ret)
5152 goto err;
5153 ret = msmsdcc_dt_get_pad_drv_info(dev, id,
5154 &pin_data->pad_data->drv);
5155 if (ret)
5156 goto err;
5157 }
5158
5159 pdata->pin_data = pin_data;
5160err:
5161 if (ret)
5162 dev_err(dev, "%s failed with err %d\n", __func__, ret);
5163 return ret;
5164}
5165
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305166#define MAX_PROP_SIZE 32
5167static int msmsdcc_dt_parse_vreg_info(struct device *dev,
5168 struct msm_mmc_reg_data **vreg_data, const char *vreg_name)
5169{
5170 int len, ret = 0;
5171 const __be32 *prop;
5172 char prop_name[MAX_PROP_SIZE];
5173 struct msm_mmc_reg_data *vreg;
5174 struct device_node *np = dev->of_node;
5175
5176 snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", vreg_name);
5177 if (of_parse_phandle(np, prop_name, 0)) {
5178 vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
5179 if (!vreg) {
5180 dev_err(dev, "No memory for vreg: %s\n", vreg_name);
5181 ret = -ENOMEM;
5182 goto err;
5183 }
5184
5185 vreg->name = vreg_name;
5186
5187 snprintf(prop_name, MAX_PROP_SIZE,
5188 "qcom,sdcc-%s-always_on", vreg_name);
5189 if (of_get_property(np, prop_name, NULL))
5190 vreg->always_on = true;
5191
5192 snprintf(prop_name, MAX_PROP_SIZE,
5193 "qcom,sdcc-%s-lpm_sup", vreg_name);
5194 if (of_get_property(np, prop_name, NULL))
5195 vreg->lpm_sup = true;
5196
5197 snprintf(prop_name, MAX_PROP_SIZE,
5198 "qcom,sdcc-%s-voltage_level", vreg_name);
5199 prop = of_get_property(np, prop_name, &len);
5200 if (!prop || (len != (2 * sizeof(__be32)))) {
5201 dev_warn(dev, "%s %s property\n",
5202 prop ? "invalid format" : "no", prop_name);
5203 } else {
5204 vreg->low_vol_level = be32_to_cpup(&prop[0]);
5205 vreg->high_vol_level = be32_to_cpup(&prop[1]);
5206 }
5207
5208 snprintf(prop_name, MAX_PROP_SIZE,
5209 "qcom,sdcc-%s-current_level", vreg_name);
5210 prop = of_get_property(np, prop_name, &len);
5211 if (!prop || (len != (2 * sizeof(__be32)))) {
5212 dev_warn(dev, "%s %s property\n",
5213 prop ? "invalid format" : "no", prop_name);
5214 } else {
5215 vreg->lpm_uA = be32_to_cpup(&prop[0]);
5216 vreg->hpm_uA = be32_to_cpup(&prop[1]);
5217 }
5218
5219 *vreg_data = vreg;
5220 dev_dbg(dev, "%s: %s %s vol=[%d %d]uV, curr=[%d %d]uA\n",
5221 vreg->name, vreg->always_on ? "always_on," : "",
5222 vreg->lpm_sup ? "lpm_sup," : "", vreg->low_vol_level,
5223 vreg->high_vol_level, vreg->lpm_uA, vreg->hpm_uA);
5224 }
5225
5226err:
5227 return ret;
5228}
5229
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305230static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
5231{
5232 int i, ret;
5233 struct mmc_platform_data *pdata;
5234 struct device_node *np = dev->of_node;
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305235 u32 bus_width = 0, current_limit = 0;
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305236 u32 *clk_table, *sup_voltages;
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305237 int clk_table_len, sup_volt_len, len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305238
5239 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
5240 if (!pdata) {
5241 dev_err(dev, "could not allocate memory for platform data\n");
5242 goto err;
5243 }
5244
5245 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
5246 if (bus_width == 8) {
5247 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
5248 } else if (bus_width == 4) {
5249 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
5250 } else {
5251 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
5252 pdata->mmc_bus_width = 0;
5253 }
5254
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305255 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-sup-voltages",
5256 &sup_voltages, &sup_volt_len, 0);
5257 if (!ret) {
5258 for (i = 0; i < sup_volt_len; i += 2) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305259 u32 mask;
5260
5261 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
5262 sup_voltages[i + 1]);
5263 if (!mask)
5264 dev_err(dev, "Invalide voltage range %d\n", i);
5265 pdata->ocr_mask |= mask;
5266 }
5267 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305268 }
5269
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305270 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-clk-rates",
5271 &clk_table, &clk_table_len, 0);
5272 if (!ret) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305273 pdata->sup_clk_table = clk_table;
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305274 pdata->sup_clk_cnt = clk_table_len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305275 }
5276
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305277 pdata->vreg_data = devm_kzalloc(dev,
5278 sizeof(struct msm_mmc_slot_reg_data), GFP_KERNEL);
5279 if (!pdata->vreg_data) {
5280 dev_err(dev, "could not allocate memory for vreg_data\n");
5281 goto err;
5282 }
5283
5284 if (msmsdcc_dt_parse_vreg_info(dev,
5285 &pdata->vreg_data->vdd_data, "vdd"))
5286 goto err;
5287
5288 if (msmsdcc_dt_parse_vreg_info(dev,
5289 &pdata->vreg_data->vdd_io_data, "vdd-io"))
5290 goto err;
5291
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305292 if (msmsdcc_dt_parse_gpio_info(dev, pdata))
5293 goto err;
5294
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305295 len = of_property_count_strings(np, "qcom,sdcc-bus-speed-mode");
5296
5297 for (i = 0; i < len; i++) {
5298 const char *name = NULL;
5299
5300 of_property_read_string_index(np,
5301 "qcom,sdcc-bus-speed-mode", i, &name);
5302 if (!name)
5303 continue;
5304
5305 if (!strncmp(name, "SDR12", sizeof("SDR12")))
5306 pdata->uhs_caps |= MMC_CAP_UHS_SDR12;
5307 else if (!strncmp(name, "SDR25", sizeof("SDR25")))
5308 pdata->uhs_caps |= MMC_CAP_UHS_SDR25;
5309 else if (!strncmp(name, "SDR50", sizeof("SDR50")))
5310 pdata->uhs_caps |= MMC_CAP_UHS_SDR50;
5311 else if (!strncmp(name, "DDR50", sizeof("DDR50")))
5312 pdata->uhs_caps |= MMC_CAP_UHS_DDR50;
5313 else if (!strncmp(name, "SDR104", sizeof("SDR104")))
5314 pdata->uhs_caps |= MMC_CAP_UHS_SDR104;
5315 else if (!strncmp(name, "HS200_1p8v", sizeof("HS200_1p8v")))
5316 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_8V_SDR;
5317 else if (!strncmp(name, "HS200_1p2v", sizeof("HS200_1p2v")))
5318 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_2V_SDR;
5319 else if (!strncmp(name, "DDR_1p8v", sizeof("DDR_1p8v")))
5320 pdata->uhs_caps |= MMC_CAP_1_8V_DDR
5321 | MMC_CAP_UHS_DDR50;
5322 else if (!strncmp(name, "DDR_1p2v", sizeof("DDR_1p2v")))
5323 pdata->uhs_caps |= MMC_CAP_1_2V_DDR
5324 | MMC_CAP_UHS_DDR50;
5325 }
5326
5327 of_property_read_u32(np, "qcom,sdcc-current-limit", &current_limit);
5328 if (current_limit == 800)
5329 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_800;
5330 else if (current_limit == 600)
5331 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_600;
5332 else if (current_limit == 400)
5333 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_400;
5334 else if (current_limit == 200)
5335 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_200;
5336
5337 if (of_get_property(np, "qcom,sdcc-xpc", NULL))
5338 pdata->xpc_cap = true;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305339 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
5340 pdata->nonremovable = true;
5341 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
5342 pdata->disable_cmd23 = true;
5343
5344 return pdata;
5345err:
5346 return NULL;
5347}
5348
San Mehat9d2bd732009-09-22 16:44:22 -07005349static int
5350msmsdcc_probe(struct platform_device *pdev)
5351{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305352 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07005353 struct msmsdcc_host *host;
5354 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005355 unsigned long flags;
5356 struct resource *core_irqres = NULL;
5357 struct resource *bam_irqres = NULL;
5358 struct resource *core_memres = NULL;
5359 struct resource *dml_memres = NULL;
5360 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07005361 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07005362 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05305363 int ret = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07005364
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305365 if (pdev->dev.of_node) {
5366 plat = msmsdcc_populate_pdata(&pdev->dev);
5367 of_property_read_u32((&pdev->dev)->of_node,
5368 "cell-index", &pdev->id);
5369 } else {
5370 plat = pdev->dev.platform_data;
5371 }
San Mehat9d2bd732009-09-22 16:44:22 -07005372
5373 /* must have platform data */
5374 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005375 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005376 ret = -EINVAL;
5377 goto out;
5378 }
5379
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005380 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07005381 return -EINVAL;
5382
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305383 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
5384 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
5385 return -EINVAL;
5386 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005387
San Mehat9d2bd732009-09-22 16:44:22 -07005388 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005389 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005390 return -ENXIO;
5391 }
5392
Sujit Reddy Thumma1dfac2c2012-07-30 10:15:39 +05305393 core_memres = platform_get_resource_byname(pdev,
5394 IORESOURCE_MEM, "core_mem");
5395 bam_memres = platform_get_resource_byname(pdev,
5396 IORESOURCE_MEM, "bam_mem");
5397 dml_memres = platform_get_resource_byname(pdev,
5398 IORESOURCE_MEM, "dml_mem");
5399 core_irqres = platform_get_resource_byname(pdev,
5400 IORESOURCE_IRQ, "core_irq");
5401 bam_irqres = platform_get_resource_byname(pdev,
5402 IORESOURCE_IRQ, "bam_irq");
5403 dmares = platform_get_resource_byname(pdev,
5404 IORESOURCE_DMA, "dma_chnl");
5405 dma_crci_res = platform_get_resource_byname(pdev,
5406 IORESOURCE_DMA, "dma_crci");
San Mehat9d2bd732009-09-22 16:44:22 -07005407
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005408 if (!core_irqres || !core_memres) {
5409 pr_err("%s: Invalid sdcc core resource\n", __func__);
5410 return -ENXIO;
5411 }
5412
5413 /*
5414 * Both BAM and DML memory resource should be preset.
5415 * BAM IRQ resource should also be present.
5416 */
5417 if ((bam_memres && !dml_memres) ||
5418 (!bam_memres && dml_memres) ||
5419 ((bam_memres && dml_memres) && !bam_irqres)) {
5420 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005421 return -ENXIO;
5422 }
5423
5424 /*
5425 * Setup our host structure
5426 */
San Mehat9d2bd732009-09-22 16:44:22 -07005427 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
5428 if (!mmc) {
5429 ret = -ENOMEM;
5430 goto out;
5431 }
5432
5433 host = mmc_priv(mmc);
5434 host->pdev_id = pdev->id;
5435 host->plat = plat;
5436 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08005437 host->curr.cmd = NULL;
Sahitya Tummala19207f02011-05-02 18:10:01 +05305438
Sahitya Tummalad9df3272011-08-19 16:50:46 +05305439 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305440 set_hw_caps(host, MSMSDCC_SPS_BAM_SUP);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005441 else if (dmares)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305442 set_hw_caps(host, MSMSDCC_DMA_SUP);
San Mehat9d2bd732009-09-22 16:44:22 -07005443
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005444 host->base = ioremap(core_memres->start,
5445 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07005446 if (!host->base) {
5447 ret = -ENOMEM;
Sahitya Tummaladce7c752011-05-02 18:06:05 +05305448 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005449 }
5450
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005451 host->core_irqres = core_irqres;
5452 host->bam_irqres = bam_irqres;
5453 host->core_memres = core_memres;
5454 host->dml_memres = dml_memres;
5455 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07005456 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07005457 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07005458 spin_lock_init(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305459 mutex_init(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07005460
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005461#ifdef CONFIG_MMC_EMBEDDED_SDIO
5462 if (plat->embedded_sdio)
5463 mmc_set_embedded_sdio_data(mmc,
5464 &plat->embedded_sdio->cis,
5465 &plat->embedded_sdio->cccr,
5466 plat->embedded_sdio->funcs,
5467 plat->embedded_sdio->num_funcs);
5468#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005469
Sahitya Tummala62612cf2010-12-08 15:03:03 +05305470 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
5471 (unsigned long)host);
5472
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005473 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
5474 (unsigned long)host);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305475 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005476 /* Setup DMA */
Subhash Jadavani190657c2011-05-02 18:10:40 +05305477 ret = msmsdcc_init_dma(host);
5478 if (ret)
5479 goto ioremap_free;
5480 } else {
5481 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07005482 host->dma.crci = -1;
Subhash Jadavani190657c2011-05-02 18:10:40 +05305483 }
San Mehat9d2bd732009-09-22 16:44:22 -07005484
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005485 /*
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305486 * Setup SDCC bus voter clock.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005487 */
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305488 host->bus_clk = clk_get(&pdev->dev, "bus_clk");
5489 if (!IS_ERR_OR_NULL(host->bus_clk)) {
5490 /* Vote for max. clk rate for max. performance */
5491 ret = clk_set_rate(host->bus_clk, INT_MAX);
5492 if (ret)
5493 goto bus_clk_put;
5494 ret = clk_prepare_enable(host->bus_clk);
5495 if (ret)
5496 goto bus_clk_put;
San Mehat9d2bd732009-09-22 16:44:22 -07005497 }
5498
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005499 /*
5500 * Setup main peripheral bus clock
5501 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07005502 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005503 if (!IS_ERR(host->pclk)) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305504 ret = clk_prepare_enable(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005505 if (ret)
5506 goto pclk_put;
5507
5508 host->pclk_rate = clk_get_rate(host->pclk);
5509 }
5510
5511 /*
5512 * Setup SDC MMC clock
5513 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07005514 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07005515 if (IS_ERR(host->clk)) {
5516 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005517 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07005518 }
5519
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005520 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
Sahitya Tummala514d9ed2011-05-02 18:07:01 +05305521 if (ret) {
5522 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
5523 goto clk_put;
5524 }
5525
Asutosh Dasf5298c32012-04-03 14:51:47 +05305526 ret = clk_prepare_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07005527 if (ret)
5528 goto clk_put;
5529
San Mehat9d2bd732009-09-22 16:44:22 -07005530 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05305531 if (!host->clk_rate)
5532 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05305533
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305534 set_default_hw_caps(host);
5535
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05305536 /*
5537 * Set the register write delay according to min. clock frequency
5538 * supported and update later when the host->clk_rate changes.
5539 */
5540 host->reg_write_delay =
5541 (1 + ((3 * USEC_PER_SEC) /
5542 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005543
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305544 atomic_set(&host->clks_on, 1);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05305545 /* Apply Hard reset to SDCC to put it in power on default state */
5546 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005547
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005548#define MSM_MMC_DEFAULT_CPUDMA_LATENCY 200 /* usecs */
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305549 /* pm qos request to prevent apps idle power collapse */
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005550 if (host->plat->cpu_dma_latency)
5551 host->cpu_dma_latency = host->plat->cpu_dma_latency;
5552 else
5553 host->cpu_dma_latency = MSM_MMC_DEFAULT_CPUDMA_LATENCY;
5554 pm_qos_add_request(&host->pm_qos_req_dma,
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305555 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
5556
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305557 ret = msmsdcc_msm_bus_register(host);
5558 if (ret)
5559 goto pm_qos_remove;
5560
5561 if (host->msm_bus_vote.client_handle)
5562 INIT_DELAYED_WORK(&host->msm_bus_vote.vote_work,
5563 msmsdcc_msm_bus_work);
5564
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005565 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07005566 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005567 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07005568 goto clk_disable;
5569 }
5570
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005571
5572 /* Clocks has to be running before accessing SPS/DML HW blocks */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305573 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005574 /* Initialize SPS */
5575 ret = msmsdcc_sps_init(host);
5576 if (ret)
5577 goto vreg_deinit;
5578 /* Initialize DML */
5579 ret = msmsdcc_dml_init(host);
5580 if (ret)
5581 goto sps_exit;
5582 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05305583 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07005584
San Mehat9d2bd732009-09-22 16:44:22 -07005585 /*
5586 * Setup MMC host structure
5587 */
5588 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005589 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
5590 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005591 mmc->ocr_avail = plat->ocr_mask;
Sujit Reddy Thumma0e05f022012-06-11 19:44:18 +05305592 mmc->clkgate_delay = MSM_MMC_CLK_GATE_DELAY;
5593
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005594 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
5595 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07005596 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05305597 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
San Mehat9d2bd732009-09-22 16:44:22 -07005598
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05305599 /*
5600 * If we send the CMD23 before multi block write/read command
5601 * then we need not to send CMD12 at the end of the transfer.
5602 * If we don't send the CMD12 then only way to detect the PROG_DONE
5603 * status is to use the AUTO_PROG_DONE status provided by SDCC4
5604 * controller. So let's enable the CMD23 for SDCC4 only.
5605 */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305606 if (!plat->disable_cmd23 && is_auto_prog_done(host))
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05305607 mmc->caps |= MMC_CAP_CMD23;
San Mehat9d2bd732009-09-22 16:44:22 -07005608
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005609 mmc->caps |= plat->uhs_caps;
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305610 mmc->caps2 |= plat->uhs_caps2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005611 /*
5612 * XPC controls the maximum current in the default speed mode of SDXC
5613 * card. XPC=0 means 100mA (max.) but speed class is not supported.
5614 * XPC=1 means 150mA (max.) and speed class is supported.
5615 */
5616 if (plat->xpc_cap)
5617 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
5618 MMC_CAP_SET_XPC_180);
5619
Maya Erez25e22612012-05-20 08:45:01 +03005620 mmc->caps2 |= MMC_CAP2_PACKED_WR;
Maya Erez8afe8d22012-05-20 15:11:52 +03005621 mmc->caps2 |= MMC_CAP2_PACKED_WR_CONTROL;
Subhash Jadavani6bb34a82012-04-18 13:18:40 +05305622 mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
Yaniv Gardi14098552012-06-04 10:56:03 +03005623 mmc->caps2 |= MMC_CAP2_SANITIZE;
5624
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005625 if (plat->nonremovable)
5626 mmc->caps |= MMC_CAP_NONREMOVABLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005627 mmc->caps |= MMC_CAP_SDIO_IRQ;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005628
Konstantin Dorfman9db69fc2012-06-01 14:04:45 +03005629 mmc->caps2 |= MMC_CAP2_INIT_BKOPS | MMC_CAP2_BKOPS;
5630
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005631 if (plat->is_sdio_al_client)
5632 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07005633
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305634 mmc->max_segs = msmsdcc_get_nr_sg(host);
5635 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
5636 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07005637
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305638 mmc->max_req_size = MMC_MAX_REQ_SIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07005639 mmc->max_seg_size = mmc->max_req_size;
5640
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005641 writel_relaxed(0, host->base + MMCIMASK0);
5642 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05305643 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005644
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005645 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
5646 mb();
5647 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07005648
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005649 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
5650 DRIVER_NAME " (cmd)", host);
5651 if (ret)
5652 goto dml_exit;
5653
5654 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
5655 DRIVER_NAME " (pio)", host);
5656 if (ret)
5657 goto irq_free;
5658
5659 /*
5660 * Enable SDCC IRQ only when host is powered on. Otherwise, this
5661 * IRQ is un-necessarily being monitored by MPM (Modem power
5662 * management block) during idle-power collapse. The MPM will be
5663 * configured to monitor the DATA1 GPIO line with level-low trigger
5664 * and thus depending on the GPIO status, it prevents TCXO shutdown
5665 * during idle-power collapse.
5666 */
5667 disable_irq(core_irqres->start);
5668 host->sdcc_irq_disabled = 1;
5669
5670 if (plat->sdiowakeup_irq) {
5671 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5672 mmc_hostname(mmc));
5673 ret = request_irq(plat->sdiowakeup_irq,
5674 msmsdcc_platform_sdiowakeup_irq,
5675 IRQF_SHARED | IRQF_TRIGGER_LOW,
5676 DRIVER_NAME "sdiowakeup", host);
5677 if (ret) {
5678 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
5679 plat->sdiowakeup_irq, ret);
5680 goto pio_irq_free;
5681 } else {
5682 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305683 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005684 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305685 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005686 }
5687 spin_unlock_irqrestore(&host->lock, flags);
5688 }
5689 }
5690
Subhash Jadavanic9b85752012-04-13 11:16:49 +05305691 if (host->plat->mpm_sdiowakeup_int) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005692 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5693 mmc_hostname(mmc));
5694 }
5695
5696 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
5697 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005698 /*
5699 * Setup card detect change
5700 */
5701
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305702 if (!plat->status_gpio)
5703 plat->status_gpio = -ENOENT;
5704 if (!plat->wpswitch_gpio)
5705 plat->wpswitch_gpio = -ENOENT;
5706
5707 if (plat->status || gpio_is_valid(plat->status_gpio)) {
Krishna Konda941604a2012-01-10 17:46:34 -08005708 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005709 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08005710 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005711 host->oldstat = msmsdcc_slot_status(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005712
Krishna Konda941604a2012-01-10 17:46:34 -08005713 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005714 }
San Mehat9d2bd732009-09-22 16:44:22 -07005715
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005716 if (plat->status_irq) {
5717 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07005718 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005719 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07005720 DRIVER_NAME " (slot)",
5721 host);
5722 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005723 pr_err("Unable to get slot IRQ %d (%d)\n",
5724 plat->status_irq, ret);
5725 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005726 }
5727 } else if (plat->register_status_notify) {
5728 plat->register_status_notify(msmsdcc_status_notify_cb, host);
5729 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005730 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07005731 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005732
5733 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005734
5735 ret = pm_runtime_set_active(&(pdev)->dev);
5736 if (ret < 0)
5737 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
5738 __func__, ret);
5739 /*
5740 * There is no notion of suspend/resume for SD/MMC/SDIO
5741 * cards. So host can be suspended/resumed with out
5742 * worrying about its children.
5743 */
5744 pm_suspend_ignore_children(&(pdev)->dev, true);
5745
5746 /*
5747 * MMC/SD/SDIO bus suspend/resume operations are defined
5748 * only for the slots that will be used for non-removable
5749 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
5750 * defined. Otherwise, they simply become card removal and
5751 * insertion events during suspend and resume respectively.
5752 * Hence, enable run-time PM only for slots for which bus
5753 * suspend/resume operations are defined.
5754 */
5755#ifdef CONFIG_MMC_UNSAFE_RESUME
5756 /*
5757 * If this capability is set, MMC core will enable/disable host
5758 * for every claim/release operation on a host. We use this
5759 * notification to increment/decrement runtime pm usage count.
5760 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005761 pm_runtime_enable(&(pdev)->dev);
5762#else
5763 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005764 pm_runtime_enable(&(pdev)->dev);
5765 }
5766#endif
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305767 host->idle_tout_ms = MSM_MMC_DEFAULT_IDLE_TIMEOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005768 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
5769 (unsigned long)host);
5770
San Mehat9d2bd732009-09-22 16:44:22 -07005771 mmc_add_host(mmc);
5772
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005773#ifdef CONFIG_HAS_EARLYSUSPEND
5774 host->early_suspend.suspend = msmsdcc_early_suspend;
5775 host->early_suspend.resume = msmsdcc_late_resume;
5776 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
5777 register_early_suspend(&host->early_suspend);
5778#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005779
Krishna Konda25786ec2011-07-25 16:21:36 -07005780 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
5781 " dmacrcri %d\n", mmc_hostname(mmc),
5782 (unsigned long long)core_memres->start,
5783 (unsigned int) core_irqres->start,
5784 (unsigned int) plat->status_irq, host->dma.channel,
5785 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005786
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305787 pr_info("%s: Controller capabilities: 0x%.8x\n",
5788 mmc_hostname(mmc), host->hw_caps);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005789 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
5790 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
5791 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
5792 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
5793 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
5794 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
5795 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
5796 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
5797 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
5798 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
5799 host->eject);
5800 pr_info("%s: Power save feature enable = %d\n",
5801 mmc_hostname(mmc), msmsdcc_pwrsave);
5802
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305803 if (is_dma_mode(host) && host->dma.channel != -1
Krishna Konda25786ec2011-07-25 16:21:36 -07005804 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005805 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005806 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005807 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005808 mmc_hostname(mmc), host->dma.cmd_busaddr,
5809 host->dma.cmdptr_busaddr);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305810 } else if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005811 pr_info("%s: SPS-BAM data transfer mode available\n",
5812 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005813 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005814 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005815
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005816#if defined(CONFIG_DEBUG_FS)
5817 msmsdcc_dbg_createhost(host);
5818#endif
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305819
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305820 host->max_bus_bw.show = show_sdcc_to_mem_max_bus_bw;
5821 host->max_bus_bw.store = store_sdcc_to_mem_max_bus_bw;
5822 sysfs_attr_init(&host->max_bus_bw.attr);
5823 host->max_bus_bw.attr.name = "max_bus_bw";
5824 host->max_bus_bw.attr.mode = S_IRUGO | S_IWUSR;
5825 ret = device_create_file(&pdev->dev, &host->max_bus_bw);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305826 if (ret)
5827 goto platform_irq_free;
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305828
5829 if (!plat->status_irq) {
5830 host->polling.show = show_polling;
5831 host->polling.store = store_polling;
5832 sysfs_attr_init(&host->polling.attr);
5833 host->polling.attr.name = "polling";
5834 host->polling.attr.mode = S_IRUGO | S_IWUSR;
5835 ret = device_create_file(&pdev->dev, &host->polling);
5836 if (ret)
5837 goto remove_max_bus_bw_file;
5838 }
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305839 host->idle_timeout.show = show_idle_timeout;
5840 host->idle_timeout.store = store_idle_timeout;
5841 sysfs_attr_init(&host->idle_timeout.attr);
5842 host->idle_timeout.attr.name = "idle_timeout";
5843 host->idle_timeout.attr.mode = S_IRUGO | S_IWUSR;
5844 ret = device_create_file(&pdev->dev, &host->idle_timeout);
5845 if (ret)
5846 goto remove_polling_file;
San Mehat9d2bd732009-09-22 16:44:22 -07005847 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005848
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305849 remove_polling_file:
5850 if (!plat->status_irq)
5851 device_remove_file(&pdev->dev, &host->polling);
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305852 remove_max_bus_bw_file:
5853 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005854 platform_irq_free:
5855 del_timer_sync(&host->req_tout_timer);
5856 pm_runtime_disable(&(pdev)->dev);
5857 pm_runtime_set_suspended(&(pdev)->dev);
5858
5859 if (plat->status_irq)
5860 free_irq(plat->status_irq, host);
5861 sdiowakeup_irq_free:
5862 wake_lock_destroy(&host->sdio_suspend_wlock);
5863 if (plat->sdiowakeup_irq)
5864 free_irq(plat->sdiowakeup_irq, host);
5865 pio_irq_free:
5866 if (plat->sdiowakeup_irq)
5867 wake_lock_destroy(&host->sdio_wlock);
5868 free_irq(core_irqres->start, host);
5869 irq_free:
5870 free_irq(core_irqres->start, host);
5871 dml_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305872 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005873 msmsdcc_dml_exit(host);
5874 sps_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305875 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005876 msmsdcc_sps_exit(host);
5877 vreg_deinit:
5878 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07005879 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005880 clk_disable(host->clk);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305881 msmsdcc_msm_bus_unregister(host);
5882 pm_qos_remove:
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005883 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305884 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07005885 clk_put:
5886 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005887 pclk_disable:
5888 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05305889 clk_disable_unprepare(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07005890 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005891 if (!IS_ERR(host->pclk))
5892 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305893 if (!IS_ERR_OR_NULL(host->bus_clk))
5894 clk_disable_unprepare(host->bus_clk);
5895 bus_clk_put:
5896 if (!IS_ERR_OR_NULL(host->bus_clk))
5897 clk_put(host->bus_clk);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305898 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005899 if (host->dmares)
5900 dma_free_coherent(NULL,
5901 sizeof(struct msmsdcc_nc_dmadata),
5902 host->dma.nc, host->dma.nc_busaddr);
5903 }
5904 ioremap_free:
Sahitya Tummaladce7c752011-05-02 18:06:05 +05305905 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07005906 host_free:
5907 mmc_free_host(mmc);
5908 out:
5909 return ret;
5910}
5911
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005912static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07005913{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005914 struct mmc_host *mmc = mmc_get_drvdata(pdev);
5915 struct mmc_platform_data *plat;
5916 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07005917
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005918 if (!mmc)
5919 return -ENXIO;
5920
5921 if (pm_runtime_suspended(&(pdev)->dev))
5922 pm_runtime_resume(&(pdev)->dev);
5923
5924 host = mmc_priv(mmc);
5925
5926 DBG(host, "Removing SDCC device = %d\n", pdev->id);
5927 plat = host->plat;
5928
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305929 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005930 if (!plat->status_irq)
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305931 device_remove_file(&pdev->dev, &host->polling);
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305932 device_remove_file(&pdev->dev, &host->idle_timeout);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005933
5934 del_timer_sync(&host->req_tout_timer);
5935 tasklet_kill(&host->dma_tlet);
5936 tasklet_kill(&host->sps.tlet);
5937 mmc_remove_host(mmc);
5938
5939 if (plat->status_irq)
5940 free_irq(plat->status_irq, host);
5941
5942 wake_lock_destroy(&host->sdio_suspend_wlock);
5943 if (plat->sdiowakeup_irq) {
5944 wake_lock_destroy(&host->sdio_wlock);
5945 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
5946 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07005947 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005948
5949 free_irq(host->core_irqres->start, host);
5950 free_irq(host->core_irqres->start, host);
5951
5952 clk_put(host->clk);
5953 if (!IS_ERR(host->pclk))
5954 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305955 if (!IS_ERR_OR_NULL(host->bus_clk))
5956 clk_put(host->bus_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005957
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005958 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305959 pm_qos_remove_request(&host->pm_qos_req_dma);
5960
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305961 if (host->msm_bus_vote.client_handle) {
5962 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
5963 msmsdcc_msm_bus_unregister(host);
5964 }
5965
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005966 msmsdcc_vreg_init(host, false);
5967
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305968 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005969 if (host->dmares)
5970 dma_free_coherent(NULL,
5971 sizeof(struct msmsdcc_nc_dmadata),
5972 host->dma.nc, host->dma.nc_busaddr);
5973 }
5974
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305975 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005976 msmsdcc_dml_exit(host);
5977 msmsdcc_sps_exit(host);
5978 }
5979
5980 iounmap(host->base);
5981 mmc_free_host(mmc);
5982
5983#ifdef CONFIG_HAS_EARLYSUSPEND
5984 unregister_early_suspend(&host->early_suspend);
5985#endif
5986 pm_runtime_disable(&(pdev)->dev);
5987 pm_runtime_set_suspended(&(pdev)->dev);
5988
5989 return 0;
5990}
5991
5992#ifdef CONFIG_MSM_SDIO_AL
5993int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
5994{
5995 struct msmsdcc_host *host = mmc_priv(mmc);
5996 unsigned long flags;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305997 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005998
Asutosh Dasf5298c32012-04-03 14:51:47 +05305999 mutex_lock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006000 spin_lock_irqsave(&host->lock, flags);
6001 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
6002 enable ? "En" : "Dis");
6003
6004 if (enable) {
6005 if (!host->sdcc_irq_disabled) {
6006 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05306007 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006008 host->sdcc_irq_disabled = 1;
6009 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306010 rc = msmsdcc_setup_clocks(host, false);
6011 if (rc)
6012 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006013
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05306014 if (host->plat->sdio_lpm_gpio_setup &&
6015 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006016 spin_unlock_irqrestore(&host->lock, flags);
6017 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
6018 spin_lock_irqsave(&host->lock, flags);
6019 host->sdio_gpio_lpm = 1;
6020 }
6021
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306022 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006023 msmsdcc_enable_irq_wake(host);
6024 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306025 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006026 }
6027 } else {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306028 rc = msmsdcc_setup_clocks(host, true);
6029 if (rc)
6030 goto out;
6031
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306032 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006033 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306034 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006035 msmsdcc_disable_irq_wake(host);
6036 }
6037
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05306038 if (host->plat->sdio_lpm_gpio_setup &&
6039 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006040 spin_unlock_irqrestore(&host->lock, flags);
6041 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
6042 spin_lock_irqsave(&host->lock, flags);
6043 host->sdio_gpio_lpm = 0;
6044 }
6045
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306046 if (host->sdcc_irq_disabled && atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006047 writel_relaxed(host->mci_irqenable,
6048 host->base + MMCIMASK0);
6049 mb();
6050 enable_irq(host->core_irqres->start);
6051 host->sdcc_irq_disabled = 0;
6052 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006053 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306054out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006055 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05306056 mutex_unlock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306057 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006058}
6059#else
6060int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
6061{
6062 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07006063}
6064#endif
6065
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006066#ifdef CONFIG_PM
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306067#ifdef CONFIG_MMC_CLKGATE
6068static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6069{
6070 struct mmc_host *mmc = host->mmc;
6071 unsigned long flags;
6072
6073 mmc_host_clk_hold(mmc);
6074 spin_lock_irqsave(&mmc->clk_lock, flags);
6075 mmc->clk_old = mmc->ios.clock;
6076 mmc->ios.clock = 0;
6077 mmc->clk_gated = true;
6078 spin_unlock_irqrestore(&mmc->clk_lock, flags);
6079 mmc_set_ios(mmc);
6080 mmc_host_clk_release(mmc);
6081}
6082
6083static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6084{
6085 struct mmc_host *mmc = host->mmc;
6086
6087 mmc_host_clk_hold(mmc);
6088 mmc->ios.clock = host->clk_rate;
6089 mmc_set_ios(mmc);
6090 mmc_host_clk_release(mmc);
6091}
6092#else
6093static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6094{
6095 struct mmc_host *mmc = host->mmc;
6096
6097 mmc->ios.clock = 0;
6098 mmc_set_ios(mmc);
6099}
6100
6101static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6102{
6103 struct mmc_host *mmc = host->mmc;
6104
6105 mmc->ios.clock = host->clk_rate;
6106 mmc_set_ios(mmc);
6107}
6108#endif
6109
San Mehat9d2bd732009-09-22 16:44:22 -07006110static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006111msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006112{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006113 struct mmc_host *mmc = dev_get_drvdata(dev);
6114 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006115 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306116 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07006117
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306118 if (host->plat->is_sdio_al_client) {
6119 rc = 0;
6120 goto out;
San Mehat9d2bd732009-09-22 16:44:22 -07006121 }
San Mehat9d2bd732009-09-22 16:44:22 -07006122
Sahitya Tummala7661a452011-07-18 13:28:35 +05306123 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006124 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006125 host->sdcc_suspending = 1;
6126 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07006127
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006128 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006129 * MMC core thinks that host is disabled by now since
6130 * runtime suspend is scheduled after msmsdcc_disable()
6131 * is called. Thus, MMC core will try to enable the host
6132 * while suspending it. This results in a synchronous
6133 * runtime resume request while in runtime suspending
6134 * context and hence inorder to complete this resume
6135 * requet, it will wait for suspend to be complete,
6136 * but runtime suspend also can not proceed further
6137 * until the host is resumed. Thus, it leads to a hang.
6138 * Hence, increase the pm usage count before suspending
6139 * the host so that any resume requests after this will
6140 * simple become pm usage counter increment operations.
6141 */
6142 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306143 /* If there is pending detect work abort runtime suspend */
6144 if (unlikely(work_busy(&mmc->detect.work)))
6145 rc = -EAGAIN;
6146 else
6147 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006148 pm_runtime_put_noidle(dev);
6149
6150 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306151 spin_lock_irqsave(&host->lock, flags);
6152 host->sdcc_suspended = true;
6153 spin_unlock_irqrestore(&host->lock, flags);
6154 if (mmc->card && mmc_card_sdio(mmc->card) &&
6155 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006156 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306157 * If SDIO function driver doesn't want
6158 * to power off the card, atleast turn off
6159 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006160 */
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306161 msmsdcc_gate_clock(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006162 }
6163 }
6164 host->sdcc_suspending = 0;
6165 mmc->suspend_task = NULL;
6166 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
6167 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006168 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306169 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306170out:
6171 /* set bus bandwidth to 0 immediately */
6172 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
San Mehat9d2bd732009-09-22 16:44:22 -07006173 return rc;
6174}
6175
6176static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006177msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006178{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006179 struct mmc_host *mmc = dev_get_drvdata(dev);
6180 struct msmsdcc_host *host = mmc_priv(mmc);
6181 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07006182
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006183 if (host->plat->is_sdio_al_client)
6184 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07006185
Sahitya Tummala7661a452011-07-18 13:28:35 +05306186 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006187 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306188 if (mmc->card && mmc_card_sdio(mmc->card) &&
6189 mmc_card_keep_power(mmc)) {
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306190 msmsdcc_ungate_clock(host);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05306191 }
San Mehat9d2bd732009-09-22 16:44:22 -07006192
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006193 mmc_resume_host(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006194
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006195 /*
6196 * FIXME: Clearing of flags must be handled in clients
6197 * resume handler.
6198 */
6199 spin_lock_irqsave(&host->lock, flags);
6200 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306201 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006202 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07006203
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006204 /*
6205 * After resuming the host wait for sometime so that
6206 * the SDIO work will be processed.
6207 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306208 if (mmc->card && mmc_card_sdio(mmc->card)) {
Subhash Jadavanic9b85752012-04-13 11:16:49 +05306209 if ((host->plat->mpm_sdiowakeup_int ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006210 host->plat->sdiowakeup_irq) &&
6211 wake_lock_active(&host->sdio_wlock))
6212 wake_lock_timeout(&host->sdio_wlock, 1);
6213 }
6214
6215 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006216 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05306217 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006218 return 0;
6219}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006220
6221static int msmsdcc_runtime_idle(struct device *dev)
6222{
6223 struct mmc_host *mmc = dev_get_drvdata(dev);
6224 struct msmsdcc_host *host = mmc_priv(mmc);
6225
6226 if (host->plat->is_sdio_al_client)
6227 return 0;
6228
6229 /* Idle timeout is not configurable for now */
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306230 pm_schedule_suspend(dev, host->idle_tout_ms);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006231
6232 return -EAGAIN;
6233}
6234
6235static int msmsdcc_pm_suspend(struct device *dev)
6236{
6237 struct mmc_host *mmc = dev_get_drvdata(dev);
6238 struct msmsdcc_host *host = mmc_priv(mmc);
6239 int rc = 0;
6240
6241 if (host->plat->is_sdio_al_client)
6242 return 0;
6243
6244
6245 if (host->plat->status_irq)
6246 disable_irq(host->plat->status_irq);
6247
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006248 if (!pm_runtime_suspended(dev))
6249 rc = msmsdcc_runtime_suspend(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006250
6251 return rc;
6252}
6253
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306254static int msmsdcc_suspend_noirq(struct device *dev)
6255{
6256 struct mmc_host *mmc = dev_get_drvdata(dev);
6257 struct msmsdcc_host *host = mmc_priv(mmc);
6258 int rc = 0;
6259
6260 /*
6261 * After platform suspend there may be active request
6262 * which might have enabled clocks. For example, in SDIO
6263 * case, ksdioirq thread might have scheduled after sdcc
6264 * suspend but before system freeze. In that case abort
6265 * suspend and retry instead of keeping the clocks on
6266 * during suspend and not allowing TCXO.
6267 */
6268
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306269 if (atomic_read(&host->clks_on) && !host->plat->is_sdio_al_client) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306270 pr_warn("%s: clocks are on after suspend, aborting system "
6271 "suspend\n", mmc_hostname(mmc));
6272 rc = -EAGAIN;
6273 }
6274
6275 return rc;
6276}
6277
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006278static int msmsdcc_pm_resume(struct device *dev)
6279{
6280 struct mmc_host *mmc = dev_get_drvdata(dev);
6281 struct msmsdcc_host *host = mmc_priv(mmc);
6282 int rc = 0;
6283
6284 if (host->plat->is_sdio_al_client)
6285 return 0;
6286
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006287 if (mmc->card && mmc_card_sdio(mmc->card))
Sahitya Tummalafb486372011-09-02 19:01:49 +05306288 rc = msmsdcc_runtime_resume(dev);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006289 else
6290 host->pending_resume = true;
6291
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006292 if (host->plat->status_irq) {
6293 msmsdcc_check_status((unsigned long)host);
6294 enable_irq(host->plat->status_irq);
6295 }
6296
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006297 return rc;
6298}
6299
Daniel Walker08ecfde2010-06-23 12:32:20 -07006300#else
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006301static int msmsdcc_runtime_suspend(struct device *dev)
6302{
6303 return 0;
6304}
6305static int msmsdcc_runtime_idle(struct device *dev)
6306{
6307 return 0;
6308}
6309static int msmsdcc_pm_suspend(struct device *dev)
6310{
6311 return 0;
6312}
6313static int msmsdcc_pm_resume(struct device *dev)
6314{
6315 return 0;
6316}
6317static int msmsdcc_suspend_noirq(struct device *dev)
6318{
6319 return 0;
6320}
6321static int msmsdcc_runtime_resume(struct device *dev)
6322{
6323 return 0;
6324}
Daniel Walker08ecfde2010-06-23 12:32:20 -07006325#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006326
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006327static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
6328 .runtime_suspend = msmsdcc_runtime_suspend,
6329 .runtime_resume = msmsdcc_runtime_resume,
6330 .runtime_idle = msmsdcc_runtime_idle,
6331 .suspend = msmsdcc_pm_suspend,
6332 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306333 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006334};
6335
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306336static const struct of_device_id msmsdcc_dt_match[] = {
6337 {.compatible = "qcom,msm-sdcc"},
6338
6339};
6340MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
6341
San Mehat9d2bd732009-09-22 16:44:22 -07006342static struct platform_driver msmsdcc_driver = {
6343 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006344 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07006345 .driver = {
6346 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006347 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306348 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07006349 },
6350};
6351
6352static int __init msmsdcc_init(void)
6353{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006354#if defined(CONFIG_DEBUG_FS)
6355 int ret = 0;
6356 ret = msmsdcc_dbg_init();
6357 if (ret) {
6358 pr_err("Failed to create debug fs dir \n");
6359 return ret;
6360 }
6361#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006362 return platform_driver_register(&msmsdcc_driver);
6363}
San Mehat9d2bd732009-09-22 16:44:22 -07006364
San Mehat9d2bd732009-09-22 16:44:22 -07006365static void __exit msmsdcc_exit(void)
6366{
6367 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006368
6369#if defined(CONFIG_DEBUG_FS)
6370 debugfs_remove(debugfs_file);
6371 debugfs_remove(debugfs_dir);
6372#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006373}
6374
6375module_init(msmsdcc_init);
6376module_exit(msmsdcc_exit);
6377
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006378MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07006379MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006380
6381#if defined(CONFIG_DEBUG_FS)
6382
6383static int
6384msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
6385{
6386 file->private_data = inode->i_private;
6387 return 0;
6388}
6389
6390static ssize_t
6391msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
6392 size_t count, loff_t *ppos)
6393{
6394 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08006395 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006396 int max, i;
6397
6398 i = 0;
6399 max = sizeof(buf) - 1;
6400
6401 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
6402 host->curr.cmd, host->curr.data);
6403 if (host->curr.cmd) {
6404 struct mmc_command *cmd = host->curr.cmd;
6405
6406 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
6407 cmd->opcode, cmd->arg, cmd->flags);
6408 }
6409 if (host->curr.data) {
6410 struct mmc_data *data = host->curr.data;
6411 i += scnprintf(buf + i, max - i,
6412 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
6413 data->timeout_ns, data->timeout_clks,
6414 data->blksz, data->blocks, data->error,
6415 data->flags);
6416 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
6417 host->curr.xfer_size, host->curr.xfer_remain,
6418 host->curr.data_xfered, host->dma.sg);
6419 }
6420
6421 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
6422}
6423
6424static const struct file_operations msmsdcc_dbg_state_ops = {
6425 .read = msmsdcc_dbg_state_read,
6426 .open = msmsdcc_dbg_state_open,
6427};
6428
6429static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
6430{
6431 if (debugfs_dir) {
6432 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
6433 0644, debugfs_dir, host,
6434 &msmsdcc_dbg_state_ops);
6435 }
6436}
6437
6438static int __init msmsdcc_dbg_init(void)
6439{
6440 int err;
6441
6442 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
6443 if (IS_ERR(debugfs_dir)) {
6444 err = PTR_ERR(debugfs_dir);
6445 debugfs_dir = NULL;
6446 return err;
6447 }
6448
6449 return 0;
6450}
6451#endif