blob: b22e2f0334107f5db97b016912eccb0a1822fb5f [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;
Asutosh Dasebd7d092012-07-09 19:08:26 +05302388 if (!curr_slot) {
2389 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002390 goto out;
Asutosh Dasebd7d092012-07-09 19:08:26 +05302391 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002392
Subhash Jadavani937c7502012-06-01 15:34:46 +05302393 vreg_table[0] = curr_slot->vdd_data;
2394 vreg_table[1] = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002395
2396 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2397 if (vreg_table[i]) {
2398 if (enable)
2399 rc = msmsdcc_vreg_enable(vreg_table[i]);
2400 else
Krishna Konda3c4142d2012-06-27 11:01:56 -07002401 rc = msmsdcc_vreg_disable(vreg_table[i],
2402 is_init);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002403 if (rc)
2404 goto out;
2405 }
2406 }
2407out:
2408 return rc;
2409}
2410
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002411/*
2412 * Reset vreg by ensuring it is off during probe. A call
2413 * to enable vreg is needed to balance disable vreg
2414 */
2415static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2416{
2417 int rc;
2418
Krishna Konda3c4142d2012-06-27 11:01:56 -07002419 rc = msmsdcc_setup_vreg(host, 1, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002420 if (rc)
2421 return rc;
Krishna Konda3c4142d2012-06-27 11:01:56 -07002422 rc = msmsdcc_setup_vreg(host, 0, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002423 return rc;
2424}
2425
Subhash Jadavani937c7502012-06-01 15:34:46 +05302426enum vdd_io_level {
2427 /* set vdd_io_data->low_vol_level */
2428 VDD_IO_LOW,
2429 /* set vdd_io_data->high_vol_level */
2430 VDD_IO_HIGH,
2431 /*
2432 * set whatever there in voltage_level (third argument) of
2433 * msmsdcc_set_vdd_io_vol() function.
2434 */
2435 VDD_IO_SET_LEVEL,
2436};
2437
2438static int msmsdcc_set_vdd_io_vol(struct msmsdcc_host *host,
2439 enum vdd_io_level level,
2440 unsigned int voltage_level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002441{
2442 int rc = 0;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302443 int set_level;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002444
2445 if (host->plat->vreg_data) {
Subhash Jadavani937c7502012-06-01 15:34:46 +05302446 struct msm_mmc_reg_data *vdd_io_reg =
2447 host->plat->vreg_data->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002448
Subhash Jadavani937c7502012-06-01 15:34:46 +05302449 if (vdd_io_reg && vdd_io_reg->is_enabled) {
2450 switch (level) {
2451 case VDD_IO_LOW:
2452 set_level = vdd_io_reg->low_vol_level;
2453 break;
2454 case VDD_IO_HIGH:
2455 set_level = vdd_io_reg->high_vol_level;
2456 break;
2457 case VDD_IO_SET_LEVEL:
2458 set_level = voltage_level;
2459 break;
2460 default:
2461 pr_err("%s: %s: invalid argument level = %d",
2462 mmc_hostname(host->mmc), __func__,
2463 level);
2464 rc = -EINVAL;
2465 goto out;
2466 }
2467 rc = msmsdcc_vreg_set_voltage(vdd_io_reg,
2468 set_level, set_level);
2469 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002470 }
2471
Subhash Jadavani937c7502012-06-01 15:34:46 +05302472out:
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302473 return rc;
2474}
2475
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002476static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2477{
2478 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2479 return 1;
2480 return 0;
2481}
2482
Asutosh Dasf5298c32012-04-03 14:51:47 +05302483/*
2484 * Any function calling msmsdcc_setup_clocks must
2485 * acquire clk_mutex. May sleep.
2486 */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302487static int msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002488{
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302489 int rc = 0;
2490
2491 if (enable && !atomic_read(&host->clks_on)) {
2492 if (!IS_ERR_OR_NULL(host->bus_clk)) {
2493 rc = clk_prepare_enable(host->bus_clk);
2494 if (rc) {
2495 pr_err("%s: %s: failed to enable the bus-clock with error %d\n",
2496 mmc_hostname(host->mmc), __func__, rc);
2497 goto out;
2498 }
2499 }
2500 if (!IS_ERR(host->pclk)) {
2501 rc = clk_prepare_enable(host->pclk);
2502 if (rc) {
2503 pr_err("%s: %s: failed to enable the pclk with error %d\n",
2504 mmc_hostname(host->mmc), __func__, rc);
2505 goto disable_bus;
2506 }
2507 }
2508 rc = clk_prepare_enable(host->clk);
2509 if (rc) {
2510 pr_err("%s: %s: failed to enable the host-clk with error %d\n",
2511 mmc_hostname(host->mmc), __func__, rc);
2512 goto disable_pclk;
2513 }
Subhash Jadavanidd432952012-03-28 11:25:56 +05302514 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302515 msmsdcc_delay(host);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302516 atomic_set(&host->clks_on, 1);
2517 } else if (!enable && atomic_read(&host->clks_on)) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05302518 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302519 msmsdcc_delay(host);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302520 clk_disable_unprepare(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002521 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302522 clk_disable_unprepare(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05302523 if (!IS_ERR_OR_NULL(host->bus_clk))
2524 clk_disable_unprepare(host->bus_clk);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302525 atomic_set(&host->clks_on, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002526 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302527 goto out;
2528
2529disable_pclk:
2530 if (!IS_ERR_OR_NULL(host->pclk))
2531 clk_disable_unprepare(host->pclk);
2532disable_bus:
2533 if (!IS_ERR_OR_NULL(host->bus_clk))
2534 clk_disable_unprepare(host->bus_clk);
2535out:
2536 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002537}
2538
2539static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2540 unsigned int req_clk)
2541{
2542 unsigned int sel_clk = -1;
2543
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302544 if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
2545 sel_clk = msmsdcc_get_min_sup_clk_rate(host);
2546 goto out;
2547 }
2548
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002549 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2550 unsigned char cnt;
2551
2552 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2553 if (host->plat->sup_clk_table[cnt] > req_clk)
2554 break;
2555 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2556 sel_clk = host->plat->sup_clk_table[cnt];
2557 break;
2558 } else
2559 sel_clk = host->plat->sup_clk_table[cnt];
2560 }
2561 } else {
2562 if ((req_clk < host->plat->msmsdcc_fmax) &&
2563 (req_clk > host->plat->msmsdcc_fmid))
2564 sel_clk = host->plat->msmsdcc_fmid;
2565 else
2566 sel_clk = req_clk;
2567 }
2568
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302569out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002570 return sel_clk;
2571}
2572
2573static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2574 struct msmsdcc_host *host)
2575{
2576 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2577 return host->plat->sup_clk_table[0];
2578 else
2579 return host->plat->msmsdcc_fmin;
2580}
2581
2582static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2583 struct msmsdcc_host *host)
2584{
2585 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2586 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2587 else
2588 return host->plat->msmsdcc_fmax;
2589}
2590
2591static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302592{
2593 struct msm_mmc_gpio_data *curr;
2594 int i, rc = 0;
2595
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002596 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302597 for (i = 0; i < curr->size; i++) {
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05302598 if (!gpio_is_valid(curr->gpio[i].no)) {
2599 rc = -EINVAL;
2600 pr_err("%s: Invalid gpio = %d\n",
2601 mmc_hostname(host->mmc), curr->gpio[i].no);
2602 goto free_gpios;
2603 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302604 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002605 if (curr->gpio[i].is_always_on &&
2606 curr->gpio[i].is_enabled)
2607 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302608 rc = gpio_request(curr->gpio[i].no,
2609 curr->gpio[i].name);
2610 if (rc) {
2611 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2612 mmc_hostname(host->mmc),
2613 curr->gpio[i].no,
2614 curr->gpio[i].name, rc);
2615 goto free_gpios;
2616 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002617 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302618 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002619 if (curr->gpio[i].is_always_on)
2620 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302621 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002622 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302623 }
2624 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002625 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302626
2627free_gpios:
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05302628 for (i--; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302629 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002630 curr->gpio[i].is_enabled = false;
2631 }
2632out:
2633 return rc;
2634}
2635
2636static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2637{
2638 struct msm_mmc_pad_data *curr;
2639 int i;
2640
2641 curr = host->plat->pin_data->pad_data;
2642 for (i = 0; i < curr->drv->size; i++) {
2643 if (enable)
2644 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2645 curr->drv->on[i].val);
2646 else
2647 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2648 curr->drv->off[i].val);
2649 }
2650
2651 for (i = 0; i < curr->pull->size; i++) {
2652 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002653 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002654 curr->pull->on[i].val);
2655 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002656 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002657 curr->pull->off[i].val);
2658 }
2659
2660 return 0;
2661}
2662
2663static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2664{
2665 int rc = 0;
2666
2667 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2668 return 0;
2669
2670 if (host->plat->pin_data->is_gpio)
2671 rc = msmsdcc_setup_gpio(host, enable);
2672 else
2673 rc = msmsdcc_setup_pad(host, enable);
2674
2675 if (!rc)
2676 host->plat->pin_data->cfg_sts = enable;
2677
2678 return rc;
2679}
2680
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302681static int msmsdcc_cfg_mpm_sdiowakeup(struct msmsdcc_host *host,
2682 unsigned mode)
2683{
2684 int ret = 0;
2685 unsigned int pin = host->plat->mpm_sdiowakeup_int;
2686
2687 if (!pin)
2688 return 0;
2689
2690 switch (mode) {
2691 case SDC_DAT1_DISABLE:
2692 ret = msm_mpm_enable_pin(pin, 0);
2693 break;
2694 case SDC_DAT1_ENABLE:
2695 ret = msm_mpm_set_pin_type(pin, IRQ_TYPE_LEVEL_LOW);
2696 ret = msm_mpm_enable_pin(pin, 1);
2697 break;
2698 case SDC_DAT1_ENWAKE:
2699 ret = msm_mpm_set_pin_wake(pin, 1);
2700 break;
2701 case SDC_DAT1_DISWAKE:
2702 ret = msm_mpm_set_pin_wake(pin, 0);
2703 break;
2704 default:
2705 ret = -EINVAL;
2706 break;
2707 }
2708
2709 return ret;
2710}
2711
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302712static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2713{
2714 u32 pwr = 0;
2715 int ret = 0;
2716 struct mmc_host *mmc = host->mmc;
2717
2718 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2719 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2720 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
Krishna Konda3c4142d2012-06-27 11:01:56 -07002721 ret = msmsdcc_setup_vreg(host, !!ios->vdd, false);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302722
2723 if (ret) {
2724 pr_err("%s: Failed to setup voltage regulators\n",
2725 mmc_hostname(host->mmc));
2726 goto out;
2727 }
2728
2729 switch (ios->power_mode) {
2730 case MMC_POWER_OFF:
2731 pwr = MCI_PWR_OFF;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302732 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302733 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05302734 * If VDD IO rail is always on, set low voltage for VDD
2735 * IO rail when slot is not in use (like when card is not
2736 * present or during system suspend).
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302737 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302738 msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302739 msmsdcc_setup_pins(host, false);
2740 break;
2741 case MMC_POWER_UP:
2742 /* writing PWR_UP bit is redundant */
2743 pwr = MCI_PWR_UP;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302744 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302745
Subhash Jadavani937c7502012-06-01 15:34:46 +05302746 msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302747 msmsdcc_setup_pins(host, true);
2748 break;
2749 case MMC_POWER_ON:
2750 pwr = MCI_PWR_ON;
2751 break;
2752 }
2753
2754out:
2755 return pwr;
2756}
2757
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002758static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2759{
2760 unsigned int wakeup_irq;
2761
2762 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2763 host->plat->sdiowakeup_irq :
2764 host->core_irqres->start;
2765
2766 if (!host->irq_wake_enabled) {
2767 enable_irq_wake(wakeup_irq);
2768 host->irq_wake_enabled = true;
2769 }
2770}
2771
2772static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2773{
2774 unsigned int wakeup_irq;
2775
2776 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2777 host->plat->sdiowakeup_irq :
2778 host->core_irqres->start;
2779
2780 if (host->irq_wake_enabled) {
2781 disable_irq_wake(wakeup_irq);
2782 host->irq_wake_enabled = false;
2783 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302784}
2785
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05302786/* Returns required bandwidth in Bytes per Sec */
2787static unsigned int msmsdcc_get_bw_required(struct msmsdcc_host *host,
2788 struct mmc_ios *ios)
2789{
2790 unsigned int bw;
2791
2792 bw = host->clk_rate;
2793 /*
2794 * For DDR mode, SDCC controller clock will be at
2795 * the double rate than the actual clock that goes to card.
2796 */
2797 if (ios->bus_width == MMC_BUS_WIDTH_4)
2798 bw /= 2;
2799 else if (ios->bus_width == MMC_BUS_WIDTH_1)
2800 bw /= 8;
2801
2802 return bw;
2803}
2804
2805static int msmsdcc_msm_bus_get_vote_for_bw(struct msmsdcc_host *host,
2806 unsigned int bw)
2807{
2808 unsigned int *table = host->plat->msm_bus_voting_data->bw_vecs;
2809 unsigned int size = host->plat->msm_bus_voting_data->bw_vecs_size;
2810 int i;
2811
2812 if (host->msm_bus_vote.is_max_bw_needed && bw)
2813 return host->msm_bus_vote.max_bw_vote;
2814
2815 for (i = 0; i < size; i++) {
2816 if (bw <= table[i])
2817 break;
2818 }
2819
2820 if (i && (i == size))
2821 i--;
2822
2823 return i;
2824}
2825
2826static int msmsdcc_msm_bus_register(struct msmsdcc_host *host)
2827{
2828 int rc = 0;
2829 struct msm_bus_scale_pdata *use_cases;
2830
2831 if (host->plat->msm_bus_voting_data &&
2832 host->plat->msm_bus_voting_data->use_cases &&
2833 host->plat->msm_bus_voting_data->bw_vecs &&
2834 host->plat->msm_bus_voting_data->bw_vecs_size) {
2835 use_cases = host->plat->msm_bus_voting_data->use_cases;
2836 host->msm_bus_vote.client_handle =
2837 msm_bus_scale_register_client(use_cases);
2838 } else {
2839 return 0;
2840 }
2841
2842 if (!host->msm_bus_vote.client_handle) {
2843 pr_err("%s: msm_bus_scale_register_client() failed\n",
2844 mmc_hostname(host->mmc));
2845 rc = -EFAULT;
2846 } else {
2847 /* cache the vote index for minimum and maximum bandwidth */
2848 host->msm_bus_vote.min_bw_vote =
2849 msmsdcc_msm_bus_get_vote_for_bw(host, 0);
2850 host->msm_bus_vote.max_bw_vote =
2851 msmsdcc_msm_bus_get_vote_for_bw(host, UINT_MAX);
2852 }
2853
2854 return rc;
2855}
2856
2857static void msmsdcc_msm_bus_unregister(struct msmsdcc_host *host)
2858{
2859 if (host->msm_bus_vote.client_handle)
2860 msm_bus_scale_unregister_client(
2861 host->msm_bus_vote.client_handle);
2862}
2863
2864/*
2865 * This function must be called with host lock acquired.
2866 * Caller of this function should also ensure that msm bus client
2867 * handle is not null.
2868 */
2869static inline int msmsdcc_msm_bus_set_vote(struct msmsdcc_host *host,
2870 int vote,
2871 unsigned long flags)
2872{
2873 int rc = 0;
2874
2875 if (vote != host->msm_bus_vote.curr_vote) {
2876 spin_unlock_irqrestore(&host->lock, flags);
2877 rc = msm_bus_scale_client_update_request(
2878 host->msm_bus_vote.client_handle, vote);
2879 if (rc)
2880 pr_err("%s: msm_bus_scale_client_update_request() failed."
2881 " bus_client_handle=0x%x, vote=%d, err=%d\n",
2882 mmc_hostname(host->mmc),
2883 host->msm_bus_vote.client_handle, vote, rc);
2884 spin_lock_irqsave(&host->lock, flags);
2885 if (!rc)
2886 host->msm_bus_vote.curr_vote = vote;
2887 }
2888
2889 return rc;
2890}
2891
2892/*
2893 * Internal work. Work to set 0 bandwidth for msm bus.
2894 */
2895static void msmsdcc_msm_bus_work(struct work_struct *work)
2896{
2897 struct msmsdcc_host *host = container_of(work,
2898 struct msmsdcc_host,
2899 msm_bus_vote.vote_work.work);
2900 unsigned long flags;
2901
2902 if (!host->msm_bus_vote.client_handle)
2903 return;
2904
2905 spin_lock_irqsave(&host->lock, flags);
2906 /* don't vote for 0 bandwidth if any request is in progress */
2907 if (!host->curr.mrq)
2908 msmsdcc_msm_bus_set_vote(host,
2909 host->msm_bus_vote.min_bw_vote, flags);
2910 else
2911 pr_warning("%s: %s: SDCC transfer in progress. skipping"
2912 " bus voting to 0 bandwidth\n",
2913 mmc_hostname(host->mmc), __func__);
2914 spin_unlock_irqrestore(&host->lock, flags);
2915}
2916
2917/*
2918 * This function cancels any scheduled delayed work
2919 * and sets the bus vote based on ios argument.
2920 * If "ios" argument is NULL, bandwidth required is 0 else
2921 * calculate the bandwidth based on ios parameters.
2922 */
2923static void msmsdcc_msm_bus_cancel_work_and_set_vote(
2924 struct msmsdcc_host *host,
2925 struct mmc_ios *ios)
2926{
2927 unsigned long flags;
2928 unsigned int bw;
2929 int vote;
2930
2931 if (!host->msm_bus_vote.client_handle)
2932 return;
2933
2934 bw = ios ? msmsdcc_get_bw_required(host, ios) : 0;
2935
2936 cancel_delayed_work_sync(&host->msm_bus_vote.vote_work);
2937 spin_lock_irqsave(&host->lock, flags);
2938 vote = msmsdcc_msm_bus_get_vote_for_bw(host, bw);
2939 msmsdcc_msm_bus_set_vote(host, vote, flags);
2940 spin_unlock_irqrestore(&host->lock, flags);
2941}
2942
2943/* This function queues a work which will set the bandwidth requiement to 0 */
2944static void msmsdcc_msm_bus_queue_work(struct msmsdcc_host *host)
2945{
2946 unsigned long flags;
2947
2948 if (!host->msm_bus_vote.client_handle)
2949 return;
2950
2951 spin_lock_irqsave(&host->lock, flags);
2952 if (host->msm_bus_vote.min_bw_vote != host->msm_bus_vote.curr_vote)
2953 queue_delayed_work(system_nrt_wq,
2954 &host->msm_bus_vote.vote_work,
2955 msecs_to_jiffies(MSM_MMC_BUS_VOTING_DELAY));
2956 spin_unlock_irqrestore(&host->lock, flags);
2957}
2958
San Mehat9d2bd732009-09-22 16:44:22 -07002959static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302960msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
2961{
2962 struct mmc_host *mmc = host->mmc;
2963
2964 /*
2965 * SDIO_AL clients has different mechanism of handling LPM through
2966 * sdio_al driver itself. The sdio wakeup interrupt is configured as
2967 * part of that. Here, we are interested only in clients like WLAN.
2968 */
2969 if (!(mmc->card && mmc_card_sdio(mmc->card))
2970 || host->plat->is_sdio_al_client)
2971 goto out;
2972
2973 if (!host->sdcc_suspended) {
2974 /*
2975 * When MSM is not in power collapse and we
2976 * are disabling clocks, enable bit 22 in MASK0
2977 * to handle asynchronous SDIO interrupts.
2978 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302979 if (enable_wakeup_irq) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302980 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302981 mb();
2982 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302983 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302984 msmsdcc_sync_reg_wr(host);
2985 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302986 goto out;
2987 } else if (!mmc_card_wake_sdio_irq(mmc)) {
2988 /*
2989 * Wakeup MSM only if SDIO function drivers set
2990 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
2991 */
2992 goto out;
2993 }
2994
2995 if (enable_wakeup_irq) {
2996 if (!host->plat->sdiowakeup_irq) {
2997 /*
2998 * When there is no gpio line that can be configured
2999 * as wakeup interrupt handle it by configuring
3000 * asynchronous sdio interrupts and DAT1 line.
3001 */
3002 writel_relaxed(MCI_SDIOINTMASK,
3003 host->base + MMCIMASK0);
3004 mb();
Subhash Jadavanic9b85752012-04-13 11:16:49 +05303005 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303006 /* configure sdcc core interrupt as wakeup interrupt */
3007 msmsdcc_enable_irq_wake(host);
3008 } else {
3009 /* Let gpio line handle wakeup interrupt */
3010 writel_relaxed(0, host->base + MMCIMASK0);
3011 mb();
3012 if (host->sdio_wakeupirq_disabled) {
3013 host->sdio_wakeupirq_disabled = 0;
3014 /* configure gpio line as wakeup interrupt */
3015 msmsdcc_enable_irq_wake(host);
3016 enable_irq(host->plat->sdiowakeup_irq);
3017 }
3018 }
3019 } else {
3020 if (!host->plat->sdiowakeup_irq) {
3021 /*
3022 * We may not have cleared bit 22 in the interrupt
3023 * handler as the clocks might be off at that time.
3024 */
3025 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303026 msmsdcc_sync_reg_wr(host);
Subhash Jadavanic9b85752012-04-13 11:16:49 +05303027 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303028 msmsdcc_disable_irq_wake(host);
3029 } else if (!host->sdio_wakeupirq_disabled) {
3030 disable_irq_nosync(host->plat->sdiowakeup_irq);
3031 msmsdcc_disable_irq_wake(host);
3032 host->sdio_wakeupirq_disabled = 1;
3033 }
3034 }
3035out:
3036 return;
San Mehat9d2bd732009-09-22 16:44:22 -07003037}
3038
3039static void
3040msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
3041{
3042 struct msmsdcc_host *host = mmc_priv(mmc);
3043 u32 clk = 0, pwr = 0;
3044 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08003045 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003046 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07003047
Sahitya Tummala7a892482011-01-18 11:22:49 +05303048
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303049 /*
3050 * Disable SDCC core interrupt until set_ios is completed.
3051 * This avoids any race conditions with interrupt raised
3052 * when turning on/off the clocks. One possible
3053 * scenario is SDIO operational interrupt while the clock
3054 * is turned off.
Asutosh Dasf5298c32012-04-03 14:51:47 +05303055 * host->lock is being released intermittently below.
3056 * Thus, prevent concurrent access to host.
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303057 */
3058
Asutosh Dasf5298c32012-04-03 14:51:47 +05303059 mutex_lock(&host->clk_mutex);
3060 DBG(host, "ios->clock = %u\n", ios->clock);
San Mehat9d2bd732009-09-22 16:44:22 -07003061 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303062 if (!host->sdcc_irq_disabled) {
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05303063 disable_irq_nosync(host->core_irqres->start);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303064 host->sdcc_irq_disabled = 1;
3065 }
San Mehatd0719e52009-12-03 10:58:54 -08003066 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07003067
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05303068 /* Make sure sdcc core irq is synchronized */
3069 synchronize_irq(host->core_irqres->start);
3070
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303071 pwr = msmsdcc_setup_pwr(host, ios);
3072
3073 spin_lock_irqsave(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07003074 if (ios->clock) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303075 spin_unlock_irqrestore(&host->lock, flags);
3076 rc = msmsdcc_setup_clocks(host, true);
3077 if (rc)
3078 goto out;
3079 spin_lock_irqsave(&host->lock, flags);
3080 writel_relaxed(host->mci_irqenable, host->base + MMCIMASK0);
3081 mb();
3082 msmsdcc_cfg_sdio_wakeup(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003083 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303084
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003085 /*
3086 * For DDR50 mode, controller needs clock rate to be
3087 * double than what is required on the SD card CLK pin.
3088 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05303089 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003090 /*
3091 * Make sure that we don't double the clock if
3092 * doubled clock rate is already set
3093 */
3094 if (!host->ddr_doubled_clk_rate ||
3095 (host->ddr_doubled_clk_rate &&
3096 (host->ddr_doubled_clk_rate != ios->clock))) {
3097 host->ddr_doubled_clk_rate =
3098 msmsdcc_get_sup_clk_rate(
3099 host, (ios->clock * 2));
3100 clock = host->ddr_doubled_clk_rate;
3101 }
3102 } else {
3103 host->ddr_doubled_clk_rate = 0;
3104 }
3105
3106 if (clock != host->clk_rate) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05303107 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003108 rc = clk_set_rate(host->clk, clock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303109 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003110 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303111 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003112 mmc_hostname(mmc), clock);
3113 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303114 host->reg_write_delay =
3115 (1 + ((3 * USEC_PER_SEC) /
3116 (host->clk_rate ? host->clk_rate :
3117 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003118 }
3119 /*
3120 * give atleast 2 MCLK cycles delay for clocks
3121 * and SDCC core to stabilize
3122 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05303123 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003124 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003125 clk |= MCI_CLK_ENABLE;
3126 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003127 if (ios->bus_width == MMC_BUS_WIDTH_8)
3128 clk |= MCI_CLK_WIDEBUS_8;
3129 else if (ios->bus_width == MMC_BUS_WIDTH_4)
3130 clk |= MCI_CLK_WIDEBUS_4;
3131 else
3132 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07003133
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003134 if (msmsdcc_is_pwrsave(host))
3135 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07003136
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003137 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07003138
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003139 host->tuning_needed = 0;
3140 /*
3141 * Select the controller timing mode according
3142 * to current bus speed mode
3143 */
Subhash Jadavanif97d2992012-07-13 14:47:47 +05303144 if (host->clk_rate > (100 * 1000 * 1000) &&
3145 (ios->timing == MMC_TIMING_UHS_SDR104 ||
3146 ios->timing == MMC_TIMING_MMC_HS200)) {
3147 /* Card clock frequency must be > 100MHz to enable tuning */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003148 clk |= (4 << 14);
3149 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05303150 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003151 clk |= (3 << 14);
3152 } else {
3153 clk |= (2 << 14); /* feedback clock */
San Mehat9d2bd732009-09-22 16:44:22 -07003154 }
3155
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003156 /* Select free running MCLK as input clock of cm_dll_sdc4 */
3157 clk |= (2 << 23);
San Mehat9d2bd732009-09-22 16:44:22 -07003158
Subhash Jadavani00083572012-02-15 16:18:01 +05303159 /* Clear IO_PAD_PWR_SWITCH while powering off the card */
3160 if (!ios->vdd)
3161 host->io_pad_pwr_switch = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07003162
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003163 if (host->io_pad_pwr_switch)
3164 clk |= IO_PAD_PWR_SWITCH;
3165
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303166 /* Don't write into registers if clocks are disabled */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303167 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303168 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
3169 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303170 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003171 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303172 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
3173 host->pwr = pwr;
3174 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303175 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003176 }
San Mehat9d2bd732009-09-22 16:44:22 -07003177 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003178
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303179 if (!(clk & MCI_CLK_ENABLE) && atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303180 msmsdcc_cfg_sdio_wakeup(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303181 spin_unlock_irqrestore(&host->lock, flags);
3182 /*
3183 * May get a wake-up interrupt the instant we disable the
3184 * clocks. This would disable the wake-up interrupt.
3185 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003186 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303187 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003188 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303189
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303190 if (host->tuning_in_progress)
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303191 WARN(!atomic_read(&host->clks_on),
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303192 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303193
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303194 /* Let interrupts be disabled if the host is powered off */
3195 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
3196 enable_irq(host->core_irqres->start);
3197 host->sdcc_irq_disabled = 0;
3198 }
San Mehat4adbbcc2009-11-08 13:00:37 -08003199 spin_unlock_irqrestore(&host->lock, flags);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303200out:
Asutosh Dasf5298c32012-04-03 14:51:47 +05303201 mutex_unlock(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07003202}
3203
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003204int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
3205{
3206 struct msmsdcc_host *host = mmc_priv(mmc);
3207 u32 clk;
3208
3209 clk = readl_relaxed(host->base + MMCICLOCK);
3210 pr_debug("Changing to pwr_save=%d", pwrsave);
3211 if (pwrsave && msmsdcc_is_pwrsave(host))
3212 clk |= MCI_CLK_PWRSAVE;
3213 else
3214 clk &= ~MCI_CLK_PWRSAVE;
3215 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303216 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003217
3218 return 0;
3219}
3220
3221static int msmsdcc_get_ro(struct mmc_host *mmc)
3222{
3223 int status = -ENOSYS;
3224 struct msmsdcc_host *host = mmc_priv(mmc);
3225
3226 if (host->plat->wpswitch) {
3227 status = host->plat->wpswitch(mmc_dev(mmc));
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05303228 } else if (gpio_is_valid(host->plat->wpswitch_gpio)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003229 status = gpio_request(host->plat->wpswitch_gpio,
3230 "SD_WP_Switch");
3231 if (status) {
3232 pr_err("%s: %s: Failed to request GPIO %d\n",
3233 mmc_hostname(mmc), __func__,
3234 host->plat->wpswitch_gpio);
3235 } else {
3236 status = gpio_direction_input(
3237 host->plat->wpswitch_gpio);
3238 if (!status) {
3239 /*
3240 * Wait for atleast 300ms as debounce
3241 * time for GPIO input to stabilize.
3242 */
3243 msleep(300);
3244 status = gpio_get_value_cansleep(
3245 host->plat->wpswitch_gpio);
Sujit Reddy Thumma8f912ea2012-06-22 16:18:43 +05303246 status ^= !host->plat->is_wpswitch_active_low;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003247 }
3248 gpio_free(host->plat->wpswitch_gpio);
3249 }
3250 }
3251
3252 if (status < 0)
3253 status = -ENOSYS;
3254 pr_debug("%s: Card read-only status %d\n", __func__, status);
3255
3256 return status;
San Mehat9d2bd732009-09-22 16:44:22 -07003257}
3258
3259static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
3260{
3261 struct msmsdcc_host *host = mmc_priv(mmc);
3262 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003263
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303264 /*
3265 * We may come here with clocks turned off in that case don't
3266 * attempt to write into MASK0 register. While turning on the
3267 * clocks mci_irqenable will be written to MASK0 register.
3268 */
San Mehat9d2bd732009-09-22 16:44:22 -07003269
3270 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003271 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003272 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303273 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303274 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003275 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303276 mb();
3277 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003278 } else {
3279 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303280 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303281 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003282 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303283 mb();
3284 }
San Mehat9d2bd732009-09-22 16:44:22 -07003285 }
3286 spin_unlock_irqrestore(&host->lock, flags);
3287}
3288
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003289#ifdef CONFIG_PM_RUNTIME
subhashj245831e2012-04-30 18:46:17 +05303290static void msmsdcc_print_rpm_info(struct msmsdcc_host *host)
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003291{
subhashj245831e2012-04-30 18:46:17 +05303292 struct device *dev = mmc_dev(host->mmc);
3293
3294 pr_info("%s: RPM: runtime_status=%d, usage_count=%d,"
3295 " is_suspended=%d, disable_depth=%d, runtime_error=%d,"
3296 " request_pending=%d, request=%d\n",
3297 mmc_hostname(host->mmc), dev->power.runtime_status,
3298 atomic_read(&dev->power.usage_count),
3299 dev->power.is_suspended, dev->power.disable_depth,
3300 dev->power.runtime_error, dev->power.request_pending,
3301 dev->power.request);
3302}
3303
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003304static int msmsdcc_enable(struct mmc_host *mmc)
3305{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003306 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003307 struct device *dev = mmc->parent;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003308 struct msmsdcc_host *host = mmc_priv(mmc);
3309
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303310 msmsdcc_pm_qos_update_latency(host, 1);
3311
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003312 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303313 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003314
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003315 if (host->sdcc_suspended && host->pending_resume &&
3316 !pm_runtime_suspended(dev)) {
3317 host->pending_resume = false;
3318 pm_runtime_get_noresume(dev);
3319 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303320 goto skip_get_sync;
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003321 }
3322
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303323 if (dev->power.runtime_status == RPM_SUSPENDING) {
3324 if (mmc->suspend_task == current) {
3325 pm_runtime_get_noresume(dev);
3326 goto out;
3327 }
Sujit Reddy Thumma112bd752012-06-20 12:29:45 +05303328 } else if (dev->power.runtime_status == RPM_RESUMING) {
3329 pm_runtime_get_noresume(dev);
3330 goto out;
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303331 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003332
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303333 rc = pm_runtime_get_sync(dev);
3334
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303335skip_get_sync:
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303336 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003337 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3338 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303339 msmsdcc_print_rpm_info(host);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303340 return rc;
3341 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303342out:
3343 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303344 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003345}
3346
Steve Mucklef132c6c2012-06-06 18:30:57 -07003347static int msmsdcc_disable(struct mmc_host *mmc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003348{
3349 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303350 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003351
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303352 msmsdcc_pm_qos_update_latency(host, 0);
3353
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303354 if (mmc->card && mmc_card_sdio(mmc->card)) {
3355 rc = 0;
3356 goto out;
3357 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303358
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303359 if (host->plat->disable_runtime_pm)
3360 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003361
3362 rc = pm_runtime_put_sync(mmc->parent);
3363
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003364 /*
3365 * Ignore -EAGAIN as that is not fatal, it means that
3366 * either runtime usage count is non-zero or the runtime
3367 * pm itself is disabled or not in proper state to process
3368 * idle notification.
3369 */
3370 if (rc < 0 && (rc != -EAGAIN)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003371 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3372 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303373 msmsdcc_print_rpm_info(host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003374 return rc;
3375 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303376
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303377out:
3378 msmsdcc_msm_bus_queue_work(host);
3379 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003380}
3381#else
subhashj245831e2012-04-30 18:46:17 +05303382static void msmsdcc_print_rpm_info(struct msmsdcc_host *host) {}
3383
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303384static int msmsdcc_enable(struct mmc_host *mmc)
3385{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003386 struct device *dev = mmc->parent;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303387 struct msmsdcc_host *host = mmc_priv(mmc);
3388 unsigned long flags;
Sujit Reddy Thumma7f5051c2012-05-04 10:14:07 +05303389 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303390
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303391 msmsdcc_pm_qos_update_latency(host, 1);
3392
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303393 if (mmc->card && mmc_card_sdio(mmc->card)) {
3394 rc = 0;
3395 goto out;
3396 }
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003397
3398 if (host->sdcc_suspended && host->pending_resume) {
3399 host->pending_resume = false;
3400 rc = msmsdcc_runtime_resume(dev);
3401 goto out;
3402 }
3403
Asutosh Dasf5298c32012-04-03 14:51:47 +05303404 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303405 rc = msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303406 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303407
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003408out:
3409 if (rc < 0) {
3410 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3411 __func__, rc);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303412 msmsdcc_pm_qos_update_latency(host, 0);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003413 return rc;
3414 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303415 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303416 return 0;
3417}
3418
Steve Mucklef132c6c2012-06-06 18:30:57 -07003419static int msmsdcc_disable(struct mmc_host *mmc)
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303420{
3421 struct msmsdcc_host *host = mmc_priv(mmc);
3422 unsigned long flags;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303423 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303424
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303425 msmsdcc_pm_qos_update_latency(host, 0);
3426
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303427 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303428 goto out;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303429
Asutosh Dasf5298c32012-04-03 14:51:47 +05303430 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303431 rc = msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303432 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303433
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303434 if (rc) {
3435 msmsdcc_pm_qos_update_latency(host, 1);
3436 return rc;
3437 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303438out:
3439 msmsdcc_msm_bus_queue_work(host);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303440 return rc;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303441}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003442#endif
3443
Subhash Jadavani937c7502012-06-01 15:34:46 +05303444static int msmsdcc_switch_io_voltage(struct mmc_host *mmc,
3445 struct mmc_ios *ios)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003446{
3447 struct msmsdcc_host *host = mmc_priv(mmc);
3448 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303449 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003450
Subhash Jadavani00083572012-02-15 16:18:01 +05303451 spin_lock_irqsave(&host->lock, flags);
3452 host->io_pad_pwr_switch = 0;
3453 spin_unlock_irqrestore(&host->lock, flags);
3454
Subhash Jadavani937c7502012-06-01 15:34:46 +05303455 switch (ios->signal_voltage) {
3456 case MMC_SIGNAL_VOLTAGE_330:
3457 /* Set VDD IO to high voltage range (2.7v - 3.6v) */
3458 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303459 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303460 case MMC_SIGNAL_VOLTAGE_180:
3461 break;
3462 case MMC_SIGNAL_VOLTAGE_120:
3463 /*
3464 * For eMMC cards, VDD_IO voltage range must be changed
3465 * only if it operates in HS200 SDR 1.2V mode or in
3466 * DDR 1.2V mode.
3467 */
3468 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_SET_LEVEL, 1200000);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003469 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303470 default:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003471 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303472 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003473 goto out;
3474 }
San Mehat9d2bd732009-09-22 16:44:22 -07003475
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003476 /*
3477 * If we are here means voltage switch from high voltage to
3478 * low voltage is required
3479 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303480 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003481
3482 /*
3483 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
3484 * register until they become all zeros.
3485 */
3486 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303487 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003488 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
3489 mmc_hostname(mmc), __func__);
3490 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07003491 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003492
3493 /* Stop SD CLK output. */
3494 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3495 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303496 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003497 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003498
3499 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05303500 * Switch VDD Io from high voltage range (2.7v - 3.6v) to
3501 * low voltage range (1.7v - 1.95v).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003502 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303503 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303504 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003505 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003506
3507 spin_lock_irqsave(&host->lock, flags);
3508 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3509 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303510 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003511 host->io_pad_pwr_switch = 1;
3512 spin_unlock_irqrestore(&host->lock, flags);
3513
3514 /* Wait 5 ms for the voltage regulater in the card to become stable. */
3515 usleep_range(5000, 5500);
3516
3517 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303518 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003519 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3520 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303521 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003522 spin_unlock_irqrestore(&host->lock, flags);
3523
3524 /*
3525 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
3526 * don't become all ones within 1 ms then a Voltage Switch
3527 * sequence has failed and a power cycle to the card is required.
3528 * Otherwise Voltage Switch sequence is completed successfully.
3529 */
3530 usleep_range(1000, 1500);
3531
3532 spin_lock_irqsave(&host->lock, flags);
3533 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
3534 != (0xF << 1)) {
3535 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
3536 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303537 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003538 goto out_unlock;
3539 }
3540
3541out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303542 /* Enable PWRSAVE */
3543 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3544 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303545 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003546 spin_unlock_irqrestore(&host->lock, flags);
3547out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303548 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003549}
3550
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303551static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003552{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003553 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003554
3555 /* Program the MCLK value to MCLK_FREQ bit field */
3556 if (host->clk_rate <= 112000000)
3557 mclk_freq = 0;
3558 else if (host->clk_rate <= 125000000)
3559 mclk_freq = 1;
3560 else if (host->clk_rate <= 137000000)
3561 mclk_freq = 2;
3562 else if (host->clk_rate <= 150000000)
3563 mclk_freq = 3;
3564 else if (host->clk_rate <= 162000000)
3565 mclk_freq = 4;
3566 else if (host->clk_rate <= 175000000)
3567 mclk_freq = 5;
3568 else if (host->clk_rate <= 187000000)
3569 mclk_freq = 6;
3570 else if (host->clk_rate <= 200000000)
3571 mclk_freq = 7;
3572
3573 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3574 & ~(7 << 24)) | (mclk_freq << 24)),
3575 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003576}
3577
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303578/* Initialize the DLL (Programmable Delay Line ) */
3579static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003580{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003581 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303582 unsigned long flags;
3583 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003584
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303585 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003586 /*
3587 * Make sure that clock is always enabled when DLL
3588 * tuning is in progress. Keeping PWRSAVE ON may
3589 * turn off the clock. So let's disable the PWRSAVE
3590 * here and re-enable it once tuning is completed.
3591 */
3592 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3593 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303594 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303595
3596 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3597 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3598 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3599
3600 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3601 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3602 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3603
3604 msmsdcc_cm_sdc4_dll_set_freq(host);
3605
3606 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3607 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3608 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3609
3610 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3611 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3612 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3613
3614 /* Set DLL_EN bit to 1. */
3615 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3616 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3617
3618 /* Set CK_OUT_EN bit to 1. */
3619 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3620 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3621
3622 wait_cnt = 50;
3623 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3624 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3625 /* max. wait for 50us sec for LOCK bit to be set */
3626 if (--wait_cnt == 0) {
3627 pr_err("%s: %s: DLL failed to LOCK\n",
3628 mmc_hostname(host->mmc), __func__);
3629 rc = -ETIMEDOUT;
3630 goto out;
3631 }
3632 /* wait for 1us before polling again */
3633 udelay(1);
3634 }
3635
3636out:
3637 /* re-enable PWRSAVE */
3638 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3639 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303640 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303641 spin_unlock_irqrestore(&host->lock, flags);
3642
3643 return rc;
3644}
3645
3646static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3647 u8 poll)
3648{
3649 int rc = 0;
3650 u32 wait_cnt = 50;
3651 u8 ck_out_en = 0;
3652
3653 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3654 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3655 MCI_CK_OUT_EN);
3656
3657 while (ck_out_en != poll) {
3658 if (--wait_cnt == 0) {
3659 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3660 mmc_hostname(host->mmc), __func__, poll);
3661 rc = -ETIMEDOUT;
3662 goto out;
3663 }
3664 udelay(1);
3665
3666 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3667 MCI_CK_OUT_EN);
3668 }
3669out:
3670 return rc;
3671}
3672
3673/*
3674 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3675 * calibration sequence. This function should be called before
3676 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3677 * commands (CMD17/CMD18).
3678 *
3679 * This function gets called when host spinlock acquired.
3680 */
3681static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3682{
3683 int rc = 0;
3684 u32 config;
3685
3686 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3687 config |= MCI_CDR_EN;
3688 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3689 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3690
3691 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3692 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3693 if (rc)
3694 goto err_out;
3695
3696 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3697 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3698 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3699
3700 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3701 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3702 if (rc)
3703 goto err_out;
3704
3705 goto out;
3706
3707err_out:
3708 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3709out:
3710 return rc;
3711}
3712
3713static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3714 u8 phase)
3715{
3716 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303717 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3718 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3719 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303720 unsigned long flags;
3721 u32 config;
3722
3723 spin_lock_irqsave(&host->lock, flags);
3724
3725 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3726 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3727 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3728 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3729
3730 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3731 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3732 if (rc)
3733 goto err_out;
3734
3735 /*
3736 * Write the selected DLL clock output phase (0 ... 15)
3737 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
3738 */
3739 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3740 & ~(0xF << 20))
3741 | (grey_coded_phase_table[phase] << 20)),
3742 host->base + MCI_DLL_CONFIG);
3743
3744 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3745 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3746 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3747
3748 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3749 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3750 if (rc)
3751 goto err_out;
3752
3753 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3754 config |= MCI_CDR_EN;
3755 config &= ~MCI_CDR_EXT_EN;
3756 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3757 goto out;
3758
3759err_out:
3760 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3761 mmc_hostname(host->mmc), __func__, phase);
3762out:
3763 spin_unlock_irqrestore(&host->lock, flags);
3764 return rc;
3765}
3766
3767/*
3768 * Find out the greatest range of consecuitive selected
3769 * DLL clock output phases that can be used as sampling
3770 * setting for SD3.0 UHS-I card read operation (in SDR104
3771 * timing mode) or for eMMC4.5 card read operation (in HS200
3772 * timing mode).
3773 * Select the 3/4 of the range and configure the DLL with the
3774 * selected DLL clock output phase.
3775*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303776static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303777 u8 *phase_table, u8 total_phases)
3778{
Subhash Jadavani6159c622012-03-15 19:05:55 +05303779 #define MAX_PHASES 16
Subhash Jadavani34187042012-03-02 10:59:49 +05303780 int ret;
Subhash Jadavani6159c622012-03-15 19:05:55 +05303781 u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
3782 u8 phases_per_row[MAX_PHASES] = {0};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303783 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303784 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3785 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303786
Subhash Jadavani6159c622012-03-15 19:05:55 +05303787 if (!total_phases || (total_phases > MAX_PHASES)) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303788 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3789 mmc_hostname(host->mmc), __func__, total_phases);
3790 return -EINVAL;
3791 }
3792
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303793 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303794 ranges[row_index][col_index] = phase_table[cnt];
3795 phases_per_row[row_index] += 1;
3796 col_index++;
3797
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303798 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303799 continue;
3800 /* check if next phase in phase_table is consecutive or not */
3801 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3802 row_index++;
3803 col_index = 0;
3804 }
3805 }
3806
Subhash Jadavani6159c622012-03-15 19:05:55 +05303807 if (row_index >= MAX_PHASES)
3808 return -EINVAL;
3809
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303810 /* Check if phase-0 is present in first valid window? */
3811 if (!ranges[0][0]) {
3812 phase_0_found = true;
3813 phase_0_raw_index = 0;
3814 /* Check if cycle exist between 2 valid windows */
3815 for (cnt = 1; cnt <= row_index; cnt++) {
3816 if (phases_per_row[cnt]) {
Subhash Jadavani6159c622012-03-15 19:05:55 +05303817 for (i = 0; i < phases_per_row[cnt]; i++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303818 if (ranges[cnt][i] == 15) {
3819 phase_15_found = true;
3820 phase_15_raw_index = cnt;
3821 break;
3822 }
3823 }
3824 }
3825 }
3826 }
3827
3828 /* If 2 valid windows form cycle then merge them as single window */
3829 if (phase_0_found && phase_15_found) {
3830 /* number of phases in raw where phase 0 is present */
3831 u8 phases_0 = phases_per_row[phase_0_raw_index];
3832 /* number of phases in raw where phase 15 is present */
3833 u8 phases_15 = phases_per_row[phase_15_raw_index];
3834
Subhash Jadavani6159c622012-03-15 19:05:55 +05303835 if (phases_0 + phases_15 >= MAX_PHASES)
3836 /*
3837 * If there are more than 1 phase windows then total
3838 * number of phases in both the windows should not be
3839 * more than or equal to MAX_PHASES.
3840 */
3841 return -EINVAL;
3842
3843 /* Merge 2 cyclic windows */
3844 i = phases_15;
3845 for (cnt = 0; cnt < phases_0; cnt++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303846 ranges[phase_15_raw_index][i] =
3847 ranges[phase_0_raw_index][cnt];
Subhash Jadavani6159c622012-03-15 19:05:55 +05303848 if (++i >= MAX_PHASES)
3849 break;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303850 }
Subhash Jadavani6159c622012-03-15 19:05:55 +05303851
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303852 phases_per_row[phase_0_raw_index] = 0;
3853 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
3854 }
3855
3856 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303857 if (phases_per_row[cnt] > curr_max) {
3858 curr_max = phases_per_row[cnt];
3859 selected_row_index = cnt;
3860 }
3861 }
3862
Subhash Jadavani6159c622012-03-15 19:05:55 +05303863 i = ((curr_max * 3) / 4);
3864 if (i)
3865 i--;
3866
Subhash Jadavani34187042012-03-02 10:59:49 +05303867 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303868
Subhash Jadavani6159c622012-03-15 19:05:55 +05303869 if (ret >= MAX_PHASES) {
3870 ret = -EINVAL;
3871 pr_err("%s: %s: invalid phase selected=%d\n",
3872 mmc_hostname(host->mmc), __func__, ret);
3873 }
3874
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303875 return ret;
3876}
3877
Girish K Sa3f41692012-02-29 12:00:09 +05303878static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303879{
3880 int rc = 0;
3881 struct msmsdcc_host *host = mmc_priv(mmc);
3882 unsigned long flags;
3883 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303884 const u32 *tuning_block_pattern = tuning_block_64;
3885 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303886
3887 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
3888
3889 /* Tuning is only required for SDR104 modes */
3890 if (!host->tuning_needed) {
3891 rc = 0;
3892 goto exit;
3893 }
3894
3895 spin_lock_irqsave(&host->lock, flags);
3896 WARN(!host->pwr, "SDCC power is turned off\n");
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303897 WARN(!atomic_read(&host->clks_on), "SDCC clocks are turned off\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303898 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
3899
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303900 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303901 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
3902 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
3903 tuning_block_pattern = tuning_block_128;
3904 size = sizeof(tuning_block_128);
3905 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303906 spin_unlock_irqrestore(&host->lock, flags);
3907
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003908 /* first of all reset the tuning block */
3909 rc = msmsdcc_init_cm_sdc4_dll(host);
3910 if (rc)
3911 goto out;
3912
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303913 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003914 if (!data_buf) {
3915 rc = -ENOMEM;
3916 goto out;
3917 }
3918
3919 phase = 0;
3920 do {
3921 struct mmc_command cmd = {0};
3922 struct mmc_data data = {0};
3923 struct mmc_request mrq = {
3924 .cmd = &cmd,
3925 .data = &data
3926 };
3927 struct scatterlist sg;
3928
3929 /* set the phase in delay line hw block */
3930 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3931 if (rc)
3932 goto kfree;
3933
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303934 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003935 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
3936
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303937 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003938 data.blocks = 1;
3939 data.flags = MMC_DATA_READ;
3940 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
3941
3942 data.sg = &sg;
3943 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303944 sg_init_one(&sg, data_buf, size);
3945 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003946 mmc_wait_for_req(mmc, &mrq);
3947
3948 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303949 !memcmp(data_buf, tuning_block_pattern, size)) {
3950 /* tuning is successful at this tuning point */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003951 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303952 pr_debug("%s: %s: found good phase = %d\n",
3953 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003954 }
3955 } while (++phase < 16);
3956
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003957 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303958 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303959 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05303960 if (rc < 0)
3961 goto kfree;
3962 else
3963 phase = (u8)rc;
3964
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003965 /*
3966 * Finally set the selected phase in delay
3967 * line hw block.
3968 */
3969 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3970 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303971 goto kfree;
3972 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
3973 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003974 } else {
3975 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303976 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003977 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303978 msmsdcc_dump_sdcc_state(host);
3979 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003980 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003981
3982kfree:
3983 kfree(data_buf);
3984out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303985 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303986 host->tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303987 spin_unlock_irqrestore(&host->lock, flags);
3988exit:
3989 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003990 return rc;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003991}
3992
Asutosh Dasebd7d092012-07-09 19:08:26 +05303993/*
3994 * Work around of the unavailability of a power_reset functionality in SD cards
3995 * by turning the OFF & back ON the regulators supplying the SD card.
3996 */
3997void msmsdcc_hw_reset(struct mmc_host *mmc)
3998{
3999 struct mmc_card *card = mmc->card;
4000 struct msmsdcc_host *host = mmc_priv(mmc);
4001 int rc;
4002
4003 /* Write-protection bits would be lost on a hardware reset in emmc */
4004 if (!card || !mmc_card_sd(card))
4005 return;
4006
4007 /*
4008 * Continuing on failing to disable regulator would lead to a panic
4009 * anyway, since the commands would fail and console would be flooded
4010 * with prints, eventually leading to a watchdog bark
4011 */
4012 rc = msmsdcc_setup_vreg(host, false, false);
4013 if (rc) {
4014 pr_err("%s: %s disable regulator: failed: %d\n",
4015 mmc_hostname(mmc), __func__, rc);
4016 BUG_ON(rc);
4017 }
4018
4019 /* 10ms delay for the supply to reach the desired voltage level */
4020 usleep_range(10000, 12000);
4021
4022 /*
4023 * Continuing on failing to enable regulator would lead to a panic
4024 * anyway, since the commands would fail and console would be flooded
4025 * with prints, eventually leading to a watchdog bark
4026 */
4027 rc = msmsdcc_setup_vreg(host, true, false);
4028 if (rc) {
4029 pr_err("%s: %s enable regulator: failed: %d\n",
4030 mmc_hostname(mmc), __func__, rc);
4031 BUG_ON(rc);
4032 }
4033
4034 /* 10ms delay for the supply to reach the desired voltage level */
4035 usleep_range(10000, 12000);
4036}
4037
San Mehat9d2bd732009-09-22 16:44:22 -07004038static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004039 .enable = msmsdcc_enable,
4040 .disable = msmsdcc_disable,
Asutosh Dasaccacd42012-03-08 14:33:17 +05304041 .pre_req = msmsdcc_pre_req,
4042 .post_req = msmsdcc_post_req,
San Mehat9d2bd732009-09-22 16:44:22 -07004043 .request = msmsdcc_request,
4044 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004045 .get_ro = msmsdcc_get_ro,
San Mehat9d2bd732009-09-22 16:44:22 -07004046 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Subhash Jadavani937c7502012-06-01 15:34:46 +05304047 .start_signal_voltage_switch = msmsdcc_switch_io_voltage,
Asutosh Dasebd7d092012-07-09 19:08:26 +05304048 .execute_tuning = msmsdcc_execute_tuning,
4049 .hw_reset = msmsdcc_hw_reset,
San Mehat9d2bd732009-09-22 16:44:22 -07004050};
4051
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004052static unsigned int
4053msmsdcc_slot_status(struct msmsdcc_host *host)
4054{
4055 int status;
4056 unsigned int gpio_no = host->plat->status_gpio;
4057
4058 status = gpio_request(gpio_no, "SD_HW_Detect");
4059 if (status) {
4060 pr_err("%s: %s: Failed to request GPIO %d\n",
4061 mmc_hostname(host->mmc), __func__, gpio_no);
4062 } else {
4063 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08004064 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08004065 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08004066 if (host->plat->is_status_gpio_active_low)
4067 status = !status;
4068 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004069 gpio_free(gpio_no);
4070 }
4071 return status;
4072}
4073
San Mehat9d2bd732009-09-22 16:44:22 -07004074static void
4075msmsdcc_check_status(unsigned long data)
4076{
4077 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4078 unsigned int status;
4079
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05304080 if (host->plat->status || gpio_is_valid(host->plat->status_gpio)) {
Krishna Konda941604a2012-01-10 17:46:34 -08004081 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004082 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004083 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004084 status = msmsdcc_slot_status(host);
4085
Krishna Konda941604a2012-01-10 17:46:34 -08004086 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08004087
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004088 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08004089 if (host->plat->status)
4090 pr_info("%s: Slot status change detected "
4091 "(%d -> %d)\n",
4092 mmc_hostname(host->mmc),
4093 host->oldstat, status);
4094 else if (host->plat->is_status_gpio_active_low)
4095 pr_info("%s: Slot status change detected "
4096 "(%d -> %d) and the card detect GPIO"
4097 " is ACTIVE_LOW\n",
4098 mmc_hostname(host->mmc),
4099 host->oldstat, status);
4100 else
4101 pr_info("%s: Slot status change detected "
4102 "(%d -> %d) and the card detect GPIO"
4103 " is ACTIVE_HIGH\n",
4104 mmc_hostname(host->mmc),
4105 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07004106 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004107 }
4108 host->oldstat = status;
4109 } else {
4110 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07004111 }
San Mehat9d2bd732009-09-22 16:44:22 -07004112}
4113
4114static irqreturn_t
4115msmsdcc_platform_status_irq(int irq, void *dev_id)
4116{
4117 struct msmsdcc_host *host = dev_id;
4118
Girish K Sa3c76eb2011-10-11 11:44:09 +05304119 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07004120 msmsdcc_check_status((unsigned long) host);
4121 return IRQ_HANDLED;
4122}
4123
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004124static irqreturn_t
4125msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
4126{
4127 struct msmsdcc_host *host = dev_id;
4128
4129 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
4130 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304131 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004132 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304133 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004134 wake_lock(&host->sdio_wlock);
4135 msmsdcc_disable_irq_wake(host);
4136 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304137 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004138 }
4139 if (host->plat->is_sdio_al_client) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004140 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304141 spin_unlock(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304142 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304143 goto out_unlocked;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004144 }
4145 spin_unlock(&host->lock);
4146
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304147out_unlocked:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004148 return IRQ_HANDLED;
4149}
4150
San Mehat9d2bd732009-09-22 16:44:22 -07004151static void
4152msmsdcc_status_notify_cb(int card_present, void *dev_id)
4153{
4154 struct msmsdcc_host *host = dev_id;
4155
Girish K Sa3c76eb2011-10-11 11:44:09 +05304156 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07004157 card_present);
4158 msmsdcc_check_status((unsigned long) host);
4159}
4160
San Mehat9d2bd732009-09-22 16:44:22 -07004161static int
4162msmsdcc_init_dma(struct msmsdcc_host *host)
4163{
4164 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
4165 host->dma.host = host;
4166 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004167 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004168
4169 if (!host->dmares)
4170 return -ENODEV;
4171
4172 host->dma.nc = dma_alloc_coherent(NULL,
4173 sizeof(struct msmsdcc_nc_dmadata),
4174 &host->dma.nc_busaddr,
4175 GFP_KERNEL);
4176 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004177 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07004178 return -ENOMEM;
4179 }
4180 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
4181 host->dma.cmd_busaddr = host->dma.nc_busaddr;
4182 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
4183 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
4184 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07004185 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07004186
4187 return 0;
4188}
4189
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004190#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
4191/**
4192 * Allocate and Connect a SDCC peripheral's SPS endpoint
4193 *
4194 * This function allocates endpoint context and
4195 * connect it with memory endpoint by calling
4196 * appropriate SPS driver APIs.
4197 *
4198 * Also registers a SPS callback function with
4199 * SPS driver
4200 *
4201 * This function should only be called once typically
4202 * during driver probe.
4203 *
4204 * @host - Pointer to sdcc host structure
4205 * @ep - Pointer to sps endpoint data structure
4206 * @is_produce - 1 means Producer endpoint
4207 * 0 means Consumer endpoint
4208 *
4209 * @return - 0 if successful else negative value.
4210 *
4211 */
4212static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
4213 struct msmsdcc_sps_ep_conn_data *ep,
4214 bool is_producer)
4215{
4216 int rc = 0;
4217 struct sps_pipe *sps_pipe_handle;
4218 struct sps_connect *sps_config = &ep->config;
4219 struct sps_register_event *sps_event = &ep->event;
4220
4221 /* Allocate endpoint context */
4222 sps_pipe_handle = sps_alloc_endpoint();
4223 if (!sps_pipe_handle) {
4224 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
4225 mmc_hostname(host->mmc), is_producer);
4226 rc = -ENOMEM;
4227 goto out;
4228 }
4229
4230 /* Get default connection configuration for an endpoint */
4231 rc = sps_get_config(sps_pipe_handle, sps_config);
4232 if (rc) {
4233 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
4234 " rc=%d", mmc_hostname(host->mmc),
4235 (u32)sps_pipe_handle, rc);
4236 goto get_config_err;
4237 }
4238
4239 /* Modify the default connection configuration */
4240 if (is_producer) {
4241 /*
4242 * For SDCC producer transfer, source should be
4243 * SDCC peripheral where as destination should
4244 * be system memory.
4245 */
4246 sps_config->source = host->sps.bam_handle;
4247 sps_config->destination = SPS_DEV_HANDLE_MEM;
4248 /* Producer pipe will handle this connection */
4249 sps_config->mode = SPS_MODE_SRC;
4250 sps_config->options =
4251 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4252 } else {
4253 /*
4254 * For SDCC consumer transfer, source should be
4255 * system memory where as destination should
4256 * SDCC peripheral
4257 */
4258 sps_config->source = SPS_DEV_HANDLE_MEM;
4259 sps_config->destination = host->sps.bam_handle;
4260 sps_config->mode = SPS_MODE_DEST;
4261 sps_config->options =
4262 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4263 }
4264
4265 /* Producer pipe index */
4266 sps_config->src_pipe_index = host->sps.src_pipe_index;
4267 /* Consumer pipe index */
4268 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
4269 /*
4270 * This event thresold value is only significant for BAM-to-BAM
4271 * transfer. It's ignored for BAM-to-System mode transfer.
4272 */
4273 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304274
4275 /* Allocate maximum descriptor fifo size */
4276 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
4277 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004278 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
4279 sps_config->desc.size,
4280 &sps_config->desc.phys_base,
4281 GFP_KERNEL);
4282
Pratibhasagar V00b94332011-10-18 14:57:27 +05304283 if (!sps_config->desc.base) {
4284 rc = -ENOMEM;
4285 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
4286 , mmc_hostname(host->mmc));
4287 goto get_config_err;
4288 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004289 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
4290
4291 /* Establish connection between peripheral and memory endpoint */
4292 rc = sps_connect(sps_pipe_handle, sps_config);
4293 if (rc) {
4294 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4295 " rc=%d", mmc_hostname(host->mmc),
4296 (u32)sps_pipe_handle, rc);
4297 goto sps_connect_err;
4298 }
4299
4300 sps_event->mode = SPS_TRIGGER_CALLBACK;
4301 sps_event->options = SPS_O_EOT;
4302 sps_event->callback = msmsdcc_sps_complete_cb;
4303 sps_event->xfer_done = NULL;
4304 sps_event->user = (void *)host;
4305
4306 /* Register callback event for EOT (End of transfer) event. */
4307 rc = sps_register_event(sps_pipe_handle, sps_event);
4308 if (rc) {
4309 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4310 " rc=%d", mmc_hostname(host->mmc),
4311 (u32)sps_pipe_handle, rc);
4312 goto reg_event_err;
4313 }
4314 /* Now save the sps pipe handle */
4315 ep->pipe_handle = sps_pipe_handle;
4316 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
4317 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
4318 __func__, is_producer ? "READ" : "WRITE",
4319 (u32)sps_pipe_handle, sps_config->desc.phys_base);
4320 goto out;
4321
4322reg_event_err:
4323 sps_disconnect(sps_pipe_handle);
4324sps_connect_err:
4325 dma_free_coherent(mmc_dev(host->mmc),
4326 sps_config->desc.size,
4327 sps_config->desc.base,
4328 sps_config->desc.phys_base);
4329get_config_err:
4330 sps_free_endpoint(sps_pipe_handle);
4331out:
4332 return rc;
4333}
4334
4335/**
4336 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
4337 *
4338 * This function disconnect endpoint and deallocates
4339 * endpoint context.
4340 *
4341 * This function should only be called once typically
4342 * during driver remove.
4343 *
4344 * @host - Pointer to sdcc host structure
4345 * @ep - Pointer to sps endpoint data structure
4346 *
4347 */
4348static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
4349 struct msmsdcc_sps_ep_conn_data *ep)
4350{
4351 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4352 struct sps_connect *sps_config = &ep->config;
4353 struct sps_register_event *sps_event = &ep->event;
4354
4355 sps_event->xfer_done = NULL;
4356 sps_event->callback = NULL;
4357 sps_register_event(sps_pipe_handle, sps_event);
4358 sps_disconnect(sps_pipe_handle);
4359 dma_free_coherent(mmc_dev(host->mmc),
4360 sps_config->desc.size,
4361 sps_config->desc.base,
4362 sps_config->desc.phys_base);
4363 sps_free_endpoint(sps_pipe_handle);
4364}
4365
4366/**
4367 * Reset SDCC peripheral's SPS endpoint
4368 *
4369 * This function disconnects an endpoint.
4370 *
4371 * This function should be called for reseting
4372 * SPS endpoint when data transfer error is
4373 * encountered during data transfer. This
4374 * can be considered as soft reset to endpoint.
4375 *
4376 * This function should only be called if
4377 * msmsdcc_sps_init() is already called.
4378 *
4379 * @host - Pointer to sdcc host structure
4380 * @ep - Pointer to sps endpoint data structure
4381 *
4382 * @return - 0 if successful else negative value.
4383 */
4384static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
4385 struct msmsdcc_sps_ep_conn_data *ep)
4386{
4387 int rc = 0;
4388 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4389
4390 rc = sps_disconnect(sps_pipe_handle);
4391 if (rc) {
4392 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
4393 " rc=%d", mmc_hostname(host->mmc), __func__,
4394 (u32)sps_pipe_handle, rc);
4395 goto out;
4396 }
4397 out:
4398 return rc;
4399}
4400
4401/**
4402 * Restore SDCC peripheral's SPS endpoint
4403 *
4404 * This function connects an endpoint.
4405 *
4406 * This function should be called for restoring
4407 * SPS endpoint after data transfer error is
4408 * encountered during data transfer. This
4409 * can be considered as soft reset to endpoint.
4410 *
4411 * This function should only be called if
4412 * msmsdcc_sps_reset_ep() is called before.
4413 *
4414 * @host - Pointer to sdcc host structure
4415 * @ep - Pointer to sps endpoint data structure
4416 *
4417 * @return - 0 if successful else negative value.
4418 */
4419static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
4420 struct msmsdcc_sps_ep_conn_data *ep)
4421{
4422 int rc = 0;
4423 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4424 struct sps_connect *sps_config = &ep->config;
4425 struct sps_register_event *sps_event = &ep->event;
4426
4427 /* Establish connection between peripheral and memory endpoint */
4428 rc = sps_connect(sps_pipe_handle, sps_config);
4429 if (rc) {
4430 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
4431 " rc=%d", mmc_hostname(host->mmc), __func__,
4432 (u32)sps_pipe_handle, rc);
4433 goto out;
4434 }
4435
4436 /* Register callback event for EOT (End of transfer) event. */
4437 rc = sps_register_event(sps_pipe_handle, sps_event);
4438 if (rc) {
4439 pr_err("%s: %s: sps_register_event() failed!!!"
4440 " pipe_handle=0x%x, rc=%d",
4441 mmc_hostname(host->mmc), __func__,
4442 (u32)sps_pipe_handle, rc);
4443 goto reg_event_err;
4444 }
4445 goto out;
4446
4447reg_event_err:
4448 sps_disconnect(sps_pipe_handle);
4449out:
4450 return rc;
4451}
4452
4453/**
Krishna Konda5af8f972012-05-14 16:15:24 -07004454 * Handle BAM device's global error condition
4455 *
4456 * This is an error handler for the SDCC bam device
4457 *
4458 * This function is registered as a callback with SPS-BAM
4459 * driver and will called in case there are an errors for
4460 * the SDCC BAM deivce. Any error conditions in the BAM
4461 * device are global and will be result in this function
4462 * being called once per device.
4463 *
4464 * This function will be called from the sps driver's
4465 * interrupt context.
4466 *
4467 * @sps_cb_case - indicates what error it is
4468 * @user - Pointer to sdcc host structure
4469 */
4470static void
4471msmsdcc_sps_bam_global_irq_cb(enum sps_callback_case sps_cb_case, void *user)
4472{
4473 struct msmsdcc_host *host = (struct msmsdcc_host *)user;
4474 struct mmc_request *mrq;
4475 unsigned long flags;
4476 int32_t error = 0;
4477
4478 BUG_ON(!host);
4479 BUG_ON(!is_sps_mode(host));
4480
4481 if (sps_cb_case == SPS_CALLBACK_BAM_ERROR_IRQ) {
4482 /**
4483 * Reset the all endpoints along with reseting the sps device.
4484 */
4485 host->sps.pipe_reset_pending = true;
4486 host->sps.reset_device = true;
4487
4488 pr_err("%s: BAM Global ERROR IRQ happened\n",
4489 mmc_hostname(host->mmc));
4490 error = EAGAIN;
4491 } else if (sps_cb_case == SPS_CALLBACK_BAM_HRESP_ERR_IRQ) {
4492 /**
4493 * This means that there was an AHB access error and
4494 * the address we are trying to read/write is something
4495 * we dont have priviliges to do so.
4496 */
4497 pr_err("%s: BAM HRESP_ERR_IRQ happened\n",
4498 mmc_hostname(host->mmc));
4499 error = EACCES;
4500 } else {
4501 /**
4502 * This should not have happened ideally. If this happens
4503 * there is some seriously wrong.
4504 */
4505 pr_err("%s: BAM global IRQ callback received, type:%d\n",
4506 mmc_hostname(host->mmc), (u32) sps_cb_case);
4507 error = EIO;
4508 }
4509
4510 spin_lock_irqsave(&host->lock, flags);
4511
4512 mrq = host->curr.mrq;
4513
4514 if (mrq && mrq->cmd) {
4515 msmsdcc_dump_sdcc_state(host);
4516
4517 if (!mrq->cmd->error)
4518 mrq->cmd->error = -error;
4519 if (host->curr.data) {
4520 if (mrq->data && !mrq->data->error)
4521 mrq->data->error = -error;
4522 host->curr.data_xfered = 0;
4523 if (host->sps.sg && is_sps_mode(host)) {
4524 /* Stop current SPS transfer */
4525 msmsdcc_sps_exit_curr_xfer(host);
4526 } else {
4527 /* this condition should not have happened */
4528 pr_err("%s: something is seriously wrong. "\
4529 "Funtion: %s, line: %d\n",
4530 mmc_hostname(host->mmc),
4531 __func__, __LINE__);
4532 }
4533 } else {
4534 /* this condition should not have happened */
4535 pr_err("%s: something is seriously wrong. Funtion: "\
4536 "%s, line: %d\n", mmc_hostname(host->mmc),
4537 __func__, __LINE__);
4538 }
4539 }
4540 spin_unlock_irqrestore(&host->lock, flags);
4541}
4542
4543/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004544 * Initialize SPS HW connected with SDCC core
4545 *
4546 * This function register BAM HW resources with
4547 * SPS driver and then initialize 2 SPS endpoints
4548 *
4549 * This function should only be called once typically
4550 * during driver probe.
4551 *
4552 * @host - Pointer to sdcc host structure
4553 *
4554 * @return - 0 if successful else negative value.
4555 *
4556 */
4557static int msmsdcc_sps_init(struct msmsdcc_host *host)
4558{
4559 int rc = 0;
4560 struct sps_bam_props bam = {0};
4561
4562 host->bam_base = ioremap(host->bam_memres->start,
4563 resource_size(host->bam_memres));
4564 if (!host->bam_base) {
4565 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
4566 " size=0x%x", mmc_hostname(host->mmc),
4567 host->bam_memres->start,
4568 (host->bam_memres->end -
4569 host->bam_memres->start));
4570 rc = -ENOMEM;
4571 goto out;
4572 }
4573
4574 bam.phys_addr = host->bam_memres->start;
4575 bam.virt_addr = host->bam_base;
4576 /*
4577 * This event thresold value is only significant for BAM-to-BAM
4578 * transfer. It's ignored for BAM-to-System mode transfer.
4579 */
4580 bam.event_threshold = 0x10; /* Pipe event threshold */
4581 /*
4582 * This threshold controls when the BAM publish
4583 * the descriptor size on the sideband interface.
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304584 * SPS HW will be used for data transfer size even
4585 * less than SDCC FIFO size. So let's set BAM summing
4586 * thresold to SPS_MIN_XFER_SIZE bytes.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004587 */
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304588 bam.summing_threshold = SPS_MIN_XFER_SIZE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004589 /* SPS driver wll handle the SDCC BAM IRQ */
4590 bam.irq = (u32)host->bam_irqres->start;
4591 bam.manage = SPS_BAM_MGR_LOCAL;
Krishna Konda5af8f972012-05-14 16:15:24 -07004592 bam.callback = msmsdcc_sps_bam_global_irq_cb;
4593 bam.user = (void *)host;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004594
4595 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
4596 (u32)bam.phys_addr);
4597 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
4598 (u32)bam.virt_addr);
4599
4600 /* Register SDCC Peripheral BAM device to SPS driver */
4601 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
4602 if (rc) {
4603 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
4604 mmc_hostname(host->mmc), rc);
4605 goto reg_bam_err;
4606 }
4607 pr_info("%s: BAM device registered. bam_handle=0x%x",
4608 mmc_hostname(host->mmc), host->sps.bam_handle);
4609
4610 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
4611 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
4612
4613 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
4614 SPS_PROD_PERIPHERAL);
4615 if (rc)
4616 goto sps_reset_err;
4617 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
4618 SPS_CONS_PERIPHERAL);
4619 if (rc)
4620 goto cons_conn_err;
4621
4622 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
4623 mmc_hostname(host->mmc),
4624 (unsigned long long)host->bam_memres->start,
4625 (unsigned int)host->bam_irqres->start);
4626 goto out;
4627
4628cons_conn_err:
4629 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4630sps_reset_err:
4631 sps_deregister_bam_device(host->sps.bam_handle);
4632reg_bam_err:
4633 iounmap(host->bam_base);
4634out:
4635 return rc;
4636}
4637
4638/**
4639 * De-initialize SPS HW connected with SDCC core
4640 *
4641 * This function deinitialize SPS endpoints and then
4642 * deregisters BAM resources from SPS driver.
4643 *
4644 * This function should only be called once typically
4645 * during driver remove.
4646 *
4647 * @host - Pointer to sdcc host structure
4648 *
4649 */
4650static void msmsdcc_sps_exit(struct msmsdcc_host *host)
4651{
4652 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
4653 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4654 sps_deregister_bam_device(host->sps.bam_handle);
4655 iounmap(host->bam_base);
4656}
4657#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
4658
4659static ssize_t
4660show_polling(struct device *dev, struct device_attribute *attr, char *buf)
4661{
4662 struct mmc_host *mmc = dev_get_drvdata(dev);
4663 struct msmsdcc_host *host = mmc_priv(mmc);
4664 int poll;
4665 unsigned long flags;
4666
4667 spin_lock_irqsave(&host->lock, flags);
4668 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
4669 spin_unlock_irqrestore(&host->lock, flags);
4670
4671 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
4672}
4673
4674static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05304675store_polling(struct device *dev, struct device_attribute *attr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004676 const char *buf, size_t count)
4677{
4678 struct mmc_host *mmc = dev_get_drvdata(dev);
4679 struct msmsdcc_host *host = mmc_priv(mmc);
4680 int value;
4681 unsigned long flags;
4682
4683 sscanf(buf, "%d", &value);
4684
4685 spin_lock_irqsave(&host->lock, flags);
4686 if (value) {
4687 mmc->caps |= MMC_CAP_NEEDS_POLL;
4688 mmc_detect_change(host->mmc, 0);
4689 } else {
4690 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4691 }
4692#ifdef CONFIG_HAS_EARLYSUSPEND
4693 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
4694#endif
4695 spin_unlock_irqrestore(&host->lock, flags);
4696 return count;
4697}
4698
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304699static ssize_t
4700show_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
4701 char *buf)
4702{
4703 struct mmc_host *mmc = dev_get_drvdata(dev);
4704 struct msmsdcc_host *host = mmc_priv(mmc);
4705
4706 return snprintf(buf, PAGE_SIZE, "%u\n",
4707 host->msm_bus_vote.is_max_bw_needed);
4708}
4709
4710static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05304711store_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304712 const char *buf, size_t count)
4713{
4714 struct mmc_host *mmc = dev_get_drvdata(dev);
4715 struct msmsdcc_host *host = mmc_priv(mmc);
4716 uint32_t value;
4717 unsigned long flags;
4718
4719 if (!kstrtou32(buf, 0, &value)) {
4720 spin_lock_irqsave(&host->lock, flags);
4721 host->msm_bus_vote.is_max_bw_needed = !!value;
4722 spin_unlock_irqrestore(&host->lock, flags);
4723 }
4724
4725 return count;
4726}
4727
Pratibhasagar V13d1d032012-07-09 20:12:38 +05304728static ssize_t
4729show_idle_timeout(struct device *dev, struct device_attribute *attr,
4730 char *buf)
4731{
4732 struct mmc_host *mmc = dev_get_drvdata(dev);
4733 struct msmsdcc_host *host = mmc_priv(mmc);
4734
4735 return snprintf(buf, PAGE_SIZE, "%u (Min 5 sec)\n",
4736 host->idle_tout_ms / 1000);
4737}
4738
4739static ssize_t
4740store_idle_timeout(struct device *dev, struct device_attribute *attr,
4741 const char *buf, size_t count)
4742{
4743 struct mmc_host *mmc = dev_get_drvdata(dev);
4744 struct msmsdcc_host *host = mmc_priv(mmc);
4745 unsigned int long flags;
4746 int timeout; /* in secs */
4747
4748 if (!kstrtou32(buf, 0, &timeout)
4749 && (timeout > MSM_MMC_DEFAULT_IDLE_TIMEOUT / 1000)) {
4750 spin_lock_irqsave(&host->lock, flags);
4751 host->idle_tout_ms = timeout * 1000;
4752 spin_unlock_irqrestore(&host->lock, flags);
4753 }
4754 return count;
4755}
4756
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004757#ifdef CONFIG_HAS_EARLYSUSPEND
4758static void msmsdcc_early_suspend(struct early_suspend *h)
4759{
4760 struct msmsdcc_host *host =
4761 container_of(h, struct msmsdcc_host, early_suspend);
4762 unsigned long flags;
4763
4764 spin_lock_irqsave(&host->lock, flags);
4765 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
4766 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4767 spin_unlock_irqrestore(&host->lock, flags);
4768};
4769static void msmsdcc_late_resume(struct early_suspend *h)
4770{
4771 struct msmsdcc_host *host =
4772 container_of(h, struct msmsdcc_host, early_suspend);
4773 unsigned long flags;
4774
4775 if (host->polling_enabled) {
4776 spin_lock_irqsave(&host->lock, flags);
4777 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
4778 mmc_detect_change(host->mmc, 0);
4779 spin_unlock_irqrestore(&host->lock, flags);
4780 }
4781};
4782#endif
4783
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304784static void msmsdcc_print_regs(const char *name, void __iomem *base,
4785 u32 phys_base, unsigned int no_of_regs)
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304786{
4787 unsigned int i;
4788
4789 if (!base)
4790 return;
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304791
4792 pr_info("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
4793 " =====\n", name, phys_base, (u32)base);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304794 for (i = 0; i < no_of_regs; i = i + 4) {
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304795 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
4796 (u32)readl_relaxed(base + i*4),
4797 (u32)readl_relaxed(base + ((i+1)*4)),
4798 (u32)readl_relaxed(base + ((i+2)*4)),
4799 (u32)readl_relaxed(base + ((i+3)*4)));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304800 }
4801}
4802
4803static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
4804{
4805 /* Dump current state of SDCC clocks, power and irq */
4806 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304807 (host->pwr ? "ON" : "OFF"));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304808 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304809 mmc_hostname(host->mmc),
4810 (atomic_read(&host->clks_on) ? "ON" : "OFF"),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304811 (u32)clk_get_rate(host->clk));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304812 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
4813 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
4814
4815 /* Now dump SDCC registers. Don't print FIFO registers */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304816 if (atomic_read(&host->clks_on))
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304817 msmsdcc_print_regs("SDCC-CORE", host->base,
4818 host->core_memres->start, 28);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304819
4820 if (host->curr.data) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304821 if (!msmsdcc_is_dma_possible(host, host->curr.data))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304822 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304823 else if (is_dma_mode(host))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304824 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
4825 mmc_hostname(host->mmc), host->dma.busy,
4826 host->dma.channel, host->dma.crci);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304827 else if (is_sps_mode(host)) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304828 if (host->sps.busy && atomic_read(&host->clks_on))
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304829 msmsdcc_print_regs("SDCC-DML", host->dml_base,
4830 host->dml_memres->start,
4831 16);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304832 pr_info("%s: SPS mode: busy=%d\n",
4833 mmc_hostname(host->mmc), host->sps.busy);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304834 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304835
4836 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
4837 mmc_hostname(host->mmc), host->curr.xfer_size,
4838 host->curr.data_xfered, host->curr.xfer_remain);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304839 }
4840
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304841 pr_info("%s: got_dataend=%d, prog_enable=%d,"
Subhash Jadavani8706ced2012-05-25 16:09:21 +05304842 " wait_for_auto_prog_done=%d, got_auto_prog_done=%d,"
4843 " req_tout_ms=%d\n", mmc_hostname(host->mmc),
4844 host->curr.got_dataend, host->prog_enable,
4845 host->curr.wait_for_auto_prog_done,
4846 host->curr.got_auto_prog_done, host->curr.req_tout_ms);
subhashj245831e2012-04-30 18:46:17 +05304847 msmsdcc_print_rpm_info(host);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304848}
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304849
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004850static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
4851{
4852 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4853 struct mmc_request *mrq;
4854 unsigned long flags;
4855
4856 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004857 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004858 pr_info("%s: %s: dummy CMD52 timeout\n",
4859 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004860 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004861 }
4862
4863 mrq = host->curr.mrq;
4864
4865 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304866 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
4867 mrq->cmd->opcode);
4868 msmsdcc_dump_sdcc_state(host);
4869
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004870 if (!mrq->cmd->error)
4871 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304872 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004873 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004874 if (mrq->data && !mrq->data->error)
4875 mrq->data->error = -ETIMEDOUT;
4876 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304877 if (host->dma.sg && is_dma_mode(host)) {
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07004878 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304879 } else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004880 /* Stop current SPS transfer */
4881 msmsdcc_sps_exit_curr_xfer(host);
4882 } else {
4883 msmsdcc_reset_and_restore(host);
4884 msmsdcc_stop_data(host);
4885 if (mrq->data && mrq->data->stop)
4886 msmsdcc_start_command(host,
4887 mrq->data->stop, 0);
4888 else
4889 msmsdcc_request_end(host, mrq);
4890 }
4891 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304892 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05304893 host->curr.wait_for_auto_prog_done = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004894 msmsdcc_reset_and_restore(host);
4895 msmsdcc_request_end(host, mrq);
4896 }
4897 }
4898 spin_unlock_irqrestore(&host->lock, flags);
4899}
4900
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05304901/*
4902 * msmsdcc_dt_get_array - Wrapper fn to read an array of 32 bit integers
4903 *
4904 * @dev: device node from which the property value is to be read.
4905 * @prop_name: name of the property to be searched.
4906 * @out_array: filled array returned to caller
4907 * @len: filled array size returned to caller
4908 * @size: expected size of the array
4909 *
4910 * If expected "size" doesn't match with "len" an error is returned. If
4911 * expected size is zero, the length of actual array is returned provided
4912 * return value is zero.
4913 *
4914 * RETURNS:
4915 * zero on success, negative error if failed.
4916 */
4917static int msmsdcc_dt_get_array(struct device *dev, const char *prop_name,
4918 u32 **out_array, int *len, int size)
4919{
4920 int ret = 0;
4921 u32 *array = NULL;
4922 struct device_node *np = dev->of_node;
4923
4924 if (of_get_property(np, prop_name, len)) {
4925 size_t sz;
4926 sz = *len = *len / sizeof(*array);
4927
4928 if (sz > 0 && !(size > 0 && (sz != size))) {
4929 array = devm_kzalloc(dev, sz * sizeof(*array),
4930 GFP_KERNEL);
4931 if (!array) {
4932 dev_err(dev, "%s: no memory\n", prop_name);
4933 ret = -ENOMEM;
4934 goto out;
4935 }
4936
4937 ret = of_property_read_u32_array(np, prop_name,
4938 array, sz);
4939 if (ret < 0) {
4940 dev_err(dev, "%s: error reading array %d\n",
4941 prop_name, ret);
4942 goto out;
4943 }
4944 } else {
4945 dev_err(dev, "%s invalid size\n", prop_name);
4946 ret = -EINVAL;
4947 goto out;
4948 }
4949 } else {
4950 dev_err(dev, "%s not specified\n", prop_name);
4951 ret = -EINVAL;
4952 goto out;
4953 }
4954 *out_array = array;
4955out:
4956 if (ret)
4957 *len = 0;
4958 return ret;
4959}
4960
4961static int msmsdcc_dt_get_pad_pull_info(struct device *dev, int id,
4962 struct msm_mmc_pad_pull_data **pad_pull_data)
4963{
4964 int ret = 0, base = 0, len, i;
4965 u32 *tmp;
4966 struct msm_mmc_pad_pull_data *pull_data;
4967 struct msm_mmc_pad_pull *pull;
4968
4969 switch (id) {
4970 case 1:
4971 base = TLMM_PULL_SDC1_CLK;
4972 break;
4973 case 2:
4974 base = TLMM_PULL_SDC2_CLK;
4975 break;
4976 case 3:
4977 base = TLMM_PULL_SDC3_CLK;
4978 break;
4979 case 4:
4980 base = TLMM_PULL_SDC4_CLK;
4981 break;
4982 default:
4983 dev_err(dev, "%s: Invalid slot id\n", __func__);
4984 ret = -EINVAL;
4985 goto err;
4986 }
4987
4988 pull_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_pull_data),
4989 GFP_KERNEL);
4990 if (!pull_data) {
4991 dev_err(dev, "No memory msm_mmc_pad_pull_data\n");
4992 ret = -ENOMEM;
4993 goto err;
4994 }
4995 pull_data->size = 3; /* array size for clk, cmd, data */
4996
4997 /* Allocate on, off configs for clk, cmd, data */
4998 pull = devm_kzalloc(dev, 2 * pull_data->size *\
4999 sizeof(struct msm_mmc_pad_pull), GFP_KERNEL);
5000 if (!pull) {
5001 dev_err(dev, "No memory for msm_mmc_pad_pull\n");
5002 ret = -ENOMEM;
5003 goto err;
5004 }
5005 pull_data->on = pull;
5006 pull_data->off = pull + pull_data->size;
5007
5008 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-pull-on",
5009 &tmp, &len, pull_data->size);
5010 if (!ret) {
5011 for (i = 0; i < len; i++) {
5012 pull_data->on[i].no = base + i;
5013 pull_data->on[i].val = tmp[i];
5014 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5015 i, pull_data->on[i].val);
5016 }
5017 } else {
5018 goto err;
5019 }
5020
5021 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-pull-off",
5022 &tmp, &len, pull_data->size);
5023 if (!ret) {
5024 for (i = 0; i < len; i++) {
5025 pull_data->off[i].no = base + i;
5026 pull_data->off[i].val = tmp[i];
5027 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5028 i, pull_data->off[i].val);
5029 }
5030 } else {
5031 goto err;
5032 }
5033
5034 *pad_pull_data = pull_data;
5035err:
5036 return ret;
5037}
5038
5039static int msmsdcc_dt_get_pad_drv_info(struct device *dev, int id,
5040 struct msm_mmc_pad_drv_data **pad_drv_data)
5041{
5042 int ret = 0, base = 0, len, i;
5043 u32 *tmp;
5044 struct msm_mmc_pad_drv_data *drv_data;
5045 struct msm_mmc_pad_drv *drv;
5046
5047 switch (id) {
5048 case 1:
5049 base = TLMM_HDRV_SDC1_CLK;
5050 break;
5051 case 2:
5052 base = TLMM_HDRV_SDC2_CLK;
5053 break;
5054 case 3:
5055 base = TLMM_HDRV_SDC3_CLK;
5056 break;
5057 case 4:
5058 base = TLMM_HDRV_SDC4_CLK;
5059 break;
5060 default:
5061 dev_err(dev, "%s: Invalid slot id\n", __func__);
5062 ret = -EINVAL;
5063 goto err;
5064 }
5065
5066 drv_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_drv_data),
5067 GFP_KERNEL);
5068 if (!drv_data) {
5069 dev_err(dev, "No memory for msm_mmc_pad_drv_data\n");
5070 ret = -ENOMEM;
5071 goto err;
5072 }
5073 drv_data->size = 3; /* array size for clk, cmd, data */
5074
5075 /* Allocate on, off configs for clk, cmd, data */
5076 drv = devm_kzalloc(dev, 2 * drv_data->size *\
5077 sizeof(struct msm_mmc_pad_drv), GFP_KERNEL);
5078 if (!drv) {
5079 dev_err(dev, "No memory msm_mmc_pad_drv\n");
5080 ret = -ENOMEM;
5081 goto err;
5082 }
5083 drv_data->on = drv;
5084 drv_data->off = drv + drv_data->size;
5085
5086 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-drv-on",
5087 &tmp, &len, drv_data->size);
5088 if (!ret) {
5089 for (i = 0; i < len; i++) {
5090 drv_data->on[i].no = base + i;
5091 drv_data->on[i].val = tmp[i];
5092 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5093 i, drv_data->on[i].val);
5094 }
5095 } else {
5096 goto err;
5097 }
5098
5099 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-drv-off",
5100 &tmp, &len, drv_data->size);
5101 if (!ret) {
5102 for (i = 0; i < len; i++) {
5103 drv_data->off[i].no = base + i;
5104 drv_data->off[i].val = tmp[i];
5105 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5106 i, drv_data->off[i].val);
5107 }
5108 } else {
5109 goto err;
5110 }
5111
5112 *pad_drv_data = drv_data;
5113err:
5114 return ret;
5115}
5116
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305117static void msmsdcc_dt_get_cd_wp_gpio(struct device *dev,
5118 struct mmc_platform_data *pdata)
5119{
5120 enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
5121 struct device_node *np = dev->of_node;
5122
5123 pdata->status_gpio = of_get_named_gpio_flags(np,
5124 "cd-gpios", 0, &flags);
5125 if (gpio_is_valid(pdata->status_gpio)) {
5126 pdata->status_irq = gpio_to_irq(pdata->status_gpio);
5127 pdata->is_status_gpio_active_low = flags & OF_GPIO_ACTIVE_LOW;
5128 }
5129
5130 pdata->wpswitch_gpio = of_get_named_gpio_flags(np,
5131 "wp-gpios", 0, &flags);
5132 if (gpio_is_valid(pdata->wpswitch_gpio))
5133 pdata->is_wpswitch_active_low = flags & OF_GPIO_ACTIVE_LOW;
5134}
5135
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305136static int msmsdcc_dt_parse_gpio_info(struct device *dev,
5137 struct mmc_platform_data *pdata)
5138{
5139 int ret = 0, id = 0, cnt, i;
5140 struct msm_mmc_pin_data *pin_data;
5141 struct device_node *np = dev->of_node;
5142
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305143 msmsdcc_dt_get_cd_wp_gpio(dev, pdata);
5144
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305145 pin_data = devm_kzalloc(dev, sizeof(*pin_data), GFP_KERNEL);
5146 if (!pin_data) {
5147 dev_err(dev, "No memory for pin_data\n");
5148 ret = -ENOMEM;
5149 goto err;
5150 }
5151
5152 cnt = of_gpio_count(np);
5153 if (cnt > 0) {
5154 pin_data->is_gpio = true;
5155
5156 pin_data->gpio_data = devm_kzalloc(dev,
5157 sizeof(struct msm_mmc_gpio_data), GFP_KERNEL);
5158 if (!pin_data->gpio_data) {
5159 dev_err(dev, "No memory for gpio_data\n");
5160 ret = -ENOMEM;
5161 goto err;
5162 }
5163 pin_data->gpio_data->size = cnt;
5164 pin_data->gpio_data->gpio = devm_kzalloc(dev,
5165 cnt * sizeof(struct msm_mmc_gpio), GFP_KERNEL);
5166 if (!pin_data->gpio_data->gpio) {
5167 dev_err(dev, "No memory for gpio\n");
5168 ret = -ENOMEM;
5169 goto err;
5170 }
5171
5172 for (i = 0; i < cnt; i++) {
5173 const char *name = NULL;
5174 char result[32];
5175 pin_data->gpio_data->gpio[i].no = of_get_gpio(np, i);
5176 of_property_read_string_index(np,
5177 "qcom,sdcc-gpio-names", i, &name);
5178
5179 snprintf(result, 32, "%s-%s",
5180 dev_name(dev), name ? name : "?");
5181 pin_data->gpio_data->gpio[i].name = result;
5182 dev_dbg(dev, "%s: gpio[%s] = %d\n", __func__,
5183 pin_data->gpio_data->gpio[i].name,
5184 pin_data->gpio_data->gpio[i].no);
5185 }
5186 } else {
5187 pin_data->pad_data = devm_kzalloc(dev,
5188 sizeof(struct msm_mmc_pad_data), GFP_KERNEL);
5189 if (!pin_data->pad_data) {
5190 dev_err(dev, "No memory for pin_data->pad_data\n");
5191 ret = -ENOMEM;
5192 goto err;
5193 }
5194
5195 of_property_read_u32(np, "cell-index", &id);
5196
5197 ret = msmsdcc_dt_get_pad_pull_info(dev, id,
5198 &pin_data->pad_data->pull);
5199 if (ret)
5200 goto err;
5201 ret = msmsdcc_dt_get_pad_drv_info(dev, id,
5202 &pin_data->pad_data->drv);
5203 if (ret)
5204 goto err;
5205 }
5206
5207 pdata->pin_data = pin_data;
5208err:
5209 if (ret)
5210 dev_err(dev, "%s failed with err %d\n", __func__, ret);
5211 return ret;
5212}
5213
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305214#define MAX_PROP_SIZE 32
5215static int msmsdcc_dt_parse_vreg_info(struct device *dev,
5216 struct msm_mmc_reg_data **vreg_data, const char *vreg_name)
5217{
5218 int len, ret = 0;
5219 const __be32 *prop;
5220 char prop_name[MAX_PROP_SIZE];
5221 struct msm_mmc_reg_data *vreg;
5222 struct device_node *np = dev->of_node;
5223
5224 snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", vreg_name);
5225 if (of_parse_phandle(np, prop_name, 0)) {
5226 vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
5227 if (!vreg) {
5228 dev_err(dev, "No memory for vreg: %s\n", vreg_name);
5229 ret = -ENOMEM;
5230 goto err;
5231 }
5232
5233 vreg->name = vreg_name;
5234
5235 snprintf(prop_name, MAX_PROP_SIZE,
5236 "qcom,sdcc-%s-always_on", vreg_name);
5237 if (of_get_property(np, prop_name, NULL))
5238 vreg->always_on = true;
5239
5240 snprintf(prop_name, MAX_PROP_SIZE,
5241 "qcom,sdcc-%s-lpm_sup", vreg_name);
5242 if (of_get_property(np, prop_name, NULL))
5243 vreg->lpm_sup = true;
5244
5245 snprintf(prop_name, MAX_PROP_SIZE,
5246 "qcom,sdcc-%s-voltage_level", vreg_name);
5247 prop = of_get_property(np, prop_name, &len);
5248 if (!prop || (len != (2 * sizeof(__be32)))) {
5249 dev_warn(dev, "%s %s property\n",
5250 prop ? "invalid format" : "no", prop_name);
5251 } else {
5252 vreg->low_vol_level = be32_to_cpup(&prop[0]);
5253 vreg->high_vol_level = be32_to_cpup(&prop[1]);
5254 }
5255
5256 snprintf(prop_name, MAX_PROP_SIZE,
5257 "qcom,sdcc-%s-current_level", vreg_name);
5258 prop = of_get_property(np, prop_name, &len);
5259 if (!prop || (len != (2 * sizeof(__be32)))) {
5260 dev_warn(dev, "%s %s property\n",
5261 prop ? "invalid format" : "no", prop_name);
5262 } else {
5263 vreg->lpm_uA = be32_to_cpup(&prop[0]);
5264 vreg->hpm_uA = be32_to_cpup(&prop[1]);
5265 }
5266
5267 *vreg_data = vreg;
5268 dev_dbg(dev, "%s: %s %s vol=[%d %d]uV, curr=[%d %d]uA\n",
5269 vreg->name, vreg->always_on ? "always_on," : "",
5270 vreg->lpm_sup ? "lpm_sup," : "", vreg->low_vol_level,
5271 vreg->high_vol_level, vreg->lpm_uA, vreg->hpm_uA);
5272 }
5273
5274err:
5275 return ret;
5276}
5277
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305278static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
5279{
5280 int i, ret;
5281 struct mmc_platform_data *pdata;
5282 struct device_node *np = dev->of_node;
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305283 u32 bus_width = 0, current_limit = 0;
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305284 u32 *clk_table, *sup_voltages;
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305285 int clk_table_len, sup_volt_len, len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305286
5287 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
5288 if (!pdata) {
5289 dev_err(dev, "could not allocate memory for platform data\n");
5290 goto err;
5291 }
5292
5293 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
5294 if (bus_width == 8) {
5295 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
5296 } else if (bus_width == 4) {
5297 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
5298 } else {
5299 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
5300 pdata->mmc_bus_width = 0;
5301 }
5302
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305303 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-sup-voltages",
5304 &sup_voltages, &sup_volt_len, 0);
5305 if (!ret) {
5306 for (i = 0; i < sup_volt_len; i += 2) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305307 u32 mask;
5308
5309 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
5310 sup_voltages[i + 1]);
5311 if (!mask)
5312 dev_err(dev, "Invalide voltage range %d\n", i);
5313 pdata->ocr_mask |= mask;
5314 }
5315 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305316 }
5317
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305318 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-clk-rates",
5319 &clk_table, &clk_table_len, 0);
5320 if (!ret) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305321 pdata->sup_clk_table = clk_table;
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305322 pdata->sup_clk_cnt = clk_table_len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305323 }
5324
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305325 pdata->vreg_data = devm_kzalloc(dev,
5326 sizeof(struct msm_mmc_slot_reg_data), GFP_KERNEL);
5327 if (!pdata->vreg_data) {
5328 dev_err(dev, "could not allocate memory for vreg_data\n");
5329 goto err;
5330 }
5331
5332 if (msmsdcc_dt_parse_vreg_info(dev,
5333 &pdata->vreg_data->vdd_data, "vdd"))
5334 goto err;
5335
5336 if (msmsdcc_dt_parse_vreg_info(dev,
5337 &pdata->vreg_data->vdd_io_data, "vdd-io"))
5338 goto err;
5339
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305340 if (msmsdcc_dt_parse_gpio_info(dev, pdata))
5341 goto err;
5342
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305343 len = of_property_count_strings(np, "qcom,sdcc-bus-speed-mode");
5344
5345 for (i = 0; i < len; i++) {
5346 const char *name = NULL;
5347
5348 of_property_read_string_index(np,
5349 "qcom,sdcc-bus-speed-mode", i, &name);
5350 if (!name)
5351 continue;
5352
5353 if (!strncmp(name, "SDR12", sizeof("SDR12")))
5354 pdata->uhs_caps |= MMC_CAP_UHS_SDR12;
5355 else if (!strncmp(name, "SDR25", sizeof("SDR25")))
5356 pdata->uhs_caps |= MMC_CAP_UHS_SDR25;
5357 else if (!strncmp(name, "SDR50", sizeof("SDR50")))
5358 pdata->uhs_caps |= MMC_CAP_UHS_SDR50;
5359 else if (!strncmp(name, "DDR50", sizeof("DDR50")))
5360 pdata->uhs_caps |= MMC_CAP_UHS_DDR50;
5361 else if (!strncmp(name, "SDR104", sizeof("SDR104")))
5362 pdata->uhs_caps |= MMC_CAP_UHS_SDR104;
5363 else if (!strncmp(name, "HS200_1p8v", sizeof("HS200_1p8v")))
5364 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_8V_SDR;
5365 else if (!strncmp(name, "HS200_1p2v", sizeof("HS200_1p2v")))
5366 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_2V_SDR;
5367 else if (!strncmp(name, "DDR_1p8v", sizeof("DDR_1p8v")))
5368 pdata->uhs_caps |= MMC_CAP_1_8V_DDR
5369 | MMC_CAP_UHS_DDR50;
5370 else if (!strncmp(name, "DDR_1p2v", sizeof("DDR_1p2v")))
5371 pdata->uhs_caps |= MMC_CAP_1_2V_DDR
5372 | MMC_CAP_UHS_DDR50;
5373 }
5374
5375 of_property_read_u32(np, "qcom,sdcc-current-limit", &current_limit);
5376 if (current_limit == 800)
5377 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_800;
5378 else if (current_limit == 600)
5379 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_600;
5380 else if (current_limit == 400)
5381 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_400;
5382 else if (current_limit == 200)
5383 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_200;
5384
5385 if (of_get_property(np, "qcom,sdcc-xpc", NULL))
5386 pdata->xpc_cap = true;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305387 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
5388 pdata->nonremovable = true;
5389 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
5390 pdata->disable_cmd23 = true;
5391
5392 return pdata;
5393err:
5394 return NULL;
5395}
5396
San Mehat9d2bd732009-09-22 16:44:22 -07005397static int
5398msmsdcc_probe(struct platform_device *pdev)
5399{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305400 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07005401 struct msmsdcc_host *host;
5402 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005403 unsigned long flags;
5404 struct resource *core_irqres = NULL;
5405 struct resource *bam_irqres = NULL;
5406 struct resource *core_memres = NULL;
5407 struct resource *dml_memres = NULL;
5408 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07005409 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07005410 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05305411 int ret = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07005412
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305413 if (pdev->dev.of_node) {
5414 plat = msmsdcc_populate_pdata(&pdev->dev);
5415 of_property_read_u32((&pdev->dev)->of_node,
5416 "cell-index", &pdev->id);
5417 } else {
5418 plat = pdev->dev.platform_data;
5419 }
San Mehat9d2bd732009-09-22 16:44:22 -07005420
5421 /* must have platform data */
5422 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005423 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005424 ret = -EINVAL;
5425 goto out;
5426 }
5427
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005428 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07005429 return -EINVAL;
5430
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305431 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
5432 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
5433 return -EINVAL;
5434 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005435
San Mehat9d2bd732009-09-22 16:44:22 -07005436 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005437 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005438 return -ENXIO;
5439 }
5440
Sujit Reddy Thumma1dfac2c2012-07-30 10:15:39 +05305441 core_memres = platform_get_resource_byname(pdev,
5442 IORESOURCE_MEM, "core_mem");
5443 bam_memres = platform_get_resource_byname(pdev,
5444 IORESOURCE_MEM, "bam_mem");
5445 dml_memres = platform_get_resource_byname(pdev,
5446 IORESOURCE_MEM, "dml_mem");
5447 core_irqres = platform_get_resource_byname(pdev,
5448 IORESOURCE_IRQ, "core_irq");
5449 bam_irqres = platform_get_resource_byname(pdev,
5450 IORESOURCE_IRQ, "bam_irq");
5451 dmares = platform_get_resource_byname(pdev,
5452 IORESOURCE_DMA, "dma_chnl");
5453 dma_crci_res = platform_get_resource_byname(pdev,
5454 IORESOURCE_DMA, "dma_crci");
San Mehat9d2bd732009-09-22 16:44:22 -07005455
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005456 if (!core_irqres || !core_memres) {
5457 pr_err("%s: Invalid sdcc core resource\n", __func__);
5458 return -ENXIO;
5459 }
5460
5461 /*
5462 * Both BAM and DML memory resource should be preset.
5463 * BAM IRQ resource should also be present.
5464 */
5465 if ((bam_memres && !dml_memres) ||
5466 (!bam_memres && dml_memres) ||
5467 ((bam_memres && dml_memres) && !bam_irqres)) {
5468 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005469 return -ENXIO;
5470 }
5471
5472 /*
5473 * Setup our host structure
5474 */
San Mehat9d2bd732009-09-22 16:44:22 -07005475 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
5476 if (!mmc) {
5477 ret = -ENOMEM;
5478 goto out;
5479 }
5480
5481 host = mmc_priv(mmc);
5482 host->pdev_id = pdev->id;
5483 host->plat = plat;
5484 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08005485 host->curr.cmd = NULL;
Sahitya Tummala19207f02011-05-02 18:10:01 +05305486
Sahitya Tummalad9df3272011-08-19 16:50:46 +05305487 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305488 set_hw_caps(host, MSMSDCC_SPS_BAM_SUP);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005489 else if (dmares)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305490 set_hw_caps(host, MSMSDCC_DMA_SUP);
San Mehat9d2bd732009-09-22 16:44:22 -07005491
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005492 host->base = ioremap(core_memres->start,
5493 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07005494 if (!host->base) {
5495 ret = -ENOMEM;
Sahitya Tummaladce7c752011-05-02 18:06:05 +05305496 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005497 }
5498
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005499 host->core_irqres = core_irqres;
5500 host->bam_irqres = bam_irqres;
5501 host->core_memres = core_memres;
5502 host->dml_memres = dml_memres;
5503 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07005504 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07005505 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07005506 spin_lock_init(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305507 mutex_init(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07005508
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005509#ifdef CONFIG_MMC_EMBEDDED_SDIO
5510 if (plat->embedded_sdio)
5511 mmc_set_embedded_sdio_data(mmc,
5512 &plat->embedded_sdio->cis,
5513 &plat->embedded_sdio->cccr,
5514 plat->embedded_sdio->funcs,
5515 plat->embedded_sdio->num_funcs);
5516#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005517
Sahitya Tummala62612cf2010-12-08 15:03:03 +05305518 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
5519 (unsigned long)host);
5520
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005521 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
5522 (unsigned long)host);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305523 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005524 /* Setup DMA */
Subhash Jadavani190657c2011-05-02 18:10:40 +05305525 ret = msmsdcc_init_dma(host);
5526 if (ret)
5527 goto ioremap_free;
5528 } else {
5529 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07005530 host->dma.crci = -1;
Subhash Jadavani190657c2011-05-02 18:10:40 +05305531 }
San Mehat9d2bd732009-09-22 16:44:22 -07005532
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005533 /*
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305534 * Setup SDCC bus voter clock.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005535 */
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305536 host->bus_clk = clk_get(&pdev->dev, "bus_clk");
5537 if (!IS_ERR_OR_NULL(host->bus_clk)) {
5538 /* Vote for max. clk rate for max. performance */
5539 ret = clk_set_rate(host->bus_clk, INT_MAX);
5540 if (ret)
5541 goto bus_clk_put;
5542 ret = clk_prepare_enable(host->bus_clk);
5543 if (ret)
5544 goto bus_clk_put;
San Mehat9d2bd732009-09-22 16:44:22 -07005545 }
5546
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005547 /*
5548 * Setup main peripheral bus clock
5549 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07005550 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005551 if (!IS_ERR(host->pclk)) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305552 ret = clk_prepare_enable(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005553 if (ret)
5554 goto pclk_put;
5555
5556 host->pclk_rate = clk_get_rate(host->pclk);
5557 }
5558
5559 /*
5560 * Setup SDC MMC clock
5561 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07005562 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07005563 if (IS_ERR(host->clk)) {
5564 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005565 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07005566 }
5567
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005568 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
Sahitya Tummala514d9ed2011-05-02 18:07:01 +05305569 if (ret) {
5570 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
5571 goto clk_put;
5572 }
5573
Asutosh Dasf5298c32012-04-03 14:51:47 +05305574 ret = clk_prepare_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07005575 if (ret)
5576 goto clk_put;
5577
San Mehat9d2bd732009-09-22 16:44:22 -07005578 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05305579 if (!host->clk_rate)
5580 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05305581
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305582 set_default_hw_caps(host);
5583
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05305584 /*
5585 * Set the register write delay according to min. clock frequency
5586 * supported and update later when the host->clk_rate changes.
5587 */
5588 host->reg_write_delay =
5589 (1 + ((3 * USEC_PER_SEC) /
5590 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005591
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305592 atomic_set(&host->clks_on, 1);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05305593 /* Apply Hard reset to SDCC to put it in power on default state */
5594 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005595
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005596#define MSM_MMC_DEFAULT_CPUDMA_LATENCY 200 /* usecs */
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305597 /* pm qos request to prevent apps idle power collapse */
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005598 if (host->plat->cpu_dma_latency)
5599 host->cpu_dma_latency = host->plat->cpu_dma_latency;
5600 else
5601 host->cpu_dma_latency = MSM_MMC_DEFAULT_CPUDMA_LATENCY;
5602 pm_qos_add_request(&host->pm_qos_req_dma,
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305603 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
5604
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305605 ret = msmsdcc_msm_bus_register(host);
5606 if (ret)
5607 goto pm_qos_remove;
5608
5609 if (host->msm_bus_vote.client_handle)
5610 INIT_DELAYED_WORK(&host->msm_bus_vote.vote_work,
5611 msmsdcc_msm_bus_work);
5612
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005613 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07005614 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005615 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07005616 goto clk_disable;
5617 }
5618
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005619
5620 /* Clocks has to be running before accessing SPS/DML HW blocks */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305621 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005622 /* Initialize SPS */
5623 ret = msmsdcc_sps_init(host);
5624 if (ret)
5625 goto vreg_deinit;
5626 /* Initialize DML */
5627 ret = msmsdcc_dml_init(host);
5628 if (ret)
5629 goto sps_exit;
5630 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05305631 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07005632
San Mehat9d2bd732009-09-22 16:44:22 -07005633 /*
5634 * Setup MMC host structure
5635 */
5636 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005637 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
5638 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005639 mmc->ocr_avail = plat->ocr_mask;
Sujit Reddy Thumma0e05f022012-06-11 19:44:18 +05305640 mmc->clkgate_delay = MSM_MMC_CLK_GATE_DELAY;
5641
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005642 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
5643 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07005644 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05305645 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
Asutosh Dasebd7d092012-07-09 19:08:26 +05305646 mmc->caps |= MMC_CAP_HW_RESET;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05305647 /*
5648 * If we send the CMD23 before multi block write/read command
5649 * then we need not to send CMD12 at the end of the transfer.
5650 * If we don't send the CMD12 then only way to detect the PROG_DONE
5651 * status is to use the AUTO_PROG_DONE status provided by SDCC4
5652 * controller. So let's enable the CMD23 for SDCC4 only.
5653 */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305654 if (!plat->disable_cmd23 && is_auto_prog_done(host))
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05305655 mmc->caps |= MMC_CAP_CMD23;
San Mehat9d2bd732009-09-22 16:44:22 -07005656
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005657 mmc->caps |= plat->uhs_caps;
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305658 mmc->caps2 |= plat->uhs_caps2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005659 /*
5660 * XPC controls the maximum current in the default speed mode of SDXC
5661 * card. XPC=0 means 100mA (max.) but speed class is not supported.
5662 * XPC=1 means 150mA (max.) and speed class is supported.
5663 */
5664 if (plat->xpc_cap)
5665 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
5666 MMC_CAP_SET_XPC_180);
5667
Maya Erez25e22612012-05-20 08:45:01 +03005668 mmc->caps2 |= MMC_CAP2_PACKED_WR;
Maya Erez8afe8d22012-05-20 15:11:52 +03005669 mmc->caps2 |= MMC_CAP2_PACKED_WR_CONTROL;
Subhash Jadavani6bb34a82012-04-18 13:18:40 +05305670 mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
Yaniv Gardi14098552012-06-04 10:56:03 +03005671 mmc->caps2 |= MMC_CAP2_SANITIZE;
5672
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005673 if (plat->nonremovable)
5674 mmc->caps |= MMC_CAP_NONREMOVABLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005675 mmc->caps |= MMC_CAP_SDIO_IRQ;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005676
Konstantin Dorfman9db69fc2012-06-01 14:04:45 +03005677 mmc->caps2 |= MMC_CAP2_INIT_BKOPS | MMC_CAP2_BKOPS;
5678
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005679 if (plat->is_sdio_al_client)
5680 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07005681
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305682 mmc->max_segs = msmsdcc_get_nr_sg(host);
5683 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
5684 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07005685
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305686 mmc->max_req_size = MMC_MAX_REQ_SIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07005687 mmc->max_seg_size = mmc->max_req_size;
5688
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005689 writel_relaxed(0, host->base + MMCIMASK0);
5690 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05305691 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005692
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005693 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
5694 mb();
5695 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07005696
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005697 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
5698 DRIVER_NAME " (cmd)", host);
5699 if (ret)
5700 goto dml_exit;
5701
5702 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
5703 DRIVER_NAME " (pio)", host);
5704 if (ret)
5705 goto irq_free;
5706
5707 /*
5708 * Enable SDCC IRQ only when host is powered on. Otherwise, this
5709 * IRQ is un-necessarily being monitored by MPM (Modem power
5710 * management block) during idle-power collapse. The MPM will be
5711 * configured to monitor the DATA1 GPIO line with level-low trigger
5712 * and thus depending on the GPIO status, it prevents TCXO shutdown
5713 * during idle-power collapse.
5714 */
5715 disable_irq(core_irqres->start);
5716 host->sdcc_irq_disabled = 1;
5717
5718 if (plat->sdiowakeup_irq) {
5719 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5720 mmc_hostname(mmc));
5721 ret = request_irq(plat->sdiowakeup_irq,
5722 msmsdcc_platform_sdiowakeup_irq,
5723 IRQF_SHARED | IRQF_TRIGGER_LOW,
5724 DRIVER_NAME "sdiowakeup", host);
5725 if (ret) {
5726 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
5727 plat->sdiowakeup_irq, ret);
5728 goto pio_irq_free;
5729 } else {
5730 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305731 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005732 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305733 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005734 }
5735 spin_unlock_irqrestore(&host->lock, flags);
5736 }
5737 }
5738
Subhash Jadavanic9b85752012-04-13 11:16:49 +05305739 if (host->plat->mpm_sdiowakeup_int) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005740 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5741 mmc_hostname(mmc));
5742 }
5743
5744 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
5745 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005746 /*
5747 * Setup card detect change
5748 */
5749
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305750 if (!plat->status_gpio)
5751 plat->status_gpio = -ENOENT;
5752 if (!plat->wpswitch_gpio)
5753 plat->wpswitch_gpio = -ENOENT;
5754
5755 if (plat->status || gpio_is_valid(plat->status_gpio)) {
Krishna Konda941604a2012-01-10 17:46:34 -08005756 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005757 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08005758 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005759 host->oldstat = msmsdcc_slot_status(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005760
Krishna Konda941604a2012-01-10 17:46:34 -08005761 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005762 }
San Mehat9d2bd732009-09-22 16:44:22 -07005763
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005764 if (plat->status_irq) {
5765 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07005766 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005767 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07005768 DRIVER_NAME " (slot)",
5769 host);
5770 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005771 pr_err("Unable to get slot IRQ %d (%d)\n",
5772 plat->status_irq, ret);
5773 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005774 }
5775 } else if (plat->register_status_notify) {
5776 plat->register_status_notify(msmsdcc_status_notify_cb, host);
5777 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005778 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07005779 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005780
5781 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005782
5783 ret = pm_runtime_set_active(&(pdev)->dev);
5784 if (ret < 0)
5785 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
5786 __func__, ret);
5787 /*
5788 * There is no notion of suspend/resume for SD/MMC/SDIO
5789 * cards. So host can be suspended/resumed with out
5790 * worrying about its children.
5791 */
5792 pm_suspend_ignore_children(&(pdev)->dev, true);
5793
5794 /*
5795 * MMC/SD/SDIO bus suspend/resume operations are defined
5796 * only for the slots that will be used for non-removable
5797 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
5798 * defined. Otherwise, they simply become card removal and
5799 * insertion events during suspend and resume respectively.
5800 * Hence, enable run-time PM only for slots for which bus
5801 * suspend/resume operations are defined.
5802 */
5803#ifdef CONFIG_MMC_UNSAFE_RESUME
5804 /*
5805 * If this capability is set, MMC core will enable/disable host
5806 * for every claim/release operation on a host. We use this
5807 * notification to increment/decrement runtime pm usage count.
5808 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005809 pm_runtime_enable(&(pdev)->dev);
5810#else
5811 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005812 pm_runtime_enable(&(pdev)->dev);
5813 }
5814#endif
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305815 host->idle_tout_ms = MSM_MMC_DEFAULT_IDLE_TIMEOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005816 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
5817 (unsigned long)host);
5818
San Mehat9d2bd732009-09-22 16:44:22 -07005819 mmc_add_host(mmc);
5820
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005821#ifdef CONFIG_HAS_EARLYSUSPEND
5822 host->early_suspend.suspend = msmsdcc_early_suspend;
5823 host->early_suspend.resume = msmsdcc_late_resume;
5824 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
5825 register_early_suspend(&host->early_suspend);
5826#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005827
Krishna Konda25786ec2011-07-25 16:21:36 -07005828 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
5829 " dmacrcri %d\n", mmc_hostname(mmc),
5830 (unsigned long long)core_memres->start,
5831 (unsigned int) core_irqres->start,
5832 (unsigned int) plat->status_irq, host->dma.channel,
5833 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005834
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305835 pr_info("%s: Controller capabilities: 0x%.8x\n",
5836 mmc_hostname(mmc), host->hw_caps);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005837 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
5838 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
5839 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
5840 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
5841 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
5842 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
5843 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
5844 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
5845 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
5846 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
5847 host->eject);
5848 pr_info("%s: Power save feature enable = %d\n",
5849 mmc_hostname(mmc), msmsdcc_pwrsave);
5850
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305851 if (is_dma_mode(host) && host->dma.channel != -1
Krishna Konda25786ec2011-07-25 16:21:36 -07005852 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005853 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005854 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005855 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005856 mmc_hostname(mmc), host->dma.cmd_busaddr,
5857 host->dma.cmdptr_busaddr);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305858 } else if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005859 pr_info("%s: SPS-BAM data transfer mode available\n",
5860 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005861 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005862 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005863
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005864#if defined(CONFIG_DEBUG_FS)
5865 msmsdcc_dbg_createhost(host);
5866#endif
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305867
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305868 host->max_bus_bw.show = show_sdcc_to_mem_max_bus_bw;
5869 host->max_bus_bw.store = store_sdcc_to_mem_max_bus_bw;
5870 sysfs_attr_init(&host->max_bus_bw.attr);
5871 host->max_bus_bw.attr.name = "max_bus_bw";
5872 host->max_bus_bw.attr.mode = S_IRUGO | S_IWUSR;
5873 ret = device_create_file(&pdev->dev, &host->max_bus_bw);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305874 if (ret)
5875 goto platform_irq_free;
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305876
5877 if (!plat->status_irq) {
5878 host->polling.show = show_polling;
5879 host->polling.store = store_polling;
5880 sysfs_attr_init(&host->polling.attr);
5881 host->polling.attr.name = "polling";
5882 host->polling.attr.mode = S_IRUGO | S_IWUSR;
5883 ret = device_create_file(&pdev->dev, &host->polling);
5884 if (ret)
5885 goto remove_max_bus_bw_file;
5886 }
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305887 host->idle_timeout.show = show_idle_timeout;
5888 host->idle_timeout.store = store_idle_timeout;
5889 sysfs_attr_init(&host->idle_timeout.attr);
5890 host->idle_timeout.attr.name = "idle_timeout";
5891 host->idle_timeout.attr.mode = S_IRUGO | S_IWUSR;
5892 ret = device_create_file(&pdev->dev, &host->idle_timeout);
5893 if (ret)
5894 goto remove_polling_file;
San Mehat9d2bd732009-09-22 16:44:22 -07005895 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005896
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305897 remove_polling_file:
5898 if (!plat->status_irq)
5899 device_remove_file(&pdev->dev, &host->polling);
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305900 remove_max_bus_bw_file:
5901 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005902 platform_irq_free:
5903 del_timer_sync(&host->req_tout_timer);
5904 pm_runtime_disable(&(pdev)->dev);
5905 pm_runtime_set_suspended(&(pdev)->dev);
5906
5907 if (plat->status_irq)
5908 free_irq(plat->status_irq, host);
5909 sdiowakeup_irq_free:
5910 wake_lock_destroy(&host->sdio_suspend_wlock);
5911 if (plat->sdiowakeup_irq)
5912 free_irq(plat->sdiowakeup_irq, host);
5913 pio_irq_free:
5914 if (plat->sdiowakeup_irq)
5915 wake_lock_destroy(&host->sdio_wlock);
5916 free_irq(core_irqres->start, host);
5917 irq_free:
5918 free_irq(core_irqres->start, host);
5919 dml_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305920 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005921 msmsdcc_dml_exit(host);
5922 sps_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305923 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005924 msmsdcc_sps_exit(host);
5925 vreg_deinit:
5926 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07005927 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005928 clk_disable(host->clk);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305929 msmsdcc_msm_bus_unregister(host);
5930 pm_qos_remove:
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005931 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305932 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07005933 clk_put:
5934 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005935 pclk_disable:
5936 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05305937 clk_disable_unprepare(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07005938 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005939 if (!IS_ERR(host->pclk))
5940 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305941 if (!IS_ERR_OR_NULL(host->bus_clk))
5942 clk_disable_unprepare(host->bus_clk);
5943 bus_clk_put:
5944 if (!IS_ERR_OR_NULL(host->bus_clk))
5945 clk_put(host->bus_clk);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305946 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005947 if (host->dmares)
5948 dma_free_coherent(NULL,
5949 sizeof(struct msmsdcc_nc_dmadata),
5950 host->dma.nc, host->dma.nc_busaddr);
5951 }
5952 ioremap_free:
Sahitya Tummaladce7c752011-05-02 18:06:05 +05305953 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07005954 host_free:
5955 mmc_free_host(mmc);
5956 out:
5957 return ret;
5958}
5959
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005960static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07005961{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005962 struct mmc_host *mmc = mmc_get_drvdata(pdev);
5963 struct mmc_platform_data *plat;
5964 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07005965
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005966 if (!mmc)
5967 return -ENXIO;
5968
5969 if (pm_runtime_suspended(&(pdev)->dev))
5970 pm_runtime_resume(&(pdev)->dev);
5971
5972 host = mmc_priv(mmc);
5973
5974 DBG(host, "Removing SDCC device = %d\n", pdev->id);
5975 plat = host->plat;
5976
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305977 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005978 if (!plat->status_irq)
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305979 device_remove_file(&pdev->dev, &host->polling);
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305980 device_remove_file(&pdev->dev, &host->idle_timeout);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005981
5982 del_timer_sync(&host->req_tout_timer);
5983 tasklet_kill(&host->dma_tlet);
5984 tasklet_kill(&host->sps.tlet);
5985 mmc_remove_host(mmc);
5986
5987 if (plat->status_irq)
5988 free_irq(plat->status_irq, host);
5989
5990 wake_lock_destroy(&host->sdio_suspend_wlock);
5991 if (plat->sdiowakeup_irq) {
5992 wake_lock_destroy(&host->sdio_wlock);
5993 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
5994 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07005995 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005996
5997 free_irq(host->core_irqres->start, host);
5998 free_irq(host->core_irqres->start, host);
5999
6000 clk_put(host->clk);
6001 if (!IS_ERR(host->pclk))
6002 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05306003 if (!IS_ERR_OR_NULL(host->bus_clk))
6004 clk_put(host->bus_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006005
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006006 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306007 pm_qos_remove_request(&host->pm_qos_req_dma);
6008
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306009 if (host->msm_bus_vote.client_handle) {
6010 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
6011 msmsdcc_msm_bus_unregister(host);
6012 }
6013
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006014 msmsdcc_vreg_init(host, false);
6015
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306016 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006017 if (host->dmares)
6018 dma_free_coherent(NULL,
6019 sizeof(struct msmsdcc_nc_dmadata),
6020 host->dma.nc, host->dma.nc_busaddr);
6021 }
6022
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306023 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006024 msmsdcc_dml_exit(host);
6025 msmsdcc_sps_exit(host);
6026 }
6027
6028 iounmap(host->base);
6029 mmc_free_host(mmc);
6030
6031#ifdef CONFIG_HAS_EARLYSUSPEND
6032 unregister_early_suspend(&host->early_suspend);
6033#endif
6034 pm_runtime_disable(&(pdev)->dev);
6035 pm_runtime_set_suspended(&(pdev)->dev);
6036
6037 return 0;
6038}
6039
6040#ifdef CONFIG_MSM_SDIO_AL
6041int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
6042{
6043 struct msmsdcc_host *host = mmc_priv(mmc);
6044 unsigned long flags;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306045 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006046
Asutosh Dasf5298c32012-04-03 14:51:47 +05306047 mutex_lock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006048 spin_lock_irqsave(&host->lock, flags);
6049 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
6050 enable ? "En" : "Dis");
6051
6052 if (enable) {
6053 if (!host->sdcc_irq_disabled) {
6054 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05306055 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006056 host->sdcc_irq_disabled = 1;
6057 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306058 rc = msmsdcc_setup_clocks(host, false);
6059 if (rc)
6060 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006061
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05306062 if (host->plat->sdio_lpm_gpio_setup &&
6063 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006064 spin_unlock_irqrestore(&host->lock, flags);
6065 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
6066 spin_lock_irqsave(&host->lock, flags);
6067 host->sdio_gpio_lpm = 1;
6068 }
6069
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306070 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006071 msmsdcc_enable_irq_wake(host);
6072 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306073 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006074 }
6075 } else {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306076 rc = msmsdcc_setup_clocks(host, true);
6077 if (rc)
6078 goto out;
6079
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306080 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006081 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306082 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006083 msmsdcc_disable_irq_wake(host);
6084 }
6085
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05306086 if (host->plat->sdio_lpm_gpio_setup &&
6087 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006088 spin_unlock_irqrestore(&host->lock, flags);
6089 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
6090 spin_lock_irqsave(&host->lock, flags);
6091 host->sdio_gpio_lpm = 0;
6092 }
6093
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306094 if (host->sdcc_irq_disabled && atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006095 writel_relaxed(host->mci_irqenable,
6096 host->base + MMCIMASK0);
6097 mb();
6098 enable_irq(host->core_irqres->start);
6099 host->sdcc_irq_disabled = 0;
6100 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006101 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306102out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006103 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05306104 mutex_unlock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306105 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006106}
6107#else
6108int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
6109{
6110 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07006111}
6112#endif
6113
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006114#ifdef CONFIG_PM
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306115#ifdef CONFIG_MMC_CLKGATE
6116static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6117{
6118 struct mmc_host *mmc = host->mmc;
6119 unsigned long flags;
6120
6121 mmc_host_clk_hold(mmc);
6122 spin_lock_irqsave(&mmc->clk_lock, flags);
6123 mmc->clk_old = mmc->ios.clock;
6124 mmc->ios.clock = 0;
6125 mmc->clk_gated = true;
6126 spin_unlock_irqrestore(&mmc->clk_lock, flags);
6127 mmc_set_ios(mmc);
6128 mmc_host_clk_release(mmc);
6129}
6130
6131static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6132{
6133 struct mmc_host *mmc = host->mmc;
6134
6135 mmc_host_clk_hold(mmc);
6136 mmc->ios.clock = host->clk_rate;
6137 mmc_set_ios(mmc);
6138 mmc_host_clk_release(mmc);
6139}
6140#else
6141static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6142{
6143 struct mmc_host *mmc = host->mmc;
6144
6145 mmc->ios.clock = 0;
6146 mmc_set_ios(mmc);
6147}
6148
6149static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6150{
6151 struct mmc_host *mmc = host->mmc;
6152
6153 mmc->ios.clock = host->clk_rate;
6154 mmc_set_ios(mmc);
6155}
6156#endif
6157
San Mehat9d2bd732009-09-22 16:44:22 -07006158static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006159msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006160{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006161 struct mmc_host *mmc = dev_get_drvdata(dev);
6162 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006163 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306164 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07006165
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306166 if (host->plat->is_sdio_al_client) {
6167 rc = 0;
6168 goto out;
San Mehat9d2bd732009-09-22 16:44:22 -07006169 }
San Mehat9d2bd732009-09-22 16:44:22 -07006170
Sahitya Tummala7661a452011-07-18 13:28:35 +05306171 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006172 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006173 host->sdcc_suspending = 1;
6174 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07006175
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006176 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006177 * MMC core thinks that host is disabled by now since
6178 * runtime suspend is scheduled after msmsdcc_disable()
6179 * is called. Thus, MMC core will try to enable the host
6180 * while suspending it. This results in a synchronous
6181 * runtime resume request while in runtime suspending
6182 * context and hence inorder to complete this resume
6183 * requet, it will wait for suspend to be complete,
6184 * but runtime suspend also can not proceed further
6185 * until the host is resumed. Thus, it leads to a hang.
6186 * Hence, increase the pm usage count before suspending
6187 * the host so that any resume requests after this will
6188 * simple become pm usage counter increment operations.
6189 */
6190 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306191 /* If there is pending detect work abort runtime suspend */
6192 if (unlikely(work_busy(&mmc->detect.work)))
6193 rc = -EAGAIN;
6194 else
6195 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006196 pm_runtime_put_noidle(dev);
6197
6198 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306199 spin_lock_irqsave(&host->lock, flags);
6200 host->sdcc_suspended = true;
6201 spin_unlock_irqrestore(&host->lock, flags);
6202 if (mmc->card && mmc_card_sdio(mmc->card) &&
6203 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006204 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306205 * If SDIO function driver doesn't want
6206 * to power off the card, atleast turn off
6207 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006208 */
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306209 msmsdcc_gate_clock(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006210 }
6211 }
6212 host->sdcc_suspending = 0;
6213 mmc->suspend_task = NULL;
6214 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
6215 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006216 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306217 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306218out:
6219 /* set bus bandwidth to 0 immediately */
6220 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
San Mehat9d2bd732009-09-22 16:44:22 -07006221 return rc;
6222}
6223
6224static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006225msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006226{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006227 struct mmc_host *mmc = dev_get_drvdata(dev);
6228 struct msmsdcc_host *host = mmc_priv(mmc);
6229 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07006230
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006231 if (host->plat->is_sdio_al_client)
6232 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07006233
Sahitya Tummala7661a452011-07-18 13:28:35 +05306234 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006235 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306236 if (mmc->card && mmc_card_sdio(mmc->card) &&
6237 mmc_card_keep_power(mmc)) {
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306238 msmsdcc_ungate_clock(host);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05306239 }
San Mehat9d2bd732009-09-22 16:44:22 -07006240
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006241 mmc_resume_host(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006242
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006243 /*
6244 * FIXME: Clearing of flags must be handled in clients
6245 * resume handler.
6246 */
6247 spin_lock_irqsave(&host->lock, flags);
6248 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306249 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006250 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07006251
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006252 /*
6253 * After resuming the host wait for sometime so that
6254 * the SDIO work will be processed.
6255 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306256 if (mmc->card && mmc_card_sdio(mmc->card)) {
Subhash Jadavanic9b85752012-04-13 11:16:49 +05306257 if ((host->plat->mpm_sdiowakeup_int ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006258 host->plat->sdiowakeup_irq) &&
6259 wake_lock_active(&host->sdio_wlock))
6260 wake_lock_timeout(&host->sdio_wlock, 1);
6261 }
6262
6263 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006264 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05306265 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006266 return 0;
6267}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006268
6269static int msmsdcc_runtime_idle(struct device *dev)
6270{
6271 struct mmc_host *mmc = dev_get_drvdata(dev);
6272 struct msmsdcc_host *host = mmc_priv(mmc);
6273
6274 if (host->plat->is_sdio_al_client)
6275 return 0;
6276
6277 /* Idle timeout is not configurable for now */
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306278 pm_schedule_suspend(dev, host->idle_tout_ms);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006279
6280 return -EAGAIN;
6281}
6282
6283static int msmsdcc_pm_suspend(struct device *dev)
6284{
6285 struct mmc_host *mmc = dev_get_drvdata(dev);
6286 struct msmsdcc_host *host = mmc_priv(mmc);
6287 int rc = 0;
6288
6289 if (host->plat->is_sdio_al_client)
6290 return 0;
6291
6292
6293 if (host->plat->status_irq)
6294 disable_irq(host->plat->status_irq);
6295
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006296 if (!pm_runtime_suspended(dev))
6297 rc = msmsdcc_runtime_suspend(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006298
6299 return rc;
6300}
6301
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306302static int msmsdcc_suspend_noirq(struct device *dev)
6303{
6304 struct mmc_host *mmc = dev_get_drvdata(dev);
6305 struct msmsdcc_host *host = mmc_priv(mmc);
6306 int rc = 0;
6307
6308 /*
6309 * After platform suspend there may be active request
6310 * which might have enabled clocks. For example, in SDIO
6311 * case, ksdioirq thread might have scheduled after sdcc
6312 * suspend but before system freeze. In that case abort
6313 * suspend and retry instead of keeping the clocks on
6314 * during suspend and not allowing TCXO.
6315 */
6316
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306317 if (atomic_read(&host->clks_on) && !host->plat->is_sdio_al_client) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306318 pr_warn("%s: clocks are on after suspend, aborting system "
6319 "suspend\n", mmc_hostname(mmc));
6320 rc = -EAGAIN;
6321 }
6322
6323 return rc;
6324}
6325
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006326static int msmsdcc_pm_resume(struct device *dev)
6327{
6328 struct mmc_host *mmc = dev_get_drvdata(dev);
6329 struct msmsdcc_host *host = mmc_priv(mmc);
6330 int rc = 0;
6331
6332 if (host->plat->is_sdio_al_client)
6333 return 0;
6334
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006335 if (mmc->card && mmc_card_sdio(mmc->card))
Sahitya Tummalafb486372011-09-02 19:01:49 +05306336 rc = msmsdcc_runtime_resume(dev);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006337 else
6338 host->pending_resume = true;
6339
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006340 if (host->plat->status_irq) {
6341 msmsdcc_check_status((unsigned long)host);
6342 enable_irq(host->plat->status_irq);
6343 }
6344
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006345 return rc;
6346}
6347
Daniel Walker08ecfde2010-06-23 12:32:20 -07006348#else
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006349static int msmsdcc_runtime_suspend(struct device *dev)
6350{
6351 return 0;
6352}
6353static int msmsdcc_runtime_idle(struct device *dev)
6354{
6355 return 0;
6356}
6357static int msmsdcc_pm_suspend(struct device *dev)
6358{
6359 return 0;
6360}
6361static int msmsdcc_pm_resume(struct device *dev)
6362{
6363 return 0;
6364}
6365static int msmsdcc_suspend_noirq(struct device *dev)
6366{
6367 return 0;
6368}
6369static int msmsdcc_runtime_resume(struct device *dev)
6370{
6371 return 0;
6372}
Daniel Walker08ecfde2010-06-23 12:32:20 -07006373#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006374
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006375static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
6376 .runtime_suspend = msmsdcc_runtime_suspend,
6377 .runtime_resume = msmsdcc_runtime_resume,
6378 .runtime_idle = msmsdcc_runtime_idle,
6379 .suspend = msmsdcc_pm_suspend,
6380 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306381 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006382};
6383
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306384static const struct of_device_id msmsdcc_dt_match[] = {
6385 {.compatible = "qcom,msm-sdcc"},
6386
6387};
6388MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
6389
San Mehat9d2bd732009-09-22 16:44:22 -07006390static struct platform_driver msmsdcc_driver = {
6391 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006392 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07006393 .driver = {
6394 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006395 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306396 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07006397 },
6398};
6399
6400static int __init msmsdcc_init(void)
6401{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006402#if defined(CONFIG_DEBUG_FS)
6403 int ret = 0;
6404 ret = msmsdcc_dbg_init();
6405 if (ret) {
6406 pr_err("Failed to create debug fs dir \n");
6407 return ret;
6408 }
6409#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006410 return platform_driver_register(&msmsdcc_driver);
6411}
San Mehat9d2bd732009-09-22 16:44:22 -07006412
San Mehat9d2bd732009-09-22 16:44:22 -07006413static void __exit msmsdcc_exit(void)
6414{
6415 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006416
6417#if defined(CONFIG_DEBUG_FS)
6418 debugfs_remove(debugfs_file);
6419 debugfs_remove(debugfs_dir);
6420#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006421}
6422
6423module_init(msmsdcc_init);
6424module_exit(msmsdcc_exit);
6425
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006426MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07006427MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006428
6429#if defined(CONFIG_DEBUG_FS)
6430
6431static int
6432msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
6433{
6434 file->private_data = inode->i_private;
6435 return 0;
6436}
6437
6438static ssize_t
6439msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
6440 size_t count, loff_t *ppos)
6441{
6442 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08006443 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006444 int max, i;
6445
6446 i = 0;
6447 max = sizeof(buf) - 1;
6448
6449 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
6450 host->curr.cmd, host->curr.data);
6451 if (host->curr.cmd) {
6452 struct mmc_command *cmd = host->curr.cmd;
6453
6454 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
6455 cmd->opcode, cmd->arg, cmd->flags);
6456 }
6457 if (host->curr.data) {
6458 struct mmc_data *data = host->curr.data;
6459 i += scnprintf(buf + i, max - i,
6460 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
6461 data->timeout_ns, data->timeout_clks,
6462 data->blksz, data->blocks, data->error,
6463 data->flags);
6464 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
6465 host->curr.xfer_size, host->curr.xfer_remain,
6466 host->curr.data_xfered, host->dma.sg);
6467 }
6468
6469 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
6470}
6471
6472static const struct file_operations msmsdcc_dbg_state_ops = {
6473 .read = msmsdcc_dbg_state_read,
6474 .open = msmsdcc_dbg_state_open,
6475};
6476
6477static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
6478{
6479 if (debugfs_dir) {
6480 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
6481 0644, debugfs_dir, host,
6482 &msmsdcc_dbg_state_ops);
6483 }
6484}
6485
6486static int __init msmsdcc_dbg_init(void)
6487{
6488 int err;
6489
6490 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
6491 if (IS_ERR(debugfs_dir)) {
6492 err = PTR_ERR(debugfs_dir);
6493 debugfs_dir = NULL;
6494 return err;
6495 }
6496
6497 return 0;
6498}
6499#endif