blob: 804a6ede1cc93e847eb6b2c4e38f12121328a941 [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
Subhash Jadavani1371d192012-08-16 18:46:57 +05303294 pr_info("%s: PM: sdcc_suspended=%d, pending_resume=%d, sdcc_suspending=%d\n",
3295 mmc_hostname(host->mmc), host->sdcc_suspended,
3296 host->pending_resume, host->sdcc_suspending);
subhashj245831e2012-04-30 18:46:17 +05303297 pr_info("%s: RPM: runtime_status=%d, usage_count=%d,"
3298 " is_suspended=%d, disable_depth=%d, runtime_error=%d,"
3299 " request_pending=%d, request=%d\n",
3300 mmc_hostname(host->mmc), dev->power.runtime_status,
3301 atomic_read(&dev->power.usage_count),
3302 dev->power.is_suspended, dev->power.disable_depth,
3303 dev->power.runtime_error, dev->power.request_pending,
3304 dev->power.request);
3305}
3306
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003307static int msmsdcc_enable(struct mmc_host *mmc)
3308{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003309 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003310 struct device *dev = mmc->parent;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003311 struct msmsdcc_host *host = mmc_priv(mmc);
3312
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303313 msmsdcc_pm_qos_update_latency(host, 1);
3314
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003315 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303316 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003317
Subhash Jadavani1371d192012-08-16 18:46:57 +05303318 if (host->sdcc_suspended && host->pending_resume) {
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003319 host->pending_resume = false;
3320 pm_runtime_get_noresume(dev);
3321 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303322 goto skip_get_sync;
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003323 }
3324
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303325 if (dev->power.runtime_status == RPM_SUSPENDING) {
3326 if (mmc->suspend_task == current) {
3327 pm_runtime_get_noresume(dev);
3328 goto out;
3329 }
Sujit Reddy Thumma112bd752012-06-20 12:29:45 +05303330 } else if (dev->power.runtime_status == RPM_RESUMING) {
3331 pm_runtime_get_noresume(dev);
3332 goto out;
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303333 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003334
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303335 rc = pm_runtime_get_sync(dev);
3336
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303337skip_get_sync:
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303338 if (rc < 0) {
Subhash Jadavani1371d192012-08-16 18:46:57 +05303339 WARN(1, "%s: %s: failed with error %d\n", mmc_hostname(mmc),
3340 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303341 msmsdcc_print_rpm_info(host);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303342 return rc;
3343 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303344out:
3345 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303346 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003347}
3348
Steve Mucklef132c6c2012-06-06 18:30:57 -07003349static int msmsdcc_disable(struct mmc_host *mmc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003350{
3351 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303352 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003353
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303354 msmsdcc_pm_qos_update_latency(host, 0);
3355
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303356 if (mmc->card && mmc_card_sdio(mmc->card)) {
3357 rc = 0;
3358 goto out;
3359 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303360
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303361 if (host->plat->disable_runtime_pm)
3362 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003363
3364 rc = pm_runtime_put_sync(mmc->parent);
3365
Subhash Jadavani1371d192012-08-16 18:46:57 +05303366 if (rc < 0) {
3367 WARN(1, "%s: %s: failed with error %d\n", mmc_hostname(mmc),
3368 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303369 msmsdcc_print_rpm_info(host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003370 return rc;
3371 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303372
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303373out:
3374 msmsdcc_msm_bus_queue_work(host);
3375 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003376}
3377#else
subhashj245831e2012-04-30 18:46:17 +05303378static void msmsdcc_print_rpm_info(struct msmsdcc_host *host) {}
3379
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303380static int msmsdcc_enable(struct mmc_host *mmc)
3381{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003382 struct device *dev = mmc->parent;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303383 struct msmsdcc_host *host = mmc_priv(mmc);
Sujit Reddy Thumma7f5051c2012-05-04 10:14:07 +05303384 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303385
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303386 msmsdcc_pm_qos_update_latency(host, 1);
3387
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303388 if (mmc->card && mmc_card_sdio(mmc->card)) {
3389 rc = 0;
3390 goto out;
3391 }
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003392
3393 if (host->sdcc_suspended && host->pending_resume) {
3394 host->pending_resume = false;
3395 rc = msmsdcc_runtime_resume(dev);
3396 goto out;
3397 }
3398
Asutosh Dasf5298c32012-04-03 14:51:47 +05303399 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303400 rc = msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303401 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303402
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003403out:
3404 if (rc < 0) {
3405 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3406 __func__, rc);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303407 msmsdcc_pm_qos_update_latency(host, 0);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003408 return rc;
3409 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303410 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303411 return 0;
3412}
3413
Steve Mucklef132c6c2012-06-06 18:30:57 -07003414static int msmsdcc_disable(struct mmc_host *mmc)
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303415{
3416 struct msmsdcc_host *host = mmc_priv(mmc);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303417 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303418
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303419 msmsdcc_pm_qos_update_latency(host, 0);
3420
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303421 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303422 goto out;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303423
Asutosh Dasf5298c32012-04-03 14:51:47 +05303424 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303425 rc = msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303426 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303427
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303428 if (rc) {
3429 msmsdcc_pm_qos_update_latency(host, 1);
3430 return rc;
3431 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303432out:
3433 msmsdcc_msm_bus_queue_work(host);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303434 return rc;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303435}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003436#endif
3437
Subhash Jadavani937c7502012-06-01 15:34:46 +05303438static int msmsdcc_switch_io_voltage(struct mmc_host *mmc,
3439 struct mmc_ios *ios)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003440{
3441 struct msmsdcc_host *host = mmc_priv(mmc);
3442 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303443 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003444
Subhash Jadavani00083572012-02-15 16:18:01 +05303445 spin_lock_irqsave(&host->lock, flags);
3446 host->io_pad_pwr_switch = 0;
3447 spin_unlock_irqrestore(&host->lock, flags);
3448
Subhash Jadavani937c7502012-06-01 15:34:46 +05303449 switch (ios->signal_voltage) {
3450 case MMC_SIGNAL_VOLTAGE_330:
3451 /* Set VDD IO to high voltage range (2.7v - 3.6v) */
3452 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303453 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303454 case MMC_SIGNAL_VOLTAGE_180:
3455 break;
3456 case MMC_SIGNAL_VOLTAGE_120:
3457 /*
3458 * For eMMC cards, VDD_IO voltage range must be changed
3459 * only if it operates in HS200 SDR 1.2V mode or in
3460 * DDR 1.2V mode.
3461 */
3462 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_SET_LEVEL, 1200000);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003463 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303464 default:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003465 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303466 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003467 goto out;
3468 }
San Mehat9d2bd732009-09-22 16:44:22 -07003469
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003470 /*
3471 * If we are here means voltage switch from high voltage to
3472 * low voltage is required
3473 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303474 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003475
3476 /*
3477 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
3478 * register until they become all zeros.
3479 */
3480 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303481 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003482 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
3483 mmc_hostname(mmc), __func__);
3484 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07003485 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003486
3487 /* Stop SD CLK output. */
3488 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3489 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303490 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003491 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003492
3493 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05303494 * Switch VDD Io from high voltage range (2.7v - 3.6v) to
3495 * low voltage range (1.7v - 1.95v).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003496 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303497 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303498 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003499 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003500
3501 spin_lock_irqsave(&host->lock, flags);
3502 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3503 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303504 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003505 host->io_pad_pwr_switch = 1;
3506 spin_unlock_irqrestore(&host->lock, flags);
3507
3508 /* Wait 5 ms for the voltage regulater in the card to become stable. */
3509 usleep_range(5000, 5500);
3510
3511 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303512 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003513 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3514 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303515 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003516 spin_unlock_irqrestore(&host->lock, flags);
3517
3518 /*
3519 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
3520 * don't become all ones within 1 ms then a Voltage Switch
3521 * sequence has failed and a power cycle to the card is required.
3522 * Otherwise Voltage Switch sequence is completed successfully.
3523 */
3524 usleep_range(1000, 1500);
3525
3526 spin_lock_irqsave(&host->lock, flags);
3527 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
3528 != (0xF << 1)) {
3529 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
3530 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303531 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003532 goto out_unlock;
3533 }
3534
3535out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303536 /* Enable PWRSAVE */
3537 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3538 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303539 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003540 spin_unlock_irqrestore(&host->lock, flags);
3541out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303542 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003543}
3544
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303545static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003546{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003547 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003548
3549 /* Program the MCLK value to MCLK_FREQ bit field */
3550 if (host->clk_rate <= 112000000)
3551 mclk_freq = 0;
3552 else if (host->clk_rate <= 125000000)
3553 mclk_freq = 1;
3554 else if (host->clk_rate <= 137000000)
3555 mclk_freq = 2;
3556 else if (host->clk_rate <= 150000000)
3557 mclk_freq = 3;
3558 else if (host->clk_rate <= 162000000)
3559 mclk_freq = 4;
3560 else if (host->clk_rate <= 175000000)
3561 mclk_freq = 5;
3562 else if (host->clk_rate <= 187000000)
3563 mclk_freq = 6;
3564 else if (host->clk_rate <= 200000000)
3565 mclk_freq = 7;
3566
3567 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3568 & ~(7 << 24)) | (mclk_freq << 24)),
3569 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003570}
3571
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303572/* Initialize the DLL (Programmable Delay Line ) */
3573static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003574{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003575 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303576 unsigned long flags;
3577 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003578
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303579 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003580 /*
3581 * Make sure that clock is always enabled when DLL
3582 * tuning is in progress. Keeping PWRSAVE ON may
3583 * turn off the clock. So let's disable the PWRSAVE
3584 * here and re-enable it once tuning is completed.
3585 */
3586 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3587 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303588 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303589
3590 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3591 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3592 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3593
3594 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3595 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3596 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3597
3598 msmsdcc_cm_sdc4_dll_set_freq(host);
3599
3600 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3601 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3602 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3603
3604 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3605 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3606 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3607
3608 /* Set DLL_EN bit to 1. */
3609 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3610 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3611
3612 /* Set CK_OUT_EN bit to 1. */
3613 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3614 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3615
3616 wait_cnt = 50;
3617 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3618 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3619 /* max. wait for 50us sec for LOCK bit to be set */
3620 if (--wait_cnt == 0) {
3621 pr_err("%s: %s: DLL failed to LOCK\n",
3622 mmc_hostname(host->mmc), __func__);
3623 rc = -ETIMEDOUT;
3624 goto out;
3625 }
3626 /* wait for 1us before polling again */
3627 udelay(1);
3628 }
3629
3630out:
3631 /* re-enable PWRSAVE */
3632 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3633 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303634 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303635 spin_unlock_irqrestore(&host->lock, flags);
3636
3637 return rc;
3638}
3639
3640static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3641 u8 poll)
3642{
3643 int rc = 0;
3644 u32 wait_cnt = 50;
3645 u8 ck_out_en = 0;
3646
3647 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3648 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3649 MCI_CK_OUT_EN);
3650
3651 while (ck_out_en != poll) {
3652 if (--wait_cnt == 0) {
3653 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3654 mmc_hostname(host->mmc), __func__, poll);
3655 rc = -ETIMEDOUT;
3656 goto out;
3657 }
3658 udelay(1);
3659
3660 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3661 MCI_CK_OUT_EN);
3662 }
3663out:
3664 return rc;
3665}
3666
3667/*
3668 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3669 * calibration sequence. This function should be called before
3670 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3671 * commands (CMD17/CMD18).
3672 *
3673 * This function gets called when host spinlock acquired.
3674 */
3675static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3676{
3677 int rc = 0;
3678 u32 config;
3679
3680 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3681 config |= MCI_CDR_EN;
3682 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3683 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3684
3685 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3686 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3687 if (rc)
3688 goto err_out;
3689
3690 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3691 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3692 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3693
3694 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3695 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3696 if (rc)
3697 goto err_out;
3698
3699 goto out;
3700
3701err_out:
3702 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3703out:
3704 return rc;
3705}
3706
3707static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3708 u8 phase)
3709{
3710 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303711 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3712 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3713 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303714 unsigned long flags;
3715 u32 config;
3716
3717 spin_lock_irqsave(&host->lock, flags);
3718
3719 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3720 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3721 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3722 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3723
3724 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3725 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3726 if (rc)
3727 goto err_out;
3728
3729 /*
3730 * Write the selected DLL clock output phase (0 ... 15)
3731 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
3732 */
3733 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3734 & ~(0xF << 20))
3735 | (grey_coded_phase_table[phase] << 20)),
3736 host->base + MCI_DLL_CONFIG);
3737
3738 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3739 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3740 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3741
3742 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3743 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3744 if (rc)
3745 goto err_out;
3746
3747 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3748 config |= MCI_CDR_EN;
3749 config &= ~MCI_CDR_EXT_EN;
3750 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3751 goto out;
3752
3753err_out:
3754 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3755 mmc_hostname(host->mmc), __func__, phase);
3756out:
3757 spin_unlock_irqrestore(&host->lock, flags);
3758 return rc;
3759}
3760
3761/*
3762 * Find out the greatest range of consecuitive selected
3763 * DLL clock output phases that can be used as sampling
3764 * setting for SD3.0 UHS-I card read operation (in SDR104
3765 * timing mode) or for eMMC4.5 card read operation (in HS200
3766 * timing mode).
3767 * Select the 3/4 of the range and configure the DLL with the
3768 * selected DLL clock output phase.
3769*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303770static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303771 u8 *phase_table, u8 total_phases)
3772{
Subhash Jadavani6159c622012-03-15 19:05:55 +05303773 #define MAX_PHASES 16
Subhash Jadavani34187042012-03-02 10:59:49 +05303774 int ret;
Subhash Jadavani6159c622012-03-15 19:05:55 +05303775 u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
3776 u8 phases_per_row[MAX_PHASES] = {0};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303777 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303778 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3779 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303780
Subhash Jadavani6159c622012-03-15 19:05:55 +05303781 if (!total_phases || (total_phases > MAX_PHASES)) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303782 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3783 mmc_hostname(host->mmc), __func__, total_phases);
3784 return -EINVAL;
3785 }
3786
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303787 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303788 ranges[row_index][col_index] = phase_table[cnt];
3789 phases_per_row[row_index] += 1;
3790 col_index++;
3791
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303792 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303793 continue;
3794 /* check if next phase in phase_table is consecutive or not */
3795 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3796 row_index++;
3797 col_index = 0;
3798 }
3799 }
3800
Subhash Jadavani6159c622012-03-15 19:05:55 +05303801 if (row_index >= MAX_PHASES)
3802 return -EINVAL;
3803
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303804 /* Check if phase-0 is present in first valid window? */
3805 if (!ranges[0][0]) {
3806 phase_0_found = true;
3807 phase_0_raw_index = 0;
3808 /* Check if cycle exist between 2 valid windows */
3809 for (cnt = 1; cnt <= row_index; cnt++) {
3810 if (phases_per_row[cnt]) {
Subhash Jadavani6159c622012-03-15 19:05:55 +05303811 for (i = 0; i < phases_per_row[cnt]; i++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303812 if (ranges[cnt][i] == 15) {
3813 phase_15_found = true;
3814 phase_15_raw_index = cnt;
3815 break;
3816 }
3817 }
3818 }
3819 }
3820 }
3821
3822 /* If 2 valid windows form cycle then merge them as single window */
3823 if (phase_0_found && phase_15_found) {
3824 /* number of phases in raw where phase 0 is present */
3825 u8 phases_0 = phases_per_row[phase_0_raw_index];
3826 /* number of phases in raw where phase 15 is present */
3827 u8 phases_15 = phases_per_row[phase_15_raw_index];
3828
Subhash Jadavani6159c622012-03-15 19:05:55 +05303829 if (phases_0 + phases_15 >= MAX_PHASES)
3830 /*
3831 * If there are more than 1 phase windows then total
3832 * number of phases in both the windows should not be
3833 * more than or equal to MAX_PHASES.
3834 */
3835 return -EINVAL;
3836
3837 /* Merge 2 cyclic windows */
3838 i = phases_15;
3839 for (cnt = 0; cnt < phases_0; cnt++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303840 ranges[phase_15_raw_index][i] =
3841 ranges[phase_0_raw_index][cnt];
Subhash Jadavani6159c622012-03-15 19:05:55 +05303842 if (++i >= MAX_PHASES)
3843 break;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303844 }
Subhash Jadavani6159c622012-03-15 19:05:55 +05303845
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303846 phases_per_row[phase_0_raw_index] = 0;
3847 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
3848 }
3849
3850 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303851 if (phases_per_row[cnt] > curr_max) {
3852 curr_max = phases_per_row[cnt];
3853 selected_row_index = cnt;
3854 }
3855 }
3856
Subhash Jadavani6159c622012-03-15 19:05:55 +05303857 i = ((curr_max * 3) / 4);
3858 if (i)
3859 i--;
3860
Subhash Jadavani34187042012-03-02 10:59:49 +05303861 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303862
Subhash Jadavani6159c622012-03-15 19:05:55 +05303863 if (ret >= MAX_PHASES) {
3864 ret = -EINVAL;
3865 pr_err("%s: %s: invalid phase selected=%d\n",
3866 mmc_hostname(host->mmc), __func__, ret);
3867 }
3868
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303869 return ret;
3870}
3871
Girish K Sa3f41692012-02-29 12:00:09 +05303872static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303873{
3874 int rc = 0;
3875 struct msmsdcc_host *host = mmc_priv(mmc);
3876 unsigned long flags;
3877 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303878 const u32 *tuning_block_pattern = tuning_block_64;
3879 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303880
3881 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
3882
3883 /* Tuning is only required for SDR104 modes */
3884 if (!host->tuning_needed) {
3885 rc = 0;
3886 goto exit;
3887 }
3888
3889 spin_lock_irqsave(&host->lock, flags);
3890 WARN(!host->pwr, "SDCC power is turned off\n");
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303891 WARN(!atomic_read(&host->clks_on), "SDCC clocks are turned off\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303892 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
3893
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303894 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303895 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
3896 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
3897 tuning_block_pattern = tuning_block_128;
3898 size = sizeof(tuning_block_128);
3899 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303900 spin_unlock_irqrestore(&host->lock, flags);
3901
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003902 /* first of all reset the tuning block */
3903 rc = msmsdcc_init_cm_sdc4_dll(host);
3904 if (rc)
3905 goto out;
3906
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303907 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003908 if (!data_buf) {
3909 rc = -ENOMEM;
3910 goto out;
3911 }
3912
3913 phase = 0;
3914 do {
3915 struct mmc_command cmd = {0};
3916 struct mmc_data data = {0};
3917 struct mmc_request mrq = {
3918 .cmd = &cmd,
3919 .data = &data
3920 };
3921 struct scatterlist sg;
3922
3923 /* set the phase in delay line hw block */
3924 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3925 if (rc)
3926 goto kfree;
3927
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303928 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003929 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
3930
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303931 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003932 data.blocks = 1;
3933 data.flags = MMC_DATA_READ;
3934 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
3935
3936 data.sg = &sg;
3937 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303938 sg_init_one(&sg, data_buf, size);
3939 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003940 mmc_wait_for_req(mmc, &mrq);
3941
3942 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303943 !memcmp(data_buf, tuning_block_pattern, size)) {
3944 /* tuning is successful at this tuning point */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003945 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303946 pr_debug("%s: %s: found good phase = %d\n",
3947 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003948 }
3949 } while (++phase < 16);
3950
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003951 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303952 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303953 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05303954 if (rc < 0)
3955 goto kfree;
3956 else
3957 phase = (u8)rc;
3958
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003959 /*
3960 * Finally set the selected phase in delay
3961 * line hw block.
3962 */
3963 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3964 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303965 goto kfree;
3966 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
3967 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003968 } else {
3969 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303970 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003971 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303972 msmsdcc_dump_sdcc_state(host);
3973 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003974 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003975
3976kfree:
3977 kfree(data_buf);
3978out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303979 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303980 host->tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303981 spin_unlock_irqrestore(&host->lock, flags);
3982exit:
3983 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003984 return rc;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003985}
3986
Asutosh Dasebd7d092012-07-09 19:08:26 +05303987/*
3988 * Work around of the unavailability of a power_reset functionality in SD cards
3989 * by turning the OFF & back ON the regulators supplying the SD card.
3990 */
3991void msmsdcc_hw_reset(struct mmc_host *mmc)
3992{
3993 struct mmc_card *card = mmc->card;
3994 struct msmsdcc_host *host = mmc_priv(mmc);
3995 int rc;
3996
3997 /* Write-protection bits would be lost on a hardware reset in emmc */
3998 if (!card || !mmc_card_sd(card))
3999 return;
4000
4001 /*
4002 * Continuing on failing to disable regulator would lead to a panic
4003 * anyway, since the commands would fail and console would be flooded
4004 * with prints, eventually leading to a watchdog bark
4005 */
4006 rc = msmsdcc_setup_vreg(host, false, false);
4007 if (rc) {
4008 pr_err("%s: %s disable regulator: failed: %d\n",
4009 mmc_hostname(mmc), __func__, rc);
4010 BUG_ON(rc);
4011 }
4012
4013 /* 10ms delay for the supply to reach the desired voltage level */
4014 usleep_range(10000, 12000);
4015
4016 /*
4017 * Continuing on failing to enable regulator would lead to a panic
4018 * anyway, since the commands would fail and console would be flooded
4019 * with prints, eventually leading to a watchdog bark
4020 */
4021 rc = msmsdcc_setup_vreg(host, true, false);
4022 if (rc) {
4023 pr_err("%s: %s enable regulator: failed: %d\n",
4024 mmc_hostname(mmc), __func__, rc);
4025 BUG_ON(rc);
4026 }
4027
4028 /* 10ms delay for the supply to reach the desired voltage level */
4029 usleep_range(10000, 12000);
4030}
4031
San Mehat9d2bd732009-09-22 16:44:22 -07004032static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004033 .enable = msmsdcc_enable,
4034 .disable = msmsdcc_disable,
Asutosh Dasaccacd42012-03-08 14:33:17 +05304035 .pre_req = msmsdcc_pre_req,
4036 .post_req = msmsdcc_post_req,
San Mehat9d2bd732009-09-22 16:44:22 -07004037 .request = msmsdcc_request,
4038 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004039 .get_ro = msmsdcc_get_ro,
San Mehat9d2bd732009-09-22 16:44:22 -07004040 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Subhash Jadavani937c7502012-06-01 15:34:46 +05304041 .start_signal_voltage_switch = msmsdcc_switch_io_voltage,
Asutosh Dasebd7d092012-07-09 19:08:26 +05304042 .execute_tuning = msmsdcc_execute_tuning,
4043 .hw_reset = msmsdcc_hw_reset,
San Mehat9d2bd732009-09-22 16:44:22 -07004044};
4045
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004046static unsigned int
4047msmsdcc_slot_status(struct msmsdcc_host *host)
4048{
4049 int status;
4050 unsigned int gpio_no = host->plat->status_gpio;
4051
4052 status = gpio_request(gpio_no, "SD_HW_Detect");
4053 if (status) {
4054 pr_err("%s: %s: Failed to request GPIO %d\n",
4055 mmc_hostname(host->mmc), __func__, gpio_no);
4056 } else {
4057 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08004058 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08004059 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08004060 if (host->plat->is_status_gpio_active_low)
4061 status = !status;
4062 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004063 gpio_free(gpio_no);
4064 }
4065 return status;
4066}
4067
San Mehat9d2bd732009-09-22 16:44:22 -07004068static void
4069msmsdcc_check_status(unsigned long data)
4070{
4071 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4072 unsigned int status;
4073
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05304074 if (host->plat->status || gpio_is_valid(host->plat->status_gpio)) {
Krishna Konda941604a2012-01-10 17:46:34 -08004075 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004076 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004077 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004078 status = msmsdcc_slot_status(host);
4079
Krishna Konda941604a2012-01-10 17:46:34 -08004080 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08004081
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004082 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08004083 if (host->plat->status)
4084 pr_info("%s: Slot status change detected "
4085 "(%d -> %d)\n",
4086 mmc_hostname(host->mmc),
4087 host->oldstat, status);
4088 else if (host->plat->is_status_gpio_active_low)
4089 pr_info("%s: Slot status change detected "
4090 "(%d -> %d) and the card detect GPIO"
4091 " is ACTIVE_LOW\n",
4092 mmc_hostname(host->mmc),
4093 host->oldstat, status);
4094 else
4095 pr_info("%s: Slot status change detected "
4096 "(%d -> %d) and the card detect GPIO"
4097 " is ACTIVE_HIGH\n",
4098 mmc_hostname(host->mmc),
4099 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07004100 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004101 }
4102 host->oldstat = status;
4103 } else {
4104 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07004105 }
San Mehat9d2bd732009-09-22 16:44:22 -07004106}
4107
4108static irqreturn_t
4109msmsdcc_platform_status_irq(int irq, void *dev_id)
4110{
4111 struct msmsdcc_host *host = dev_id;
4112
Girish K Sa3c76eb2011-10-11 11:44:09 +05304113 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07004114 msmsdcc_check_status((unsigned long) host);
4115 return IRQ_HANDLED;
4116}
4117
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004118static irqreturn_t
4119msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
4120{
4121 struct msmsdcc_host *host = dev_id;
4122
4123 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
4124 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304125 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004126 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304127 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004128 wake_lock(&host->sdio_wlock);
4129 msmsdcc_disable_irq_wake(host);
4130 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304131 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004132 }
4133 if (host->plat->is_sdio_al_client) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004134 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304135 spin_unlock(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304136 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304137 goto out_unlocked;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004138 }
4139 spin_unlock(&host->lock);
4140
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304141out_unlocked:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004142 return IRQ_HANDLED;
4143}
4144
San Mehat9d2bd732009-09-22 16:44:22 -07004145static void
4146msmsdcc_status_notify_cb(int card_present, void *dev_id)
4147{
4148 struct msmsdcc_host *host = dev_id;
4149
Girish K Sa3c76eb2011-10-11 11:44:09 +05304150 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07004151 card_present);
4152 msmsdcc_check_status((unsigned long) host);
4153}
4154
San Mehat9d2bd732009-09-22 16:44:22 -07004155static int
4156msmsdcc_init_dma(struct msmsdcc_host *host)
4157{
4158 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
4159 host->dma.host = host;
4160 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004161 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004162
4163 if (!host->dmares)
4164 return -ENODEV;
4165
4166 host->dma.nc = dma_alloc_coherent(NULL,
4167 sizeof(struct msmsdcc_nc_dmadata),
4168 &host->dma.nc_busaddr,
4169 GFP_KERNEL);
4170 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004171 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07004172 return -ENOMEM;
4173 }
4174 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
4175 host->dma.cmd_busaddr = host->dma.nc_busaddr;
4176 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
4177 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
4178 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07004179 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07004180
4181 return 0;
4182}
4183
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004184#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
4185/**
4186 * Allocate and Connect a SDCC peripheral's SPS endpoint
4187 *
4188 * This function allocates endpoint context and
4189 * connect it with memory endpoint by calling
4190 * appropriate SPS driver APIs.
4191 *
4192 * Also registers a SPS callback function with
4193 * SPS driver
4194 *
4195 * This function should only be called once typically
4196 * during driver probe.
4197 *
4198 * @host - Pointer to sdcc host structure
4199 * @ep - Pointer to sps endpoint data structure
4200 * @is_produce - 1 means Producer endpoint
4201 * 0 means Consumer endpoint
4202 *
4203 * @return - 0 if successful else negative value.
4204 *
4205 */
4206static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
4207 struct msmsdcc_sps_ep_conn_data *ep,
4208 bool is_producer)
4209{
4210 int rc = 0;
4211 struct sps_pipe *sps_pipe_handle;
4212 struct sps_connect *sps_config = &ep->config;
4213 struct sps_register_event *sps_event = &ep->event;
4214
4215 /* Allocate endpoint context */
4216 sps_pipe_handle = sps_alloc_endpoint();
4217 if (!sps_pipe_handle) {
4218 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
4219 mmc_hostname(host->mmc), is_producer);
4220 rc = -ENOMEM;
4221 goto out;
4222 }
4223
4224 /* Get default connection configuration for an endpoint */
4225 rc = sps_get_config(sps_pipe_handle, sps_config);
4226 if (rc) {
4227 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
4228 " rc=%d", mmc_hostname(host->mmc),
4229 (u32)sps_pipe_handle, rc);
4230 goto get_config_err;
4231 }
4232
4233 /* Modify the default connection configuration */
4234 if (is_producer) {
4235 /*
4236 * For SDCC producer transfer, source should be
4237 * SDCC peripheral where as destination should
4238 * be system memory.
4239 */
4240 sps_config->source = host->sps.bam_handle;
4241 sps_config->destination = SPS_DEV_HANDLE_MEM;
4242 /* Producer pipe will handle this connection */
4243 sps_config->mode = SPS_MODE_SRC;
4244 sps_config->options =
4245 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4246 } else {
4247 /*
4248 * For SDCC consumer transfer, source should be
4249 * system memory where as destination should
4250 * SDCC peripheral
4251 */
4252 sps_config->source = SPS_DEV_HANDLE_MEM;
4253 sps_config->destination = host->sps.bam_handle;
4254 sps_config->mode = SPS_MODE_DEST;
4255 sps_config->options =
4256 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4257 }
4258
4259 /* Producer pipe index */
4260 sps_config->src_pipe_index = host->sps.src_pipe_index;
4261 /* Consumer pipe index */
4262 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
4263 /*
4264 * This event thresold value is only significant for BAM-to-BAM
4265 * transfer. It's ignored for BAM-to-System mode transfer.
4266 */
4267 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304268
4269 /* Allocate maximum descriptor fifo size */
4270 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
4271 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004272 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
4273 sps_config->desc.size,
4274 &sps_config->desc.phys_base,
4275 GFP_KERNEL);
4276
Pratibhasagar V00b94332011-10-18 14:57:27 +05304277 if (!sps_config->desc.base) {
4278 rc = -ENOMEM;
4279 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
4280 , mmc_hostname(host->mmc));
4281 goto get_config_err;
4282 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004283 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
4284
4285 /* Establish connection between peripheral and memory endpoint */
4286 rc = sps_connect(sps_pipe_handle, sps_config);
4287 if (rc) {
4288 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4289 " rc=%d", mmc_hostname(host->mmc),
4290 (u32)sps_pipe_handle, rc);
4291 goto sps_connect_err;
4292 }
4293
4294 sps_event->mode = SPS_TRIGGER_CALLBACK;
4295 sps_event->options = SPS_O_EOT;
4296 sps_event->callback = msmsdcc_sps_complete_cb;
4297 sps_event->xfer_done = NULL;
4298 sps_event->user = (void *)host;
4299
4300 /* Register callback event for EOT (End of transfer) event. */
4301 rc = sps_register_event(sps_pipe_handle, sps_event);
4302 if (rc) {
4303 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4304 " rc=%d", mmc_hostname(host->mmc),
4305 (u32)sps_pipe_handle, rc);
4306 goto reg_event_err;
4307 }
4308 /* Now save the sps pipe handle */
4309 ep->pipe_handle = sps_pipe_handle;
4310 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
4311 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
4312 __func__, is_producer ? "READ" : "WRITE",
4313 (u32)sps_pipe_handle, sps_config->desc.phys_base);
4314 goto out;
4315
4316reg_event_err:
4317 sps_disconnect(sps_pipe_handle);
4318sps_connect_err:
4319 dma_free_coherent(mmc_dev(host->mmc),
4320 sps_config->desc.size,
4321 sps_config->desc.base,
4322 sps_config->desc.phys_base);
4323get_config_err:
4324 sps_free_endpoint(sps_pipe_handle);
4325out:
4326 return rc;
4327}
4328
4329/**
4330 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
4331 *
4332 * This function disconnect endpoint and deallocates
4333 * endpoint context.
4334 *
4335 * This function should only be called once typically
4336 * during driver remove.
4337 *
4338 * @host - Pointer to sdcc host structure
4339 * @ep - Pointer to sps endpoint data structure
4340 *
4341 */
4342static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
4343 struct msmsdcc_sps_ep_conn_data *ep)
4344{
4345 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4346 struct sps_connect *sps_config = &ep->config;
4347 struct sps_register_event *sps_event = &ep->event;
4348
4349 sps_event->xfer_done = NULL;
4350 sps_event->callback = NULL;
4351 sps_register_event(sps_pipe_handle, sps_event);
4352 sps_disconnect(sps_pipe_handle);
4353 dma_free_coherent(mmc_dev(host->mmc),
4354 sps_config->desc.size,
4355 sps_config->desc.base,
4356 sps_config->desc.phys_base);
4357 sps_free_endpoint(sps_pipe_handle);
4358}
4359
4360/**
4361 * Reset SDCC peripheral's SPS endpoint
4362 *
4363 * This function disconnects an endpoint.
4364 *
4365 * This function should be called for reseting
4366 * SPS endpoint when data transfer error is
4367 * encountered during data transfer. This
4368 * can be considered as soft reset to endpoint.
4369 *
4370 * This function should only be called if
4371 * msmsdcc_sps_init() is already called.
4372 *
4373 * @host - Pointer to sdcc host structure
4374 * @ep - Pointer to sps endpoint data structure
4375 *
4376 * @return - 0 if successful else negative value.
4377 */
4378static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
4379 struct msmsdcc_sps_ep_conn_data *ep)
4380{
4381 int rc = 0;
4382 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4383
4384 rc = sps_disconnect(sps_pipe_handle);
4385 if (rc) {
4386 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
4387 " rc=%d", mmc_hostname(host->mmc), __func__,
4388 (u32)sps_pipe_handle, rc);
4389 goto out;
4390 }
4391 out:
4392 return rc;
4393}
4394
4395/**
4396 * Restore SDCC peripheral's SPS endpoint
4397 *
4398 * This function connects an endpoint.
4399 *
4400 * This function should be called for restoring
4401 * SPS endpoint after data transfer error is
4402 * encountered during data transfer. This
4403 * can be considered as soft reset to endpoint.
4404 *
4405 * This function should only be called if
4406 * msmsdcc_sps_reset_ep() is called before.
4407 *
4408 * @host - Pointer to sdcc host structure
4409 * @ep - Pointer to sps endpoint data structure
4410 *
4411 * @return - 0 if successful else negative value.
4412 */
4413static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
4414 struct msmsdcc_sps_ep_conn_data *ep)
4415{
4416 int rc = 0;
4417 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4418 struct sps_connect *sps_config = &ep->config;
4419 struct sps_register_event *sps_event = &ep->event;
4420
4421 /* Establish connection between peripheral and memory endpoint */
4422 rc = sps_connect(sps_pipe_handle, sps_config);
4423 if (rc) {
4424 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
4425 " rc=%d", mmc_hostname(host->mmc), __func__,
4426 (u32)sps_pipe_handle, rc);
4427 goto out;
4428 }
4429
4430 /* Register callback event for EOT (End of transfer) event. */
4431 rc = sps_register_event(sps_pipe_handle, sps_event);
4432 if (rc) {
4433 pr_err("%s: %s: sps_register_event() failed!!!"
4434 " pipe_handle=0x%x, rc=%d",
4435 mmc_hostname(host->mmc), __func__,
4436 (u32)sps_pipe_handle, rc);
4437 goto reg_event_err;
4438 }
4439 goto out;
4440
4441reg_event_err:
4442 sps_disconnect(sps_pipe_handle);
4443out:
4444 return rc;
4445}
4446
4447/**
Krishna Konda5af8f972012-05-14 16:15:24 -07004448 * Handle BAM device's global error condition
4449 *
4450 * This is an error handler for the SDCC bam device
4451 *
4452 * This function is registered as a callback with SPS-BAM
4453 * driver and will called in case there are an errors for
4454 * the SDCC BAM deivce. Any error conditions in the BAM
4455 * device are global and will be result in this function
4456 * being called once per device.
4457 *
4458 * This function will be called from the sps driver's
4459 * interrupt context.
4460 *
4461 * @sps_cb_case - indicates what error it is
4462 * @user - Pointer to sdcc host structure
4463 */
4464static void
4465msmsdcc_sps_bam_global_irq_cb(enum sps_callback_case sps_cb_case, void *user)
4466{
4467 struct msmsdcc_host *host = (struct msmsdcc_host *)user;
4468 struct mmc_request *mrq;
4469 unsigned long flags;
4470 int32_t error = 0;
4471
4472 BUG_ON(!host);
4473 BUG_ON(!is_sps_mode(host));
4474
4475 if (sps_cb_case == SPS_CALLBACK_BAM_ERROR_IRQ) {
4476 /**
4477 * Reset the all endpoints along with reseting the sps device.
4478 */
4479 host->sps.pipe_reset_pending = true;
4480 host->sps.reset_device = true;
4481
4482 pr_err("%s: BAM Global ERROR IRQ happened\n",
4483 mmc_hostname(host->mmc));
4484 error = EAGAIN;
4485 } else if (sps_cb_case == SPS_CALLBACK_BAM_HRESP_ERR_IRQ) {
4486 /**
4487 * This means that there was an AHB access error and
4488 * the address we are trying to read/write is something
4489 * we dont have priviliges to do so.
4490 */
4491 pr_err("%s: BAM HRESP_ERR_IRQ happened\n",
4492 mmc_hostname(host->mmc));
4493 error = EACCES;
4494 } else {
4495 /**
4496 * This should not have happened ideally. If this happens
4497 * there is some seriously wrong.
4498 */
4499 pr_err("%s: BAM global IRQ callback received, type:%d\n",
4500 mmc_hostname(host->mmc), (u32) sps_cb_case);
4501 error = EIO;
4502 }
4503
4504 spin_lock_irqsave(&host->lock, flags);
4505
4506 mrq = host->curr.mrq;
4507
4508 if (mrq && mrq->cmd) {
4509 msmsdcc_dump_sdcc_state(host);
4510
4511 if (!mrq->cmd->error)
4512 mrq->cmd->error = -error;
4513 if (host->curr.data) {
4514 if (mrq->data && !mrq->data->error)
4515 mrq->data->error = -error;
4516 host->curr.data_xfered = 0;
4517 if (host->sps.sg && is_sps_mode(host)) {
4518 /* Stop current SPS transfer */
4519 msmsdcc_sps_exit_curr_xfer(host);
4520 } else {
4521 /* this condition should not have happened */
4522 pr_err("%s: something is seriously wrong. "\
4523 "Funtion: %s, line: %d\n",
4524 mmc_hostname(host->mmc),
4525 __func__, __LINE__);
4526 }
4527 } else {
4528 /* this condition should not have happened */
4529 pr_err("%s: something is seriously wrong. Funtion: "\
4530 "%s, line: %d\n", mmc_hostname(host->mmc),
4531 __func__, __LINE__);
4532 }
4533 }
4534 spin_unlock_irqrestore(&host->lock, flags);
4535}
4536
4537/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004538 * Initialize SPS HW connected with SDCC core
4539 *
4540 * This function register BAM HW resources with
4541 * SPS driver and then initialize 2 SPS endpoints
4542 *
4543 * This function should only be called once typically
4544 * during driver probe.
4545 *
4546 * @host - Pointer to sdcc host structure
4547 *
4548 * @return - 0 if successful else negative value.
4549 *
4550 */
4551static int msmsdcc_sps_init(struct msmsdcc_host *host)
4552{
4553 int rc = 0;
4554 struct sps_bam_props bam = {0};
4555
4556 host->bam_base = ioremap(host->bam_memres->start,
4557 resource_size(host->bam_memres));
4558 if (!host->bam_base) {
4559 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
4560 " size=0x%x", mmc_hostname(host->mmc),
4561 host->bam_memres->start,
4562 (host->bam_memres->end -
4563 host->bam_memres->start));
4564 rc = -ENOMEM;
4565 goto out;
4566 }
4567
4568 bam.phys_addr = host->bam_memres->start;
4569 bam.virt_addr = host->bam_base;
4570 /*
4571 * This event thresold value is only significant for BAM-to-BAM
4572 * transfer. It's ignored for BAM-to-System mode transfer.
4573 */
4574 bam.event_threshold = 0x10; /* Pipe event threshold */
4575 /*
4576 * This threshold controls when the BAM publish
4577 * the descriptor size on the sideband interface.
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304578 * SPS HW will be used for data transfer size even
4579 * less than SDCC FIFO size. So let's set BAM summing
4580 * thresold to SPS_MIN_XFER_SIZE bytes.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004581 */
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304582 bam.summing_threshold = SPS_MIN_XFER_SIZE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004583 /* SPS driver wll handle the SDCC BAM IRQ */
4584 bam.irq = (u32)host->bam_irqres->start;
4585 bam.manage = SPS_BAM_MGR_LOCAL;
Krishna Konda5af8f972012-05-14 16:15:24 -07004586 bam.callback = msmsdcc_sps_bam_global_irq_cb;
4587 bam.user = (void *)host;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004588
4589 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
4590 (u32)bam.phys_addr);
4591 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
4592 (u32)bam.virt_addr);
4593
4594 /* Register SDCC Peripheral BAM device to SPS driver */
4595 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
4596 if (rc) {
4597 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
4598 mmc_hostname(host->mmc), rc);
4599 goto reg_bam_err;
4600 }
4601 pr_info("%s: BAM device registered. bam_handle=0x%x",
4602 mmc_hostname(host->mmc), host->sps.bam_handle);
4603
4604 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
4605 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
4606
4607 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
4608 SPS_PROD_PERIPHERAL);
4609 if (rc)
4610 goto sps_reset_err;
4611 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
4612 SPS_CONS_PERIPHERAL);
4613 if (rc)
4614 goto cons_conn_err;
4615
4616 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
4617 mmc_hostname(host->mmc),
4618 (unsigned long long)host->bam_memres->start,
4619 (unsigned int)host->bam_irqres->start);
4620 goto out;
4621
4622cons_conn_err:
4623 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4624sps_reset_err:
4625 sps_deregister_bam_device(host->sps.bam_handle);
4626reg_bam_err:
4627 iounmap(host->bam_base);
4628out:
4629 return rc;
4630}
4631
4632/**
4633 * De-initialize SPS HW connected with SDCC core
4634 *
4635 * This function deinitialize SPS endpoints and then
4636 * deregisters BAM resources from SPS driver.
4637 *
4638 * This function should only be called once typically
4639 * during driver remove.
4640 *
4641 * @host - Pointer to sdcc host structure
4642 *
4643 */
4644static void msmsdcc_sps_exit(struct msmsdcc_host *host)
4645{
4646 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
4647 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4648 sps_deregister_bam_device(host->sps.bam_handle);
4649 iounmap(host->bam_base);
4650}
4651#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
4652
4653static ssize_t
4654show_polling(struct device *dev, struct device_attribute *attr, char *buf)
4655{
4656 struct mmc_host *mmc = dev_get_drvdata(dev);
4657 struct msmsdcc_host *host = mmc_priv(mmc);
4658 int poll;
4659 unsigned long flags;
4660
4661 spin_lock_irqsave(&host->lock, flags);
4662 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
4663 spin_unlock_irqrestore(&host->lock, flags);
4664
4665 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
4666}
4667
4668static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05304669store_polling(struct device *dev, struct device_attribute *attr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004670 const char *buf, size_t count)
4671{
4672 struct mmc_host *mmc = dev_get_drvdata(dev);
4673 struct msmsdcc_host *host = mmc_priv(mmc);
4674 int value;
4675 unsigned long flags;
4676
4677 sscanf(buf, "%d", &value);
4678
4679 spin_lock_irqsave(&host->lock, flags);
4680 if (value) {
4681 mmc->caps |= MMC_CAP_NEEDS_POLL;
4682 mmc_detect_change(host->mmc, 0);
4683 } else {
4684 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4685 }
4686#ifdef CONFIG_HAS_EARLYSUSPEND
4687 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
4688#endif
4689 spin_unlock_irqrestore(&host->lock, flags);
4690 return count;
4691}
4692
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304693static ssize_t
4694show_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
4695 char *buf)
4696{
4697 struct mmc_host *mmc = dev_get_drvdata(dev);
4698 struct msmsdcc_host *host = mmc_priv(mmc);
4699
4700 return snprintf(buf, PAGE_SIZE, "%u\n",
4701 host->msm_bus_vote.is_max_bw_needed);
4702}
4703
4704static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05304705store_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304706 const char *buf, size_t count)
4707{
4708 struct mmc_host *mmc = dev_get_drvdata(dev);
4709 struct msmsdcc_host *host = mmc_priv(mmc);
4710 uint32_t value;
4711 unsigned long flags;
4712
4713 if (!kstrtou32(buf, 0, &value)) {
4714 spin_lock_irqsave(&host->lock, flags);
4715 host->msm_bus_vote.is_max_bw_needed = !!value;
4716 spin_unlock_irqrestore(&host->lock, flags);
4717 }
4718
4719 return count;
4720}
4721
Pratibhasagar V13d1d032012-07-09 20:12:38 +05304722static ssize_t
4723show_idle_timeout(struct device *dev, struct device_attribute *attr,
4724 char *buf)
4725{
4726 struct mmc_host *mmc = dev_get_drvdata(dev);
4727 struct msmsdcc_host *host = mmc_priv(mmc);
4728
4729 return snprintf(buf, PAGE_SIZE, "%u (Min 5 sec)\n",
4730 host->idle_tout_ms / 1000);
4731}
4732
4733static ssize_t
4734store_idle_timeout(struct device *dev, struct device_attribute *attr,
4735 const char *buf, size_t count)
4736{
4737 struct mmc_host *mmc = dev_get_drvdata(dev);
4738 struct msmsdcc_host *host = mmc_priv(mmc);
4739 unsigned int long flags;
4740 int timeout; /* in secs */
4741
4742 if (!kstrtou32(buf, 0, &timeout)
4743 && (timeout > MSM_MMC_DEFAULT_IDLE_TIMEOUT / 1000)) {
4744 spin_lock_irqsave(&host->lock, flags);
4745 host->idle_tout_ms = timeout * 1000;
4746 spin_unlock_irqrestore(&host->lock, flags);
4747 }
4748 return count;
4749}
4750
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004751#ifdef CONFIG_HAS_EARLYSUSPEND
4752static void msmsdcc_early_suspend(struct early_suspend *h)
4753{
4754 struct msmsdcc_host *host =
4755 container_of(h, struct msmsdcc_host, early_suspend);
4756 unsigned long flags;
4757
4758 spin_lock_irqsave(&host->lock, flags);
4759 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
4760 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4761 spin_unlock_irqrestore(&host->lock, flags);
4762};
4763static void msmsdcc_late_resume(struct early_suspend *h)
4764{
4765 struct msmsdcc_host *host =
4766 container_of(h, struct msmsdcc_host, early_suspend);
4767 unsigned long flags;
4768
4769 if (host->polling_enabled) {
4770 spin_lock_irqsave(&host->lock, flags);
4771 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
4772 mmc_detect_change(host->mmc, 0);
4773 spin_unlock_irqrestore(&host->lock, flags);
4774 }
4775};
4776#endif
4777
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304778static void msmsdcc_print_regs(const char *name, void __iomem *base,
4779 u32 phys_base, unsigned int no_of_regs)
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304780{
4781 unsigned int i;
4782
4783 if (!base)
4784 return;
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304785
4786 pr_info("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
4787 " =====\n", name, phys_base, (u32)base);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304788 for (i = 0; i < no_of_regs; i = i + 4) {
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304789 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
4790 (u32)readl_relaxed(base + i*4),
4791 (u32)readl_relaxed(base + ((i+1)*4)),
4792 (u32)readl_relaxed(base + ((i+2)*4)),
4793 (u32)readl_relaxed(base + ((i+3)*4)));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304794 }
4795}
4796
4797static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
4798{
4799 /* Dump current state of SDCC clocks, power and irq */
4800 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304801 (host->pwr ? "ON" : "OFF"));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304802 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304803 mmc_hostname(host->mmc),
4804 (atomic_read(&host->clks_on) ? "ON" : "OFF"),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304805 (u32)clk_get_rate(host->clk));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304806 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
4807 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
4808
4809 /* Now dump SDCC registers. Don't print FIFO registers */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304810 if (atomic_read(&host->clks_on))
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304811 msmsdcc_print_regs("SDCC-CORE", host->base,
4812 host->core_memres->start, 28);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304813
4814 if (host->curr.data) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304815 if (!msmsdcc_is_dma_possible(host, host->curr.data))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304816 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304817 else if (is_dma_mode(host))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304818 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
4819 mmc_hostname(host->mmc), host->dma.busy,
4820 host->dma.channel, host->dma.crci);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304821 else if (is_sps_mode(host)) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304822 if (host->sps.busy && atomic_read(&host->clks_on))
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304823 msmsdcc_print_regs("SDCC-DML", host->dml_base,
4824 host->dml_memres->start,
4825 16);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304826 pr_info("%s: SPS mode: busy=%d\n",
4827 mmc_hostname(host->mmc), host->sps.busy);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304828 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304829
4830 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
4831 mmc_hostname(host->mmc), host->curr.xfer_size,
4832 host->curr.data_xfered, host->curr.xfer_remain);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304833 }
4834
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304835 pr_info("%s: got_dataend=%d, prog_enable=%d,"
Subhash Jadavani8706ced2012-05-25 16:09:21 +05304836 " wait_for_auto_prog_done=%d, got_auto_prog_done=%d,"
4837 " req_tout_ms=%d\n", mmc_hostname(host->mmc),
4838 host->curr.got_dataend, host->prog_enable,
4839 host->curr.wait_for_auto_prog_done,
4840 host->curr.got_auto_prog_done, host->curr.req_tout_ms);
subhashj245831e2012-04-30 18:46:17 +05304841 msmsdcc_print_rpm_info(host);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304842}
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304843
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004844static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
4845{
4846 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4847 struct mmc_request *mrq;
4848 unsigned long flags;
4849
4850 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004851 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004852 pr_info("%s: %s: dummy CMD52 timeout\n",
4853 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004854 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004855 }
4856
4857 mrq = host->curr.mrq;
4858
4859 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304860 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
4861 mrq->cmd->opcode);
4862 msmsdcc_dump_sdcc_state(host);
4863
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004864 if (!mrq->cmd->error)
4865 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304866 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004867 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004868 if (mrq->data && !mrq->data->error)
4869 mrq->data->error = -ETIMEDOUT;
4870 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304871 if (host->dma.sg && is_dma_mode(host)) {
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07004872 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304873 } else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004874 /* Stop current SPS transfer */
4875 msmsdcc_sps_exit_curr_xfer(host);
4876 } else {
4877 msmsdcc_reset_and_restore(host);
4878 msmsdcc_stop_data(host);
4879 if (mrq->data && mrq->data->stop)
4880 msmsdcc_start_command(host,
4881 mrq->data->stop, 0);
4882 else
4883 msmsdcc_request_end(host, mrq);
4884 }
4885 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304886 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05304887 host->curr.wait_for_auto_prog_done = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004888 msmsdcc_reset_and_restore(host);
4889 msmsdcc_request_end(host, mrq);
4890 }
4891 }
4892 spin_unlock_irqrestore(&host->lock, flags);
4893}
4894
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05304895/*
4896 * msmsdcc_dt_get_array - Wrapper fn to read an array of 32 bit integers
4897 *
4898 * @dev: device node from which the property value is to be read.
4899 * @prop_name: name of the property to be searched.
4900 * @out_array: filled array returned to caller
4901 * @len: filled array size returned to caller
4902 * @size: expected size of the array
4903 *
4904 * If expected "size" doesn't match with "len" an error is returned. If
4905 * expected size is zero, the length of actual array is returned provided
4906 * return value is zero.
4907 *
4908 * RETURNS:
4909 * zero on success, negative error if failed.
4910 */
4911static int msmsdcc_dt_get_array(struct device *dev, const char *prop_name,
4912 u32 **out_array, int *len, int size)
4913{
4914 int ret = 0;
4915 u32 *array = NULL;
4916 struct device_node *np = dev->of_node;
4917
4918 if (of_get_property(np, prop_name, len)) {
4919 size_t sz;
4920 sz = *len = *len / sizeof(*array);
4921
4922 if (sz > 0 && !(size > 0 && (sz != size))) {
4923 array = devm_kzalloc(dev, sz * sizeof(*array),
4924 GFP_KERNEL);
4925 if (!array) {
4926 dev_err(dev, "%s: no memory\n", prop_name);
4927 ret = -ENOMEM;
4928 goto out;
4929 }
4930
4931 ret = of_property_read_u32_array(np, prop_name,
4932 array, sz);
4933 if (ret < 0) {
4934 dev_err(dev, "%s: error reading array %d\n",
4935 prop_name, ret);
4936 goto out;
4937 }
4938 } else {
4939 dev_err(dev, "%s invalid size\n", prop_name);
4940 ret = -EINVAL;
4941 goto out;
4942 }
4943 } else {
4944 dev_err(dev, "%s not specified\n", prop_name);
4945 ret = -EINVAL;
4946 goto out;
4947 }
4948 *out_array = array;
4949out:
4950 if (ret)
4951 *len = 0;
4952 return ret;
4953}
4954
4955static int msmsdcc_dt_get_pad_pull_info(struct device *dev, int id,
4956 struct msm_mmc_pad_pull_data **pad_pull_data)
4957{
4958 int ret = 0, base = 0, len, i;
4959 u32 *tmp;
4960 struct msm_mmc_pad_pull_data *pull_data;
4961 struct msm_mmc_pad_pull *pull;
4962
4963 switch (id) {
4964 case 1:
4965 base = TLMM_PULL_SDC1_CLK;
4966 break;
4967 case 2:
4968 base = TLMM_PULL_SDC2_CLK;
4969 break;
4970 case 3:
4971 base = TLMM_PULL_SDC3_CLK;
4972 break;
4973 case 4:
4974 base = TLMM_PULL_SDC4_CLK;
4975 break;
4976 default:
4977 dev_err(dev, "%s: Invalid slot id\n", __func__);
4978 ret = -EINVAL;
4979 goto err;
4980 }
4981
4982 pull_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_pull_data),
4983 GFP_KERNEL);
4984 if (!pull_data) {
4985 dev_err(dev, "No memory msm_mmc_pad_pull_data\n");
4986 ret = -ENOMEM;
4987 goto err;
4988 }
4989 pull_data->size = 3; /* array size for clk, cmd, data */
4990
4991 /* Allocate on, off configs for clk, cmd, data */
4992 pull = devm_kzalloc(dev, 2 * pull_data->size *\
4993 sizeof(struct msm_mmc_pad_pull), GFP_KERNEL);
4994 if (!pull) {
4995 dev_err(dev, "No memory for msm_mmc_pad_pull\n");
4996 ret = -ENOMEM;
4997 goto err;
4998 }
4999 pull_data->on = pull;
5000 pull_data->off = pull + pull_data->size;
5001
5002 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-pull-on",
5003 &tmp, &len, pull_data->size);
5004 if (!ret) {
5005 for (i = 0; i < len; i++) {
5006 pull_data->on[i].no = base + i;
5007 pull_data->on[i].val = tmp[i];
5008 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5009 i, pull_data->on[i].val);
5010 }
5011 } else {
5012 goto err;
5013 }
5014
5015 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-pull-off",
5016 &tmp, &len, pull_data->size);
5017 if (!ret) {
5018 for (i = 0; i < len; i++) {
5019 pull_data->off[i].no = base + i;
5020 pull_data->off[i].val = tmp[i];
5021 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5022 i, pull_data->off[i].val);
5023 }
5024 } else {
5025 goto err;
5026 }
5027
5028 *pad_pull_data = pull_data;
5029err:
5030 return ret;
5031}
5032
5033static int msmsdcc_dt_get_pad_drv_info(struct device *dev, int id,
5034 struct msm_mmc_pad_drv_data **pad_drv_data)
5035{
5036 int ret = 0, base = 0, len, i;
5037 u32 *tmp;
5038 struct msm_mmc_pad_drv_data *drv_data;
5039 struct msm_mmc_pad_drv *drv;
5040
5041 switch (id) {
5042 case 1:
5043 base = TLMM_HDRV_SDC1_CLK;
5044 break;
5045 case 2:
5046 base = TLMM_HDRV_SDC2_CLK;
5047 break;
5048 case 3:
5049 base = TLMM_HDRV_SDC3_CLK;
5050 break;
5051 case 4:
5052 base = TLMM_HDRV_SDC4_CLK;
5053 break;
5054 default:
5055 dev_err(dev, "%s: Invalid slot id\n", __func__);
5056 ret = -EINVAL;
5057 goto err;
5058 }
5059
5060 drv_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_drv_data),
5061 GFP_KERNEL);
5062 if (!drv_data) {
5063 dev_err(dev, "No memory for msm_mmc_pad_drv_data\n");
5064 ret = -ENOMEM;
5065 goto err;
5066 }
5067 drv_data->size = 3; /* array size for clk, cmd, data */
5068
5069 /* Allocate on, off configs for clk, cmd, data */
5070 drv = devm_kzalloc(dev, 2 * drv_data->size *\
5071 sizeof(struct msm_mmc_pad_drv), GFP_KERNEL);
5072 if (!drv) {
5073 dev_err(dev, "No memory msm_mmc_pad_drv\n");
5074 ret = -ENOMEM;
5075 goto err;
5076 }
5077 drv_data->on = drv;
5078 drv_data->off = drv + drv_data->size;
5079
5080 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-drv-on",
5081 &tmp, &len, drv_data->size);
5082 if (!ret) {
5083 for (i = 0; i < len; i++) {
5084 drv_data->on[i].no = base + i;
5085 drv_data->on[i].val = tmp[i];
5086 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5087 i, drv_data->on[i].val);
5088 }
5089 } else {
5090 goto err;
5091 }
5092
5093 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-drv-off",
5094 &tmp, &len, drv_data->size);
5095 if (!ret) {
5096 for (i = 0; i < len; i++) {
5097 drv_data->off[i].no = base + i;
5098 drv_data->off[i].val = tmp[i];
5099 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5100 i, drv_data->off[i].val);
5101 }
5102 } else {
5103 goto err;
5104 }
5105
5106 *pad_drv_data = drv_data;
5107err:
5108 return ret;
5109}
5110
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305111static void msmsdcc_dt_get_cd_wp_gpio(struct device *dev,
5112 struct mmc_platform_data *pdata)
5113{
5114 enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
5115 struct device_node *np = dev->of_node;
5116
5117 pdata->status_gpio = of_get_named_gpio_flags(np,
5118 "cd-gpios", 0, &flags);
5119 if (gpio_is_valid(pdata->status_gpio)) {
5120 pdata->status_irq = gpio_to_irq(pdata->status_gpio);
5121 pdata->is_status_gpio_active_low = flags & OF_GPIO_ACTIVE_LOW;
5122 }
5123
5124 pdata->wpswitch_gpio = of_get_named_gpio_flags(np,
5125 "wp-gpios", 0, &flags);
5126 if (gpio_is_valid(pdata->wpswitch_gpio))
5127 pdata->is_wpswitch_active_low = flags & OF_GPIO_ACTIVE_LOW;
5128}
5129
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305130static int msmsdcc_dt_parse_gpio_info(struct device *dev,
5131 struct mmc_platform_data *pdata)
5132{
5133 int ret = 0, id = 0, cnt, i;
5134 struct msm_mmc_pin_data *pin_data;
5135 struct device_node *np = dev->of_node;
5136
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305137 msmsdcc_dt_get_cd_wp_gpio(dev, pdata);
5138
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305139 pin_data = devm_kzalloc(dev, sizeof(*pin_data), GFP_KERNEL);
5140 if (!pin_data) {
5141 dev_err(dev, "No memory for pin_data\n");
5142 ret = -ENOMEM;
5143 goto err;
5144 }
5145
5146 cnt = of_gpio_count(np);
5147 if (cnt > 0) {
5148 pin_data->is_gpio = true;
5149
5150 pin_data->gpio_data = devm_kzalloc(dev,
5151 sizeof(struct msm_mmc_gpio_data), GFP_KERNEL);
5152 if (!pin_data->gpio_data) {
5153 dev_err(dev, "No memory for gpio_data\n");
5154 ret = -ENOMEM;
5155 goto err;
5156 }
5157 pin_data->gpio_data->size = cnt;
5158 pin_data->gpio_data->gpio = devm_kzalloc(dev,
5159 cnt * sizeof(struct msm_mmc_gpio), GFP_KERNEL);
5160 if (!pin_data->gpio_data->gpio) {
5161 dev_err(dev, "No memory for gpio\n");
5162 ret = -ENOMEM;
5163 goto err;
5164 }
5165
5166 for (i = 0; i < cnt; i++) {
5167 const char *name = NULL;
5168 char result[32];
5169 pin_data->gpio_data->gpio[i].no = of_get_gpio(np, i);
5170 of_property_read_string_index(np,
5171 "qcom,sdcc-gpio-names", i, &name);
5172
5173 snprintf(result, 32, "%s-%s",
5174 dev_name(dev), name ? name : "?");
5175 pin_data->gpio_data->gpio[i].name = result;
5176 dev_dbg(dev, "%s: gpio[%s] = %d\n", __func__,
5177 pin_data->gpio_data->gpio[i].name,
5178 pin_data->gpio_data->gpio[i].no);
5179 }
5180 } else {
5181 pin_data->pad_data = devm_kzalloc(dev,
5182 sizeof(struct msm_mmc_pad_data), GFP_KERNEL);
5183 if (!pin_data->pad_data) {
5184 dev_err(dev, "No memory for pin_data->pad_data\n");
5185 ret = -ENOMEM;
5186 goto err;
5187 }
5188
5189 of_property_read_u32(np, "cell-index", &id);
5190
5191 ret = msmsdcc_dt_get_pad_pull_info(dev, id,
5192 &pin_data->pad_data->pull);
5193 if (ret)
5194 goto err;
5195 ret = msmsdcc_dt_get_pad_drv_info(dev, id,
5196 &pin_data->pad_data->drv);
5197 if (ret)
5198 goto err;
5199 }
5200
5201 pdata->pin_data = pin_data;
5202err:
5203 if (ret)
5204 dev_err(dev, "%s failed with err %d\n", __func__, ret);
5205 return ret;
5206}
5207
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305208#define MAX_PROP_SIZE 32
5209static int msmsdcc_dt_parse_vreg_info(struct device *dev,
5210 struct msm_mmc_reg_data **vreg_data, const char *vreg_name)
5211{
5212 int len, ret = 0;
5213 const __be32 *prop;
5214 char prop_name[MAX_PROP_SIZE];
5215 struct msm_mmc_reg_data *vreg;
5216 struct device_node *np = dev->of_node;
5217
5218 snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", vreg_name);
5219 if (of_parse_phandle(np, prop_name, 0)) {
5220 vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
5221 if (!vreg) {
5222 dev_err(dev, "No memory for vreg: %s\n", vreg_name);
5223 ret = -ENOMEM;
5224 goto err;
5225 }
5226
5227 vreg->name = vreg_name;
5228
5229 snprintf(prop_name, MAX_PROP_SIZE,
5230 "qcom,sdcc-%s-always_on", vreg_name);
5231 if (of_get_property(np, prop_name, NULL))
5232 vreg->always_on = true;
5233
5234 snprintf(prop_name, MAX_PROP_SIZE,
5235 "qcom,sdcc-%s-lpm_sup", vreg_name);
5236 if (of_get_property(np, prop_name, NULL))
5237 vreg->lpm_sup = true;
5238
5239 snprintf(prop_name, MAX_PROP_SIZE,
5240 "qcom,sdcc-%s-voltage_level", vreg_name);
5241 prop = of_get_property(np, prop_name, &len);
5242 if (!prop || (len != (2 * sizeof(__be32)))) {
5243 dev_warn(dev, "%s %s property\n",
5244 prop ? "invalid format" : "no", prop_name);
5245 } else {
5246 vreg->low_vol_level = be32_to_cpup(&prop[0]);
5247 vreg->high_vol_level = be32_to_cpup(&prop[1]);
5248 }
5249
5250 snprintf(prop_name, MAX_PROP_SIZE,
5251 "qcom,sdcc-%s-current_level", vreg_name);
5252 prop = of_get_property(np, prop_name, &len);
5253 if (!prop || (len != (2 * sizeof(__be32)))) {
5254 dev_warn(dev, "%s %s property\n",
5255 prop ? "invalid format" : "no", prop_name);
5256 } else {
5257 vreg->lpm_uA = be32_to_cpup(&prop[0]);
5258 vreg->hpm_uA = be32_to_cpup(&prop[1]);
5259 }
5260
5261 *vreg_data = vreg;
5262 dev_dbg(dev, "%s: %s %s vol=[%d %d]uV, curr=[%d %d]uA\n",
5263 vreg->name, vreg->always_on ? "always_on," : "",
5264 vreg->lpm_sup ? "lpm_sup," : "", vreg->low_vol_level,
5265 vreg->high_vol_level, vreg->lpm_uA, vreg->hpm_uA);
5266 }
5267
5268err:
5269 return ret;
5270}
5271
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305272static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
5273{
5274 int i, ret;
5275 struct mmc_platform_data *pdata;
5276 struct device_node *np = dev->of_node;
Devin Kim9ccbff52012-07-16 20:55:14 -07005277 u32 bus_width = 0, current_limit = 0;
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305278 u32 *clk_table, *sup_voltages;
Devin Kim9ccbff52012-07-16 20:55:14 -07005279 int clk_table_len, sup_volt_len, len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305280
5281 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
5282 if (!pdata) {
5283 dev_err(dev, "could not allocate memory for platform data\n");
5284 goto err;
5285 }
5286
5287 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
5288 if (bus_width == 8) {
5289 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
5290 } else if (bus_width == 4) {
5291 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
5292 } else {
5293 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
5294 pdata->mmc_bus_width = 0;
5295 }
5296
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305297 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-sup-voltages",
5298 &sup_voltages, &sup_volt_len, 0);
5299 if (!ret) {
5300 for (i = 0; i < sup_volt_len; i += 2) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305301 u32 mask;
5302
5303 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
5304 sup_voltages[i + 1]);
5305 if (!mask)
5306 dev_err(dev, "Invalide voltage range %d\n", i);
5307 pdata->ocr_mask |= mask;
5308 }
5309 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305310 }
5311
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305312 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-clk-rates",
5313 &clk_table, &clk_table_len, 0);
5314 if (!ret) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305315 pdata->sup_clk_table = clk_table;
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305316 pdata->sup_clk_cnt = clk_table_len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305317 }
5318
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305319 pdata->vreg_data = devm_kzalloc(dev,
5320 sizeof(struct msm_mmc_slot_reg_data), GFP_KERNEL);
5321 if (!pdata->vreg_data) {
5322 dev_err(dev, "could not allocate memory for vreg_data\n");
5323 goto err;
5324 }
5325
5326 if (msmsdcc_dt_parse_vreg_info(dev,
5327 &pdata->vreg_data->vdd_data, "vdd"))
5328 goto err;
5329
5330 if (msmsdcc_dt_parse_vreg_info(dev,
5331 &pdata->vreg_data->vdd_io_data, "vdd-io"))
5332 goto err;
5333
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305334 if (msmsdcc_dt_parse_gpio_info(dev, pdata))
5335 goto err;
5336
Devin Kim9ccbff52012-07-16 20:55:14 -07005337 len = of_property_count_strings(np, "qcom,sdcc-bus-speed-mode");
5338
5339 for (i = 0; i < len; i++) {
5340 const char *name = NULL;
5341
5342 of_property_read_string_index(np,
5343 "qcom,sdcc-bus-speed-mode", i, &name);
5344 if (!name)
5345 continue;
5346
5347 if (!strncmp(name, "SDR12", sizeof("SDR12")))
5348 pdata->uhs_caps |= MMC_CAP_UHS_SDR12;
5349 else if (!strncmp(name, "SDR25", sizeof("SDR25")))
5350 pdata->uhs_caps |= MMC_CAP_UHS_SDR25;
5351 else if (!strncmp(name, "SDR50", sizeof("SDR50")))
5352 pdata->uhs_caps |= MMC_CAP_UHS_SDR50;
5353 else if (!strncmp(name, "DDR50", sizeof("DDR50")))
5354 pdata->uhs_caps |= MMC_CAP_UHS_DDR50;
5355 else if (!strncmp(name, "SDR104", sizeof("SDR104")))
5356 pdata->uhs_caps |= MMC_CAP_UHS_SDR104;
5357 else if (!strncmp(name, "HS200_1p8v", sizeof("HS200_1p8v")))
5358 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_8V_SDR;
5359 else if (!strncmp(name, "HS200_1p2v", sizeof("HS200_1p2v")))
5360 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_2V_SDR;
5361 else if (!strncmp(name, "DDR_1p8v", sizeof("DDR_1p8v")))
5362 pdata->uhs_caps |= MMC_CAP_1_8V_DDR
5363 | MMC_CAP_UHS_DDR50;
5364 else if (!strncmp(name, "DDR_1p2v", sizeof("DDR_1p2v")))
5365 pdata->uhs_caps |= MMC_CAP_1_2V_DDR
5366 | MMC_CAP_UHS_DDR50;
5367 }
5368
5369 of_property_read_u32(np, "qcom,sdcc-current-limit", &current_limit);
5370 if (current_limit == 800)
5371 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_800;
5372 else if (current_limit == 600)
5373 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_600;
5374 else if (current_limit == 400)
5375 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_400;
5376 else if (current_limit == 200)
5377 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_200;
5378
5379 if (of_get_property(np, "qcom,sdcc-xpc", NULL))
5380 pdata->xpc_cap = true;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305381 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
5382 pdata->nonremovable = true;
5383 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
5384 pdata->disable_cmd23 = true;
5385
5386 return pdata;
5387err:
5388 return NULL;
5389}
5390
San Mehat9d2bd732009-09-22 16:44:22 -07005391static int
5392msmsdcc_probe(struct platform_device *pdev)
5393{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305394 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07005395 struct msmsdcc_host *host;
5396 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005397 unsigned long flags;
5398 struct resource *core_irqres = NULL;
5399 struct resource *bam_irqres = NULL;
5400 struct resource *core_memres = NULL;
5401 struct resource *dml_memres = NULL;
5402 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07005403 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07005404 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05305405 int ret = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07005406
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305407 if (pdev->dev.of_node) {
5408 plat = msmsdcc_populate_pdata(&pdev->dev);
5409 of_property_read_u32((&pdev->dev)->of_node,
5410 "cell-index", &pdev->id);
5411 } else {
5412 plat = pdev->dev.platform_data;
5413 }
San Mehat9d2bd732009-09-22 16:44:22 -07005414
5415 /* must have platform data */
5416 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005417 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005418 ret = -EINVAL;
5419 goto out;
5420 }
5421
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005422 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07005423 return -EINVAL;
5424
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305425 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
5426 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
5427 return -EINVAL;
5428 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005429
San Mehat9d2bd732009-09-22 16:44:22 -07005430 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005431 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005432 return -ENXIO;
5433 }
5434
Sujit Reddy Thumma1dfac2c2012-07-30 10:15:39 +05305435 core_memres = platform_get_resource_byname(pdev,
5436 IORESOURCE_MEM, "core_mem");
5437 bam_memres = platform_get_resource_byname(pdev,
5438 IORESOURCE_MEM, "bam_mem");
5439 dml_memres = platform_get_resource_byname(pdev,
5440 IORESOURCE_MEM, "dml_mem");
5441 core_irqres = platform_get_resource_byname(pdev,
5442 IORESOURCE_IRQ, "core_irq");
5443 bam_irqres = platform_get_resource_byname(pdev,
5444 IORESOURCE_IRQ, "bam_irq");
5445 dmares = platform_get_resource_byname(pdev,
5446 IORESOURCE_DMA, "dma_chnl");
5447 dma_crci_res = platform_get_resource_byname(pdev,
5448 IORESOURCE_DMA, "dma_crci");
San Mehat9d2bd732009-09-22 16:44:22 -07005449
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005450 if (!core_irqres || !core_memres) {
5451 pr_err("%s: Invalid sdcc core resource\n", __func__);
5452 return -ENXIO;
5453 }
5454
5455 /*
5456 * Both BAM and DML memory resource should be preset.
5457 * BAM IRQ resource should also be present.
5458 */
5459 if ((bam_memres && !dml_memres) ||
5460 (!bam_memres && dml_memres) ||
5461 ((bam_memres && dml_memres) && !bam_irqres)) {
5462 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005463 return -ENXIO;
5464 }
5465
5466 /*
5467 * Setup our host structure
5468 */
San Mehat9d2bd732009-09-22 16:44:22 -07005469 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
5470 if (!mmc) {
5471 ret = -ENOMEM;
5472 goto out;
5473 }
5474
5475 host = mmc_priv(mmc);
5476 host->pdev_id = pdev->id;
5477 host->plat = plat;
5478 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08005479 host->curr.cmd = NULL;
Sahitya Tummala19207f02011-05-02 18:10:01 +05305480
Sahitya Tummalad9df3272011-08-19 16:50:46 +05305481 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305482 set_hw_caps(host, MSMSDCC_SPS_BAM_SUP);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005483 else if (dmares)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305484 set_hw_caps(host, MSMSDCC_DMA_SUP);
San Mehat9d2bd732009-09-22 16:44:22 -07005485
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005486 host->base = ioremap(core_memres->start,
5487 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07005488 if (!host->base) {
5489 ret = -ENOMEM;
Sahitya Tummaladce7c752011-05-02 18:06:05 +05305490 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005491 }
5492
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005493 host->core_irqres = core_irqres;
5494 host->bam_irqres = bam_irqres;
5495 host->core_memres = core_memres;
5496 host->dml_memres = dml_memres;
5497 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07005498 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07005499 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07005500 spin_lock_init(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305501 mutex_init(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07005502
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005503#ifdef CONFIG_MMC_EMBEDDED_SDIO
5504 if (plat->embedded_sdio)
5505 mmc_set_embedded_sdio_data(mmc,
5506 &plat->embedded_sdio->cis,
5507 &plat->embedded_sdio->cccr,
5508 plat->embedded_sdio->funcs,
5509 plat->embedded_sdio->num_funcs);
5510#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005511
Sahitya Tummala62612cf2010-12-08 15:03:03 +05305512 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
5513 (unsigned long)host);
5514
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005515 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
5516 (unsigned long)host);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305517 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005518 /* Setup DMA */
Subhash Jadavani190657c2011-05-02 18:10:40 +05305519 ret = msmsdcc_init_dma(host);
5520 if (ret)
5521 goto ioremap_free;
5522 } else {
5523 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07005524 host->dma.crci = -1;
Subhash Jadavani190657c2011-05-02 18:10:40 +05305525 }
San Mehat9d2bd732009-09-22 16:44:22 -07005526
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005527 /*
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305528 * Setup SDCC bus voter clock.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005529 */
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305530 host->bus_clk = clk_get(&pdev->dev, "bus_clk");
5531 if (!IS_ERR_OR_NULL(host->bus_clk)) {
5532 /* Vote for max. clk rate for max. performance */
5533 ret = clk_set_rate(host->bus_clk, INT_MAX);
5534 if (ret)
5535 goto bus_clk_put;
5536 ret = clk_prepare_enable(host->bus_clk);
5537 if (ret)
5538 goto bus_clk_put;
San Mehat9d2bd732009-09-22 16:44:22 -07005539 }
5540
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005541 /*
5542 * Setup main peripheral bus clock
5543 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07005544 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005545 if (!IS_ERR(host->pclk)) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305546 ret = clk_prepare_enable(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005547 if (ret)
5548 goto pclk_put;
5549
5550 host->pclk_rate = clk_get_rate(host->pclk);
5551 }
5552
5553 /*
5554 * Setup SDC MMC clock
5555 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07005556 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07005557 if (IS_ERR(host->clk)) {
5558 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005559 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07005560 }
5561
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005562 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
Sahitya Tummala514d9ed2011-05-02 18:07:01 +05305563 if (ret) {
5564 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
5565 goto clk_put;
5566 }
5567
Asutosh Dasf5298c32012-04-03 14:51:47 +05305568 ret = clk_prepare_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07005569 if (ret)
5570 goto clk_put;
5571
San Mehat9d2bd732009-09-22 16:44:22 -07005572 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05305573 if (!host->clk_rate)
5574 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05305575
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305576 set_default_hw_caps(host);
5577
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05305578 /*
5579 * Set the register write delay according to min. clock frequency
5580 * supported and update later when the host->clk_rate changes.
5581 */
5582 host->reg_write_delay =
5583 (1 + ((3 * USEC_PER_SEC) /
5584 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005585
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305586 atomic_set(&host->clks_on, 1);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05305587 /* Apply Hard reset to SDCC to put it in power on default state */
5588 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005589
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005590#define MSM_MMC_DEFAULT_CPUDMA_LATENCY 200 /* usecs */
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305591 /* pm qos request to prevent apps idle power collapse */
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005592 if (host->plat->cpu_dma_latency)
5593 host->cpu_dma_latency = host->plat->cpu_dma_latency;
5594 else
5595 host->cpu_dma_latency = MSM_MMC_DEFAULT_CPUDMA_LATENCY;
5596 pm_qos_add_request(&host->pm_qos_req_dma,
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305597 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
5598
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305599 ret = msmsdcc_msm_bus_register(host);
5600 if (ret)
5601 goto pm_qos_remove;
5602
5603 if (host->msm_bus_vote.client_handle)
5604 INIT_DELAYED_WORK(&host->msm_bus_vote.vote_work,
5605 msmsdcc_msm_bus_work);
5606
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005607 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07005608 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005609 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07005610 goto clk_disable;
5611 }
5612
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005613
5614 /* Clocks has to be running before accessing SPS/DML HW blocks */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305615 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005616 /* Initialize SPS */
5617 ret = msmsdcc_sps_init(host);
5618 if (ret)
5619 goto vreg_deinit;
5620 /* Initialize DML */
5621 ret = msmsdcc_dml_init(host);
5622 if (ret)
5623 goto sps_exit;
5624 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05305625 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07005626
San Mehat9d2bd732009-09-22 16:44:22 -07005627 /*
5628 * Setup MMC host structure
5629 */
5630 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005631 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
5632 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005633 mmc->ocr_avail = plat->ocr_mask;
Sujit Reddy Thumma0e05f022012-06-11 19:44:18 +05305634 mmc->clkgate_delay = MSM_MMC_CLK_GATE_DELAY;
5635
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005636 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
5637 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07005638 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05305639 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
Asutosh Dasebd7d092012-07-09 19:08:26 +05305640 mmc->caps |= MMC_CAP_HW_RESET;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05305641 /*
5642 * If we send the CMD23 before multi block write/read command
5643 * then we need not to send CMD12 at the end of the transfer.
5644 * If we don't send the CMD12 then only way to detect the PROG_DONE
5645 * status is to use the AUTO_PROG_DONE status provided by SDCC4
5646 * controller. So let's enable the CMD23 for SDCC4 only.
5647 */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305648 if (!plat->disable_cmd23 && is_auto_prog_done(host))
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05305649 mmc->caps |= MMC_CAP_CMD23;
San Mehat9d2bd732009-09-22 16:44:22 -07005650
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005651 mmc->caps |= plat->uhs_caps;
Devin Kim9ccbff52012-07-16 20:55:14 -07005652 mmc->caps2 |= plat->uhs_caps2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005653 /*
5654 * XPC controls the maximum current in the default speed mode of SDXC
5655 * card. XPC=0 means 100mA (max.) but speed class is not supported.
5656 * XPC=1 means 150mA (max.) and speed class is supported.
5657 */
5658 if (plat->xpc_cap)
5659 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
5660 MMC_CAP_SET_XPC_180);
5661
Devin Kim9b67ee02012-07-16 21:13:05 -07005662 /* packed write */
5663 mmc->caps2 |= plat->packed_write;
5664
Subhash Jadavani6bb34a82012-04-18 13:18:40 +05305665 mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
Yaniv Gardi14098552012-06-04 10:56:03 +03005666 mmc->caps2 |= MMC_CAP2_SANITIZE;
5667
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005668 if (plat->nonremovable)
5669 mmc->caps |= MMC_CAP_NONREMOVABLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005670 mmc->caps |= MMC_CAP_SDIO_IRQ;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005671
Konstantin Dorfman9db69fc2012-06-01 14:04:45 +03005672 mmc->caps2 |= MMC_CAP2_INIT_BKOPS | MMC_CAP2_BKOPS;
5673
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005674 if (plat->is_sdio_al_client)
5675 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07005676
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305677 mmc->max_segs = msmsdcc_get_nr_sg(host);
5678 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
5679 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07005680
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305681 mmc->max_req_size = MMC_MAX_REQ_SIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07005682 mmc->max_seg_size = mmc->max_req_size;
5683
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005684 writel_relaxed(0, host->base + MMCIMASK0);
5685 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05305686 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005687
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005688 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
5689 mb();
5690 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07005691
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005692 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
5693 DRIVER_NAME " (cmd)", host);
5694 if (ret)
5695 goto dml_exit;
5696
5697 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
5698 DRIVER_NAME " (pio)", host);
5699 if (ret)
5700 goto irq_free;
5701
5702 /*
5703 * Enable SDCC IRQ only when host is powered on. Otherwise, this
5704 * IRQ is un-necessarily being monitored by MPM (Modem power
5705 * management block) during idle-power collapse. The MPM will be
5706 * configured to monitor the DATA1 GPIO line with level-low trigger
5707 * and thus depending on the GPIO status, it prevents TCXO shutdown
5708 * during idle-power collapse.
5709 */
5710 disable_irq(core_irqres->start);
5711 host->sdcc_irq_disabled = 1;
5712
5713 if (plat->sdiowakeup_irq) {
5714 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5715 mmc_hostname(mmc));
5716 ret = request_irq(plat->sdiowakeup_irq,
5717 msmsdcc_platform_sdiowakeup_irq,
5718 IRQF_SHARED | IRQF_TRIGGER_LOW,
5719 DRIVER_NAME "sdiowakeup", host);
5720 if (ret) {
5721 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
5722 plat->sdiowakeup_irq, ret);
5723 goto pio_irq_free;
5724 } else {
5725 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305726 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005727 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305728 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005729 }
5730 spin_unlock_irqrestore(&host->lock, flags);
5731 }
5732 }
5733
Subhash Jadavanic9b85752012-04-13 11:16:49 +05305734 if (host->plat->mpm_sdiowakeup_int) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005735 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5736 mmc_hostname(mmc));
5737 }
5738
5739 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
5740 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005741 /*
5742 * Setup card detect change
5743 */
5744
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305745 if (!plat->status_gpio)
5746 plat->status_gpio = -ENOENT;
5747 if (!plat->wpswitch_gpio)
5748 plat->wpswitch_gpio = -ENOENT;
5749
5750 if (plat->status || gpio_is_valid(plat->status_gpio)) {
Krishna Konda941604a2012-01-10 17:46:34 -08005751 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005752 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08005753 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005754 host->oldstat = msmsdcc_slot_status(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005755
Krishna Konda941604a2012-01-10 17:46:34 -08005756 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005757 }
San Mehat9d2bd732009-09-22 16:44:22 -07005758
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005759 if (plat->status_irq) {
5760 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07005761 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005762 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07005763 DRIVER_NAME " (slot)",
5764 host);
5765 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005766 pr_err("Unable to get slot IRQ %d (%d)\n",
5767 plat->status_irq, ret);
5768 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005769 }
5770 } else if (plat->register_status_notify) {
5771 plat->register_status_notify(msmsdcc_status_notify_cb, host);
5772 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005773 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07005774 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005775
5776 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005777
5778 ret = pm_runtime_set_active(&(pdev)->dev);
5779 if (ret < 0)
5780 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
5781 __func__, ret);
5782 /*
5783 * There is no notion of suspend/resume for SD/MMC/SDIO
5784 * cards. So host can be suspended/resumed with out
5785 * worrying about its children.
5786 */
5787 pm_suspend_ignore_children(&(pdev)->dev, true);
5788
5789 /*
5790 * MMC/SD/SDIO bus suspend/resume operations are defined
5791 * only for the slots that will be used for non-removable
5792 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
5793 * defined. Otherwise, they simply become card removal and
5794 * insertion events during suspend and resume respectively.
5795 * Hence, enable run-time PM only for slots for which bus
5796 * suspend/resume operations are defined.
5797 */
5798#ifdef CONFIG_MMC_UNSAFE_RESUME
5799 /*
5800 * If this capability is set, MMC core will enable/disable host
5801 * for every claim/release operation on a host. We use this
5802 * notification to increment/decrement runtime pm usage count.
5803 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005804 pm_runtime_enable(&(pdev)->dev);
5805#else
5806 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005807 pm_runtime_enable(&(pdev)->dev);
5808 }
5809#endif
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305810 host->idle_tout_ms = MSM_MMC_DEFAULT_IDLE_TIMEOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005811 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
5812 (unsigned long)host);
5813
San Mehat9d2bd732009-09-22 16:44:22 -07005814 mmc_add_host(mmc);
5815
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005816#ifdef CONFIG_HAS_EARLYSUSPEND
5817 host->early_suspend.suspend = msmsdcc_early_suspend;
5818 host->early_suspend.resume = msmsdcc_late_resume;
5819 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
5820 register_early_suspend(&host->early_suspend);
5821#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005822
Krishna Konda25786ec2011-07-25 16:21:36 -07005823 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
5824 " dmacrcri %d\n", mmc_hostname(mmc),
5825 (unsigned long long)core_memres->start,
5826 (unsigned int) core_irqres->start,
5827 (unsigned int) plat->status_irq, host->dma.channel,
5828 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005829
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305830 pr_info("%s: Controller capabilities: 0x%.8x\n",
5831 mmc_hostname(mmc), host->hw_caps);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005832 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
5833 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
5834 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
5835 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
5836 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
5837 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
5838 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
5839 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
5840 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
5841 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
5842 host->eject);
5843 pr_info("%s: Power save feature enable = %d\n",
5844 mmc_hostname(mmc), msmsdcc_pwrsave);
5845
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305846 if (is_dma_mode(host) && host->dma.channel != -1
Krishna Konda25786ec2011-07-25 16:21:36 -07005847 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005848 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005849 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005850 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005851 mmc_hostname(mmc), host->dma.cmd_busaddr,
5852 host->dma.cmdptr_busaddr);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305853 } else if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005854 pr_info("%s: SPS-BAM data transfer mode available\n",
5855 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005856 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005857 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005858
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005859#if defined(CONFIG_DEBUG_FS)
5860 msmsdcc_dbg_createhost(host);
5861#endif
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305862
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305863 host->max_bus_bw.show = show_sdcc_to_mem_max_bus_bw;
5864 host->max_bus_bw.store = store_sdcc_to_mem_max_bus_bw;
5865 sysfs_attr_init(&host->max_bus_bw.attr);
5866 host->max_bus_bw.attr.name = "max_bus_bw";
5867 host->max_bus_bw.attr.mode = S_IRUGO | S_IWUSR;
5868 ret = device_create_file(&pdev->dev, &host->max_bus_bw);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305869 if (ret)
5870 goto platform_irq_free;
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305871
5872 if (!plat->status_irq) {
5873 host->polling.show = show_polling;
5874 host->polling.store = store_polling;
5875 sysfs_attr_init(&host->polling.attr);
5876 host->polling.attr.name = "polling";
5877 host->polling.attr.mode = S_IRUGO | S_IWUSR;
5878 ret = device_create_file(&pdev->dev, &host->polling);
5879 if (ret)
5880 goto remove_max_bus_bw_file;
5881 }
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305882 host->idle_timeout.show = show_idle_timeout;
5883 host->idle_timeout.store = store_idle_timeout;
5884 sysfs_attr_init(&host->idle_timeout.attr);
5885 host->idle_timeout.attr.name = "idle_timeout";
5886 host->idle_timeout.attr.mode = S_IRUGO | S_IWUSR;
5887 ret = device_create_file(&pdev->dev, &host->idle_timeout);
5888 if (ret)
5889 goto remove_polling_file;
San Mehat9d2bd732009-09-22 16:44:22 -07005890 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005891
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305892 remove_polling_file:
5893 if (!plat->status_irq)
5894 device_remove_file(&pdev->dev, &host->polling);
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305895 remove_max_bus_bw_file:
5896 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005897 platform_irq_free:
5898 del_timer_sync(&host->req_tout_timer);
5899 pm_runtime_disable(&(pdev)->dev);
5900 pm_runtime_set_suspended(&(pdev)->dev);
5901
5902 if (plat->status_irq)
5903 free_irq(plat->status_irq, host);
5904 sdiowakeup_irq_free:
5905 wake_lock_destroy(&host->sdio_suspend_wlock);
5906 if (plat->sdiowakeup_irq)
5907 free_irq(plat->sdiowakeup_irq, host);
5908 pio_irq_free:
5909 if (plat->sdiowakeup_irq)
5910 wake_lock_destroy(&host->sdio_wlock);
5911 free_irq(core_irqres->start, host);
5912 irq_free:
5913 free_irq(core_irqres->start, host);
5914 dml_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305915 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005916 msmsdcc_dml_exit(host);
5917 sps_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305918 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005919 msmsdcc_sps_exit(host);
5920 vreg_deinit:
5921 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07005922 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005923 clk_disable(host->clk);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305924 msmsdcc_msm_bus_unregister(host);
5925 pm_qos_remove:
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005926 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305927 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07005928 clk_put:
5929 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005930 pclk_disable:
5931 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05305932 clk_disable_unprepare(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07005933 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005934 if (!IS_ERR(host->pclk))
5935 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305936 if (!IS_ERR_OR_NULL(host->bus_clk))
5937 clk_disable_unprepare(host->bus_clk);
5938 bus_clk_put:
5939 if (!IS_ERR_OR_NULL(host->bus_clk))
5940 clk_put(host->bus_clk);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305941 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005942 if (host->dmares)
5943 dma_free_coherent(NULL,
5944 sizeof(struct msmsdcc_nc_dmadata),
5945 host->dma.nc, host->dma.nc_busaddr);
5946 }
5947 ioremap_free:
Sahitya Tummaladce7c752011-05-02 18:06:05 +05305948 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07005949 host_free:
5950 mmc_free_host(mmc);
5951 out:
5952 return ret;
5953}
5954
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005955static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07005956{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005957 struct mmc_host *mmc = mmc_get_drvdata(pdev);
5958 struct mmc_platform_data *plat;
5959 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07005960
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005961 if (!mmc)
5962 return -ENXIO;
5963
5964 if (pm_runtime_suspended(&(pdev)->dev))
5965 pm_runtime_resume(&(pdev)->dev);
5966
5967 host = mmc_priv(mmc);
5968
5969 DBG(host, "Removing SDCC device = %d\n", pdev->id);
5970 plat = host->plat;
5971
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305972 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005973 if (!plat->status_irq)
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305974 device_remove_file(&pdev->dev, &host->polling);
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305975 device_remove_file(&pdev->dev, &host->idle_timeout);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005976
5977 del_timer_sync(&host->req_tout_timer);
5978 tasklet_kill(&host->dma_tlet);
5979 tasklet_kill(&host->sps.tlet);
5980 mmc_remove_host(mmc);
5981
5982 if (plat->status_irq)
5983 free_irq(plat->status_irq, host);
5984
5985 wake_lock_destroy(&host->sdio_suspend_wlock);
5986 if (plat->sdiowakeup_irq) {
5987 wake_lock_destroy(&host->sdio_wlock);
5988 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
5989 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07005990 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005991
5992 free_irq(host->core_irqres->start, host);
5993 free_irq(host->core_irqres->start, host);
5994
5995 clk_put(host->clk);
5996 if (!IS_ERR(host->pclk))
5997 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305998 if (!IS_ERR_OR_NULL(host->bus_clk))
5999 clk_put(host->bus_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006000
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006001 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306002 pm_qos_remove_request(&host->pm_qos_req_dma);
6003
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306004 if (host->msm_bus_vote.client_handle) {
6005 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
6006 msmsdcc_msm_bus_unregister(host);
6007 }
6008
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006009 msmsdcc_vreg_init(host, false);
6010
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306011 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006012 if (host->dmares)
6013 dma_free_coherent(NULL,
6014 sizeof(struct msmsdcc_nc_dmadata),
6015 host->dma.nc, host->dma.nc_busaddr);
6016 }
6017
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306018 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006019 msmsdcc_dml_exit(host);
6020 msmsdcc_sps_exit(host);
6021 }
6022
6023 iounmap(host->base);
6024 mmc_free_host(mmc);
6025
6026#ifdef CONFIG_HAS_EARLYSUSPEND
6027 unregister_early_suspend(&host->early_suspend);
6028#endif
6029 pm_runtime_disable(&(pdev)->dev);
6030 pm_runtime_set_suspended(&(pdev)->dev);
6031
6032 return 0;
6033}
6034
6035#ifdef CONFIG_MSM_SDIO_AL
6036int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
6037{
6038 struct msmsdcc_host *host = mmc_priv(mmc);
6039 unsigned long flags;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306040 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006041
Asutosh Dasf5298c32012-04-03 14:51:47 +05306042 mutex_lock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006043 spin_lock_irqsave(&host->lock, flags);
6044 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
6045 enable ? "En" : "Dis");
6046
6047 if (enable) {
6048 if (!host->sdcc_irq_disabled) {
6049 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05306050 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006051 host->sdcc_irq_disabled = 1;
6052 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306053 rc = msmsdcc_setup_clocks(host, false);
6054 if (rc)
6055 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006056
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05306057 if (host->plat->sdio_lpm_gpio_setup &&
6058 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006059 spin_unlock_irqrestore(&host->lock, flags);
6060 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
6061 spin_lock_irqsave(&host->lock, flags);
6062 host->sdio_gpio_lpm = 1;
6063 }
6064
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306065 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006066 msmsdcc_enable_irq_wake(host);
6067 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306068 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006069 }
6070 } else {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306071 rc = msmsdcc_setup_clocks(host, true);
6072 if (rc)
6073 goto out;
6074
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306075 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006076 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306077 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006078 msmsdcc_disable_irq_wake(host);
6079 }
6080
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05306081 if (host->plat->sdio_lpm_gpio_setup &&
6082 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006083 spin_unlock_irqrestore(&host->lock, flags);
6084 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
6085 spin_lock_irqsave(&host->lock, flags);
6086 host->sdio_gpio_lpm = 0;
6087 }
6088
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306089 if (host->sdcc_irq_disabled && atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006090 writel_relaxed(host->mci_irqenable,
6091 host->base + MMCIMASK0);
6092 mb();
6093 enable_irq(host->core_irqres->start);
6094 host->sdcc_irq_disabled = 0;
6095 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006096 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306097out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006098 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05306099 mutex_unlock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306100 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006101}
6102#else
6103int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
6104{
6105 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07006106}
6107#endif
6108
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006109#ifdef CONFIG_PM
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306110#ifdef CONFIG_MMC_CLKGATE
6111static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6112{
6113 struct mmc_host *mmc = host->mmc;
6114 unsigned long flags;
6115
6116 mmc_host_clk_hold(mmc);
6117 spin_lock_irqsave(&mmc->clk_lock, flags);
6118 mmc->clk_old = mmc->ios.clock;
6119 mmc->ios.clock = 0;
6120 mmc->clk_gated = true;
6121 spin_unlock_irqrestore(&mmc->clk_lock, flags);
6122 mmc_set_ios(mmc);
6123 mmc_host_clk_release(mmc);
6124}
6125
6126static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6127{
6128 struct mmc_host *mmc = host->mmc;
6129
6130 mmc_host_clk_hold(mmc);
6131 mmc->ios.clock = host->clk_rate;
6132 mmc_set_ios(mmc);
6133 mmc_host_clk_release(mmc);
6134}
6135#else
6136static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6137{
6138 struct mmc_host *mmc = host->mmc;
6139
6140 mmc->ios.clock = 0;
6141 mmc_set_ios(mmc);
6142}
6143
6144static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6145{
6146 struct mmc_host *mmc = host->mmc;
6147
6148 mmc->ios.clock = host->clk_rate;
6149 mmc_set_ios(mmc);
6150}
6151#endif
6152
San Mehat9d2bd732009-09-22 16:44:22 -07006153static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006154msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006155{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006156 struct mmc_host *mmc = dev_get_drvdata(dev);
6157 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006158 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306159 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07006160
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306161 if (host->plat->is_sdio_al_client) {
6162 rc = 0;
6163 goto out;
San Mehat9d2bd732009-09-22 16:44:22 -07006164 }
San Mehat9d2bd732009-09-22 16:44:22 -07006165
Sahitya Tummala7661a452011-07-18 13:28:35 +05306166 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006167 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006168 host->sdcc_suspending = 1;
6169 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07006170
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006171 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006172 * MMC core thinks that host is disabled by now since
6173 * runtime suspend is scheduled after msmsdcc_disable()
6174 * is called. Thus, MMC core will try to enable the host
6175 * while suspending it. This results in a synchronous
6176 * runtime resume request while in runtime suspending
6177 * context and hence inorder to complete this resume
6178 * requet, it will wait for suspend to be complete,
6179 * but runtime suspend also can not proceed further
6180 * until the host is resumed. Thus, it leads to a hang.
6181 * Hence, increase the pm usage count before suspending
6182 * the host so that any resume requests after this will
6183 * simple become pm usage counter increment operations.
6184 */
6185 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306186 /* If there is pending detect work abort runtime suspend */
6187 if (unlikely(work_busy(&mmc->detect.work)))
6188 rc = -EAGAIN;
6189 else
6190 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006191 pm_runtime_put_noidle(dev);
6192
6193 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306194 spin_lock_irqsave(&host->lock, flags);
6195 host->sdcc_suspended = true;
6196 spin_unlock_irqrestore(&host->lock, flags);
6197 if (mmc->card && mmc_card_sdio(mmc->card) &&
6198 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006199 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306200 * If SDIO function driver doesn't want
6201 * to power off the card, atleast turn off
6202 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006203 */
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306204 msmsdcc_gate_clock(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006205 }
6206 }
6207 host->sdcc_suspending = 0;
6208 mmc->suspend_task = NULL;
6209 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
6210 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006211 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306212 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306213out:
6214 /* set bus bandwidth to 0 immediately */
6215 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
San Mehat9d2bd732009-09-22 16:44:22 -07006216 return rc;
6217}
6218
6219static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006220msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006221{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006222 struct mmc_host *mmc = dev_get_drvdata(dev);
6223 struct msmsdcc_host *host = mmc_priv(mmc);
6224 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07006225
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006226 if (host->plat->is_sdio_al_client)
6227 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07006228
Sahitya Tummala7661a452011-07-18 13:28:35 +05306229 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006230 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306231 if (mmc->card && mmc_card_sdio(mmc->card) &&
6232 mmc_card_keep_power(mmc)) {
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306233 msmsdcc_ungate_clock(host);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05306234 }
San Mehat9d2bd732009-09-22 16:44:22 -07006235
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006236 mmc_resume_host(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006237
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006238 /*
6239 * FIXME: Clearing of flags must be handled in clients
6240 * resume handler.
6241 */
6242 spin_lock_irqsave(&host->lock, flags);
6243 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306244 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006245 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07006246
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006247 /*
6248 * After resuming the host wait for sometime so that
6249 * the SDIO work will be processed.
6250 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306251 if (mmc->card && mmc_card_sdio(mmc->card)) {
Subhash Jadavanic9b85752012-04-13 11:16:49 +05306252 if ((host->plat->mpm_sdiowakeup_int ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006253 host->plat->sdiowakeup_irq) &&
6254 wake_lock_active(&host->sdio_wlock))
6255 wake_lock_timeout(&host->sdio_wlock, 1);
6256 }
6257
6258 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006259 }
Subhash Jadavani1371d192012-08-16 18:46:57 +05306260 host->pending_resume = false;
Sahitya Tummala7661a452011-07-18 13:28:35 +05306261 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006262 return 0;
6263}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006264
6265static int msmsdcc_runtime_idle(struct device *dev)
6266{
6267 struct mmc_host *mmc = dev_get_drvdata(dev);
6268 struct msmsdcc_host *host = mmc_priv(mmc);
6269
6270 if (host->plat->is_sdio_al_client)
6271 return 0;
6272
6273 /* Idle timeout is not configurable for now */
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306274 pm_schedule_suspend(dev, host->idle_tout_ms);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006275
6276 return -EAGAIN;
6277}
6278
6279static int msmsdcc_pm_suspend(struct device *dev)
6280{
6281 struct mmc_host *mmc = dev_get_drvdata(dev);
6282 struct msmsdcc_host *host = mmc_priv(mmc);
6283 int rc = 0;
6284
6285 if (host->plat->is_sdio_al_client)
6286 return 0;
6287
6288
6289 if (host->plat->status_irq)
6290 disable_irq(host->plat->status_irq);
6291
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006292 if (!pm_runtime_suspended(dev))
6293 rc = msmsdcc_runtime_suspend(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006294
6295 return rc;
6296}
6297
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306298static int msmsdcc_suspend_noirq(struct device *dev)
6299{
6300 struct mmc_host *mmc = dev_get_drvdata(dev);
6301 struct msmsdcc_host *host = mmc_priv(mmc);
6302 int rc = 0;
6303
6304 /*
6305 * After platform suspend there may be active request
6306 * which might have enabled clocks. For example, in SDIO
6307 * case, ksdioirq thread might have scheduled after sdcc
6308 * suspend but before system freeze. In that case abort
6309 * suspend and retry instead of keeping the clocks on
6310 * during suspend and not allowing TCXO.
6311 */
6312
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306313 if (atomic_read(&host->clks_on) && !host->plat->is_sdio_al_client) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306314 pr_warn("%s: clocks are on after suspend, aborting system "
6315 "suspend\n", mmc_hostname(mmc));
6316 rc = -EAGAIN;
6317 }
6318
6319 return rc;
6320}
6321
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006322static int msmsdcc_pm_resume(struct device *dev)
6323{
6324 struct mmc_host *mmc = dev_get_drvdata(dev);
6325 struct msmsdcc_host *host = mmc_priv(mmc);
6326 int rc = 0;
6327
6328 if (host->plat->is_sdio_al_client)
6329 return 0;
6330
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006331 if (mmc->card && mmc_card_sdio(mmc->card))
Sahitya Tummalafb486372011-09-02 19:01:49 +05306332 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavani1371d192012-08-16 18:46:57 +05306333 /*
6334 * As runtime PM is enabled before calling the device's platform resume
6335 * callback, we use the pm_runtime_suspended API to know if SDCC is
6336 * really runtime suspended or not and set the pending_resume flag only
6337 * if its not runtime suspended.
6338 */
6339 else if (!pm_runtime_suspended(dev))
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006340 host->pending_resume = true;
6341
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006342 if (host->plat->status_irq) {
6343 msmsdcc_check_status((unsigned long)host);
6344 enable_irq(host->plat->status_irq);
6345 }
6346
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006347 return rc;
6348}
6349
Daniel Walker08ecfde2010-06-23 12:32:20 -07006350#else
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006351static int msmsdcc_runtime_suspend(struct device *dev)
6352{
6353 return 0;
6354}
6355static int msmsdcc_runtime_idle(struct device *dev)
6356{
6357 return 0;
6358}
6359static int msmsdcc_pm_suspend(struct device *dev)
6360{
6361 return 0;
6362}
6363static int msmsdcc_pm_resume(struct device *dev)
6364{
6365 return 0;
6366}
6367static int msmsdcc_suspend_noirq(struct device *dev)
6368{
6369 return 0;
6370}
6371static int msmsdcc_runtime_resume(struct device *dev)
6372{
6373 return 0;
6374}
Daniel Walker08ecfde2010-06-23 12:32:20 -07006375#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006376
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006377static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
6378 .runtime_suspend = msmsdcc_runtime_suspend,
6379 .runtime_resume = msmsdcc_runtime_resume,
6380 .runtime_idle = msmsdcc_runtime_idle,
6381 .suspend = msmsdcc_pm_suspend,
6382 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306383 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006384};
6385
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306386static const struct of_device_id msmsdcc_dt_match[] = {
6387 {.compatible = "qcom,msm-sdcc"},
6388
6389};
6390MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
6391
San Mehat9d2bd732009-09-22 16:44:22 -07006392static struct platform_driver msmsdcc_driver = {
6393 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006394 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07006395 .driver = {
6396 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006397 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306398 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07006399 },
6400};
6401
6402static int __init msmsdcc_init(void)
6403{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006404#if defined(CONFIG_DEBUG_FS)
6405 int ret = 0;
6406 ret = msmsdcc_dbg_init();
6407 if (ret) {
6408 pr_err("Failed to create debug fs dir \n");
6409 return ret;
6410 }
6411#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006412 return platform_driver_register(&msmsdcc_driver);
6413}
San Mehat9d2bd732009-09-22 16:44:22 -07006414
San Mehat9d2bd732009-09-22 16:44:22 -07006415static void __exit msmsdcc_exit(void)
6416{
6417 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006418
6419#if defined(CONFIG_DEBUG_FS)
6420 debugfs_remove(debugfs_file);
6421 debugfs_remove(debugfs_dir);
6422#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006423}
6424
6425module_init(msmsdcc_init);
6426module_exit(msmsdcc_exit);
6427
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006428MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07006429MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006430
6431#if defined(CONFIG_DEBUG_FS)
6432
6433static int
6434msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
6435{
6436 file->private_data = inode->i_private;
6437 return 0;
6438}
6439
6440static ssize_t
6441msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
6442 size_t count, loff_t *ppos)
6443{
6444 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08006445 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006446 int max, i;
6447
6448 i = 0;
6449 max = sizeof(buf) - 1;
6450
6451 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
6452 host->curr.cmd, host->curr.data);
6453 if (host->curr.cmd) {
6454 struct mmc_command *cmd = host->curr.cmd;
6455
6456 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
6457 cmd->opcode, cmd->arg, cmd->flags);
6458 }
6459 if (host->curr.data) {
6460 struct mmc_data *data = host->curr.data;
6461 i += scnprintf(buf + i, max - i,
6462 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
6463 data->timeout_ns, data->timeout_clks,
6464 data->blksz, data->blocks, data->error,
6465 data->flags);
6466 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
6467 host->curr.xfer_size, host->curr.xfer_remain,
6468 host->curr.data_xfered, host->dma.sg);
6469 }
6470
6471 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
6472}
6473
6474static const struct file_operations msmsdcc_dbg_state_ops = {
6475 .read = msmsdcc_dbg_state_read,
6476 .open = msmsdcc_dbg_state_open,
6477};
6478
6479static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
6480{
6481 if (debugfs_dir) {
6482 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
6483 0644, debugfs_dir, host,
6484 &msmsdcc_dbg_state_ops);
6485 }
6486}
6487
6488static int __init msmsdcc_dbg_init(void)
6489{
6490 int err;
6491
6492 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
6493 if (IS_ERR(debugfs_dir)) {
6494 err = PTR_ERR(debugfs_dir);
6495 debugfs_dir = NULL;
6496 return err;
6497 }
6498
6499 return 0;
6500}
6501#endif