blob: 71d89ef03111ea2ebe56ce5b5bda52a7f8b366ea [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/**
Maya Erezb7a086f2012-11-29 00:37:36 +0200216 * Apply reset
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530217 *
Maya Erezb7a086f2012-11-29 00:37:36 +0200218 * This function resets SPS BAM and DML cores.
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530219 *
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 */
Maya Erezb7a086f2012-11-29 00:37:36 +0200226static int msmsdcc_bam_dml_reset_and_restore(struct msmsdcc_host *host)
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530227{
228 int rc;
229
Maya Erezb7a086f2012-11-29 00:37:36 +0200230 /* Reset and init DML */
231 rc = msmsdcc_dml_init(host);
232 if (rc) {
233 pr_err("%s: msmsdcc_dml_init error=%d\n",
234 mmc_hostname(host->mmc), rc);
235 goto out;
236 }
237
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530238 /* Reset all SDCC BAM pipes */
239 rc = msmsdcc_sps_reset_ep(host, &host->sps.prod);
Maya Erezb7a086f2012-11-29 00:37:36 +0200240 if (rc) {
241 pr_err("%s: msmsdcc_sps_reset_ep(prod) error=%d\n",
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530242 mmc_hostname(host->mmc), rc);
Maya Erezb7a086f2012-11-29 00:37:36 +0200243 goto out;
244 }
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530245
Maya Erezb7a086f2012-11-29 00:37:36 +0200246 rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
247 if (rc) {
248 pr_err("%s: msmsdcc_sps_reset_ep(cons) error=%d\n",
Krishna Konda5af8f972012-05-14 16:15:24 -0700249 mmc_hostname(host->mmc), rc);
Maya Erezb7a086f2012-11-29 00:37:36 +0200250 goto out;
251 }
252
253 /* Reset BAM */
254 rc = sps_device_reset(host->sps.bam_handle);
255 if (rc) {
256 pr_err("%s: sps_device_reset error=%d\n",
257 mmc_hostname(host->mmc), rc);
258 goto out;
Krishna Konda5af8f972012-05-14 16:15:24 -0700259 }
260
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530261 /* Restore all BAM pipes connections */
262 rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
Maya Erezb7a086f2012-11-29 00:37:36 +0200263 if (rc) {
264 pr_err("%s: msmsdcc_sps_restore_ep(prod) error=%d\n",
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530265 mmc_hostname(host->mmc), rc);
Maya Erezb7a086f2012-11-29 00:37:36 +0200266 goto out;
267 }
268
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530269 rc = msmsdcc_sps_restore_ep(host, &host->sps.cons);
270 if (rc)
Maya Erezb7a086f2012-11-29 00:37:36 +0200271 pr_err("%s: msmsdcc_sps_restore_ep(cons) error=%d\n",
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530272 mmc_hostname(host->mmc), rc);
Maya Erezb7a086f2012-11-29 00:37:36 +0200273 else
274 host->sps.reset_bam = false;
275
276out:
277 return rc;
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530278}
279
280/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700281 * Apply soft reset
282 *
Maya Erezb7a086f2012-11-29 00:37:36 +0200283 * This function applies soft reset to SDCC core.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700284 *
285 * This function should be called to recover from error
286 * conditions encountered with CMD/DATA tranfsers with card.
287 *
288 * Soft reset should only be used with SDCC controller v4.
289 *
290 * @host - Pointer to driver's host structure
291 *
292 */
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530293static void msmsdcc_soft_reset(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700294{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700295 /*
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530296 * Reset controller state machines without resetting
297 * configuration registers (MCI_POWER, MCI_CLK, MCI_INT_MASKn).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700298 */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530299 if (is_sw_reset_save_config(host)) {
300 ktime_t start;
301
302 writel_relaxed(readl_relaxed(host->base + MMCIPOWER)
303 | MCI_SW_RST_CFG, host->base + MMCIPOWER);
304 msmsdcc_sync_reg_wr(host);
305
306 start = ktime_get();
307 while (readl_relaxed(host->base + MMCIPOWER) & MCI_SW_RST_CFG) {
308 /*
309 * SW reset can take upto 10HCLK + 15MCLK cycles.
310 * Calculating based on min clk rates (hclk = 27MHz,
311 * mclk = 400KHz) it comes to ~40us. Let's poll for
312 * max. 1ms for reset completion.
313 */
314 if (ktime_to_us(ktime_sub(ktime_get(), start)) > 1000) {
315 pr_err("%s: %s failed\n",
316 mmc_hostname(host->mmc), __func__);
317 BUG();
318 }
319 }
320 } else {
321 writel_relaxed(0, host->base + MMCICOMMAND);
322 msmsdcc_sync_reg_wr(host);
323 writel_relaxed(0, host->base + MMCIDATACTRL);
324 msmsdcc_sync_reg_wr(host);
325 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530326}
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530327
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530328static void msmsdcc_hard_reset(struct msmsdcc_host *host)
329{
330 int ret;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530331
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530332 /*
333 * Reset SDCC controller to power on default state.
334 * Don't issue a reset request to clock control block if
335 * SDCC controller itself can support hard reset.
336 */
337 if (is_sw_hard_reset(host)) {
338 ktime_t start;
339
340 writel_relaxed(readl_relaxed(host->base + MMCIPOWER)
341 | MCI_SW_RST, host->base + MMCIPOWER);
342 msmsdcc_sync_reg_wr(host);
343
344 start = ktime_get();
345 while (readl_relaxed(host->base + MMCIPOWER) & MCI_SW_RST) {
346 /*
347 * See comment in msmsdcc_soft_reset() on choosing 1ms
348 * poll timeout.
349 */
350 if (ktime_to_us(ktime_sub(ktime_get(), start)) > 1000) {
351 pr_err("%s: %s failed\n",
352 mmc_hostname(host->mmc), __func__);
353 BUG();
354 }
355 }
356 } else {
357 ret = clk_reset(host->clk, CLK_RESET_ASSERT);
358 if (ret)
359 pr_err("%s: Clock assert failed at %u Hz" \
360 " with err %d\n", mmc_hostname(host->mmc),
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530361 host->clk_rate, ret);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530362
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530363 ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
364 if (ret)
365 pr_err("%s: Clock deassert failed at %u Hz" \
366 " with err %d\n", mmc_hostname(host->mmc),
367 host->clk_rate, ret);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530368
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530369 mb();
370 /* Give some delay for clock reset to propogate to controller */
371 msmsdcc_delay(host);
372 }
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530373}
374
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700375static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
376{
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530377 if (is_soft_reset(host)) {
Maya Erezb7a086f2012-11-29 00:37:36 +0200378 if (is_sps_mode(host))
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530379 /*
Maya Erezb7a086f2012-11-29 00:37:36 +0200380 * delay the SPS BAM reset in thread context as
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530381 * sps_connect/sps_disconnect APIs can be called
382 * only from non-atomic context.
383 */
Maya Erezb7a086f2012-11-29 00:37:36 +0200384 host->sps.reset_bam = true;
385
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530386 msmsdcc_soft_reset(host);
387
388 pr_debug("%s: Applied soft reset to Controller\n",
389 mmc_hostname(host->mmc));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700390 } else {
Maya Erezb7a086f2012-11-29 00:37:36 +0200391 /*
392 * When there is a requirement to use this hard reset,
393 * BAM needs to be reconfigured as well by calling
394 * msmsdcc_sps_exit and msmsdcc_sps_init.
395 */
396
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700397 /* Give Clock reset (hard reset) to controller */
398 u32 mci_clk = 0;
399 u32 mci_mask0 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700400
401 /* Save the controller state */
402 mci_clk = readl_relaxed(host->base + MMCICLOCK);
403 mci_mask0 = readl_relaxed(host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +0530404 host->pwr = readl_relaxed(host->base + MMCIPOWER);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700405 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700406
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530407 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700408 pr_debug("%s: Controller has been reinitialized\n",
409 mmc_hostname(host->mmc));
410
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700411 /* Restore the contoller state */
412 writel_relaxed(host->pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530413 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700414 writel_relaxed(mci_clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530415 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700416 writel_relaxed(mci_mask0, host->base + MMCIMASK0);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530417 mb(); /* no delay required after writing to MASK0 register */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700418 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530419
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700420 if (host->dummy_52_needed)
421 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700422}
423
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530424static void msmsdcc_reset_dpsm(struct msmsdcc_host *host)
425{
426 struct mmc_request *mrq = host->curr.mrq;
427
428 if (!mrq || !mrq->cmd || (!mrq->data && !host->pending_dpsm_reset))
429 goto out;
430
431 /*
432 * For CMD24, if auto prog done is not supported defer
433 * dpsm reset until prog done is received. Otherwise,
434 * we poll here unnecessarily as TXACTIVE will not be
435 * deasserted until DAT0 goes high.
436 */
437 if ((mrq->cmd->opcode == MMC_WRITE_BLOCK) && !is_auto_prog_done(host)) {
438 host->pending_dpsm_reset = true;
439 goto out;
440 }
441
442 /* Make sure h/w (TX/RX) is inactive before resetting DPSM */
443 if (is_wait_for_tx_rx_active(host)) {
444 ktime_t start = ktime_get();
445
446 while (readl_relaxed(host->base + MMCISTATUS) &
447 (MCI_TXACTIVE | MCI_RXACTIVE)) {
448 /*
449 * TX/RX active bits may be asserted for 4HCLK + 4MCLK
450 * cycles (~11us) after data transfer due to clock mux
451 * switching delays. Let's poll for 1ms and panic if
452 * still active.
453 */
454 if (ktime_to_us(ktime_sub(ktime_get(), start)) > 1000) {
455 pr_err("%s: %s still active\n",
456 mmc_hostname(host->mmc),
457 readl_relaxed(host->base + MMCISTATUS)
458 & MCI_TXACTIVE ? "TX" : "RX");
459 msmsdcc_dump_sdcc_state(host);
460 BUG();
461 }
462 }
463 }
464
465 writel_relaxed(0, host->base + MMCIDATACTRL);
466 msmsdcc_sync_reg_wr(host); /* Allow the DPSM to be reset */
467 host->pending_dpsm_reset = false;
468out:
469 return;
470}
471
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700472static int
San Mehat9d2bd732009-09-22 16:44:22 -0700473msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
474{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700475 int retval = 0;
476
San Mehat9d2bd732009-09-22 16:44:22 -0700477 BUG_ON(host->curr.data);
478
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700479 del_timer(&host->req_tout_timer);
San Mehat9d2bd732009-09-22 16:44:22 -0700480
481 if (mrq->data)
482 mrq->data->bytes_xfered = host->curr.data_xfered;
483 if (mrq->cmd->error == -ETIMEDOUT)
484 mdelay(5);
485
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530486 msmsdcc_reset_dpsm(host);
487
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530488 /* Clear current request information as current request has ended */
489 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
490
San Mehat9d2bd732009-09-22 16:44:22 -0700491 /*
492 * Need to drop the host lock here; mmc_request_done may call
493 * back into the driver...
494 */
495 spin_unlock(&host->lock);
496 mmc_request_done(host->mmc, mrq);
497 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700498
499 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700500}
501
502static void
503msmsdcc_stop_data(struct msmsdcc_host *host)
504{
San Mehat9d2bd732009-09-22 16:44:22 -0700505 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530506 host->curr.got_dataend = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +0530507 host->curr.wait_for_auto_prog_done = false;
508 host->curr.got_auto_prog_done = false;
San Mehat9d2bd732009-09-22 16:44:22 -0700509}
510
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700511static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700512{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700513 return host->core_memres->start + MMCIFIFO;
514}
515
516static inline unsigned int msmsdcc_get_min_sup_clk_rate(
517 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530518
Subhash Jadavanidd432952012-03-28 11:25:56 +0530519static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700520{
521 mb();
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530522 if (!is_wait_for_reg_write(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +0530523 udelay(host->reg_write_delay);
524 else if (readl_relaxed(host->base + MCI_STATUS2) &
525 MCI_MCLK_REG_WR_ACTIVE) {
526 ktime_t start, diff;
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530527
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530528 start = ktime_get();
529 while (readl_relaxed(host->base + MCI_STATUS2) &
530 MCI_MCLK_REG_WR_ACTIVE) {
531 diff = ktime_sub(ktime_get(), start);
532 /* poll for max. 1 ms */
533 if (ktime_to_us(diff) > 1000) {
534 pr_warning("%s: previous reg. write is"
535 " still active\n",
536 mmc_hostname(host->mmc));
537 break;
538 }
539 }
540 }
San Mehat9d2bd732009-09-22 16:44:22 -0700541}
542
Subhash Jadavanidd432952012-03-28 11:25:56 +0530543static inline void msmsdcc_delay(struct msmsdcc_host *host)
544{
545 udelay(host->reg_write_delay);
546
San Mehat9d2bd732009-09-22 16:44:22 -0700547}
548
San Mehat56a8b5b2009-11-21 12:29:46 -0800549static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700550msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
551{
552 writel_relaxed(arg, host->base + MMCIARGUMENT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700553 writel_relaxed(c, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530554 /*
555 * As after sending the command, we don't write any of the
556 * controller registers and just wait for the
557 * CMD_RESPOND_END/CMD_SENT/Command failure notication
558 * from Controller.
559 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700560 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800561}
562
563static void
564msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
565{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700566 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800567
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700568 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
569 writel_relaxed((unsigned int)host->curr.xfer_size,
570 host->base + MMCIDATALENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700571 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530572 msmsdcc_sync_reg_wr(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800573
San Mehat6ac9ea62009-12-02 17:24:58 -0800574 if (host->cmd_cmd) {
575 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700576 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800577 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800578}
579
San Mehat9d2bd732009-09-22 16:44:22 -0700580static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530581msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700582{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530583 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700584 unsigned long flags;
585 struct mmc_request *mrq;
586
587 spin_lock_irqsave(&host->lock, flags);
588 mrq = host->curr.mrq;
589 BUG_ON(!mrq);
590
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530591 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700592 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700593 goto out;
594 }
595
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530596 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700597 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700598 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700599 } else {
600 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530601 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700602 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530603 mmc_hostname(host->mmc), host->dma.result);
604 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700605 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530606 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530607 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700608 host->dma.err.flush[0], host->dma.err.flush[1],
609 host->dma.err.flush[2], host->dma.err.flush[3],
610 host->dma.err.flush[4],
611 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530612 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700613 if (!mrq->data->error)
614 mrq->data->error = -EIO;
615 }
Asutosh Dasaccacd42012-03-08 14:33:17 +0530616 if (!mrq->data->host_cookie)
617 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
618 host->dma.num_ents, host->dma.dir);
San Mehat9d2bd732009-09-22 16:44:22 -0700619
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700620 if (host->curr.user_pages) {
621 struct scatterlist *sg = host->dma.sg;
622 int i;
623
624 for (i = 0; i < host->dma.num_ents; i++, sg++)
625 flush_dcache_page(sg_page(sg));
626 }
San Mehat9d2bd732009-09-22 16:44:22 -0700627
San Mehat9d2bd732009-09-22 16:44:22 -0700628 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800629 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700630
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530631 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
632 (host->curr.wait_for_auto_prog_done &&
633 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700634 /*
635 * If we've already gotten our DATAEND / DATABLKEND
636 * for this request, then complete it through here.
637 */
San Mehat9d2bd732009-09-22 16:44:22 -0700638
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700639 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700640 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700641 host->curr.xfer_remain -= host->curr.xfer_size;
642 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700643 if (host->dummy_52_needed) {
San Mehat9d2bd732009-09-22 16:44:22 -0700644 mrq->data->bytes_xfered = host->curr.data_xfered;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700645 host->dummy_52_sent = 1;
646 msmsdcc_start_command(host, &dummy52cmd,
647 MCI_CPSM_PROGENA);
648 goto out;
649 }
650 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530651 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530652 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700653 mrq->data->bytes_xfered = host->curr.data_xfered;
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530654 msmsdcc_reset_dpsm(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700655 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530656 /*
657 * Clear current request information as current
658 * request has ended
659 */
660 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
San Mehat9d2bd732009-09-22 16:44:22 -0700661 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700662
San Mehat9d2bd732009-09-22 16:44:22 -0700663 mmc_request_done(host->mmc, mrq);
664 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530665 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
666 || !mrq->sbc)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700667 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530668 }
San Mehat9d2bd732009-09-22 16:44:22 -0700669 }
670
671out:
672 spin_unlock_irqrestore(&host->lock, flags);
673 return;
674}
675
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700676#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
677/**
678 * Callback notification from SPS driver
679 *
680 * This callback function gets triggered called from
681 * SPS driver when requested SPS data transfer is
682 * completed.
683 *
684 * SPS driver invokes this callback in BAM irq context so
685 * SDCC driver schedule a tasklet for further processing
686 * this callback notification at later point of time in
687 * tasklet context and immediately returns control back
688 * to SPS driver.
689 *
690 * @nofity - Pointer to sps event notify sturcture
691 *
692 */
693static void
694msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
695{
696 struct msmsdcc_host *host =
697 (struct msmsdcc_host *)
698 ((struct sps_event_notify *)notify)->user;
699
700 host->sps.notify = *notify;
701 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
702 mmc_hostname(host->mmc), __func__, notify->event_id,
703 notify->data.transfer.iovec.addr,
704 notify->data.transfer.iovec.size,
705 notify->data.transfer.iovec.flags);
706 /* Schedule a tasklet for completing data transfer */
707 tasklet_schedule(&host->sps.tlet);
708}
709
710/**
711 * Tasklet handler for processing SPS callback event
712 *
713 * This function processing SPS event notification and
714 * checks if the SPS transfer is completed or not and
715 * then accordingly notifies status to MMC core layer.
716 *
717 * This function is called in tasklet context.
718 *
719 * @data - Pointer to sdcc driver data
720 *
721 */
722static void msmsdcc_sps_complete_tlet(unsigned long data)
723{
724 unsigned long flags;
725 int i, rc;
726 u32 data_xfered = 0;
727 struct mmc_request *mrq;
728 struct sps_iovec iovec;
729 struct sps_pipe *sps_pipe_handle;
730 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
731 struct sps_event_notify *notify = &host->sps.notify;
732
733 spin_lock_irqsave(&host->lock, flags);
734 if (host->sps.dir == DMA_FROM_DEVICE)
735 sps_pipe_handle = host->sps.prod.pipe_handle;
736 else
737 sps_pipe_handle = host->sps.cons.pipe_handle;
738 mrq = host->curr.mrq;
739
740 if (!mrq) {
741 spin_unlock_irqrestore(&host->lock, flags);
742 return;
743 }
744
745 pr_debug("%s: %s: sps event_id=%d\n",
746 mmc_hostname(host->mmc), __func__,
747 notify->event_id);
748
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700749 /*
750 * Got End of transfer event!!! Check if all of the data
751 * has been transferred?
752 */
753 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
754 rc = sps_get_iovec(sps_pipe_handle, &iovec);
755 if (rc) {
756 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
757 mmc_hostname(host->mmc), __func__, rc, i);
758 break;
759 }
760 data_xfered += iovec.size;
761 }
762
763 if (data_xfered == host->curr.xfer_size) {
764 host->curr.data_xfered = host->curr.xfer_size;
765 host->curr.xfer_remain -= host->curr.xfer_size;
766 pr_debug("%s: Data xfer success. data_xfered=0x%x",
767 mmc_hostname(host->mmc),
768 host->curr.xfer_size);
769 } else {
770 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
771 " xfer_size=%d", mmc_hostname(host->mmc),
772 data_xfered, host->curr.xfer_size);
773 msmsdcc_reset_and_restore(host);
774 if (!mrq->data->error)
775 mrq->data->error = -EIO;
776 }
777
778 /* Unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +0530779 if (!mrq->data->host_cookie)
780 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
781 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700782 host->sps.sg = NULL;
783 host->sps.busy = 0;
784
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530785 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
786 (host->curr.wait_for_auto_prog_done &&
787 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700788 /*
789 * If we've already gotten our DATAEND / DATABLKEND
790 * for this request, then complete it through here.
791 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700792
793 if (!mrq->data->error) {
794 host->curr.data_xfered = host->curr.xfer_size;
795 host->curr.xfer_remain -= host->curr.xfer_size;
796 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700797 if (host->dummy_52_needed) {
798 mrq->data->bytes_xfered = host->curr.data_xfered;
799 host->dummy_52_sent = 1;
800 msmsdcc_start_command(host, &dummy52cmd,
801 MCI_CPSM_PROGENA);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700802 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700803 return;
804 }
805 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530806 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530807 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700808 mrq->data->bytes_xfered = host->curr.data_xfered;
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530809 msmsdcc_reset_dpsm(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700810 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530811 /*
812 * Clear current request information as current
813 * request has ended
814 */
815 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700816 spin_unlock_irqrestore(&host->lock, flags);
817
818 mmc_request_done(host->mmc, mrq);
819 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530820 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
821 || !mrq->sbc)) {
822 msmsdcc_start_command(host, mrq->data->stop, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700823 }
824 }
825 spin_unlock_irqrestore(&host->lock, flags);
826}
827
828/**
829 * Exit from current SPS data transfer
830 *
831 * This function exits from current SPS data transfer.
832 *
833 * This function should be called when error condition
834 * is encountered during data transfer.
835 *
836 * @host - Pointer to sdcc host structure
837 *
838 */
839static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
840{
841 struct mmc_request *mrq;
842
843 mrq = host->curr.mrq;
844 BUG_ON(!mrq);
845
846 msmsdcc_reset_and_restore(host);
847 if (!mrq->data->error)
848 mrq->data->error = -EIO;
849
850 /* Unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +0530851 if (!mrq->data->host_cookie)
852 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
853 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700854
855 host->sps.sg = NULL;
856 host->sps.busy = 0;
857 if (host->curr.data)
858 msmsdcc_stop_data(host);
859
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530860 if (!mrq->data->stop || mrq->cmd->error ||
861 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700862 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530863 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
864 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700865 msmsdcc_start_command(host, mrq->data->stop, 0);
866
867}
868#else
869static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
870static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
871static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
872#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
873
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530874static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700875
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530876static void
877msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
878 unsigned int result,
879 struct msm_dmov_errdata *err)
880{
881 struct msmsdcc_dma_data *dma_data =
882 container_of(cmd, struct msmsdcc_dma_data, hdr);
883 struct msmsdcc_host *host = dma_data->host;
884
885 dma_data->result = result;
886 if (err)
887 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
888
889 tasklet_schedule(&host->dma_tlet);
890}
891
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530892static bool msmsdcc_is_dma_possible(struct msmsdcc_host *host,
893 struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700894{
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530895 bool ret = true;
896 u32 xfer_size = data->blksz * data->blocks;
San Mehat9d2bd732009-09-22 16:44:22 -0700897
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530898 if (is_sps_mode(host)) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530899 /*
900 * BAM Mode: Fall back on PIO if size is less
901 * than or equal to SPS_MIN_XFER_SIZE bytes.
902 */
903 if (xfer_size <= SPS_MIN_XFER_SIZE)
904 ret = false;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530905 } else if (is_dma_mode(host)) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530906 /*
907 * ADM Mode: Fall back on PIO if size is less than FIFO size
908 * or not integer multiple of FIFO size
909 */
910 if (xfer_size % MCI_FIFOSIZE)
911 ret = false;
912 } else {
913 /* PIO Mode */
914 ret = false;
915 }
916
917 return ret;
San Mehat9d2bd732009-09-22 16:44:22 -0700918}
919
920static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
921{
922 struct msmsdcc_nc_dmadata *nc;
923 dmov_box *box;
924 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700925 unsigned int n;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530926 int i, err = 0, box_cmd_cnt = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700927 struct scatterlist *sg = data->sg;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530928 unsigned int len, offset;
San Mehat9d2bd732009-09-22 16:44:22 -0700929
Krishna Konda25786ec2011-07-25 16:21:36 -0700930 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700931 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700932
Krishna Konda25786ec2011-07-25 16:21:36 -0700933 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
San Mehat9d2bd732009-09-22 16:44:22 -0700934
935 host->dma.sg = data->sg;
936 host->dma.num_ents = data->sg_len;
937
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530938 /* Prevent memory corruption */
939 BUG_ON(host->dma.num_ents > msmsdcc_get_nr_sg(host));
San Mehat56a8b5b2009-11-21 12:29:46 -0800940
San Mehat9d2bd732009-09-22 16:44:22 -0700941 nc = host->dma.nc;
942
San Mehat9d2bd732009-09-22 16:44:22 -0700943 if (data->flags & MMC_DATA_READ)
944 host->dma.dir = DMA_FROM_DEVICE;
945 else
946 host->dma.dir = DMA_TO_DEVICE;
947
Asutosh Dasaccacd42012-03-08 14:33:17 +0530948 if (!data->host_cookie) {
949 n = msmsdcc_prep_xfer(host, data);
950 if (unlikely(n < 0)) {
951 host->dma.sg = NULL;
952 host->dma.num_ents = 0;
953 return -ENOMEM;
954 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800955 }
San Mehat9d2bd732009-09-22 16:44:22 -0700956
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530957 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
958 host->curr.user_pages = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700959 box = &nc->cmd[0];
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530960 for (i = 0; i < host->dma.num_ents; i++) {
961 len = sg_dma_len(sg);
962 offset = 0;
963
964 do {
965 /* Check if we can do DMA */
966 if (!len || (box_cmd_cnt >= MMC_MAX_DMA_CMDS)) {
967 err = -ENOTSUPP;
968 goto unmap;
969 }
970
971 box->cmd = CMD_MODE_BOX;
972
973 if (len >= MMC_MAX_DMA_BOX_LENGTH) {
974 len = MMC_MAX_DMA_BOX_LENGTH;
975 len -= len % data->blksz;
976 }
977 rows = (len % MCI_FIFOSIZE) ?
978 (len / MCI_FIFOSIZE) + 1 :
979 (len / MCI_FIFOSIZE);
980
981 if (data->flags & MMC_DATA_READ) {
982 box->src_row_addr = msmsdcc_fifo_addr(host);
983 box->dst_row_addr = sg_dma_address(sg) + offset;
984 box->src_dst_len = (MCI_FIFOSIZE << 16) |
985 (MCI_FIFOSIZE);
986 box->row_offset = MCI_FIFOSIZE;
987 box->num_rows = rows * ((1 << 16) + 1);
988 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
989 } else {
990 box->src_row_addr = sg_dma_address(sg) + offset;
991 box->dst_row_addr = msmsdcc_fifo_addr(host);
992 box->src_dst_len = (MCI_FIFOSIZE << 16) |
993 (MCI_FIFOSIZE);
994 box->row_offset = (MCI_FIFOSIZE << 16);
995 box->num_rows = rows * ((1 << 16) + 1);
996 box->cmd |= CMD_DST_CRCI(host->dma.crci);
997 }
998
999 offset += len;
1000 len = sg_dma_len(sg) - offset;
1001 box++;
1002 box_cmd_cnt++;
1003 } while (len);
1004 sg++;
1005 }
1006 /* Mark last command */
1007 box--;
1008 box->cmd |= CMD_LC;
San Mehat9d2bd732009-09-22 16:44:22 -07001009
1010 /* location of command block must be 64 bit aligned */
1011 BUG_ON(host->dma.cmd_busaddr & 0x07);
1012
1013 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
1014 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
1015 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
1016 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
1017
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05301018 /* Flush all data to memory before starting dma */
1019 mb();
1020
1021unmap:
1022 if (err) {
Asutosh Dasaccacd42012-03-08 14:33:17 +05301023 if (!data->host_cookie)
1024 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
1025 host->dma.num_ents, host->dma.dir);
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05301026 pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
1027 mmc_hostname(host->mmc), err);
San Mehat9d2bd732009-09-22 16:44:22 -07001028 }
1029
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05301030 return err;
San Mehat9d2bd732009-09-22 16:44:22 -07001031}
1032
Asutosh Dasaccacd42012-03-08 14:33:17 +05301033static int msmsdcc_prep_xfer(struct msmsdcc_host *host,
1034 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -08001035{
Asutosh Dasaccacd42012-03-08 14:33:17 +05301036 int rc = 0;
1037 unsigned int dir;
1038
1039 /* Prevent memory corruption */
1040 BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
1041
1042 if (data->flags & MMC_DATA_READ)
1043 dir = DMA_FROM_DEVICE;
1044 else
1045 dir = DMA_TO_DEVICE;
1046
1047 /* Make sg buffers DMA ready */
1048 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
1049 dir);
1050
1051 if (unlikely(rc != data->sg_len)) {
1052 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
1053 mmc_hostname(host->mmc), rc);
1054 rc = -ENOMEM;
1055 goto dma_map_err;
1056 }
1057
1058 pr_debug("%s: %s: %s: sg_len=%d\n",
1059 mmc_hostname(host->mmc), __func__,
1060 dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
1061 data->sg_len);
1062
1063 goto out;
1064
1065dma_map_err:
1066 dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
1067 data->flags);
1068out:
1069 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07001070}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001071#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
1072/**
1073 * Submits data transfer request to SPS driver
1074 *
1075 * This function make sg (scatter gather) data buffers
1076 * DMA ready and then submits them to SPS driver for
1077 * transfer.
1078 *
1079 * @host - Pointer to sdcc host structure
1080 * @data - Pointer to mmc_data structure
1081 *
1082 * @return 0 if success else negative value
1083 */
1084static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
Asutosh Dasaccacd42012-03-08 14:33:17 +05301085 struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -07001086{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001087 int rc = 0;
1088 u32 flags;
1089 int i;
1090 u32 addr, len, data_cnt;
1091 struct scatterlist *sg = data->sg;
1092 struct sps_pipe *sps_pipe_handle;
1093
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001094 host->sps.sg = data->sg;
1095 host->sps.num_ents = data->sg_len;
1096 host->sps.xfer_req_cnt = 0;
1097 if (data->flags & MMC_DATA_READ) {
1098 host->sps.dir = DMA_FROM_DEVICE;
1099 sps_pipe_handle = host->sps.prod.pipe_handle;
1100 } else {
1101 host->sps.dir = DMA_TO_DEVICE;
1102 sps_pipe_handle = host->sps.cons.pipe_handle;
1103 }
1104
Asutosh Dasaccacd42012-03-08 14:33:17 +05301105 if (!data->host_cookie) {
1106 rc = msmsdcc_prep_xfer(host, data);
1107 if (unlikely(rc < 0)) {
1108 host->dma.sg = NULL;
1109 host->dma.num_ents = 0;
1110 goto out;
1111 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001112 }
1113
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001114 for (i = 0; i < data->sg_len; i++) {
1115 /*
1116 * Check if this is the last buffer to transfer?
1117 * If yes then set the INT and EOT flags.
1118 */
1119 len = sg_dma_len(sg);
1120 addr = sg_dma_address(sg);
1121 flags = 0;
1122 while (len > 0) {
1123 if (len > SPS_MAX_DESC_SIZE) {
1124 data_cnt = SPS_MAX_DESC_SIZE;
1125 } else {
1126 data_cnt = len;
1127 if (i == data->sg_len - 1)
1128 flags = SPS_IOVEC_FLAG_INT |
1129 SPS_IOVEC_FLAG_EOT;
1130 }
1131 rc = sps_transfer_one(sps_pipe_handle, addr,
1132 data_cnt, host, flags);
1133 if (rc) {
1134 pr_err("%s: sps_transfer_one() error! rc=%d,"
1135 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
1136 mmc_hostname(host->mmc), rc,
1137 (u32)sps_pipe_handle, (u32)sg, i);
1138 goto dma_map_err;
1139 }
1140 addr += data_cnt;
1141 len -= data_cnt;
1142 host->sps.xfer_req_cnt++;
1143 }
1144 sg++;
1145 }
1146 goto out;
1147
1148dma_map_err:
1149 /* unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +05301150 if (!data->host_cookie)
1151 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
1152 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001153out:
1154 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07001155}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001156#else
1157static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
1158 struct mmc_data *data) { return 0; }
1159#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -07001160
1161static void
San Mehat56a8b5b2009-11-21 12:29:46 -08001162msmsdcc_start_command_deferred(struct msmsdcc_host *host,
1163 struct mmc_command *cmd, u32 *c)
1164{
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301165 DBG(host, "op %02x arg %08x flags %08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001166 cmd->opcode, cmd->arg, cmd->flags);
1167
San Mehat56a8b5b2009-11-21 12:29:46 -08001168 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
1169
1170 if (cmd->flags & MMC_RSP_PRESENT) {
1171 if (cmd->flags & MMC_RSP_136)
1172 *c |= MCI_CPSM_LONGRSP;
1173 *c |= MCI_CPSM_RESPONSE;
1174 }
1175
1176 if (/*interrupt*/0)
1177 *c |= MCI_CPSM_INTERRUPT;
1178
Asutosh Das05049132012-05-09 12:38:15 +05301179 /* DAT_CMD bit should be set for all ADTC */
1180 if (mmc_cmd_type(cmd) == MMC_CMD_ADTC)
San Mehat56a8b5b2009-11-21 12:29:46 -08001181 *c |= MCI_CSPM_DATCMD;
1182
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001183 /* Check if AUTO CMD19 is required or not? */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301184 if (host->tuning_needed &&
1185 !(host->mmc->ios.timing == MMC_TIMING_MMC_HS200)) {
1186
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301187 /*
1188 * For open ended block read operation (without CMD23),
1189 * AUTO_CMD19 bit should be set while sending the READ command.
1190 * For close ended block read operation (with CMD23),
1191 * AUTO_CMD19 bit should be set while sending CMD23.
1192 */
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301193 if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
1194 host->curr.mrq->cmd->opcode ==
1195 MMC_READ_MULTIPLE_BLOCK) ||
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301196 (!host->curr.mrq->sbc &&
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301197 (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
1198 cmd->opcode == MMC_READ_MULTIPLE_BLOCK))) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301199 msmsdcc_enable_cdr_cm_sdc4_dll(host);
1200 *c |= MCI_CSPM_AUTO_CMD19;
1201 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001202 }
1203
Subhash Jadavanif97d2992012-07-13 14:47:47 +05301204 if (cmd->mrq->data && (cmd->mrq->data->flags & MMC_DATA_READ))
1205 writel_relaxed((readl_relaxed(host->base +
1206 MCI_DLL_CONFIG) | MCI_CDR_EN),
1207 host->base + MCI_DLL_CONFIG);
1208 else
1209 /* Clear CDR_EN bit for non read operations */
1210 writel_relaxed((readl_relaxed(host->base +
1211 MCI_DLL_CONFIG) & ~MCI_CDR_EN),
1212 host->base + MCI_DLL_CONFIG);
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05301213
Sujit Reddy Thumma02868752012-06-25 17:22:56 +05301214 if (((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) ||
1215 (cmd->opcode == MMC_SEND_STATUS &&
1216 !(cmd->flags & MMC_CMD_ADTC))) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301217 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001218 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301219 }
1220
San Mehat56a8b5b2009-11-21 12:29:46 -08001221 if (cmd == cmd->mrq->stop)
1222 *c |= MCI_CSPM_MCIABORT;
1223
San Mehat56a8b5b2009-11-21 12:29:46 -08001224 if (host->curr.cmd != NULL) {
Girish K Sa3c76eb2011-10-11 11:44:09 +05301225 pr_err("%s: Overlapping command requests\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001226 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -08001227 }
1228 host->curr.cmd = cmd;
1229}
1230
1231static void
1232msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1233 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001234{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301235 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001236 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001237 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001238 unsigned int pio_irqmask = 0;
1239
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301240 BUG_ON(!data->sg);
1241 BUG_ON(!data->sg_len);
1242
San Mehat9d2bd732009-09-22 16:44:22 -07001243 host->curr.data = data;
1244 host->curr.xfer_size = data->blksz * data->blocks;
1245 host->curr.xfer_remain = host->curr.xfer_size;
1246 host->curr.data_xfered = 0;
1247 host->curr.got_dataend = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301248 host->curr.got_auto_prog_done = false;
San Mehat9d2bd732009-09-22 16:44:22 -07001249
San Mehat9d2bd732009-09-22 16:44:22 -07001250 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1251
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301252 if (host->curr.wait_for_auto_prog_done)
1253 datactrl |= MCI_AUTO_PROG_DONE;
San Mehat9d2bd732009-09-22 16:44:22 -07001254
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05301255 if (msmsdcc_is_dma_possible(host, data)) {
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301256 if (is_dma_mode(host) && !msmsdcc_config_dma(host, data)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001257 datactrl |= MCI_DPSM_DMAENABLE;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301258 } else if (is_sps_mode(host)) {
Krishna Kondad337ddd2012-08-19 11:16:39 -07001259 if (!msmsdcc_sps_start_xfer(host, data)) {
1260 /* Now kick start DML transfer */
1261 mb();
1262 msmsdcc_dml_start_xfer(host, data);
1263 datactrl |= MCI_DPSM_DMAENABLE;
1264 host->sps.busy = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001265 }
1266 }
1267 }
1268
1269 /* Is data transfer in PIO mode required? */
1270 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001271 if (data->flags & MMC_DATA_READ) {
1272 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1273 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1274 pio_irqmask |= MCI_RXDATAAVLBLMASK;
1275 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001276 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1277 MCI_TXFIFOEMPTYMASK;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001278
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001279 msmsdcc_sg_start(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001280 }
1281
1282 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301283 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
Subhash Jadavanif5277752011-10-12 16:47:52 +05301284 else if (host->curr.use_wr_data_pend)
1285 datactrl |= MCI_DATA_PEND;
San Mehat9d2bd732009-09-22 16:44:22 -07001286
San Mehat56a8b5b2009-11-21 12:29:46 -08001287 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001288 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001289 timeout = data->timeout_clks + (unsigned int)clks*2 ;
Subhash Jadavani63540362012-06-12 14:56:04 +05301290 WARN(!timeout,
1291 "%s: data timeout is zero. timeout_ns=0x%x, timeout_clks=0x%x\n",
1292 mmc_hostname(host->mmc), data->timeout_ns, data->timeout_clks);
San Mehat9d2bd732009-09-22 16:44:22 -07001293
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301294 if (is_dma_mode(host) && (datactrl & MCI_DPSM_DMAENABLE)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001295 /* Use ADM (Application Data Mover) HW for Data transfer */
1296 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001297 host->cmd_timeout = timeout;
1298 host->cmd_pio_irqmask = pio_irqmask;
1299 host->cmd_datactrl = datactrl;
1300 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001301
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001302 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1303 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001304 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001305
1306 if (cmd) {
1307 msmsdcc_start_command_deferred(host, cmd, &c);
1308 host->cmd_c = c;
1309 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001310 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1311 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1312 host->base + MMCIMASK0);
1313 mb();
1314 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001315 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001316 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001317 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001318
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001319 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001320
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001321 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1322 (~(MCI_IRQ_PIO))) | pio_irqmask,
1323 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001324 writel_relaxed(datactrl, base + MMCIDATACTRL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001325
1326 if (cmd) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05301327 /* Delay between data/command */
1328 msmsdcc_sync_reg_wr(host);
San Mehat56a8b5b2009-11-21 12:29:46 -08001329 /* Daisy-chain the command if requested */
1330 msmsdcc_start_command(host, cmd, c);
Subhash Jadavanidd432952012-03-28 11:25:56 +05301331 } else {
1332 /*
1333 * We don't need delay after writing to DATA_CTRL
1334 * register if we are not writing to CMD register
1335 * immediately after this. As we already have delay
1336 * before sending the command, we just need mb() here.
1337 */
1338 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001339 }
San Mehat9d2bd732009-09-22 16:44:22 -07001340 }
1341}
1342
1343static void
1344msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1345{
San Mehat56a8b5b2009-11-21 12:29:46 -08001346 msmsdcc_start_command_deferred(host, cmd, &c);
1347 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001348}
1349
1350static void
1351msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1352 unsigned int status)
1353{
1354 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001355 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
Subhash Jadavanib30c9822012-03-27 18:03:16 +05301356 || data->mrq->cmd->opcode == MMC_BUS_TEST_R
1357 || data->mrq->cmd->opcode ==
1358 MMC_SEND_TUNING_BLOCK_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001359 pr_err("%s: Data CRC error\n",
1360 mmc_hostname(host->mmc));
1361 pr_err("%s: opcode 0x%.8x\n", __func__,
1362 data->mrq->cmd->opcode);
1363 pr_err("%s: blksz %d, blocks %d\n", __func__,
1364 data->blksz, data->blocks);
1365 data->error = -EILSEQ;
1366 }
San Mehat9d2bd732009-09-22 16:44:22 -07001367 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001368 /* CRC is optional for the bus test commands, not all
1369 * cards respond back with CRC. However controller
1370 * waits for the CRC and times out. Hence ignore the
1371 * data timeouts during the Bustest.
1372 */
1373 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1374 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301375 pr_err("%s: CMD%d: Data timeout\n",
1376 mmc_hostname(host->mmc),
1377 data->mrq->cmd->opcode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001378 data->error = -ETIMEDOUT;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301379 msmsdcc_dump_sdcc_state(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001380 }
San Mehat9d2bd732009-09-22 16:44:22 -07001381 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001382 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001383 data->error = -EIO;
1384 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001385 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001386 data->error = -EIO;
1387 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001388 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001389 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001390 data->error = -EIO;
1391 }
San Mehat9d2bd732009-09-22 16:44:22 -07001392
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001393 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001394 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001395 host->dummy_52_needed = 0;
1396}
San Mehat9d2bd732009-09-22 16:44:22 -07001397
1398static int
1399msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1400{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001401 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001402 uint32_t *ptr = (uint32_t *) buffer;
1403 int count = 0;
1404
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301405 if (remain % 4)
1406 remain = ((remain >> 2) + 1) << 2;
1407
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001408 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1409
1410 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001411 ptr++;
1412 count += sizeof(uint32_t);
1413
1414 remain -= sizeof(uint32_t);
1415 if (remain == 0)
1416 break;
1417 }
1418 return count;
1419}
1420
1421static int
1422msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001423 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001424{
1425 void __iomem *base = host->base;
1426 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001427 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001428
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001429 while (readl_relaxed(base + MMCISTATUS) &
1430 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1431 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001432
San Mehat9d2bd732009-09-22 16:44:22 -07001433 count = min(remain, maxcnt);
1434
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301435 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1436 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001437 ptr += count;
1438 remain -= count;
1439
1440 if (remain == 0)
1441 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001442 }
1443 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001444
1445 return ptr - buffer;
1446}
1447
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001448/*
1449 * Copy up to a word (4 bytes) between a scatterlist
1450 * and a temporary bounce buffer when the word lies across
1451 * two pages. The temporary buffer can then be read to/
1452 * written from the FIFO once.
1453 */
1454static void _msmsdcc_sg_consume_word(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -07001455{
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001456 struct msmsdcc_pio_data *pio = &host->pio;
1457 unsigned int bytes_avail;
1458
1459 if (host->curr.data->flags & MMC_DATA_READ)
1460 memcpy(pio->sg_miter.addr, pio->bounce_buf,
1461 pio->bounce_buf_len);
1462 else
1463 memcpy(pio->bounce_buf, pio->sg_miter.addr,
1464 pio->bounce_buf_len);
1465
1466 while (pio->bounce_buf_len != 4) {
1467 if (!sg_miter_next(&pio->sg_miter))
1468 break;
1469 bytes_avail = min_t(unsigned int, pio->sg_miter.length,
1470 4 - pio->bounce_buf_len);
1471 if (host->curr.data->flags & MMC_DATA_READ)
1472 memcpy(pio->sg_miter.addr,
1473 &pio->bounce_buf[pio->bounce_buf_len],
1474 bytes_avail);
1475 else
1476 memcpy(&pio->bounce_buf[pio->bounce_buf_len],
1477 pio->sg_miter.addr, bytes_avail);
1478
1479 pio->sg_miter.consumed = bytes_avail;
1480 pio->bounce_buf_len += bytes_avail;
San Mehat9d2bd732009-09-22 16:44:22 -07001481 }
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001482}
1483
1484/*
1485 * Use sg_miter_next to return as many 4-byte aligned
1486 * chunks as possible, using a temporary 4 byte buffer
1487 * for alignment if necessary
1488 */
1489static int msmsdcc_sg_next(struct msmsdcc_host *host, char **buf, int *len)
1490{
1491 struct msmsdcc_pio_data *pio = &host->pio;
1492 unsigned int length, rlength;
1493 char *buffer;
1494
1495 if (!sg_miter_next(&pio->sg_miter))
1496 return 0;
1497
1498 buffer = pio->sg_miter.addr;
1499 length = pio->sg_miter.length;
1500
1501 if (length < host->curr.xfer_remain) {
1502 rlength = round_down(length, 4);
1503 if (rlength) {
1504 /*
1505 * We have a 4-byte aligned chunk.
1506 * The rounding will be reflected by
1507 * a call to msmsdcc_sg_consumed
1508 */
1509 length = rlength;
1510 goto sg_next_end;
1511 }
1512 /*
1513 * We have a length less than 4 bytes. Check to
1514 * see if more buffer is available, and combine
1515 * to make 4 bytes if possible.
1516 */
1517 pio->bounce_buf_len = length;
1518 memset(pio->bounce_buf, 0, 4);
1519
1520 /*
1521 * On a read, get 4 bytes from FIFO, and distribute
1522 * (4-bouce_buf_len) bytes into consecutive
1523 * sgl buffers when msmsdcc_sg_consumed is called
1524 */
1525 if (host->curr.data->flags & MMC_DATA_READ) {
1526 buffer = pio->bounce_buf;
1527 length = 4;
1528 goto sg_next_end;
1529 } else {
1530 _msmsdcc_sg_consume_word(host);
1531 buffer = pio->bounce_buf;
1532 length = pio->bounce_buf_len;
1533 }
1534 }
1535
1536sg_next_end:
1537 *buf = buffer;
1538 *len = length;
1539 return 1;
1540}
1541
1542/*
1543 * Update sg_miter.consumed based on how many bytes were
1544 * consumed. If the bounce buffer was used to read from FIFO,
1545 * redistribute into sgls.
1546 */
1547static void msmsdcc_sg_consumed(struct msmsdcc_host *host,
1548 unsigned int length)
1549{
1550 struct msmsdcc_pio_data *pio = &host->pio;
1551
1552 if (host->curr.data->flags & MMC_DATA_READ) {
1553 if (length > pio->sg_miter.consumed)
1554 /*
1555 * consumed 4 bytes, but sgl
1556 * describes < 4 bytes
1557 */
1558 _msmsdcc_sg_consume_word(host);
1559 else
1560 pio->sg_miter.consumed = length;
1561 } else
1562 if (length < pio->sg_miter.consumed)
1563 pio->sg_miter.consumed = length;
1564}
1565
1566static void msmsdcc_sg_start(struct msmsdcc_host *host)
1567{
1568 unsigned int sg_miter_flags = SG_MITER_ATOMIC;
1569
1570 host->pio.bounce_buf_len = 0;
1571
1572 if (host->curr.data->flags & MMC_DATA_READ)
1573 sg_miter_flags |= SG_MITER_TO_SG;
1574 else
1575 sg_miter_flags |= SG_MITER_FROM_SG;
1576
1577 sg_miter_start(&host->pio.sg_miter, host->curr.data->sg,
1578 host->curr.data->sg_len, sg_miter_flags);
1579}
1580
1581static void msmsdcc_sg_stop(struct msmsdcc_host *host)
1582{
1583 sg_miter_stop(&host->pio.sg_miter);
San Mehat9d2bd732009-09-22 16:44:22 -07001584}
1585
San Mehat1cd22962010-02-03 12:59:29 -08001586static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001587msmsdcc_pio_irq(int irq, void *dev_id)
1588{
1589 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001590 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001591 uint32_t status;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001592 unsigned long flags;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001593 unsigned int remain;
1594 char *buffer;
San Mehat9d2bd732009-09-22 16:44:22 -07001595
Murali Palnati36448a42011-09-02 15:06:18 +05301596 spin_lock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301597
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001598 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001599
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001600 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301601 (MCI_IRQ_PIO)) == 0) {
1602 spin_unlock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301603 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301604 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001605#if IRQ_DEBUG
1606 msmsdcc_print_status(host, "irq1-r", status);
1607#endif
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001608 local_irq_save(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001609
1610 do {
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001611 unsigned int len;
San Mehat9d2bd732009-09-22 16:44:22 -07001612
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001613 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1614 | MCI_RXDATAAVLBL)))
1615 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001616
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001617 if (!msmsdcc_sg_next(host, &buffer, &remain))
1618 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001619
San Mehat9d2bd732009-09-22 16:44:22 -07001620 len = 0;
1621 if (status & MCI_RXACTIVE)
1622 len = msmsdcc_pio_read(host, buffer, remain);
1623 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001624 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001625
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301626 /* len might have aligned to 32bits above */
1627 if (len > remain)
1628 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001629
San Mehat9d2bd732009-09-22 16:44:22 -07001630 host->curr.xfer_remain -= len;
1631 host->curr.data_xfered += len;
1632 remain -= len;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001633 msmsdcc_sg_consumed(host, len);
San Mehat9d2bd732009-09-22 16:44:22 -07001634
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001635 if (remain) /* Done with this page? */
1636 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001637
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001638 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001639 } while (1);
1640
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001641 msmsdcc_sg_stop(host);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001642 local_irq_restore(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001643
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001644 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1645 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1646 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1647 host->base + MMCIMASK0);
1648 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301649 /*
1650 * back to back write to MASK0 register don't need
1651 * synchronization delay.
1652 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001653 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1654 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1655 }
1656 mb();
1657 } else if (!host->curr.xfer_remain) {
1658 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1659 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1660 mb();
1661 }
San Mehat9d2bd732009-09-22 16:44:22 -07001662
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001663 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001664
1665 return IRQ_HANDLED;
1666}
1667
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001668static void
1669msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1670
1671static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1672 struct mmc_data *data)
1673{
1674 u32 loop_cnt = 0;
1675
1676 /*
1677 * For read commands with data less than fifo size, it is possible to
1678 * get DATAEND first and RXDATA_AVAIL might be set later because of
1679 * synchronization delay through the asynchronous RX FIFO. Thus, for
1680 * such cases, even after DATAEND interrupt is received software
1681 * should poll for RXDATA_AVAIL until the requested data is read out
1682 * of FIFO. This change is needed to get around this abnormal but
1683 * sometimes expected behavior of SDCC3 controller.
1684 *
1685 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1686 * after the data is loaded into RX FIFO. This would amount to less
1687 * than a microsecond and thus looping for 1000 times is good enough
1688 * for that delay.
1689 */
1690 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1691 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1692 spin_unlock(&host->lock);
1693 msmsdcc_pio_irq(1, host);
1694 spin_lock(&host->lock);
1695 }
1696 }
1697 if (loop_cnt == 1000) {
1698 pr_info("%s: Timed out while polling for Rx Data\n",
1699 mmc_hostname(host->mmc));
1700 data->error = -ETIMEDOUT;
1701 msmsdcc_reset_and_restore(host);
1702 }
1703}
1704
San Mehat9d2bd732009-09-22 16:44:22 -07001705static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1706{
1707 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001708
1709 host->curr.cmd = NULL;
subhashj8046ae12012-05-02 12:14:52 +05301710 if (mmc_resp_type(cmd))
1711 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1712 /*
1713 * Read rest of the response registers only if
1714 * long response is expected for this command
1715 */
1716 if (mmc_resp_type(cmd) & MMC_RSP_136) {
1717 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1718 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1719 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
1720 }
San Mehat9d2bd732009-09-22 16:44:22 -07001721
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001722 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301723 pr_debug("%s: CMD%d: Command timeout\n",
1724 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001725 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001726 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301727 !host->tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301728 pr_err("%s: CMD%d: Command CRC error\n",
1729 mmc_hostname(host->mmc), cmd->opcode);
1730 msmsdcc_dump_sdcc_state(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001731 cmd->error = -EILSEQ;
1732 }
1733
Subhash Jadavani8706ced2012-05-25 16:09:21 +05301734 if (!cmd->error) {
1735 if (cmd->cmd_timeout_ms > host->curr.req_tout_ms) {
1736 host->curr.req_tout_ms = cmd->cmd_timeout_ms;
1737 mod_timer(&host->req_tout_timer, (jiffies +
1738 msecs_to_jiffies(host->curr.req_tout_ms)));
1739 }
1740 }
1741
San Mehat9d2bd732009-09-22 16:44:22 -07001742 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001743 if (host->curr.data && host->dma.sg &&
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301744 is_dma_mode(host))
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001745 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001746 else if (host->curr.data && host->sps.sg &&
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301747 is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001748 /* Stop current SPS transfer */
1749 msmsdcc_sps_exit_curr_xfer(host);
1750 }
San Mehat9d2bd732009-09-22 16:44:22 -07001751 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301752 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001753 msmsdcc_stop_data(host);
1754 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301755 } else { /* host->data == NULL */
1756 if (!cmd->error && host->prog_enable) {
1757 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001758 host->prog_enable = 0;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301759 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001760 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301761 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301762 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301763 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301764 host->curr.wait_for_auto_prog_done = false;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001765 if (host->dummy_52_needed)
1766 host->dummy_52_needed = 0;
1767 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001768 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301769 msmsdcc_request_end(host, cmd->mrq);
1770 }
1771 }
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301772 } else if (cmd->data) {
Subhash Jadavanif5277752011-10-12 16:47:52 +05301773 if (cmd == host->curr.mrq->sbc)
1774 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1775 else if ((cmd->data->flags & MMC_DATA_WRITE) &&
1776 !host->curr.use_wr_data_pend)
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301777 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001778 }
1779}
1780
San Mehat9d2bd732009-09-22 16:44:22 -07001781static irqreturn_t
1782msmsdcc_irq(int irq, void *dev_id)
1783{
1784 struct msmsdcc_host *host = dev_id;
Pratibhasagar Vbe4e3132012-09-20 19:46:11 +05301785 struct mmc_host *mmc = host->mmc;
San Mehat9d2bd732009-09-22 16:44:22 -07001786 u32 status;
1787 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001788 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001789
1790 spin_lock(&host->lock);
1791
1792 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001793 struct mmc_command *cmd;
1794 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001795
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001796 if (timer) {
1797 timer = 0;
1798 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001799 }
San Mehat9d2bd732009-09-22 16:44:22 -07001800
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05301801 if (!atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001802 pr_debug("%s: %s: SDIO async irq received\n",
1803 mmc_hostname(host->mmc), __func__);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301804
1805 /*
1806 * Only async interrupt can come when clocks are off,
1807 * disable further interrupts and enable them when
1808 * clocks are on.
1809 */
1810 if (!host->sdcc_irq_disabled) {
1811 disable_irq_nosync(irq);
1812 host->sdcc_irq_disabled = 1;
1813 }
1814
1815 /*
1816 * If mmc_card_wake_sdio_irq() is set, mmc core layer
1817 * will take care of signaling sdio irq during
1818 * mmc_sdio_resume().
1819 */
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301820 if (host->sdcc_suspended) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301821 /*
1822 * This is a wakeup interrupt so hold wakelock
1823 * until SDCC resume is handled.
1824 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001825 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301826 } else {
Pratibhasagar Vbe4e3132012-09-20 19:46:11 +05301827 if (!mmc->card || !mmc_card_sdio(mmc->card)) {
1828 WARN(1, "%s: SDCC core interrupt received for non-SDIO cards when SDCC clocks are off\n",
1829 mmc_hostname(mmc));
1830 ret = 1;
1831 break;
1832 }
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301833 spin_unlock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301834 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301835 spin_lock(&host->lock);
1836 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301837 ret = 1;
1838 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001839 }
1840
1841 status = readl_relaxed(host->base + MMCISTATUS);
1842
1843 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1844 (~(MCI_IRQ_PIO))) == 0)
San Mehat9d2bd732009-09-22 16:44:22 -07001845 break;
1846
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001847#if IRQ_DEBUG
1848 msmsdcc_print_status(host, "irq0-r", status);
1849#endif
1850 status &= readl_relaxed(host->base + MMCIMASK0);
1851 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301852 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301853 if (host->clk_rate <=
1854 msmsdcc_get_min_sup_clk_rate(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +05301855 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001856#if IRQ_DEBUG
1857 msmsdcc_print_status(host, "irq0-p", status);
1858#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001859
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001860 if (status & MCI_SDIOINTROPE) {
Pratibhasagar Vbe4e3132012-09-20 19:46:11 +05301861 if (!mmc->card || mmc_card_sdio(mmc->card)) {
1862 WARN(1, "%s: SDIO interrupt received for non-SDIO card\n",
1863 mmc_hostname(mmc));
1864 ret = 1;
1865 break;
1866 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001867 if (host->sdcc_suspending)
1868 wake_lock(&host->sdio_suspend_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301869 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001870 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301871 spin_lock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001872 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001873 data = host->curr.data;
1874
1875 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001876 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1877 MCI_CMDTIMEOUT)) {
1878 if (status & MCI_CMDTIMEOUT)
1879 pr_debug("%s: dummy CMD52 timeout\n",
1880 mmc_hostname(host->mmc));
1881 if (status & MCI_CMDCRCFAIL)
1882 pr_debug("%s: dummy CMD52 CRC failed\n",
1883 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001884 host->dummy_52_sent = 0;
1885 host->dummy_52_needed = 0;
1886 if (data) {
1887 msmsdcc_stop_data(host);
1888 msmsdcc_request_end(host, data->mrq);
1889 }
1890 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001891 spin_unlock(&host->lock);
1892 return IRQ_HANDLED;
1893 }
1894 break;
1895 }
1896
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001897 /*
1898 * Check for proper command response
1899 */
1900 cmd = host->curr.cmd;
1901 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1902 MCI_CMDTIMEOUT | MCI_PROGDONE |
1903 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1904 msmsdcc_do_cmdirq(host, status);
1905 }
1906
Sathish Ambley081d7842011-11-29 11:19:41 -08001907 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001908 /* Check for data errors */
1909 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1910 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1911 msmsdcc_data_err(host, data, status);
1912 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301913 if (host->dma.sg && is_dma_mode(host))
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001914 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301915 else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001916 /* Stop current SPS transfer */
1917 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301918 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001919 msmsdcc_reset_and_restore(host);
1920 if (host->curr.data)
1921 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301922 if (!data->stop || (host->curr.mrq->sbc
1923 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001924 timer |=
1925 msmsdcc_request_end(host,
1926 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301927 else if ((host->curr.mrq->sbc
1928 && data->error) ||
1929 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001930 msmsdcc_start_command(host,
1931 data->stop,
1932 0);
1933 timer = 1;
1934 }
1935 }
1936 }
1937
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301938 /* Check for prog done */
1939 if (host->curr.wait_for_auto_prog_done &&
1940 (status & MCI_PROGDONE))
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301941 host->curr.got_auto_prog_done = true;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301942
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001943 /* Check for data done */
1944 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1945 host->curr.got_dataend = 1;
1946
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301947 if (host->curr.got_dataend &&
1948 (!host->curr.wait_for_auto_prog_done ||
1949 (host->curr.wait_for_auto_prog_done &&
1950 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001951 /*
1952 * If DMA is still in progress, we complete
1953 * via the completion handler
1954 */
1955 if (!host->dma.busy && !host->sps.busy) {
1956 /*
1957 * There appears to be an issue in the
1958 * controller where if you request a
1959 * small block transfer (< fifo size),
1960 * you may get your DATAEND/DATABLKEND
1961 * irq without the PIO data irq.
1962 *
1963 * Check to see if theres still data
1964 * to be read, and simulate a PIO irq.
1965 */
1966 if (data->flags & MMC_DATA_READ)
1967 msmsdcc_wait_for_rxdata(host,
1968 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001969 if (!data->error) {
1970 host->curr.data_xfered =
1971 host->curr.xfer_size;
1972 host->curr.xfer_remain -=
1973 host->curr.xfer_size;
1974 }
1975
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001976 if (!host->dummy_52_needed) {
1977 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301978 if (!data->stop ||
1979 (host->curr.mrq->sbc
1980 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001981 msmsdcc_request_end(
1982 host,
1983 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301984 else if ((host->curr.mrq->sbc
1985 && data->error) ||
1986 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001987 msmsdcc_start_command(
1988 host,
1989 data->stop, 0);
1990 timer = 1;
1991 }
1992 } else {
1993 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001994 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001995 &dummy52cmd,
1996 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001997 }
1998 }
1999 }
2000 }
2001
San Mehat9d2bd732009-09-22 16:44:22 -07002002 ret = 1;
2003 } while (status);
2004
2005 spin_unlock(&host->lock);
2006
San Mehat9d2bd732009-09-22 16:44:22 -07002007 return IRQ_RETVAL(ret);
2008}
2009
2010static void
Asutosh Dasaccacd42012-03-08 14:33:17 +05302011msmsdcc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
2012 bool is_first_request)
2013{
2014 struct msmsdcc_host *host = mmc_priv(mmc);
2015 struct mmc_data *data = mrq->data;
2016 int rc = 0;
2017
2018 if (unlikely(!data)) {
2019 pr_err("%s: %s cannot prepare null data\n", mmc_hostname(mmc),
2020 __func__);
2021 return;
2022 }
2023 if (unlikely(data->host_cookie)) {
2024 /* Very wrong */
2025 data->host_cookie = 0;
2026 pr_err("%s: %s Request reposted for prepare\n",
2027 mmc_hostname(mmc), __func__);
2028 return;
2029 }
2030
2031 if (!msmsdcc_is_dma_possible(host, data))
2032 return;
2033
2034 rc = msmsdcc_prep_xfer(host, data);
2035 if (unlikely(rc < 0)) {
2036 data->host_cookie = 0;
2037 return;
2038 }
2039
2040 data->host_cookie = 1;
2041}
2042
2043static void
2044msmsdcc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, int err)
2045{
2046 struct msmsdcc_host *host = mmc_priv(mmc);
2047 unsigned int dir;
2048 struct mmc_data *data = mrq->data;
2049
2050 if (unlikely(!data)) {
2051 pr_err("%s: %s cannot cleanup null data\n", mmc_hostname(mmc),
2052 __func__);
2053 return;
2054 }
2055 if (data->flags & MMC_DATA_READ)
2056 dir = DMA_FROM_DEVICE;
2057 else
2058 dir = DMA_TO_DEVICE;
2059
2060 if (data->host_cookie)
2061 dma_unmap_sg(mmc_dev(host->mmc), data->sg,
2062 data->sg_len, dir);
2063
2064 data->host_cookie = 0;
2065}
2066
2067static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002068msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
2069{
Subhash Jadavanif5277752011-10-12 16:47:52 +05302070 if (mrq->data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002071 /* Queue/read data, daisy-chain command when data starts */
Subhash Jadavanif5277752011-10-12 16:47:52 +05302072 if ((mrq->data->flags & MMC_DATA_READ) ||
2073 host->curr.use_wr_data_pend)
2074 msmsdcc_start_data(host, mrq->data,
2075 mrq->sbc ? mrq->sbc : mrq->cmd,
2076 0);
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302077 else
Subhash Jadavanif5277752011-10-12 16:47:52 +05302078 msmsdcc_start_command(host,
2079 mrq->sbc ? mrq->sbc : mrq->cmd,
2080 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002081 } else {
2082 msmsdcc_start_command(host, mrq->cmd, 0);
2083 }
2084}
2085
2086static void
San Mehat9d2bd732009-09-22 16:44:22 -07002087msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
2088{
2089 struct msmsdcc_host *host = mmc_priv(mmc);
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302090 unsigned long flags;
Maya Erezb7a086f2012-11-29 00:37:36 +02002091 int retries = 5;
San Mehat9d2bd732009-09-22 16:44:22 -07002092
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002093 /*
2094 * Get the SDIO AL client out of LPM.
2095 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002096 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002097 if (host->plat->is_sdio_al_client)
2098 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002099
Maya Erezb7a086f2012-11-29 00:37:36 +02002100 /* check if sps bam needs to be reset */
2101 if (is_sps_mode(host) && host->sps.reset_bam) {
2102 while (retries) {
2103 if (!msmsdcc_bam_dml_reset_and_restore(host))
2104 break;
2105 pr_err("%s: msmsdcc_bam_dml_reset_and_restore returned error. %d attempts left.\n",
2106 mmc_hostname(host->mmc), --retries);
2107 }
Subhash Jadavanib5b07742011-08-29 17:48:07 +05302108 }
San Mehat9d2bd732009-09-22 16:44:22 -07002109
2110 spin_lock_irqsave(&host->lock, flags);
2111
San Mehat9d2bd732009-09-22 16:44:22 -07002112 if (host->eject) {
2113 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
2114 mrq->cmd->error = 0;
2115 mrq->data->bytes_xfered = mrq->data->blksz *
2116 mrq->data->blocks;
2117 } else
2118 mrq->cmd->error = -ENOMEDIUM;
2119
2120 spin_unlock_irqrestore(&host->lock, flags);
2121 mmc_request_done(mmc, mrq);
2122 return;
2123 }
2124
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302125 /*
subhashjf181c292012-05-02 13:07:40 +05302126 * Don't start the request if SDCC is not in proper state to handle it
2127 */
Maya Erezb7a086f2012-11-29 00:37:36 +02002128 if (!host->pwr || !atomic_read(&host->clks_on) ||
2129 host->sdcc_irq_disabled ||
2130 host->sps.reset_bam) {
subhashjf181c292012-05-02 13:07:40 +05302131 WARN(1, "%s: %s: SDCC is in bad state. don't process"
2132 " new request (CMD%d)\n", mmc_hostname(host->mmc),
2133 __func__, mrq->cmd->opcode);
2134 msmsdcc_dump_sdcc_state(host);
2135 mrq->cmd->error = -EIO;
2136 if (mrq->data) {
2137 mrq->data->error = -EIO;
2138 mrq->data->bytes_xfered = 0;
2139 }
2140 spin_unlock_irqrestore(&host->lock, flags);
2141 mmc_request_done(mmc, mrq);
2142 return;
2143 }
2144
2145 WARN(host->curr.mrq, "%s: %s: New request (CMD%d) received while"
2146 " other request (CMD%d) is in progress\n",
2147 mmc_hostname(host->mmc), __func__,
2148 mrq->cmd->opcode, host->curr.mrq->cmd->opcode);
2149
2150 /*
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302151 * Set timeout value to 10 secs (or more in case of buggy cards)
2152 */
2153 if ((mmc->card) && (mmc->card->quirks & MMC_QUIRK_INAND_DATA_TIMEOUT))
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302154 host->curr.req_tout_ms = 20000;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302155 else
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302156 host->curr.req_tout_ms = MSM_MMC_REQ_TIMEOUT;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302157 /*
2158 * Kick the software request timeout timer here with the timeout
2159 * value identified above
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302160 */
2161 mod_timer(&host->req_tout_timer,
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302162 (jiffies +
2163 msecs_to_jiffies(host->curr.req_tout_ms)));
San Mehat9d2bd732009-09-22 16:44:22 -07002164
San Mehat9d2bd732009-09-22 16:44:22 -07002165 host->curr.mrq = mrq;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302166 if (mrq->sbc) {
2167 mrq->sbc->mrq = mrq;
2168 mrq->sbc->data = mrq->data;
2169 }
2170
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302171 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05302172 if (is_auto_prog_done(host)) {
Sujit Reddy Thummab8e83692012-07-17 15:08:13 +05302173 /*
2174 * Auto-prog done will be enabled for following cases:
2175 * mrq->sbc | mrq->stop
2176 * _____________|________________
2177 * True | Don't care
2178 * False | False (CMD24, ACMD25 use case)
2179 */
2180 if (mrq->sbc || !mrq->stop)
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302181 host->curr.wait_for_auto_prog_done = true;
2182 } else {
2183 if ((mrq->cmd->opcode == SD_IO_RW_EXTENDED) ||
2184 (mrq->cmd->opcode == 54))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002185 host->dummy_52_needed = 1;
2186 }
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302187
Subhash Jadavanif5277752011-10-12 16:47:52 +05302188 if ((mrq->cmd->opcode == MMC_WRITE_BLOCK) ||
2189 (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK))
2190 host->curr.use_wr_data_pend = true;
San Mehat9d2bd732009-09-22 16:44:22 -07002191 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302192
Subhash Jadavanif5277752011-10-12 16:47:52 +05302193 msmsdcc_request_start(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302194
San Mehat9d2bd732009-09-22 16:44:22 -07002195 spin_unlock_irqrestore(&host->lock, flags);
2196}
2197
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002198static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
2199 int min_uV, int max_uV)
2200{
2201 int rc = 0;
2202
2203 if (vreg->set_voltage_sup) {
2204 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
2205 if (rc) {
2206 pr_err("%s: regulator_set_voltage(%s) failed."
2207 " min_uV=%d, max_uV=%d, rc=%d\n",
2208 __func__, vreg->name, min_uV, max_uV, rc);
2209 }
2210 }
2211
2212 return rc;
2213}
2214
Subhash Jadavanibf09d802012-08-11 18:11:57 +05302215static inline int msmsdcc_vreg_get_voltage(struct msm_mmc_reg_data *vreg)
2216{
2217 int rc = 0;
2218
2219 rc = regulator_get_voltage(vreg->reg);
2220 if (rc < 0)
2221 pr_err("%s: regulator_get_voltage(%s) failed. rc=%d\n",
2222 __func__, vreg->name, rc);
2223
2224 return rc;
2225}
2226
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002227static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
2228 int uA_load)
2229{
2230 int rc = 0;
2231
Krishna Kondafea60182011-11-01 16:01:34 -07002232 /* regulators that do not support regulator_set_voltage also
2233 do not support regulator_set_optimum_mode */
2234 if (vreg->set_voltage_sup) {
2235 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
2236 if (rc < 0)
2237 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
2238 "uA_load=%d) failed. rc=%d\n", __func__,
2239 vreg->name, uA_load, rc);
2240 else
2241 /* regulator_set_optimum_mode() can return non zero
2242 * value even for success case.
2243 */
2244 rc = 0;
2245 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002246
2247 return rc;
2248}
2249
2250static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
2251 struct device *dev)
2252{
2253 int rc = 0;
2254
2255 /* check if regulator is already initialized? */
2256 if (vreg->reg)
2257 goto out;
2258
2259 /* Get the regulator handle */
2260 vreg->reg = regulator_get(dev, vreg->name);
2261 if (IS_ERR(vreg->reg)) {
2262 rc = PTR_ERR(vreg->reg);
2263 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
2264 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002265 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002266 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002267
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05302268 if (regulator_count_voltages(vreg->reg) > 0) {
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002269 vreg->set_voltage_sup = 1;
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05302270 /* sanity check */
2271 if (!vreg->high_vol_level || !vreg->hpm_uA) {
2272 pr_err("%s: %s invalid constraints specified\n",
2273 __func__, vreg->name);
2274 rc = -EINVAL;
2275 }
2276 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002277
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002278out:
2279 return rc;
2280}
2281
2282static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
2283{
2284 if (vreg->reg)
2285 regulator_put(vreg->reg);
2286}
2287
2288/* This init function should be called only once for each SDCC slot */
2289static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
2290{
2291 int rc = 0;
2292 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302293 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vdd_io_reg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002294 struct device *dev = mmc_dev(host->mmc);
2295
2296 curr_slot = host->plat->vreg_data;
2297 if (!curr_slot)
2298 goto out;
2299
2300 curr_vdd_reg = curr_slot->vdd_data;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302301 curr_vdd_io_reg = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002302
2303 if (is_init) {
2304 /*
2305 * Get the regulator handle from voltage regulator framework
2306 * and then try to set the voltage level for the regulator
2307 */
2308 if (curr_vdd_reg) {
2309 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
2310 if (rc)
2311 goto out;
2312 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302313 if (curr_vdd_io_reg) {
2314 rc = msmsdcc_vreg_init_reg(curr_vdd_io_reg, dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002315 if (rc)
2316 goto vdd_reg_deinit;
2317 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002318 rc = msmsdcc_vreg_reset(host);
2319 if (rc)
2320 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
2321 host->pdev_id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002322 goto out;
2323 } else {
2324 /* Deregister all regulators from regulator framework */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302325 goto vdd_io_reg_deinit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002326 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302327vdd_io_reg_deinit:
2328 if (curr_vdd_io_reg)
2329 msmsdcc_vreg_deinit_reg(curr_vdd_io_reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002330vdd_reg_deinit:
2331 if (curr_vdd_reg)
2332 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2333out:
2334 return rc;
2335}
2336
2337static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2338{
2339 int rc = 0;
2340
Subhash Jadavanicc922692011-08-01 23:05:01 +05302341 /* Put regulator in HPM (high power mode) */
2342 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2343 if (rc < 0)
2344 goto out;
2345
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002346 if (!vreg->is_enabled) {
2347 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302348 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2349 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002350 if (rc)
2351 goto out;
2352
2353 rc = regulator_enable(vreg->reg);
2354 if (rc) {
2355 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2356 __func__, vreg->name, rc);
2357 goto out;
2358 }
2359 vreg->is_enabled = true;
2360 }
2361
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002362out:
2363 return rc;
2364}
2365
Krishna Konda3c4142d2012-06-27 11:01:56 -07002366static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg, bool is_init)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002367{
2368 int rc = 0;
2369
2370 /* Never disable regulator marked as always_on */
2371 if (vreg->is_enabled && !vreg->always_on) {
2372 rc = regulator_disable(vreg->reg);
2373 if (rc) {
2374 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2375 __func__, vreg->name, rc);
2376 goto out;
2377 }
2378 vreg->is_enabled = false;
2379
2380 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2381 if (rc < 0)
2382 goto out;
2383
2384 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302385 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002386 if (rc)
2387 goto out;
Krishna Konda3c4142d2012-06-27 11:01:56 -07002388 } else if (vreg->is_enabled && vreg->always_on) {
2389 if (!is_init && vreg->lpm_sup) {
2390 /* Put always_on regulator in LPM (low power mode) */
2391 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2392 if (rc < 0)
2393 goto out;
2394 } else if (is_init && vreg->reset_at_init) {
2395 /**
2396 * The regulator might not actually be disabled if it
2397 * is shared and in use by other drivers.
2398 */
2399 rc = regulator_disable(vreg->reg);
2400 if (rc) {
2401 pr_err("%s: regulator_disable(%s) failed at " \
2402 "bootup. rc=%d\n", __func__,
2403 vreg->name, rc);
2404 goto out;
2405 }
2406 vreg->is_enabled = false;
2407 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002408 }
2409out:
2410 return rc;
2411}
2412
Krishna Konda3c4142d2012-06-27 11:01:56 -07002413static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable,
2414 bool is_init)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002415{
2416 int rc = 0, i;
2417 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302418 struct msm_mmc_reg_data *vreg_table[2];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002419
2420 curr_slot = host->plat->vreg_data;
Asutosh Dasebd7d092012-07-09 19:08:26 +05302421 if (!curr_slot) {
2422 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002423 goto out;
Asutosh Dasebd7d092012-07-09 19:08:26 +05302424 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002425
Subhash Jadavani937c7502012-06-01 15:34:46 +05302426 vreg_table[0] = curr_slot->vdd_data;
2427 vreg_table[1] = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002428
2429 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2430 if (vreg_table[i]) {
2431 if (enable)
2432 rc = msmsdcc_vreg_enable(vreg_table[i]);
2433 else
Krishna Konda3c4142d2012-06-27 11:01:56 -07002434 rc = msmsdcc_vreg_disable(vreg_table[i],
2435 is_init);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002436 if (rc)
2437 goto out;
2438 }
2439 }
2440out:
2441 return rc;
2442}
2443
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002444/*
2445 * Reset vreg by ensuring it is off during probe. A call
2446 * to enable vreg is needed to balance disable vreg
2447 */
2448static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2449{
2450 int rc;
2451
Krishna Konda3c4142d2012-06-27 11:01:56 -07002452 rc = msmsdcc_setup_vreg(host, 1, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002453 if (rc)
2454 return rc;
Krishna Konda3c4142d2012-06-27 11:01:56 -07002455 rc = msmsdcc_setup_vreg(host, 0, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002456 return rc;
2457}
2458
Subhash Jadavani937c7502012-06-01 15:34:46 +05302459enum vdd_io_level {
2460 /* set vdd_io_data->low_vol_level */
2461 VDD_IO_LOW,
2462 /* set vdd_io_data->high_vol_level */
2463 VDD_IO_HIGH,
2464 /*
2465 * set whatever there in voltage_level (third argument) of
2466 * msmsdcc_set_vdd_io_vol() function.
2467 */
2468 VDD_IO_SET_LEVEL,
2469};
2470
Subhash Jadavanibf09d802012-08-11 18:11:57 +05302471/*
2472 * This function returns the current VDD IO voltage level.
2473 * Returns negative value if it fails to read the voltage level
2474 * Returns 0 if regulator was disabled or if VDD_IO (and VDD)
2475 * regulator were not defined for host.
2476 */
2477static int msmsdcc_get_vdd_io_vol(struct msmsdcc_host *host)
2478{
2479 int rc = 0;
2480
2481 if (host->plat->vreg_data) {
2482 struct msm_mmc_reg_data *io_reg =
2483 host->plat->vreg_data->vdd_io_data;
2484
2485 /*
2486 * If vdd_io is not defined, then we can consider that
2487 * IO voltage is same as VDD.
2488 */
2489 if (!io_reg)
2490 io_reg = host->plat->vreg_data->vdd_data;
2491
2492 if (io_reg && io_reg->is_enabled)
2493 rc = msmsdcc_vreg_get_voltage(io_reg);
2494 }
2495
2496 return rc;
2497}
2498
2499/*
2500 * This function updates the IO pad power switch bit in MCI_CLK register
2501 * based on currrent IO pad voltage level.
2502 * NOTE: This function assumes that host lock was not taken by caller.
2503 */
2504static void msmsdcc_update_io_pad_pwr_switch(struct msmsdcc_host *host)
2505{
2506 int rc = 0;
2507 unsigned long flags;
2508
2509 if (!is_io_pad_pwr_switch(host))
2510 return;
2511
2512 rc = msmsdcc_get_vdd_io_vol(host);
2513
2514 spin_lock_irqsave(&host->lock, flags);
2515 /*
2516 * Dual voltage pad is the SDCC's (chipset) functionality and not all
2517 * the SDCC instances support the dual voltage pads.
2518 * For dual-voltage pad (1.8v/3.3v), SW should set IO_PAD_PWR_SWITCH
2519 * bit before using the pads in 1.8V mode.
2520 * For regular, not dual-voltage pads (including eMMC 1.2v/1.8v pads),
2521 * IO_PAD_PWR_SWITCH bit is a don't care.
2522 * But we don't have an option to know (by reading some SDCC register)
2523 * that a particular SDCC instance supports dual voltage pads or not,
2524 * so we simply set the IO_PAD_PWR_SWITCH bit for low voltage IO
2525 * (1.8v/1.2v). For regular (not dual-voltage pads), this bit value
2526 * is anyway ignored.
2527 */
2528 if (rc > 0 && rc < 2700000)
2529 host->io_pad_pwr_switch = 1;
2530 else
2531 host->io_pad_pwr_switch = 0;
2532
2533 if (atomic_read(&host->clks_on)) {
2534 if (host->io_pad_pwr_switch)
2535 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2536 IO_PAD_PWR_SWITCH),
2537 host->base + MMCICLOCK);
2538 else
2539 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) &
2540 ~IO_PAD_PWR_SWITCH),
2541 host->base + MMCICLOCK);
2542 msmsdcc_sync_reg_wr(host);
2543 }
2544 spin_unlock_irqrestore(&host->lock, flags);
2545}
2546
Subhash Jadavani937c7502012-06-01 15:34:46 +05302547static int msmsdcc_set_vdd_io_vol(struct msmsdcc_host *host,
2548 enum vdd_io_level level,
2549 unsigned int voltage_level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002550{
2551 int rc = 0;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302552 int set_level;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002553
2554 if (host->plat->vreg_data) {
Subhash Jadavani937c7502012-06-01 15:34:46 +05302555 struct msm_mmc_reg_data *vdd_io_reg =
2556 host->plat->vreg_data->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002557
Subhash Jadavani937c7502012-06-01 15:34:46 +05302558 if (vdd_io_reg && vdd_io_reg->is_enabled) {
2559 switch (level) {
2560 case VDD_IO_LOW:
2561 set_level = vdd_io_reg->low_vol_level;
2562 break;
2563 case VDD_IO_HIGH:
2564 set_level = vdd_io_reg->high_vol_level;
2565 break;
2566 case VDD_IO_SET_LEVEL:
2567 set_level = voltage_level;
2568 break;
2569 default:
2570 pr_err("%s: %s: invalid argument level = %d",
2571 mmc_hostname(host->mmc), __func__,
2572 level);
2573 rc = -EINVAL;
2574 goto out;
2575 }
2576 rc = msmsdcc_vreg_set_voltage(vdd_io_reg,
2577 set_level, set_level);
2578 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002579 }
2580
Subhash Jadavani937c7502012-06-01 15:34:46 +05302581out:
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302582 return rc;
2583}
2584
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002585static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2586{
2587 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2588 return 1;
2589 return 0;
2590}
2591
Asutosh Dasf5298c32012-04-03 14:51:47 +05302592/*
2593 * Any function calling msmsdcc_setup_clocks must
2594 * acquire clk_mutex. May sleep.
2595 */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302596static int msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002597{
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302598 int rc = 0;
2599
2600 if (enable && !atomic_read(&host->clks_on)) {
2601 if (!IS_ERR_OR_NULL(host->bus_clk)) {
2602 rc = clk_prepare_enable(host->bus_clk);
2603 if (rc) {
2604 pr_err("%s: %s: failed to enable the bus-clock with error %d\n",
2605 mmc_hostname(host->mmc), __func__, rc);
2606 goto out;
2607 }
2608 }
2609 if (!IS_ERR(host->pclk)) {
2610 rc = clk_prepare_enable(host->pclk);
2611 if (rc) {
2612 pr_err("%s: %s: failed to enable the pclk with error %d\n",
2613 mmc_hostname(host->mmc), __func__, rc);
2614 goto disable_bus;
2615 }
2616 }
2617 rc = clk_prepare_enable(host->clk);
2618 if (rc) {
2619 pr_err("%s: %s: failed to enable the host-clk with error %d\n",
2620 mmc_hostname(host->mmc), __func__, rc);
2621 goto disable_pclk;
2622 }
Subhash Jadavanidd432952012-03-28 11:25:56 +05302623 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302624 msmsdcc_delay(host);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302625 atomic_set(&host->clks_on, 1);
2626 } else if (!enable && atomic_read(&host->clks_on)) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05302627 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302628 msmsdcc_delay(host);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302629 clk_disable_unprepare(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002630 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302631 clk_disable_unprepare(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05302632 if (!IS_ERR_OR_NULL(host->bus_clk))
2633 clk_disable_unprepare(host->bus_clk);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302634 atomic_set(&host->clks_on, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002635 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302636 goto out;
2637
2638disable_pclk:
2639 if (!IS_ERR_OR_NULL(host->pclk))
2640 clk_disable_unprepare(host->pclk);
2641disable_bus:
2642 if (!IS_ERR_OR_NULL(host->bus_clk))
2643 clk_disable_unprepare(host->bus_clk);
2644out:
2645 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002646}
2647
2648static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2649 unsigned int req_clk)
2650{
2651 unsigned int sel_clk = -1;
2652
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302653 if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
2654 sel_clk = msmsdcc_get_min_sup_clk_rate(host);
2655 goto out;
2656 }
2657
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002658 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2659 unsigned char cnt;
2660
2661 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2662 if (host->plat->sup_clk_table[cnt] > req_clk)
2663 break;
2664 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2665 sel_clk = host->plat->sup_clk_table[cnt];
2666 break;
2667 } else
2668 sel_clk = host->plat->sup_clk_table[cnt];
2669 }
2670 } else {
2671 if ((req_clk < host->plat->msmsdcc_fmax) &&
2672 (req_clk > host->plat->msmsdcc_fmid))
2673 sel_clk = host->plat->msmsdcc_fmid;
2674 else
2675 sel_clk = req_clk;
2676 }
2677
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302678out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002679 return sel_clk;
2680}
2681
2682static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2683 struct msmsdcc_host *host)
2684{
2685 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2686 return host->plat->sup_clk_table[0];
2687 else
2688 return host->plat->msmsdcc_fmin;
2689}
2690
2691static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2692 struct msmsdcc_host *host)
2693{
2694 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2695 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2696 else
2697 return host->plat->msmsdcc_fmax;
2698}
2699
2700static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302701{
2702 struct msm_mmc_gpio_data *curr;
2703 int i, rc = 0;
2704
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002705 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302706 for (i = 0; i < curr->size; i++) {
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05302707 if (!gpio_is_valid(curr->gpio[i].no)) {
2708 rc = -EINVAL;
2709 pr_err("%s: Invalid gpio = %d\n",
2710 mmc_hostname(host->mmc), curr->gpio[i].no);
2711 goto free_gpios;
2712 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302713 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002714 if (curr->gpio[i].is_always_on &&
2715 curr->gpio[i].is_enabled)
2716 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302717 rc = gpio_request(curr->gpio[i].no,
2718 curr->gpio[i].name);
2719 if (rc) {
2720 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2721 mmc_hostname(host->mmc),
2722 curr->gpio[i].no,
2723 curr->gpio[i].name, rc);
2724 goto free_gpios;
2725 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002726 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302727 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002728 if (curr->gpio[i].is_always_on)
2729 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302730 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002731 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302732 }
2733 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002734 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302735
2736free_gpios:
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05302737 for (i--; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302738 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002739 curr->gpio[i].is_enabled = false;
2740 }
2741out:
2742 return rc;
2743}
2744
2745static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2746{
2747 struct msm_mmc_pad_data *curr;
2748 int i;
2749
2750 curr = host->plat->pin_data->pad_data;
2751 for (i = 0; i < curr->drv->size; i++) {
2752 if (enable)
2753 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2754 curr->drv->on[i].val);
2755 else
2756 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2757 curr->drv->off[i].val);
2758 }
2759
2760 for (i = 0; i < curr->pull->size; i++) {
2761 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002762 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002763 curr->pull->on[i].val);
2764 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002765 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002766 curr->pull->off[i].val);
2767 }
2768
2769 return 0;
2770}
2771
2772static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2773{
2774 int rc = 0;
2775
2776 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2777 return 0;
2778
2779 if (host->plat->pin_data->is_gpio)
2780 rc = msmsdcc_setup_gpio(host, enable);
2781 else
2782 rc = msmsdcc_setup_pad(host, enable);
2783
2784 if (!rc)
2785 host->plat->pin_data->cfg_sts = enable;
2786
2787 return rc;
2788}
2789
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302790static int msmsdcc_cfg_mpm_sdiowakeup(struct msmsdcc_host *host,
2791 unsigned mode)
2792{
2793 int ret = 0;
2794 unsigned int pin = host->plat->mpm_sdiowakeup_int;
2795
2796 if (!pin)
2797 return 0;
2798
2799 switch (mode) {
2800 case SDC_DAT1_DISABLE:
2801 ret = msm_mpm_enable_pin(pin, 0);
2802 break;
2803 case SDC_DAT1_ENABLE:
2804 ret = msm_mpm_set_pin_type(pin, IRQ_TYPE_LEVEL_LOW);
2805 ret = msm_mpm_enable_pin(pin, 1);
2806 break;
2807 case SDC_DAT1_ENWAKE:
2808 ret = msm_mpm_set_pin_wake(pin, 1);
2809 break;
2810 case SDC_DAT1_DISWAKE:
2811 ret = msm_mpm_set_pin_wake(pin, 0);
2812 break;
2813 default:
2814 ret = -EINVAL;
2815 break;
2816 }
2817
2818 return ret;
2819}
2820
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302821static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2822{
2823 u32 pwr = 0;
2824 int ret = 0;
2825 struct mmc_host *mmc = host->mmc;
2826
2827 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2828 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2829 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
Krishna Konda3c4142d2012-06-27 11:01:56 -07002830 ret = msmsdcc_setup_vreg(host, !!ios->vdd, false);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302831
2832 if (ret) {
2833 pr_err("%s: Failed to setup voltage regulators\n",
2834 mmc_hostname(host->mmc));
2835 goto out;
2836 }
2837
2838 switch (ios->power_mode) {
2839 case MMC_POWER_OFF:
2840 pwr = MCI_PWR_OFF;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302841 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302842 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05302843 * If VDD IO rail is always on, set low voltage for VDD
2844 * IO rail when slot is not in use (like when card is not
2845 * present or during system suspend).
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302846 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302847 msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Subhash Jadavanibf09d802012-08-11 18:11:57 +05302848 msmsdcc_update_io_pad_pwr_switch(host);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302849 msmsdcc_setup_pins(host, false);
Pratibhasagar Vbe4e3132012-09-20 19:46:11 +05302850 /*
2851 * Reset the mask to prevent hitting any pending interrupts
2852 * after powering up the card again.
2853 */
2854 if (atomic_read(&host->clks_on)) {
2855 writel_relaxed(0, host->base + MMCIMASK0);
2856 mb();
2857 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302858 break;
2859 case MMC_POWER_UP:
2860 /* writing PWR_UP bit is redundant */
2861 pwr = MCI_PWR_UP;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302862 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302863
Subhash Jadavani937c7502012-06-01 15:34:46 +05302864 msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Subhash Jadavanibf09d802012-08-11 18:11:57 +05302865 msmsdcc_update_io_pad_pwr_switch(host);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302866 msmsdcc_setup_pins(host, true);
2867 break;
2868 case MMC_POWER_ON:
2869 pwr = MCI_PWR_ON;
2870 break;
2871 }
2872
2873out:
2874 return pwr;
2875}
2876
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002877static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2878{
2879 unsigned int wakeup_irq;
2880
2881 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2882 host->plat->sdiowakeup_irq :
2883 host->core_irqres->start;
2884
2885 if (!host->irq_wake_enabled) {
2886 enable_irq_wake(wakeup_irq);
2887 host->irq_wake_enabled = true;
2888 }
2889}
2890
2891static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2892{
2893 unsigned int wakeup_irq;
2894
2895 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2896 host->plat->sdiowakeup_irq :
2897 host->core_irqres->start;
2898
2899 if (host->irq_wake_enabled) {
2900 disable_irq_wake(wakeup_irq);
2901 host->irq_wake_enabled = false;
2902 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302903}
2904
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05302905/* Returns required bandwidth in Bytes per Sec */
2906static unsigned int msmsdcc_get_bw_required(struct msmsdcc_host *host,
2907 struct mmc_ios *ios)
2908{
2909 unsigned int bw;
2910
2911 bw = host->clk_rate;
2912 /*
2913 * For DDR mode, SDCC controller clock will be at
2914 * the double rate than the actual clock that goes to card.
2915 */
2916 if (ios->bus_width == MMC_BUS_WIDTH_4)
2917 bw /= 2;
2918 else if (ios->bus_width == MMC_BUS_WIDTH_1)
2919 bw /= 8;
2920
2921 return bw;
2922}
2923
2924static int msmsdcc_msm_bus_get_vote_for_bw(struct msmsdcc_host *host,
2925 unsigned int bw)
2926{
2927 unsigned int *table = host->plat->msm_bus_voting_data->bw_vecs;
2928 unsigned int size = host->plat->msm_bus_voting_data->bw_vecs_size;
2929 int i;
2930
2931 if (host->msm_bus_vote.is_max_bw_needed && bw)
2932 return host->msm_bus_vote.max_bw_vote;
2933
2934 for (i = 0; i < size; i++) {
2935 if (bw <= table[i])
2936 break;
2937 }
2938
2939 if (i && (i == size))
2940 i--;
2941
2942 return i;
2943}
2944
2945static int msmsdcc_msm_bus_register(struct msmsdcc_host *host)
2946{
2947 int rc = 0;
2948 struct msm_bus_scale_pdata *use_cases;
2949
2950 if (host->plat->msm_bus_voting_data &&
2951 host->plat->msm_bus_voting_data->use_cases &&
2952 host->plat->msm_bus_voting_data->bw_vecs &&
2953 host->plat->msm_bus_voting_data->bw_vecs_size) {
2954 use_cases = host->plat->msm_bus_voting_data->use_cases;
2955 host->msm_bus_vote.client_handle =
2956 msm_bus_scale_register_client(use_cases);
2957 } else {
2958 return 0;
2959 }
2960
2961 if (!host->msm_bus_vote.client_handle) {
2962 pr_err("%s: msm_bus_scale_register_client() failed\n",
2963 mmc_hostname(host->mmc));
2964 rc = -EFAULT;
2965 } else {
2966 /* cache the vote index for minimum and maximum bandwidth */
2967 host->msm_bus_vote.min_bw_vote =
2968 msmsdcc_msm_bus_get_vote_for_bw(host, 0);
2969 host->msm_bus_vote.max_bw_vote =
2970 msmsdcc_msm_bus_get_vote_for_bw(host, UINT_MAX);
2971 }
2972
2973 return rc;
2974}
2975
2976static void msmsdcc_msm_bus_unregister(struct msmsdcc_host *host)
2977{
2978 if (host->msm_bus_vote.client_handle)
2979 msm_bus_scale_unregister_client(
2980 host->msm_bus_vote.client_handle);
2981}
2982
2983/*
2984 * This function must be called with host lock acquired.
2985 * Caller of this function should also ensure that msm bus client
2986 * handle is not null.
2987 */
2988static inline int msmsdcc_msm_bus_set_vote(struct msmsdcc_host *host,
2989 int vote,
2990 unsigned long flags)
2991{
2992 int rc = 0;
2993
2994 if (vote != host->msm_bus_vote.curr_vote) {
2995 spin_unlock_irqrestore(&host->lock, flags);
2996 rc = msm_bus_scale_client_update_request(
2997 host->msm_bus_vote.client_handle, vote);
2998 if (rc)
2999 pr_err("%s: msm_bus_scale_client_update_request() failed."
3000 " bus_client_handle=0x%x, vote=%d, err=%d\n",
3001 mmc_hostname(host->mmc),
3002 host->msm_bus_vote.client_handle, vote, rc);
3003 spin_lock_irqsave(&host->lock, flags);
3004 if (!rc)
3005 host->msm_bus_vote.curr_vote = vote;
3006 }
3007
3008 return rc;
3009}
3010
3011/*
3012 * Internal work. Work to set 0 bandwidth for msm bus.
3013 */
3014static void msmsdcc_msm_bus_work(struct work_struct *work)
3015{
3016 struct msmsdcc_host *host = container_of(work,
3017 struct msmsdcc_host,
3018 msm_bus_vote.vote_work.work);
3019 unsigned long flags;
3020
3021 if (!host->msm_bus_vote.client_handle)
3022 return;
3023
3024 spin_lock_irqsave(&host->lock, flags);
3025 /* don't vote for 0 bandwidth if any request is in progress */
3026 if (!host->curr.mrq)
3027 msmsdcc_msm_bus_set_vote(host,
3028 host->msm_bus_vote.min_bw_vote, flags);
3029 else
3030 pr_warning("%s: %s: SDCC transfer in progress. skipping"
3031 " bus voting to 0 bandwidth\n",
3032 mmc_hostname(host->mmc), __func__);
3033 spin_unlock_irqrestore(&host->lock, flags);
3034}
3035
3036/*
3037 * This function cancels any scheduled delayed work
3038 * and sets the bus vote based on ios argument.
3039 * If "ios" argument is NULL, bandwidth required is 0 else
3040 * calculate the bandwidth based on ios parameters.
3041 */
3042static void msmsdcc_msm_bus_cancel_work_and_set_vote(
3043 struct msmsdcc_host *host,
3044 struct mmc_ios *ios)
3045{
3046 unsigned long flags;
3047 unsigned int bw;
3048 int vote;
3049
3050 if (!host->msm_bus_vote.client_handle)
3051 return;
3052
3053 bw = ios ? msmsdcc_get_bw_required(host, ios) : 0;
3054
3055 cancel_delayed_work_sync(&host->msm_bus_vote.vote_work);
3056 spin_lock_irqsave(&host->lock, flags);
3057 vote = msmsdcc_msm_bus_get_vote_for_bw(host, bw);
3058 msmsdcc_msm_bus_set_vote(host, vote, flags);
3059 spin_unlock_irqrestore(&host->lock, flags);
3060}
3061
3062/* This function queues a work which will set the bandwidth requiement to 0 */
3063static void msmsdcc_msm_bus_queue_work(struct msmsdcc_host *host)
3064{
3065 unsigned long flags;
3066
3067 if (!host->msm_bus_vote.client_handle)
3068 return;
3069
3070 spin_lock_irqsave(&host->lock, flags);
3071 if (host->msm_bus_vote.min_bw_vote != host->msm_bus_vote.curr_vote)
3072 queue_delayed_work(system_nrt_wq,
3073 &host->msm_bus_vote.vote_work,
3074 msecs_to_jiffies(MSM_MMC_BUS_VOTING_DELAY));
3075 spin_unlock_irqrestore(&host->lock, flags);
3076}
3077
San Mehat9d2bd732009-09-22 16:44:22 -07003078static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303079msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
3080{
3081 struct mmc_host *mmc = host->mmc;
3082
3083 /*
3084 * SDIO_AL clients has different mechanism of handling LPM through
3085 * sdio_al driver itself. The sdio wakeup interrupt is configured as
3086 * part of that. Here, we are interested only in clients like WLAN.
3087 */
3088 if (!(mmc->card && mmc_card_sdio(mmc->card))
3089 || host->plat->is_sdio_al_client)
3090 goto out;
3091
3092 if (!host->sdcc_suspended) {
3093 /*
3094 * When MSM is not in power collapse and we
3095 * are disabling clocks, enable bit 22 in MASK0
3096 * to handle asynchronous SDIO interrupts.
3097 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05303098 if (enable_wakeup_irq) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303099 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303100 mb();
3101 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303102 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303103 msmsdcc_sync_reg_wr(host);
3104 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303105 goto out;
3106 } else if (!mmc_card_wake_sdio_irq(mmc)) {
3107 /*
3108 * Wakeup MSM only if SDIO function drivers set
3109 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
3110 */
3111 goto out;
3112 }
3113
3114 if (enable_wakeup_irq) {
3115 if (!host->plat->sdiowakeup_irq) {
3116 /*
3117 * When there is no gpio line that can be configured
3118 * as wakeup interrupt handle it by configuring
3119 * asynchronous sdio interrupts and DAT1 line.
3120 */
3121 writel_relaxed(MCI_SDIOINTMASK,
3122 host->base + MMCIMASK0);
3123 mb();
Subhash Jadavanic9b85752012-04-13 11:16:49 +05303124 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303125 /* configure sdcc core interrupt as wakeup interrupt */
3126 msmsdcc_enable_irq_wake(host);
3127 } else {
3128 /* Let gpio line handle wakeup interrupt */
3129 writel_relaxed(0, host->base + MMCIMASK0);
3130 mb();
3131 if (host->sdio_wakeupirq_disabled) {
3132 host->sdio_wakeupirq_disabled = 0;
3133 /* configure gpio line as wakeup interrupt */
3134 msmsdcc_enable_irq_wake(host);
3135 enable_irq(host->plat->sdiowakeup_irq);
3136 }
3137 }
3138 } else {
3139 if (!host->plat->sdiowakeup_irq) {
3140 /*
3141 * We may not have cleared bit 22 in the interrupt
3142 * handler as the clocks might be off at that time.
3143 */
3144 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303145 msmsdcc_sync_reg_wr(host);
Subhash Jadavanic9b85752012-04-13 11:16:49 +05303146 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303147 msmsdcc_disable_irq_wake(host);
3148 } else if (!host->sdio_wakeupirq_disabled) {
3149 disable_irq_nosync(host->plat->sdiowakeup_irq);
3150 msmsdcc_disable_irq_wake(host);
3151 host->sdio_wakeupirq_disabled = 1;
3152 }
3153 }
3154out:
3155 return;
San Mehat9d2bd732009-09-22 16:44:22 -07003156}
3157
3158static void
3159msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
3160{
3161 struct msmsdcc_host *host = mmc_priv(mmc);
3162 u32 clk = 0, pwr = 0;
3163 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08003164 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003165 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07003166
Sahitya Tummala7a892482011-01-18 11:22:49 +05303167
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303168 /*
3169 * Disable SDCC core interrupt until set_ios is completed.
3170 * This avoids any race conditions with interrupt raised
3171 * when turning on/off the clocks. One possible
3172 * scenario is SDIO operational interrupt while the clock
3173 * is turned off.
Asutosh Dasf5298c32012-04-03 14:51:47 +05303174 * host->lock is being released intermittently below.
3175 * Thus, prevent concurrent access to host.
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303176 */
3177
Asutosh Dasf5298c32012-04-03 14:51:47 +05303178 mutex_lock(&host->clk_mutex);
3179 DBG(host, "ios->clock = %u\n", ios->clock);
San Mehat9d2bd732009-09-22 16:44:22 -07003180 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303181 if (!host->sdcc_irq_disabled) {
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05303182 disable_irq_nosync(host->core_irqres->start);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303183 host->sdcc_irq_disabled = 1;
3184 }
San Mehatd0719e52009-12-03 10:58:54 -08003185 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07003186
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05303187 /* Make sure sdcc core irq is synchronized */
3188 synchronize_irq(host->core_irqres->start);
3189
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303190 pwr = msmsdcc_setup_pwr(host, ios);
3191
3192 spin_lock_irqsave(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07003193 if (ios->clock) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303194 spin_unlock_irqrestore(&host->lock, flags);
3195 rc = msmsdcc_setup_clocks(host, true);
3196 if (rc)
3197 goto out;
3198 spin_lock_irqsave(&host->lock, flags);
3199 writel_relaxed(host->mci_irqenable, host->base + MMCIMASK0);
3200 mb();
3201 msmsdcc_cfg_sdio_wakeup(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003202 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303203
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003204 /*
3205 * For DDR50 mode, controller needs clock rate to be
3206 * double than what is required on the SD card CLK pin.
Subhash Jadavani2226d262012-10-09 20:01:56 +05303207 *
3208 * Setting DDR timing mode in controller before setting the
3209 * clock rate will make sure that card don't see the double
3210 * clock rate even for very small duration. Some eMMC
3211 * cards seems to lock up if they see clock frequency > 52MHz.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003212 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05303213 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Subhash Jadavani2226d262012-10-09 20:01:56 +05303214 u32 clk;
3215
3216 clk = readl_relaxed(host->base + MMCICLOCK);
3217 clk &= ~(0x7 << 14); /* clear SELECT_IN field */
3218 clk |= (3 << 14); /* set DDR timing mode */
3219 writel_relaxed(clk, host->base + MMCICLOCK);
3220 msmsdcc_sync_reg_wr(host);
3221
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003222 /*
3223 * Make sure that we don't double the clock if
3224 * doubled clock rate is already set
3225 */
3226 if (!host->ddr_doubled_clk_rate ||
3227 (host->ddr_doubled_clk_rate &&
3228 (host->ddr_doubled_clk_rate != ios->clock))) {
3229 host->ddr_doubled_clk_rate =
3230 msmsdcc_get_sup_clk_rate(
3231 host, (ios->clock * 2));
3232 clock = host->ddr_doubled_clk_rate;
3233 }
3234 } else {
3235 host->ddr_doubled_clk_rate = 0;
3236 }
3237
3238 if (clock != host->clk_rate) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05303239 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003240 rc = clk_set_rate(host->clk, clock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303241 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003242 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303243 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003244 mmc_hostname(mmc), clock);
3245 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303246 host->reg_write_delay =
3247 (1 + ((3 * USEC_PER_SEC) /
3248 (host->clk_rate ? host->clk_rate :
3249 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003250 }
3251 /*
3252 * give atleast 2 MCLK cycles delay for clocks
3253 * and SDCC core to stabilize
3254 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05303255 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003256 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003257 clk |= MCI_CLK_ENABLE;
3258 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003259 if (ios->bus_width == MMC_BUS_WIDTH_8)
3260 clk |= MCI_CLK_WIDEBUS_8;
3261 else if (ios->bus_width == MMC_BUS_WIDTH_4)
3262 clk |= MCI_CLK_WIDEBUS_4;
3263 else
3264 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07003265
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003266 if (msmsdcc_is_pwrsave(host))
3267 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07003268
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003269 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07003270
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003271 host->tuning_needed = 0;
3272 /*
3273 * Select the controller timing mode according
3274 * to current bus speed mode
3275 */
Subhash Jadavanif97d2992012-07-13 14:47:47 +05303276 if (host->clk_rate > (100 * 1000 * 1000) &&
3277 (ios->timing == MMC_TIMING_UHS_SDR104 ||
3278 ios->timing == MMC_TIMING_MMC_HS200)) {
3279 /* Card clock frequency must be > 100MHz to enable tuning */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003280 clk |= (4 << 14);
3281 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05303282 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003283 clk |= (3 << 14);
3284 } else {
3285 clk |= (2 << 14); /* feedback clock */
San Mehat9d2bd732009-09-22 16:44:22 -07003286 }
3287
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003288 /* Select free running MCLK as input clock of cm_dll_sdc4 */
3289 clk |= (2 << 23);
San Mehat9d2bd732009-09-22 16:44:22 -07003290
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003291 if (host->io_pad_pwr_switch)
3292 clk |= IO_PAD_PWR_SWITCH;
3293
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303294 /* Don't write into registers if clocks are disabled */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303295 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303296 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
3297 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303298 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003299 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303300 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
3301 host->pwr = pwr;
3302 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303303 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003304 }
San Mehat9d2bd732009-09-22 16:44:22 -07003305 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003306
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303307 if (!(clk & MCI_CLK_ENABLE) && atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303308 msmsdcc_cfg_sdio_wakeup(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303309 spin_unlock_irqrestore(&host->lock, flags);
3310 /*
3311 * May get a wake-up interrupt the instant we disable the
3312 * clocks. This would disable the wake-up interrupt.
3313 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003314 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303315 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003316 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303317
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303318 if (host->tuning_in_progress)
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303319 WARN(!atomic_read(&host->clks_on),
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303320 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303321
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303322 /* Let interrupts be disabled if the host is powered off */
3323 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
3324 enable_irq(host->core_irqres->start);
3325 host->sdcc_irq_disabled = 0;
3326 }
San Mehat4adbbcc2009-11-08 13:00:37 -08003327 spin_unlock_irqrestore(&host->lock, flags);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303328out:
Asutosh Dasf5298c32012-04-03 14:51:47 +05303329 mutex_unlock(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07003330}
3331
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003332int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
3333{
3334 struct msmsdcc_host *host = mmc_priv(mmc);
3335 u32 clk;
3336
3337 clk = readl_relaxed(host->base + MMCICLOCK);
3338 pr_debug("Changing to pwr_save=%d", pwrsave);
3339 if (pwrsave && msmsdcc_is_pwrsave(host))
3340 clk |= MCI_CLK_PWRSAVE;
3341 else
3342 clk &= ~MCI_CLK_PWRSAVE;
3343 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303344 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003345
3346 return 0;
3347}
3348
3349static int msmsdcc_get_ro(struct mmc_host *mmc)
3350{
3351 int status = -ENOSYS;
3352 struct msmsdcc_host *host = mmc_priv(mmc);
3353
3354 if (host->plat->wpswitch) {
3355 status = host->plat->wpswitch(mmc_dev(mmc));
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05303356 } else if (gpio_is_valid(host->plat->wpswitch_gpio)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003357 status = gpio_request(host->plat->wpswitch_gpio,
3358 "SD_WP_Switch");
3359 if (status) {
3360 pr_err("%s: %s: Failed to request GPIO %d\n",
3361 mmc_hostname(mmc), __func__,
3362 host->plat->wpswitch_gpio);
3363 } else {
3364 status = gpio_direction_input(
3365 host->plat->wpswitch_gpio);
3366 if (!status) {
3367 /*
3368 * Wait for atleast 300ms as debounce
3369 * time for GPIO input to stabilize.
3370 */
3371 msleep(300);
3372 status = gpio_get_value_cansleep(
3373 host->plat->wpswitch_gpio);
Sujit Reddy Thumma8f912ea2012-06-22 16:18:43 +05303374 status ^= !host->plat->is_wpswitch_active_low;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003375 }
3376 gpio_free(host->plat->wpswitch_gpio);
3377 }
3378 }
3379
3380 if (status < 0)
3381 status = -ENOSYS;
3382 pr_debug("%s: Card read-only status %d\n", __func__, status);
3383
3384 return status;
San Mehat9d2bd732009-09-22 16:44:22 -07003385}
3386
3387static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
3388{
3389 struct msmsdcc_host *host = mmc_priv(mmc);
3390 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003391
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303392 /*
3393 * We may come here with clocks turned off in that case don't
3394 * attempt to write into MASK0 register. While turning on the
3395 * clocks mci_irqenable will be written to MASK0 register.
3396 */
San Mehat9d2bd732009-09-22 16:44:22 -07003397
3398 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003399 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003400 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303401 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303402 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003403 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303404 mb();
3405 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003406 } else {
3407 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303408 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303409 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003410 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303411 mb();
3412 }
San Mehat9d2bd732009-09-22 16:44:22 -07003413 }
3414 spin_unlock_irqrestore(&host->lock, flags);
3415}
3416
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003417#ifdef CONFIG_PM_RUNTIME
subhashj245831e2012-04-30 18:46:17 +05303418static void msmsdcc_print_rpm_info(struct msmsdcc_host *host)
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003419{
subhashj245831e2012-04-30 18:46:17 +05303420 struct device *dev = mmc_dev(host->mmc);
3421
Subhash Jadavani1371d192012-08-16 18:46:57 +05303422 pr_info("%s: PM: sdcc_suspended=%d, pending_resume=%d, sdcc_suspending=%d\n",
3423 mmc_hostname(host->mmc), host->sdcc_suspended,
3424 host->pending_resume, host->sdcc_suspending);
subhashj245831e2012-04-30 18:46:17 +05303425 pr_info("%s: RPM: runtime_status=%d, usage_count=%d,"
3426 " is_suspended=%d, disable_depth=%d, runtime_error=%d,"
3427 " request_pending=%d, request=%d\n",
3428 mmc_hostname(host->mmc), dev->power.runtime_status,
3429 atomic_read(&dev->power.usage_count),
3430 dev->power.is_suspended, dev->power.disable_depth,
3431 dev->power.runtime_error, dev->power.request_pending,
3432 dev->power.request);
3433}
3434
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003435static int msmsdcc_enable(struct mmc_host *mmc)
3436{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003437 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003438 struct device *dev = mmc->parent;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003439 struct msmsdcc_host *host = mmc_priv(mmc);
3440
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303441 msmsdcc_pm_qos_update_latency(host, 1);
3442
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003443 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303444 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003445
Subhash Jadavani1371d192012-08-16 18:46:57 +05303446 if (host->sdcc_suspended && host->pending_resume) {
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003447 host->pending_resume = false;
3448 pm_runtime_get_noresume(dev);
3449 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303450 goto skip_get_sync;
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003451 }
3452
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303453 if (dev->power.runtime_status == RPM_SUSPENDING) {
3454 if (mmc->suspend_task == current) {
3455 pm_runtime_get_noresume(dev);
3456 goto out;
3457 }
Sujit Reddy Thumma112bd752012-06-20 12:29:45 +05303458 } else if (dev->power.runtime_status == RPM_RESUMING) {
3459 pm_runtime_get_noresume(dev);
3460 goto out;
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303461 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003462
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303463 rc = pm_runtime_get_sync(dev);
3464
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303465skip_get_sync:
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303466 if (rc < 0) {
Subhash Jadavani1371d192012-08-16 18:46:57 +05303467 WARN(1, "%s: %s: failed with error %d\n", mmc_hostname(mmc),
3468 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303469 msmsdcc_print_rpm_info(host);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303470 return rc;
3471 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303472out:
3473 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303474 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003475}
3476
Steve Mucklef132c6c2012-06-06 18:30:57 -07003477static int msmsdcc_disable(struct mmc_host *mmc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003478{
3479 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303480 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003481
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303482 msmsdcc_pm_qos_update_latency(host, 0);
3483
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303484 if (mmc->card && mmc_card_sdio(mmc->card)) {
3485 rc = 0;
3486 goto out;
3487 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303488
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303489 if (host->plat->disable_runtime_pm)
3490 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003491
3492 rc = pm_runtime_put_sync(mmc->parent);
3493
Subhash Jadavani1371d192012-08-16 18:46:57 +05303494 if (rc < 0) {
3495 WARN(1, "%s: %s: failed with error %d\n", mmc_hostname(mmc),
3496 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303497 msmsdcc_print_rpm_info(host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003498 return rc;
3499 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303500
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303501out:
3502 msmsdcc_msm_bus_queue_work(host);
3503 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003504}
3505#else
subhashj245831e2012-04-30 18:46:17 +05303506static void msmsdcc_print_rpm_info(struct msmsdcc_host *host) {}
3507
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303508static int msmsdcc_enable(struct mmc_host *mmc)
3509{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003510 struct device *dev = mmc->parent;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303511 struct msmsdcc_host *host = mmc_priv(mmc);
Sujit Reddy Thumma7f5051c2012-05-04 10:14:07 +05303512 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303513
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303514 msmsdcc_pm_qos_update_latency(host, 1);
3515
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303516 if (mmc->card && mmc_card_sdio(mmc->card)) {
3517 rc = 0;
3518 goto out;
3519 }
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003520
3521 if (host->sdcc_suspended && host->pending_resume) {
3522 host->pending_resume = false;
3523 rc = msmsdcc_runtime_resume(dev);
3524 goto out;
3525 }
3526
Asutosh Dasf5298c32012-04-03 14:51:47 +05303527 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303528 rc = msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303529 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303530
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003531out:
3532 if (rc < 0) {
3533 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3534 __func__, rc);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303535 msmsdcc_pm_qos_update_latency(host, 0);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003536 return rc;
3537 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303538 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303539 return 0;
3540}
3541
Steve Mucklef132c6c2012-06-06 18:30:57 -07003542static int msmsdcc_disable(struct mmc_host *mmc)
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303543{
3544 struct msmsdcc_host *host = mmc_priv(mmc);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303545 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303546
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303547 msmsdcc_pm_qos_update_latency(host, 0);
3548
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303549 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303550 goto out;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303551
Asutosh Dasf5298c32012-04-03 14:51:47 +05303552 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303553 rc = msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303554 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303555
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303556 if (rc) {
3557 msmsdcc_pm_qos_update_latency(host, 1);
3558 return rc;
3559 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303560out:
3561 msmsdcc_msm_bus_queue_work(host);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303562 return rc;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303563}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003564#endif
3565
Subhash Jadavani937c7502012-06-01 15:34:46 +05303566static int msmsdcc_switch_io_voltage(struct mmc_host *mmc,
3567 struct mmc_ios *ios)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003568{
3569 struct msmsdcc_host *host = mmc_priv(mmc);
3570 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303571 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003572
Subhash Jadavani937c7502012-06-01 15:34:46 +05303573 switch (ios->signal_voltage) {
3574 case MMC_SIGNAL_VOLTAGE_330:
3575 /* Set VDD IO to high voltage range (2.7v - 3.6v) */
3576 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Subhash Jadavanibf09d802012-08-11 18:11:57 +05303577 if (!rc)
3578 msmsdcc_update_io_pad_pwr_switch(host);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303579 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303580 case MMC_SIGNAL_VOLTAGE_180:
3581 break;
3582 case MMC_SIGNAL_VOLTAGE_120:
3583 /*
3584 * For eMMC cards, VDD_IO voltage range must be changed
3585 * only if it operates in HS200 SDR 1.2V mode or in
3586 * DDR 1.2V mode.
3587 */
3588 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_SET_LEVEL, 1200000);
Subhash Jadavanibf09d802012-08-11 18:11:57 +05303589 if (!rc)
3590 msmsdcc_update_io_pad_pwr_switch(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003591 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303592 default:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003593 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303594 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003595 goto out;
3596 }
San Mehat9d2bd732009-09-22 16:44:22 -07003597
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003598 /*
3599 * If we are here means voltage switch from high voltage to
3600 * low voltage is required
3601 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303602 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003603
3604 /*
3605 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
3606 * register until they become all zeros.
3607 */
3608 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303609 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003610 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
3611 mmc_hostname(mmc), __func__);
3612 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07003613 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003614
3615 /* Stop SD CLK output. */
3616 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3617 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303618 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003619 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003620
3621 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05303622 * Switch VDD Io from high voltage range (2.7v - 3.6v) to
3623 * low voltage range (1.7v - 1.95v).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003624 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303625 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303626 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003627 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003628
Subhash Jadavanibf09d802012-08-11 18:11:57 +05303629 msmsdcc_update_io_pad_pwr_switch(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003630
3631 /* Wait 5 ms for the voltage regulater in the card to become stable. */
3632 usleep_range(5000, 5500);
3633
3634 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303635 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003636 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3637 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303638 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003639 spin_unlock_irqrestore(&host->lock, flags);
3640
3641 /*
3642 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
3643 * don't become all ones within 1 ms then a Voltage Switch
3644 * sequence has failed and a power cycle to the card is required.
3645 * Otherwise Voltage Switch sequence is completed successfully.
3646 */
3647 usleep_range(1000, 1500);
3648
3649 spin_lock_irqsave(&host->lock, flags);
3650 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
3651 != (0xF << 1)) {
3652 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
3653 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303654 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003655 goto out_unlock;
3656 }
3657
3658out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303659 /* Enable PWRSAVE */
3660 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3661 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303662 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003663 spin_unlock_irqrestore(&host->lock, flags);
3664out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303665 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003666}
3667
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303668static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003669{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003670 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003671
3672 /* Program the MCLK value to MCLK_FREQ bit field */
3673 if (host->clk_rate <= 112000000)
3674 mclk_freq = 0;
3675 else if (host->clk_rate <= 125000000)
3676 mclk_freq = 1;
3677 else if (host->clk_rate <= 137000000)
3678 mclk_freq = 2;
3679 else if (host->clk_rate <= 150000000)
3680 mclk_freq = 3;
3681 else if (host->clk_rate <= 162000000)
3682 mclk_freq = 4;
3683 else if (host->clk_rate <= 175000000)
3684 mclk_freq = 5;
3685 else if (host->clk_rate <= 187000000)
3686 mclk_freq = 6;
3687 else if (host->clk_rate <= 200000000)
3688 mclk_freq = 7;
3689
3690 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3691 & ~(7 << 24)) | (mclk_freq << 24)),
3692 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003693}
3694
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303695/* Initialize the DLL (Programmable Delay Line ) */
3696static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003697{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003698 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303699 unsigned long flags;
3700 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003701
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303702 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003703 /*
3704 * Make sure that clock is always enabled when DLL
3705 * tuning is in progress. Keeping PWRSAVE ON may
3706 * turn off the clock. So let's disable the PWRSAVE
3707 * here and re-enable it once tuning is completed.
3708 */
3709 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3710 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303711 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303712
3713 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3714 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3715 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3716
3717 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3718 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3719 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3720
3721 msmsdcc_cm_sdc4_dll_set_freq(host);
3722
3723 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3724 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3725 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3726
3727 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3728 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3729 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3730
3731 /* Set DLL_EN bit to 1. */
3732 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3733 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3734
3735 /* Set CK_OUT_EN bit to 1. */
3736 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3737 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3738
3739 wait_cnt = 50;
3740 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3741 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3742 /* max. wait for 50us sec for LOCK bit to be set */
3743 if (--wait_cnt == 0) {
3744 pr_err("%s: %s: DLL failed to LOCK\n",
3745 mmc_hostname(host->mmc), __func__);
3746 rc = -ETIMEDOUT;
3747 goto out;
3748 }
3749 /* wait for 1us before polling again */
3750 udelay(1);
3751 }
3752
3753out:
3754 /* re-enable PWRSAVE */
3755 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3756 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303757 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303758 spin_unlock_irqrestore(&host->lock, flags);
3759
3760 return rc;
3761}
3762
3763static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3764 u8 poll)
3765{
3766 int rc = 0;
3767 u32 wait_cnt = 50;
3768 u8 ck_out_en = 0;
3769
3770 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3771 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3772 MCI_CK_OUT_EN);
3773
3774 while (ck_out_en != poll) {
3775 if (--wait_cnt == 0) {
3776 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3777 mmc_hostname(host->mmc), __func__, poll);
3778 rc = -ETIMEDOUT;
3779 goto out;
3780 }
3781 udelay(1);
3782
3783 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3784 MCI_CK_OUT_EN);
3785 }
3786out:
3787 return rc;
3788}
3789
3790/*
3791 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3792 * calibration sequence. This function should be called before
3793 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3794 * commands (CMD17/CMD18).
3795 *
3796 * This function gets called when host spinlock acquired.
3797 */
3798static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3799{
3800 int rc = 0;
3801 u32 config;
3802
3803 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3804 config |= MCI_CDR_EN;
3805 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3806 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3807
3808 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3809 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3810 if (rc)
3811 goto err_out;
3812
3813 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3814 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3815 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3816
3817 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3818 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3819 if (rc)
3820 goto err_out;
3821
3822 goto out;
3823
3824err_out:
3825 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3826out:
3827 return rc;
3828}
3829
3830static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3831 u8 phase)
3832{
3833 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303834 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3835 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3836 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303837 unsigned long flags;
3838 u32 config;
3839
3840 spin_lock_irqsave(&host->lock, flags);
3841
3842 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3843 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3844 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3845 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3846
3847 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3848 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3849 if (rc)
3850 goto err_out;
3851
3852 /*
3853 * Write the selected DLL clock output phase (0 ... 15)
3854 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
3855 */
3856 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3857 & ~(0xF << 20))
3858 | (grey_coded_phase_table[phase] << 20)),
3859 host->base + MCI_DLL_CONFIG);
3860
3861 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3862 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3863 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3864
3865 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3866 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3867 if (rc)
3868 goto err_out;
3869
3870 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3871 config |= MCI_CDR_EN;
3872 config &= ~MCI_CDR_EXT_EN;
3873 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3874 goto out;
3875
3876err_out:
3877 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3878 mmc_hostname(host->mmc), __func__, phase);
3879out:
3880 spin_unlock_irqrestore(&host->lock, flags);
3881 return rc;
3882}
3883
3884/*
3885 * Find out the greatest range of consecuitive selected
3886 * DLL clock output phases that can be used as sampling
3887 * setting for SD3.0 UHS-I card read operation (in SDR104
3888 * timing mode) or for eMMC4.5 card read operation (in HS200
3889 * timing mode).
3890 * Select the 3/4 of the range and configure the DLL with the
3891 * selected DLL clock output phase.
3892*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303893static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303894 u8 *phase_table, u8 total_phases)
3895{
Subhash Jadavani6159c622012-03-15 19:05:55 +05303896 #define MAX_PHASES 16
Subhash Jadavani34187042012-03-02 10:59:49 +05303897 int ret;
Subhash Jadavani6159c622012-03-15 19:05:55 +05303898 u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
3899 u8 phases_per_row[MAX_PHASES] = {0};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303900 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303901 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3902 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303903
Subhash Jadavani6159c622012-03-15 19:05:55 +05303904 if (!total_phases || (total_phases > MAX_PHASES)) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303905 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3906 mmc_hostname(host->mmc), __func__, total_phases);
3907 return -EINVAL;
3908 }
3909
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303910 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303911 ranges[row_index][col_index] = phase_table[cnt];
3912 phases_per_row[row_index] += 1;
3913 col_index++;
3914
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303915 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303916 continue;
3917 /* check if next phase in phase_table is consecutive or not */
3918 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3919 row_index++;
3920 col_index = 0;
3921 }
3922 }
3923
Subhash Jadavani6159c622012-03-15 19:05:55 +05303924 if (row_index >= MAX_PHASES)
3925 return -EINVAL;
3926
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303927 /* Check if phase-0 is present in first valid window? */
3928 if (!ranges[0][0]) {
3929 phase_0_found = true;
3930 phase_0_raw_index = 0;
3931 /* Check if cycle exist between 2 valid windows */
3932 for (cnt = 1; cnt <= row_index; cnt++) {
3933 if (phases_per_row[cnt]) {
Subhash Jadavani6159c622012-03-15 19:05:55 +05303934 for (i = 0; i < phases_per_row[cnt]; i++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303935 if (ranges[cnt][i] == 15) {
3936 phase_15_found = true;
3937 phase_15_raw_index = cnt;
3938 break;
3939 }
3940 }
3941 }
3942 }
3943 }
3944
3945 /* If 2 valid windows form cycle then merge them as single window */
3946 if (phase_0_found && phase_15_found) {
3947 /* number of phases in raw where phase 0 is present */
3948 u8 phases_0 = phases_per_row[phase_0_raw_index];
3949 /* number of phases in raw where phase 15 is present */
3950 u8 phases_15 = phases_per_row[phase_15_raw_index];
3951
Subhash Jadavani6159c622012-03-15 19:05:55 +05303952 if (phases_0 + phases_15 >= MAX_PHASES)
3953 /*
3954 * If there are more than 1 phase windows then total
3955 * number of phases in both the windows should not be
3956 * more than or equal to MAX_PHASES.
3957 */
3958 return -EINVAL;
3959
3960 /* Merge 2 cyclic windows */
3961 i = phases_15;
3962 for (cnt = 0; cnt < phases_0; cnt++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303963 ranges[phase_15_raw_index][i] =
3964 ranges[phase_0_raw_index][cnt];
Subhash Jadavani6159c622012-03-15 19:05:55 +05303965 if (++i >= MAX_PHASES)
3966 break;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303967 }
Subhash Jadavani6159c622012-03-15 19:05:55 +05303968
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303969 phases_per_row[phase_0_raw_index] = 0;
3970 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
3971 }
3972
3973 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303974 if (phases_per_row[cnt] > curr_max) {
3975 curr_max = phases_per_row[cnt];
3976 selected_row_index = cnt;
3977 }
3978 }
3979
Subhash Jadavani6159c622012-03-15 19:05:55 +05303980 i = ((curr_max * 3) / 4);
3981 if (i)
3982 i--;
3983
Subhash Jadavani34187042012-03-02 10:59:49 +05303984 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303985
Subhash Jadavani6159c622012-03-15 19:05:55 +05303986 if (ret >= MAX_PHASES) {
3987 ret = -EINVAL;
3988 pr_err("%s: %s: invalid phase selected=%d\n",
3989 mmc_hostname(host->mmc), __func__, ret);
3990 }
3991
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303992 return ret;
3993}
3994
Girish K Sa3f41692012-02-29 12:00:09 +05303995static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303996{
3997 int rc = 0;
3998 struct msmsdcc_host *host = mmc_priv(mmc);
3999 unsigned long flags;
4000 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304001 const u32 *tuning_block_pattern = tuning_block_64;
4002 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304003
4004 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
4005
4006 /* Tuning is only required for SDR104 modes */
4007 if (!host->tuning_needed) {
4008 rc = 0;
4009 goto exit;
4010 }
4011
4012 spin_lock_irqsave(&host->lock, flags);
4013 WARN(!host->pwr, "SDCC power is turned off\n");
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304014 WARN(!atomic_read(&host->clks_on), "SDCC clocks are turned off\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304015 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
4016
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304017 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304018 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
4019 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
4020 tuning_block_pattern = tuning_block_128;
4021 size = sizeof(tuning_block_128);
4022 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304023 spin_unlock_irqrestore(&host->lock, flags);
4024
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004025 /* first of all reset the tuning block */
4026 rc = msmsdcc_init_cm_sdc4_dll(host);
4027 if (rc)
4028 goto out;
4029
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304030 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004031 if (!data_buf) {
4032 rc = -ENOMEM;
4033 goto out;
4034 }
4035
4036 phase = 0;
4037 do {
4038 struct mmc_command cmd = {0};
4039 struct mmc_data data = {0};
4040 struct mmc_request mrq = {
4041 .cmd = &cmd,
4042 .data = &data
4043 };
4044 struct scatterlist sg;
4045
4046 /* set the phase in delay line hw block */
4047 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
4048 if (rc)
4049 goto kfree;
4050
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304051 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004052 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
4053
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304054 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004055 data.blocks = 1;
4056 data.flags = MMC_DATA_READ;
4057 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
4058
4059 data.sg = &sg;
4060 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304061 sg_init_one(&sg, data_buf, size);
4062 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004063 mmc_wait_for_req(mmc, &mrq);
4064
4065 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304066 !memcmp(data_buf, tuning_block_pattern, size)) {
4067 /* tuning is successful at this tuning point */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004068 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304069 pr_debug("%s: %s: found good phase = %d\n",
4070 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004071 }
4072 } while (++phase < 16);
4073
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004074 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05304075 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304076 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05304077 if (rc < 0)
4078 goto kfree;
4079 else
4080 phase = (u8)rc;
4081
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004082 /*
4083 * Finally set the selected phase in delay
4084 * line hw block.
4085 */
4086 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
4087 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304088 goto kfree;
4089 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
4090 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004091 } else {
4092 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304093 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004094 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304095 msmsdcc_dump_sdcc_state(host);
4096 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004097 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004098
4099kfree:
4100 kfree(data_buf);
4101out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304102 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304103 host->tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304104 spin_unlock_irqrestore(&host->lock, flags);
4105exit:
4106 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004107 return rc;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04004108}
4109
Asutosh Dasebd7d092012-07-09 19:08:26 +05304110/*
4111 * Work around of the unavailability of a power_reset functionality in SD cards
4112 * by turning the OFF & back ON the regulators supplying the SD card.
4113 */
4114void msmsdcc_hw_reset(struct mmc_host *mmc)
4115{
4116 struct mmc_card *card = mmc->card;
4117 struct msmsdcc_host *host = mmc_priv(mmc);
4118 int rc;
4119
4120 /* Write-protection bits would be lost on a hardware reset in emmc */
4121 if (!card || !mmc_card_sd(card))
4122 return;
4123
4124 /*
4125 * Continuing on failing to disable regulator would lead to a panic
4126 * anyway, since the commands would fail and console would be flooded
4127 * with prints, eventually leading to a watchdog bark
4128 */
4129 rc = msmsdcc_setup_vreg(host, false, false);
4130 if (rc) {
4131 pr_err("%s: %s disable regulator: failed: %d\n",
4132 mmc_hostname(mmc), __func__, rc);
4133 BUG_ON(rc);
4134 }
4135
4136 /* 10ms delay for the supply to reach the desired voltage level */
4137 usleep_range(10000, 12000);
4138
4139 /*
4140 * Continuing on failing to enable regulator would lead to a panic
4141 * anyway, since the commands would fail and console would be flooded
4142 * with prints, eventually leading to a watchdog bark
4143 */
4144 rc = msmsdcc_setup_vreg(host, true, false);
4145 if (rc) {
4146 pr_err("%s: %s enable regulator: failed: %d\n",
4147 mmc_hostname(mmc), __func__, rc);
4148 BUG_ON(rc);
4149 }
4150
4151 /* 10ms delay for the supply to reach the desired voltage level */
4152 usleep_range(10000, 12000);
4153}
4154
San Mehat9d2bd732009-09-22 16:44:22 -07004155static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004156 .enable = msmsdcc_enable,
4157 .disable = msmsdcc_disable,
Asutosh Dasaccacd42012-03-08 14:33:17 +05304158 .pre_req = msmsdcc_pre_req,
4159 .post_req = msmsdcc_post_req,
San Mehat9d2bd732009-09-22 16:44:22 -07004160 .request = msmsdcc_request,
4161 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004162 .get_ro = msmsdcc_get_ro,
San Mehat9d2bd732009-09-22 16:44:22 -07004163 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Subhash Jadavani937c7502012-06-01 15:34:46 +05304164 .start_signal_voltage_switch = msmsdcc_switch_io_voltage,
Asutosh Dasebd7d092012-07-09 19:08:26 +05304165 .execute_tuning = msmsdcc_execute_tuning,
4166 .hw_reset = msmsdcc_hw_reset,
San Mehat9d2bd732009-09-22 16:44:22 -07004167};
4168
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004169static unsigned int
4170msmsdcc_slot_status(struct msmsdcc_host *host)
4171{
4172 int status;
4173 unsigned int gpio_no = host->plat->status_gpio;
4174
4175 status = gpio_request(gpio_no, "SD_HW_Detect");
4176 if (status) {
4177 pr_err("%s: %s: Failed to request GPIO %d\n",
4178 mmc_hostname(host->mmc), __func__, gpio_no);
4179 } else {
4180 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08004181 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08004182 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08004183 if (host->plat->is_status_gpio_active_low)
4184 status = !status;
4185 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004186 gpio_free(gpio_no);
4187 }
4188 return status;
4189}
4190
San Mehat9d2bd732009-09-22 16:44:22 -07004191static void
4192msmsdcc_check_status(unsigned long data)
4193{
4194 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4195 unsigned int status;
4196
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05304197 if (host->plat->status || gpio_is_valid(host->plat->status_gpio)) {
Krishna Konda941604a2012-01-10 17:46:34 -08004198 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004199 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004200 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004201 status = msmsdcc_slot_status(host);
4202
Krishna Konda941604a2012-01-10 17:46:34 -08004203 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08004204
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004205 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08004206 if (host->plat->status)
4207 pr_info("%s: Slot status change detected "
4208 "(%d -> %d)\n",
4209 mmc_hostname(host->mmc),
4210 host->oldstat, status);
4211 else if (host->plat->is_status_gpio_active_low)
4212 pr_info("%s: Slot status change detected "
4213 "(%d -> %d) and the card detect GPIO"
4214 " is ACTIVE_LOW\n",
4215 mmc_hostname(host->mmc),
4216 host->oldstat, status);
4217 else
4218 pr_info("%s: Slot status change detected "
4219 "(%d -> %d) and the card detect GPIO"
4220 " is ACTIVE_HIGH\n",
4221 mmc_hostname(host->mmc),
4222 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07004223 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004224 }
4225 host->oldstat = status;
4226 } else {
4227 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07004228 }
San Mehat9d2bd732009-09-22 16:44:22 -07004229}
4230
4231static irqreturn_t
4232msmsdcc_platform_status_irq(int irq, void *dev_id)
4233{
4234 struct msmsdcc_host *host = dev_id;
4235
Girish K Sa3c76eb2011-10-11 11:44:09 +05304236 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07004237 msmsdcc_check_status((unsigned long) host);
4238 return IRQ_HANDLED;
4239}
4240
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004241static irqreturn_t
4242msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
4243{
4244 struct msmsdcc_host *host = dev_id;
4245
4246 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
4247 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304248 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004249 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304250 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004251 wake_lock(&host->sdio_wlock);
4252 msmsdcc_disable_irq_wake(host);
4253 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304254 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004255 }
4256 if (host->plat->is_sdio_al_client) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004257 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304258 spin_unlock(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304259 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304260 goto out_unlocked;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004261 }
4262 spin_unlock(&host->lock);
4263
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304264out_unlocked:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004265 return IRQ_HANDLED;
4266}
4267
San Mehat9d2bd732009-09-22 16:44:22 -07004268static void
4269msmsdcc_status_notify_cb(int card_present, void *dev_id)
4270{
4271 struct msmsdcc_host *host = dev_id;
4272
Girish K Sa3c76eb2011-10-11 11:44:09 +05304273 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07004274 card_present);
4275 msmsdcc_check_status((unsigned long) host);
4276}
4277
San Mehat9d2bd732009-09-22 16:44:22 -07004278static int
4279msmsdcc_init_dma(struct msmsdcc_host *host)
4280{
4281 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
4282 host->dma.host = host;
4283 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004284 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004285
4286 if (!host->dmares)
4287 return -ENODEV;
4288
4289 host->dma.nc = dma_alloc_coherent(NULL,
4290 sizeof(struct msmsdcc_nc_dmadata),
4291 &host->dma.nc_busaddr,
4292 GFP_KERNEL);
4293 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004294 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07004295 return -ENOMEM;
4296 }
4297 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
4298 host->dma.cmd_busaddr = host->dma.nc_busaddr;
4299 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
4300 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
4301 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07004302 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07004303
4304 return 0;
4305}
4306
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004307#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
4308/**
4309 * Allocate and Connect a SDCC peripheral's SPS endpoint
4310 *
4311 * This function allocates endpoint context and
4312 * connect it with memory endpoint by calling
4313 * appropriate SPS driver APIs.
4314 *
4315 * Also registers a SPS callback function with
4316 * SPS driver
4317 *
4318 * This function should only be called once typically
4319 * during driver probe.
4320 *
4321 * @host - Pointer to sdcc host structure
4322 * @ep - Pointer to sps endpoint data structure
4323 * @is_produce - 1 means Producer endpoint
4324 * 0 means Consumer endpoint
4325 *
4326 * @return - 0 if successful else negative value.
4327 *
4328 */
4329static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
4330 struct msmsdcc_sps_ep_conn_data *ep,
4331 bool is_producer)
4332{
4333 int rc = 0;
4334 struct sps_pipe *sps_pipe_handle;
4335 struct sps_connect *sps_config = &ep->config;
4336 struct sps_register_event *sps_event = &ep->event;
4337
4338 /* Allocate endpoint context */
4339 sps_pipe_handle = sps_alloc_endpoint();
4340 if (!sps_pipe_handle) {
4341 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
4342 mmc_hostname(host->mmc), is_producer);
4343 rc = -ENOMEM;
4344 goto out;
4345 }
4346
4347 /* Get default connection configuration for an endpoint */
4348 rc = sps_get_config(sps_pipe_handle, sps_config);
4349 if (rc) {
4350 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
4351 " rc=%d", mmc_hostname(host->mmc),
4352 (u32)sps_pipe_handle, rc);
4353 goto get_config_err;
4354 }
4355
4356 /* Modify the default connection configuration */
4357 if (is_producer) {
4358 /*
4359 * For SDCC producer transfer, source should be
4360 * SDCC peripheral where as destination should
4361 * be system memory.
4362 */
4363 sps_config->source = host->sps.bam_handle;
4364 sps_config->destination = SPS_DEV_HANDLE_MEM;
4365 /* Producer pipe will handle this connection */
4366 sps_config->mode = SPS_MODE_SRC;
4367 sps_config->options =
4368 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4369 } else {
4370 /*
4371 * For SDCC consumer transfer, source should be
4372 * system memory where as destination should
4373 * SDCC peripheral
4374 */
4375 sps_config->source = SPS_DEV_HANDLE_MEM;
4376 sps_config->destination = host->sps.bam_handle;
4377 sps_config->mode = SPS_MODE_DEST;
4378 sps_config->options =
4379 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4380 }
4381
4382 /* Producer pipe index */
4383 sps_config->src_pipe_index = host->sps.src_pipe_index;
4384 /* Consumer pipe index */
4385 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
4386 /*
4387 * This event thresold value is only significant for BAM-to-BAM
4388 * transfer. It's ignored for BAM-to-System mode transfer.
4389 */
4390 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304391
4392 /* Allocate maximum descriptor fifo size */
4393 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
4394 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004395 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
4396 sps_config->desc.size,
4397 &sps_config->desc.phys_base,
4398 GFP_KERNEL);
4399
Pratibhasagar V00b94332011-10-18 14:57:27 +05304400 if (!sps_config->desc.base) {
4401 rc = -ENOMEM;
4402 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
4403 , mmc_hostname(host->mmc));
4404 goto get_config_err;
4405 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004406 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
4407
4408 /* Establish connection between peripheral and memory endpoint */
4409 rc = sps_connect(sps_pipe_handle, sps_config);
4410 if (rc) {
4411 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4412 " rc=%d", mmc_hostname(host->mmc),
4413 (u32)sps_pipe_handle, rc);
4414 goto sps_connect_err;
4415 }
4416
4417 sps_event->mode = SPS_TRIGGER_CALLBACK;
4418 sps_event->options = SPS_O_EOT;
4419 sps_event->callback = msmsdcc_sps_complete_cb;
4420 sps_event->xfer_done = NULL;
4421 sps_event->user = (void *)host;
4422
4423 /* Register callback event for EOT (End of transfer) event. */
4424 rc = sps_register_event(sps_pipe_handle, sps_event);
4425 if (rc) {
4426 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4427 " rc=%d", mmc_hostname(host->mmc),
4428 (u32)sps_pipe_handle, rc);
4429 goto reg_event_err;
4430 }
4431 /* Now save the sps pipe handle */
4432 ep->pipe_handle = sps_pipe_handle;
4433 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
4434 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
4435 __func__, is_producer ? "READ" : "WRITE",
4436 (u32)sps_pipe_handle, sps_config->desc.phys_base);
4437 goto out;
4438
4439reg_event_err:
4440 sps_disconnect(sps_pipe_handle);
4441sps_connect_err:
4442 dma_free_coherent(mmc_dev(host->mmc),
4443 sps_config->desc.size,
4444 sps_config->desc.base,
4445 sps_config->desc.phys_base);
4446get_config_err:
4447 sps_free_endpoint(sps_pipe_handle);
4448out:
4449 return rc;
4450}
4451
4452/**
4453 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
4454 *
4455 * This function disconnect endpoint and deallocates
4456 * endpoint context.
4457 *
4458 * This function should only be called once typically
4459 * during driver remove.
4460 *
4461 * @host - Pointer to sdcc host structure
4462 * @ep - Pointer to sps endpoint data structure
4463 *
4464 */
4465static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
4466 struct msmsdcc_sps_ep_conn_data *ep)
4467{
4468 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4469 struct sps_connect *sps_config = &ep->config;
4470 struct sps_register_event *sps_event = &ep->event;
4471
4472 sps_event->xfer_done = NULL;
4473 sps_event->callback = NULL;
4474 sps_register_event(sps_pipe_handle, sps_event);
4475 sps_disconnect(sps_pipe_handle);
4476 dma_free_coherent(mmc_dev(host->mmc),
4477 sps_config->desc.size,
4478 sps_config->desc.base,
4479 sps_config->desc.phys_base);
4480 sps_free_endpoint(sps_pipe_handle);
4481}
4482
4483/**
4484 * Reset SDCC peripheral's SPS endpoint
4485 *
4486 * This function disconnects an endpoint.
4487 *
4488 * This function should be called for reseting
4489 * SPS endpoint when data transfer error is
4490 * encountered during data transfer. This
4491 * can be considered as soft reset to endpoint.
4492 *
4493 * This function should only be called if
4494 * msmsdcc_sps_init() is already called.
4495 *
4496 * @host - Pointer to sdcc host structure
4497 * @ep - Pointer to sps endpoint data structure
4498 *
4499 * @return - 0 if successful else negative value.
4500 */
4501static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
4502 struct msmsdcc_sps_ep_conn_data *ep)
4503{
4504 int rc = 0;
4505 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4506
4507 rc = sps_disconnect(sps_pipe_handle);
4508 if (rc) {
4509 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
4510 " rc=%d", mmc_hostname(host->mmc), __func__,
4511 (u32)sps_pipe_handle, rc);
4512 goto out;
4513 }
4514 out:
4515 return rc;
4516}
4517
4518/**
4519 * Restore SDCC peripheral's SPS endpoint
4520 *
4521 * This function connects an endpoint.
4522 *
4523 * This function should be called for restoring
4524 * SPS endpoint after data transfer error is
4525 * encountered during data transfer. This
4526 * can be considered as soft reset to endpoint.
4527 *
4528 * This function should only be called if
4529 * msmsdcc_sps_reset_ep() is called before.
4530 *
4531 * @host - Pointer to sdcc host structure
4532 * @ep - Pointer to sps endpoint data structure
4533 *
4534 * @return - 0 if successful else negative value.
4535 */
4536static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
4537 struct msmsdcc_sps_ep_conn_data *ep)
4538{
4539 int rc = 0;
4540 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4541 struct sps_connect *sps_config = &ep->config;
4542 struct sps_register_event *sps_event = &ep->event;
4543
4544 /* Establish connection between peripheral and memory endpoint */
4545 rc = sps_connect(sps_pipe_handle, sps_config);
4546 if (rc) {
4547 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
4548 " rc=%d", mmc_hostname(host->mmc), __func__,
4549 (u32)sps_pipe_handle, rc);
4550 goto out;
4551 }
4552
4553 /* Register callback event for EOT (End of transfer) event. */
4554 rc = sps_register_event(sps_pipe_handle, sps_event);
4555 if (rc) {
4556 pr_err("%s: %s: sps_register_event() failed!!!"
4557 " pipe_handle=0x%x, rc=%d",
4558 mmc_hostname(host->mmc), __func__,
4559 (u32)sps_pipe_handle, rc);
4560 goto reg_event_err;
4561 }
4562 goto out;
4563
4564reg_event_err:
4565 sps_disconnect(sps_pipe_handle);
4566out:
4567 return rc;
4568}
4569
4570/**
Krishna Konda5af8f972012-05-14 16:15:24 -07004571 * Handle BAM device's global error condition
4572 *
4573 * This is an error handler for the SDCC bam device
4574 *
4575 * This function is registered as a callback with SPS-BAM
4576 * driver and will called in case there are an errors for
4577 * the SDCC BAM deivce. Any error conditions in the BAM
4578 * device are global and will be result in this function
4579 * being called once per device.
4580 *
4581 * This function will be called from the sps driver's
4582 * interrupt context.
4583 *
4584 * @sps_cb_case - indicates what error it is
4585 * @user - Pointer to sdcc host structure
4586 */
4587static void
4588msmsdcc_sps_bam_global_irq_cb(enum sps_callback_case sps_cb_case, void *user)
4589{
4590 struct msmsdcc_host *host = (struct msmsdcc_host *)user;
4591 struct mmc_request *mrq;
4592 unsigned long flags;
4593 int32_t error = 0;
4594
4595 BUG_ON(!host);
4596 BUG_ON(!is_sps_mode(host));
4597
4598 if (sps_cb_case == SPS_CALLBACK_BAM_ERROR_IRQ) {
Maya Erezb7a086f2012-11-29 00:37:36 +02004599 /* Reset all endpoints along with resetting bam. */
4600 host->sps.reset_bam = true;
Krishna Konda5af8f972012-05-14 16:15:24 -07004601
4602 pr_err("%s: BAM Global ERROR IRQ happened\n",
4603 mmc_hostname(host->mmc));
4604 error = EAGAIN;
4605 } else if (sps_cb_case == SPS_CALLBACK_BAM_HRESP_ERR_IRQ) {
4606 /**
4607 * This means that there was an AHB access error and
4608 * the address we are trying to read/write is something
4609 * we dont have priviliges to do so.
4610 */
4611 pr_err("%s: BAM HRESP_ERR_IRQ happened\n",
4612 mmc_hostname(host->mmc));
4613 error = EACCES;
4614 } else {
4615 /**
4616 * This should not have happened ideally. If this happens
4617 * there is some seriously wrong.
4618 */
4619 pr_err("%s: BAM global IRQ callback received, type:%d\n",
4620 mmc_hostname(host->mmc), (u32) sps_cb_case);
4621 error = EIO;
4622 }
4623
4624 spin_lock_irqsave(&host->lock, flags);
4625
4626 mrq = host->curr.mrq;
4627
4628 if (mrq && mrq->cmd) {
4629 msmsdcc_dump_sdcc_state(host);
4630
4631 if (!mrq->cmd->error)
4632 mrq->cmd->error = -error;
4633 if (host->curr.data) {
4634 if (mrq->data && !mrq->data->error)
4635 mrq->data->error = -error;
4636 host->curr.data_xfered = 0;
4637 if (host->sps.sg && is_sps_mode(host)) {
4638 /* Stop current SPS transfer */
4639 msmsdcc_sps_exit_curr_xfer(host);
4640 } else {
4641 /* this condition should not have happened */
4642 pr_err("%s: something is seriously wrong. "\
4643 "Funtion: %s, line: %d\n",
4644 mmc_hostname(host->mmc),
4645 __func__, __LINE__);
4646 }
4647 } else {
4648 /* this condition should not have happened */
4649 pr_err("%s: something is seriously wrong. Funtion: "\
4650 "%s, line: %d\n", mmc_hostname(host->mmc),
4651 __func__, __LINE__);
4652 }
4653 }
4654 spin_unlock_irqrestore(&host->lock, flags);
4655}
4656
4657/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004658 * Initialize SPS HW connected with SDCC core
4659 *
4660 * This function register BAM HW resources with
4661 * SPS driver and then initialize 2 SPS endpoints
4662 *
4663 * This function should only be called once typically
4664 * during driver probe.
4665 *
4666 * @host - Pointer to sdcc host structure
4667 *
4668 * @return - 0 if successful else negative value.
4669 *
4670 */
4671static int msmsdcc_sps_init(struct msmsdcc_host *host)
4672{
4673 int rc = 0;
4674 struct sps_bam_props bam = {0};
4675
4676 host->bam_base = ioremap(host->bam_memres->start,
4677 resource_size(host->bam_memres));
4678 if (!host->bam_base) {
4679 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
4680 " size=0x%x", mmc_hostname(host->mmc),
4681 host->bam_memres->start,
4682 (host->bam_memres->end -
4683 host->bam_memres->start));
4684 rc = -ENOMEM;
4685 goto out;
4686 }
4687
4688 bam.phys_addr = host->bam_memres->start;
4689 bam.virt_addr = host->bam_base;
4690 /*
4691 * This event thresold value is only significant for BAM-to-BAM
4692 * transfer. It's ignored for BAM-to-System mode transfer.
4693 */
4694 bam.event_threshold = 0x10; /* Pipe event threshold */
4695 /*
4696 * This threshold controls when the BAM publish
4697 * the descriptor size on the sideband interface.
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304698 * SPS HW will be used for data transfer size even
4699 * less than SDCC FIFO size. So let's set BAM summing
4700 * thresold to SPS_MIN_XFER_SIZE bytes.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004701 */
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304702 bam.summing_threshold = SPS_MIN_XFER_SIZE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004703 /* SPS driver wll handle the SDCC BAM IRQ */
4704 bam.irq = (u32)host->bam_irqres->start;
4705 bam.manage = SPS_BAM_MGR_LOCAL;
Krishna Konda5af8f972012-05-14 16:15:24 -07004706 bam.callback = msmsdcc_sps_bam_global_irq_cb;
4707 bam.user = (void *)host;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004708
4709 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
4710 (u32)bam.phys_addr);
4711 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
4712 (u32)bam.virt_addr);
4713
4714 /* Register SDCC Peripheral BAM device to SPS driver */
4715 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
4716 if (rc) {
4717 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
4718 mmc_hostname(host->mmc), rc);
4719 goto reg_bam_err;
4720 }
4721 pr_info("%s: BAM device registered. bam_handle=0x%x",
4722 mmc_hostname(host->mmc), host->sps.bam_handle);
4723
4724 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
4725 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
4726
4727 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
4728 SPS_PROD_PERIPHERAL);
4729 if (rc)
4730 goto sps_reset_err;
4731 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
4732 SPS_CONS_PERIPHERAL);
4733 if (rc)
4734 goto cons_conn_err;
4735
4736 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
4737 mmc_hostname(host->mmc),
4738 (unsigned long long)host->bam_memres->start,
4739 (unsigned int)host->bam_irqres->start);
4740 goto out;
4741
4742cons_conn_err:
4743 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4744sps_reset_err:
4745 sps_deregister_bam_device(host->sps.bam_handle);
4746reg_bam_err:
4747 iounmap(host->bam_base);
4748out:
4749 return rc;
4750}
4751
4752/**
4753 * De-initialize SPS HW connected with SDCC core
4754 *
4755 * This function deinitialize SPS endpoints and then
4756 * deregisters BAM resources from SPS driver.
4757 *
4758 * This function should only be called once typically
4759 * during driver remove.
4760 *
4761 * @host - Pointer to sdcc host structure
4762 *
4763 */
4764static void msmsdcc_sps_exit(struct msmsdcc_host *host)
4765{
4766 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
4767 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4768 sps_deregister_bam_device(host->sps.bam_handle);
4769 iounmap(host->bam_base);
4770}
4771#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
4772
4773static ssize_t
4774show_polling(struct device *dev, struct device_attribute *attr, char *buf)
4775{
4776 struct mmc_host *mmc = dev_get_drvdata(dev);
4777 struct msmsdcc_host *host = mmc_priv(mmc);
4778 int poll;
4779 unsigned long flags;
4780
4781 spin_lock_irqsave(&host->lock, flags);
4782 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
4783 spin_unlock_irqrestore(&host->lock, flags);
4784
4785 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
4786}
4787
4788static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05304789store_polling(struct device *dev, struct device_attribute *attr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004790 const char *buf, size_t count)
4791{
4792 struct mmc_host *mmc = dev_get_drvdata(dev);
4793 struct msmsdcc_host *host = mmc_priv(mmc);
4794 int value;
4795 unsigned long flags;
4796
4797 sscanf(buf, "%d", &value);
4798
4799 spin_lock_irqsave(&host->lock, flags);
4800 if (value) {
4801 mmc->caps |= MMC_CAP_NEEDS_POLL;
4802 mmc_detect_change(host->mmc, 0);
4803 } else {
4804 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4805 }
4806#ifdef CONFIG_HAS_EARLYSUSPEND
4807 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
4808#endif
4809 spin_unlock_irqrestore(&host->lock, flags);
4810 return count;
4811}
4812
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304813static ssize_t
4814show_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
4815 char *buf)
4816{
4817 struct mmc_host *mmc = dev_get_drvdata(dev);
4818 struct msmsdcc_host *host = mmc_priv(mmc);
4819
4820 return snprintf(buf, PAGE_SIZE, "%u\n",
4821 host->msm_bus_vote.is_max_bw_needed);
4822}
4823
4824static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05304825store_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304826 const char *buf, size_t count)
4827{
4828 struct mmc_host *mmc = dev_get_drvdata(dev);
4829 struct msmsdcc_host *host = mmc_priv(mmc);
4830 uint32_t value;
4831 unsigned long flags;
4832
4833 if (!kstrtou32(buf, 0, &value)) {
4834 spin_lock_irqsave(&host->lock, flags);
4835 host->msm_bus_vote.is_max_bw_needed = !!value;
4836 spin_unlock_irqrestore(&host->lock, flags);
4837 }
4838
4839 return count;
4840}
4841
Pratibhasagar V13d1d032012-07-09 20:12:38 +05304842static ssize_t
4843show_idle_timeout(struct device *dev, struct device_attribute *attr,
4844 char *buf)
4845{
4846 struct mmc_host *mmc = dev_get_drvdata(dev);
4847 struct msmsdcc_host *host = mmc_priv(mmc);
4848
4849 return snprintf(buf, PAGE_SIZE, "%u (Min 5 sec)\n",
4850 host->idle_tout_ms / 1000);
4851}
4852
4853static ssize_t
4854store_idle_timeout(struct device *dev, struct device_attribute *attr,
4855 const char *buf, size_t count)
4856{
4857 struct mmc_host *mmc = dev_get_drvdata(dev);
4858 struct msmsdcc_host *host = mmc_priv(mmc);
4859 unsigned int long flags;
4860 int timeout; /* in secs */
4861
4862 if (!kstrtou32(buf, 0, &timeout)
4863 && (timeout > MSM_MMC_DEFAULT_IDLE_TIMEOUT / 1000)) {
4864 spin_lock_irqsave(&host->lock, flags);
4865 host->idle_tout_ms = timeout * 1000;
4866 spin_unlock_irqrestore(&host->lock, flags);
4867 }
4868 return count;
4869}
4870
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004871#ifdef CONFIG_HAS_EARLYSUSPEND
4872static void msmsdcc_early_suspend(struct early_suspend *h)
4873{
4874 struct msmsdcc_host *host =
4875 container_of(h, struct msmsdcc_host, early_suspend);
4876 unsigned long flags;
4877
4878 spin_lock_irqsave(&host->lock, flags);
4879 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
4880 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4881 spin_unlock_irqrestore(&host->lock, flags);
4882};
4883static void msmsdcc_late_resume(struct early_suspend *h)
4884{
4885 struct msmsdcc_host *host =
4886 container_of(h, struct msmsdcc_host, early_suspend);
4887 unsigned long flags;
4888
4889 if (host->polling_enabled) {
4890 spin_lock_irqsave(&host->lock, flags);
4891 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
4892 mmc_detect_change(host->mmc, 0);
4893 spin_unlock_irqrestore(&host->lock, flags);
4894 }
4895};
4896#endif
4897
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304898static void msmsdcc_print_regs(const char *name, void __iomem *base,
4899 u32 phys_base, unsigned int no_of_regs)
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304900{
4901 unsigned int i;
4902
4903 if (!base)
4904 return;
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304905
4906 pr_info("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
4907 " =====\n", name, phys_base, (u32)base);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304908 for (i = 0; i < no_of_regs; i = i + 4) {
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304909 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
4910 (u32)readl_relaxed(base + i*4),
4911 (u32)readl_relaxed(base + ((i+1)*4)),
4912 (u32)readl_relaxed(base + ((i+2)*4)),
4913 (u32)readl_relaxed(base + ((i+3)*4)));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304914 }
4915}
4916
4917static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
4918{
4919 /* Dump current state of SDCC clocks, power and irq */
4920 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304921 (host->pwr ? "ON" : "OFF"));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304922 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304923 mmc_hostname(host->mmc),
4924 (atomic_read(&host->clks_on) ? "ON" : "OFF"),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304925 (u32)clk_get_rate(host->clk));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304926 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
4927 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
4928
4929 /* Now dump SDCC registers. Don't print FIFO registers */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304930 if (atomic_read(&host->clks_on))
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304931 msmsdcc_print_regs("SDCC-CORE", host->base,
4932 host->core_memres->start, 28);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304933
4934 if (host->curr.data) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304935 if (!msmsdcc_is_dma_possible(host, host->curr.data))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304936 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304937 else if (is_dma_mode(host))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304938 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
4939 mmc_hostname(host->mmc), host->dma.busy,
4940 host->dma.channel, host->dma.crci);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304941 else if (is_sps_mode(host)) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304942 if (host->sps.busy && atomic_read(&host->clks_on))
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304943 msmsdcc_print_regs("SDCC-DML", host->dml_base,
4944 host->dml_memres->start,
4945 16);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304946 pr_info("%s: SPS mode: busy=%d\n",
4947 mmc_hostname(host->mmc), host->sps.busy);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304948 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304949
4950 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
4951 mmc_hostname(host->mmc), host->curr.xfer_size,
4952 host->curr.data_xfered, host->curr.xfer_remain);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304953 }
4954
Maya Erezb7a086f2012-11-29 00:37:36 +02004955 if (host->sps.reset_bam)
4956 pr_err("%s: SPS BAM reset failed: sps reset_bam=%d\n",
4957 mmc_hostname(host->mmc), host->sps.reset_bam);
4958
4959 pr_err("%s: got_dataend=%d, prog_enable=%d,"
Subhash Jadavani8706ced2012-05-25 16:09:21 +05304960 " wait_for_auto_prog_done=%d, got_auto_prog_done=%d,"
4961 " req_tout_ms=%d\n", mmc_hostname(host->mmc),
4962 host->curr.got_dataend, host->prog_enable,
4963 host->curr.wait_for_auto_prog_done,
4964 host->curr.got_auto_prog_done, host->curr.req_tout_ms);
subhashj245831e2012-04-30 18:46:17 +05304965 msmsdcc_print_rpm_info(host);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304966}
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304967
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004968static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
4969{
4970 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4971 struct mmc_request *mrq;
4972 unsigned long flags;
4973
4974 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004975 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004976 pr_info("%s: %s: dummy CMD52 timeout\n",
4977 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004978 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004979 }
4980
4981 mrq = host->curr.mrq;
4982
4983 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304984 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
4985 mrq->cmd->opcode);
4986 msmsdcc_dump_sdcc_state(host);
4987
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004988 if (!mrq->cmd->error)
4989 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304990 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004991 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004992 if (mrq->data && !mrq->data->error)
4993 mrq->data->error = -ETIMEDOUT;
4994 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304995 if (host->dma.sg && is_dma_mode(host)) {
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07004996 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304997 } else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004998 /* Stop current SPS transfer */
4999 msmsdcc_sps_exit_curr_xfer(host);
5000 } else {
5001 msmsdcc_reset_and_restore(host);
5002 msmsdcc_stop_data(host);
5003 if (mrq->data && mrq->data->stop)
5004 msmsdcc_start_command(host,
5005 mrq->data->stop, 0);
5006 else
5007 msmsdcc_request_end(host, mrq);
5008 }
5009 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05305010 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05305011 host->curr.wait_for_auto_prog_done = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005012 msmsdcc_reset_and_restore(host);
5013 msmsdcc_request_end(host, mrq);
5014 }
5015 }
5016 spin_unlock_irqrestore(&host->lock, flags);
5017}
5018
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305019/*
5020 * msmsdcc_dt_get_array - Wrapper fn to read an array of 32 bit integers
5021 *
5022 * @dev: device node from which the property value is to be read.
5023 * @prop_name: name of the property to be searched.
5024 * @out_array: filled array returned to caller
5025 * @len: filled array size returned to caller
5026 * @size: expected size of the array
5027 *
5028 * If expected "size" doesn't match with "len" an error is returned. If
5029 * expected size is zero, the length of actual array is returned provided
5030 * return value is zero.
5031 *
5032 * RETURNS:
5033 * zero on success, negative error if failed.
5034 */
5035static int msmsdcc_dt_get_array(struct device *dev, const char *prop_name,
5036 u32 **out_array, int *len, int size)
5037{
5038 int ret = 0;
5039 u32 *array = NULL;
5040 struct device_node *np = dev->of_node;
5041
5042 if (of_get_property(np, prop_name, len)) {
5043 size_t sz;
5044 sz = *len = *len / sizeof(*array);
5045
5046 if (sz > 0 && !(size > 0 && (sz != size))) {
5047 array = devm_kzalloc(dev, sz * sizeof(*array),
5048 GFP_KERNEL);
5049 if (!array) {
5050 dev_err(dev, "%s: no memory\n", prop_name);
5051 ret = -ENOMEM;
5052 goto out;
5053 }
5054
5055 ret = of_property_read_u32_array(np, prop_name,
5056 array, sz);
5057 if (ret < 0) {
5058 dev_err(dev, "%s: error reading array %d\n",
5059 prop_name, ret);
5060 goto out;
5061 }
5062 } else {
5063 dev_err(dev, "%s invalid size\n", prop_name);
5064 ret = -EINVAL;
5065 goto out;
5066 }
5067 } else {
5068 dev_err(dev, "%s not specified\n", prop_name);
5069 ret = -EINVAL;
5070 goto out;
5071 }
5072 *out_array = array;
5073out:
5074 if (ret)
5075 *len = 0;
5076 return ret;
5077}
5078
5079static int msmsdcc_dt_get_pad_pull_info(struct device *dev, int id,
5080 struct msm_mmc_pad_pull_data **pad_pull_data)
5081{
5082 int ret = 0, base = 0, len, i;
5083 u32 *tmp;
5084 struct msm_mmc_pad_pull_data *pull_data;
5085 struct msm_mmc_pad_pull *pull;
5086
5087 switch (id) {
5088 case 1:
5089 base = TLMM_PULL_SDC1_CLK;
5090 break;
5091 case 2:
5092 base = TLMM_PULL_SDC2_CLK;
5093 break;
5094 case 3:
5095 base = TLMM_PULL_SDC3_CLK;
5096 break;
5097 case 4:
5098 base = TLMM_PULL_SDC4_CLK;
5099 break;
5100 default:
5101 dev_err(dev, "%s: Invalid slot id\n", __func__);
5102 ret = -EINVAL;
5103 goto err;
5104 }
5105
5106 pull_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_pull_data),
5107 GFP_KERNEL);
5108 if (!pull_data) {
5109 dev_err(dev, "No memory msm_mmc_pad_pull_data\n");
5110 ret = -ENOMEM;
5111 goto err;
5112 }
5113 pull_data->size = 3; /* array size for clk, cmd, data */
5114
5115 /* Allocate on, off configs for clk, cmd, data */
5116 pull = devm_kzalloc(dev, 2 * pull_data->size *\
5117 sizeof(struct msm_mmc_pad_pull), GFP_KERNEL);
5118 if (!pull) {
5119 dev_err(dev, "No memory for msm_mmc_pad_pull\n");
5120 ret = -ENOMEM;
5121 goto err;
5122 }
5123 pull_data->on = pull;
5124 pull_data->off = pull + pull_data->size;
5125
5126 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-pull-on",
5127 &tmp, &len, pull_data->size);
5128 if (!ret) {
5129 for (i = 0; i < len; i++) {
5130 pull_data->on[i].no = base + i;
5131 pull_data->on[i].val = tmp[i];
5132 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5133 i, pull_data->on[i].val);
5134 }
5135 } else {
5136 goto err;
5137 }
5138
5139 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-pull-off",
5140 &tmp, &len, pull_data->size);
5141 if (!ret) {
5142 for (i = 0; i < len; i++) {
5143 pull_data->off[i].no = base + i;
5144 pull_data->off[i].val = tmp[i];
5145 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5146 i, pull_data->off[i].val);
5147 }
5148 } else {
5149 goto err;
5150 }
5151
5152 *pad_pull_data = pull_data;
5153err:
5154 return ret;
5155}
5156
5157static int msmsdcc_dt_get_pad_drv_info(struct device *dev, int id,
5158 struct msm_mmc_pad_drv_data **pad_drv_data)
5159{
5160 int ret = 0, base = 0, len, i;
5161 u32 *tmp;
5162 struct msm_mmc_pad_drv_data *drv_data;
5163 struct msm_mmc_pad_drv *drv;
5164
5165 switch (id) {
5166 case 1:
5167 base = TLMM_HDRV_SDC1_CLK;
5168 break;
5169 case 2:
5170 base = TLMM_HDRV_SDC2_CLK;
5171 break;
5172 case 3:
5173 base = TLMM_HDRV_SDC3_CLK;
5174 break;
5175 case 4:
5176 base = TLMM_HDRV_SDC4_CLK;
5177 break;
5178 default:
5179 dev_err(dev, "%s: Invalid slot id\n", __func__);
5180 ret = -EINVAL;
5181 goto err;
5182 }
5183
5184 drv_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_drv_data),
5185 GFP_KERNEL);
5186 if (!drv_data) {
5187 dev_err(dev, "No memory for msm_mmc_pad_drv_data\n");
5188 ret = -ENOMEM;
5189 goto err;
5190 }
5191 drv_data->size = 3; /* array size for clk, cmd, data */
5192
5193 /* Allocate on, off configs for clk, cmd, data */
5194 drv = devm_kzalloc(dev, 2 * drv_data->size *\
5195 sizeof(struct msm_mmc_pad_drv), GFP_KERNEL);
5196 if (!drv) {
5197 dev_err(dev, "No memory msm_mmc_pad_drv\n");
5198 ret = -ENOMEM;
5199 goto err;
5200 }
5201 drv_data->on = drv;
5202 drv_data->off = drv + drv_data->size;
5203
5204 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-drv-on",
5205 &tmp, &len, drv_data->size);
5206 if (!ret) {
5207 for (i = 0; i < len; i++) {
5208 drv_data->on[i].no = base + i;
5209 drv_data->on[i].val = tmp[i];
5210 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5211 i, drv_data->on[i].val);
5212 }
5213 } else {
5214 goto err;
5215 }
5216
5217 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-drv-off",
5218 &tmp, &len, drv_data->size);
5219 if (!ret) {
5220 for (i = 0; i < len; i++) {
5221 drv_data->off[i].no = base + i;
5222 drv_data->off[i].val = tmp[i];
5223 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5224 i, drv_data->off[i].val);
5225 }
5226 } else {
5227 goto err;
5228 }
5229
5230 *pad_drv_data = drv_data;
5231err:
5232 return ret;
5233}
5234
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305235static void msmsdcc_dt_get_cd_wp_gpio(struct device *dev,
5236 struct mmc_platform_data *pdata)
5237{
5238 enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
5239 struct device_node *np = dev->of_node;
5240
5241 pdata->status_gpio = of_get_named_gpio_flags(np,
5242 "cd-gpios", 0, &flags);
5243 if (gpio_is_valid(pdata->status_gpio)) {
5244 pdata->status_irq = gpio_to_irq(pdata->status_gpio);
5245 pdata->is_status_gpio_active_low = flags & OF_GPIO_ACTIVE_LOW;
5246 }
5247
5248 pdata->wpswitch_gpio = of_get_named_gpio_flags(np,
5249 "wp-gpios", 0, &flags);
5250 if (gpio_is_valid(pdata->wpswitch_gpio))
5251 pdata->is_wpswitch_active_low = flags & OF_GPIO_ACTIVE_LOW;
5252}
5253
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305254static int msmsdcc_dt_parse_gpio_info(struct device *dev,
5255 struct mmc_platform_data *pdata)
5256{
5257 int ret = 0, id = 0, cnt, i;
5258 struct msm_mmc_pin_data *pin_data;
5259 struct device_node *np = dev->of_node;
5260
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305261 msmsdcc_dt_get_cd_wp_gpio(dev, pdata);
5262
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305263 pin_data = devm_kzalloc(dev, sizeof(*pin_data), GFP_KERNEL);
5264 if (!pin_data) {
5265 dev_err(dev, "No memory for pin_data\n");
5266 ret = -ENOMEM;
5267 goto err;
5268 }
5269
5270 cnt = of_gpio_count(np);
5271 if (cnt > 0) {
5272 pin_data->is_gpio = true;
5273
5274 pin_data->gpio_data = devm_kzalloc(dev,
5275 sizeof(struct msm_mmc_gpio_data), GFP_KERNEL);
5276 if (!pin_data->gpio_data) {
5277 dev_err(dev, "No memory for gpio_data\n");
5278 ret = -ENOMEM;
5279 goto err;
5280 }
5281 pin_data->gpio_data->size = cnt;
5282 pin_data->gpio_data->gpio = devm_kzalloc(dev,
5283 cnt * sizeof(struct msm_mmc_gpio), GFP_KERNEL);
5284 if (!pin_data->gpio_data->gpio) {
5285 dev_err(dev, "No memory for gpio\n");
5286 ret = -ENOMEM;
5287 goto err;
5288 }
5289
5290 for (i = 0; i < cnt; i++) {
5291 const char *name = NULL;
5292 char result[32];
5293 pin_data->gpio_data->gpio[i].no = of_get_gpio(np, i);
5294 of_property_read_string_index(np,
5295 "qcom,sdcc-gpio-names", i, &name);
5296
5297 snprintf(result, 32, "%s-%s",
5298 dev_name(dev), name ? name : "?");
5299 pin_data->gpio_data->gpio[i].name = result;
5300 dev_dbg(dev, "%s: gpio[%s] = %d\n", __func__,
5301 pin_data->gpio_data->gpio[i].name,
5302 pin_data->gpio_data->gpio[i].no);
5303 }
5304 } else {
5305 pin_data->pad_data = devm_kzalloc(dev,
5306 sizeof(struct msm_mmc_pad_data), GFP_KERNEL);
5307 if (!pin_data->pad_data) {
5308 dev_err(dev, "No memory for pin_data->pad_data\n");
5309 ret = -ENOMEM;
5310 goto err;
5311 }
5312
5313 of_property_read_u32(np, "cell-index", &id);
5314
5315 ret = msmsdcc_dt_get_pad_pull_info(dev, id,
5316 &pin_data->pad_data->pull);
5317 if (ret)
5318 goto err;
5319 ret = msmsdcc_dt_get_pad_drv_info(dev, id,
5320 &pin_data->pad_data->drv);
5321 if (ret)
5322 goto err;
5323 }
5324
5325 pdata->pin_data = pin_data;
5326err:
5327 if (ret)
5328 dev_err(dev, "%s failed with err %d\n", __func__, ret);
5329 return ret;
5330}
5331
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305332#define MAX_PROP_SIZE 32
5333static int msmsdcc_dt_parse_vreg_info(struct device *dev,
5334 struct msm_mmc_reg_data **vreg_data, const char *vreg_name)
5335{
5336 int len, ret = 0;
5337 const __be32 *prop;
5338 char prop_name[MAX_PROP_SIZE];
5339 struct msm_mmc_reg_data *vreg;
5340 struct device_node *np = dev->of_node;
5341
5342 snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", vreg_name);
5343 if (of_parse_phandle(np, prop_name, 0)) {
5344 vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
5345 if (!vreg) {
5346 dev_err(dev, "No memory for vreg: %s\n", vreg_name);
5347 ret = -ENOMEM;
5348 goto err;
5349 }
5350
5351 vreg->name = vreg_name;
5352
5353 snprintf(prop_name, MAX_PROP_SIZE,
5354 "qcom,sdcc-%s-always_on", vreg_name);
5355 if (of_get_property(np, prop_name, NULL))
5356 vreg->always_on = true;
5357
5358 snprintf(prop_name, MAX_PROP_SIZE,
5359 "qcom,sdcc-%s-lpm_sup", vreg_name);
5360 if (of_get_property(np, prop_name, NULL))
5361 vreg->lpm_sup = true;
5362
5363 snprintf(prop_name, MAX_PROP_SIZE,
5364 "qcom,sdcc-%s-voltage_level", vreg_name);
5365 prop = of_get_property(np, prop_name, &len);
5366 if (!prop || (len != (2 * sizeof(__be32)))) {
5367 dev_warn(dev, "%s %s property\n",
5368 prop ? "invalid format" : "no", prop_name);
5369 } else {
5370 vreg->low_vol_level = be32_to_cpup(&prop[0]);
5371 vreg->high_vol_level = be32_to_cpup(&prop[1]);
5372 }
5373
5374 snprintf(prop_name, MAX_PROP_SIZE,
5375 "qcom,sdcc-%s-current_level", vreg_name);
5376 prop = of_get_property(np, prop_name, &len);
5377 if (!prop || (len != (2 * sizeof(__be32)))) {
5378 dev_warn(dev, "%s %s property\n",
5379 prop ? "invalid format" : "no", prop_name);
5380 } else {
5381 vreg->lpm_uA = be32_to_cpup(&prop[0]);
5382 vreg->hpm_uA = be32_to_cpup(&prop[1]);
5383 }
5384
5385 *vreg_data = vreg;
5386 dev_dbg(dev, "%s: %s %s vol=[%d %d]uV, curr=[%d %d]uA\n",
5387 vreg->name, vreg->always_on ? "always_on," : "",
5388 vreg->lpm_sup ? "lpm_sup," : "", vreg->low_vol_level,
5389 vreg->high_vol_level, vreg->lpm_uA, vreg->hpm_uA);
5390 }
5391
5392err:
5393 return ret;
5394}
5395
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305396static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
5397{
5398 int i, ret;
5399 struct mmc_platform_data *pdata;
5400 struct device_node *np = dev->of_node;
Devin Kim9ccbff52012-07-16 20:55:14 -07005401 u32 bus_width = 0, current_limit = 0;
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305402 u32 *clk_table, *sup_voltages;
Devin Kim9ccbff52012-07-16 20:55:14 -07005403 int clk_table_len, sup_volt_len, len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305404
5405 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
5406 if (!pdata) {
5407 dev_err(dev, "could not allocate memory for platform data\n");
5408 goto err;
5409 }
5410
5411 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
5412 if (bus_width == 8) {
5413 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
5414 } else if (bus_width == 4) {
5415 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
5416 } else {
5417 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
5418 pdata->mmc_bus_width = 0;
5419 }
5420
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305421 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-sup-voltages",
5422 &sup_voltages, &sup_volt_len, 0);
5423 if (!ret) {
5424 for (i = 0; i < sup_volt_len; i += 2) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305425 u32 mask;
5426
5427 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
5428 sup_voltages[i + 1]);
5429 if (!mask)
5430 dev_err(dev, "Invalide voltage range %d\n", i);
5431 pdata->ocr_mask |= mask;
5432 }
5433 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305434 }
5435
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305436 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-clk-rates",
5437 &clk_table, &clk_table_len, 0);
5438 if (!ret) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305439 pdata->sup_clk_table = clk_table;
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305440 pdata->sup_clk_cnt = clk_table_len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305441 }
5442
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305443 pdata->vreg_data = devm_kzalloc(dev,
5444 sizeof(struct msm_mmc_slot_reg_data), GFP_KERNEL);
5445 if (!pdata->vreg_data) {
5446 dev_err(dev, "could not allocate memory for vreg_data\n");
5447 goto err;
5448 }
5449
5450 if (msmsdcc_dt_parse_vreg_info(dev,
5451 &pdata->vreg_data->vdd_data, "vdd"))
5452 goto err;
5453
5454 if (msmsdcc_dt_parse_vreg_info(dev,
5455 &pdata->vreg_data->vdd_io_data, "vdd-io"))
5456 goto err;
5457
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305458 if (msmsdcc_dt_parse_gpio_info(dev, pdata))
5459 goto err;
5460
Devin Kim9ccbff52012-07-16 20:55:14 -07005461 len = of_property_count_strings(np, "qcom,sdcc-bus-speed-mode");
5462
5463 for (i = 0; i < len; i++) {
5464 const char *name = NULL;
5465
5466 of_property_read_string_index(np,
5467 "qcom,sdcc-bus-speed-mode", i, &name);
5468 if (!name)
5469 continue;
5470
5471 if (!strncmp(name, "SDR12", sizeof("SDR12")))
5472 pdata->uhs_caps |= MMC_CAP_UHS_SDR12;
5473 else if (!strncmp(name, "SDR25", sizeof("SDR25")))
5474 pdata->uhs_caps |= MMC_CAP_UHS_SDR25;
5475 else if (!strncmp(name, "SDR50", sizeof("SDR50")))
5476 pdata->uhs_caps |= MMC_CAP_UHS_SDR50;
5477 else if (!strncmp(name, "DDR50", sizeof("DDR50")))
5478 pdata->uhs_caps |= MMC_CAP_UHS_DDR50;
5479 else if (!strncmp(name, "SDR104", sizeof("SDR104")))
5480 pdata->uhs_caps |= MMC_CAP_UHS_SDR104;
5481 else if (!strncmp(name, "HS200_1p8v", sizeof("HS200_1p8v")))
5482 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_8V_SDR;
5483 else if (!strncmp(name, "HS200_1p2v", sizeof("HS200_1p2v")))
5484 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_2V_SDR;
5485 else if (!strncmp(name, "DDR_1p8v", sizeof("DDR_1p8v")))
5486 pdata->uhs_caps |= MMC_CAP_1_8V_DDR
5487 | MMC_CAP_UHS_DDR50;
5488 else if (!strncmp(name, "DDR_1p2v", sizeof("DDR_1p2v")))
5489 pdata->uhs_caps |= MMC_CAP_1_2V_DDR
5490 | MMC_CAP_UHS_DDR50;
5491 }
5492
5493 of_property_read_u32(np, "qcom,sdcc-current-limit", &current_limit);
5494 if (current_limit == 800)
5495 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_800;
5496 else if (current_limit == 600)
5497 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_600;
5498 else if (current_limit == 400)
5499 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_400;
5500 else if (current_limit == 200)
5501 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_200;
5502
5503 if (of_get_property(np, "qcom,sdcc-xpc", NULL))
5504 pdata->xpc_cap = true;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305505 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
5506 pdata->nonremovable = true;
5507 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
5508 pdata->disable_cmd23 = true;
5509
5510 return pdata;
5511err:
5512 return NULL;
5513}
5514
San Mehat9d2bd732009-09-22 16:44:22 -07005515static int
5516msmsdcc_probe(struct platform_device *pdev)
5517{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305518 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07005519 struct msmsdcc_host *host;
5520 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005521 unsigned long flags;
5522 struct resource *core_irqres = NULL;
5523 struct resource *bam_irqres = NULL;
5524 struct resource *core_memres = NULL;
5525 struct resource *dml_memres = NULL;
5526 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07005527 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07005528 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05305529 int ret = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07005530
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305531 if (pdev->dev.of_node) {
5532 plat = msmsdcc_populate_pdata(&pdev->dev);
5533 of_property_read_u32((&pdev->dev)->of_node,
5534 "cell-index", &pdev->id);
5535 } else {
5536 plat = pdev->dev.platform_data;
5537 }
San Mehat9d2bd732009-09-22 16:44:22 -07005538
5539 /* must have platform data */
5540 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005541 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005542 ret = -EINVAL;
5543 goto out;
5544 }
5545
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005546 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07005547 return -EINVAL;
5548
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305549 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
5550 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
5551 return -EINVAL;
5552 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005553
San Mehat9d2bd732009-09-22 16:44:22 -07005554 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005555 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005556 return -ENXIO;
5557 }
5558
Sujit Reddy Thumma1dfac2c2012-07-30 10:15:39 +05305559 core_memres = platform_get_resource_byname(pdev,
5560 IORESOURCE_MEM, "core_mem");
5561 bam_memres = platform_get_resource_byname(pdev,
5562 IORESOURCE_MEM, "bam_mem");
5563 dml_memres = platform_get_resource_byname(pdev,
5564 IORESOURCE_MEM, "dml_mem");
5565 core_irqres = platform_get_resource_byname(pdev,
5566 IORESOURCE_IRQ, "core_irq");
5567 bam_irqres = platform_get_resource_byname(pdev,
5568 IORESOURCE_IRQ, "bam_irq");
5569 dmares = platform_get_resource_byname(pdev,
5570 IORESOURCE_DMA, "dma_chnl");
5571 dma_crci_res = platform_get_resource_byname(pdev,
5572 IORESOURCE_DMA, "dma_crci");
San Mehat9d2bd732009-09-22 16:44:22 -07005573
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005574 if (!core_irqres || !core_memres) {
5575 pr_err("%s: Invalid sdcc core resource\n", __func__);
5576 return -ENXIO;
5577 }
5578
5579 /*
5580 * Both BAM and DML memory resource should be preset.
5581 * BAM IRQ resource should also be present.
5582 */
5583 if ((bam_memres && !dml_memres) ||
5584 (!bam_memres && dml_memres) ||
5585 ((bam_memres && dml_memres) && !bam_irqres)) {
5586 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005587 return -ENXIO;
5588 }
5589
5590 /*
5591 * Setup our host structure
5592 */
San Mehat9d2bd732009-09-22 16:44:22 -07005593 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
5594 if (!mmc) {
5595 ret = -ENOMEM;
5596 goto out;
5597 }
5598
5599 host = mmc_priv(mmc);
5600 host->pdev_id = pdev->id;
5601 host->plat = plat;
5602 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08005603 host->curr.cmd = NULL;
Sahitya Tummala19207f02011-05-02 18:10:01 +05305604
Sahitya Tummalad9df3272011-08-19 16:50:46 +05305605 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305606 set_hw_caps(host, MSMSDCC_SPS_BAM_SUP);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005607 else if (dmares)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305608 set_hw_caps(host, MSMSDCC_DMA_SUP);
San Mehat9d2bd732009-09-22 16:44:22 -07005609
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005610 host->base = ioremap(core_memres->start,
5611 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07005612 if (!host->base) {
5613 ret = -ENOMEM;
Sahitya Tummaladce7c752011-05-02 18:06:05 +05305614 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005615 }
5616
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005617 host->core_irqres = core_irqres;
5618 host->bam_irqres = bam_irqres;
5619 host->core_memres = core_memres;
5620 host->dml_memres = dml_memres;
5621 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07005622 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07005623 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07005624 spin_lock_init(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305625 mutex_init(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07005626
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005627#ifdef CONFIG_MMC_EMBEDDED_SDIO
5628 if (plat->embedded_sdio)
5629 mmc_set_embedded_sdio_data(mmc,
5630 &plat->embedded_sdio->cis,
5631 &plat->embedded_sdio->cccr,
5632 plat->embedded_sdio->funcs,
5633 plat->embedded_sdio->num_funcs);
5634#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005635
Sahitya Tummala62612cf2010-12-08 15:03:03 +05305636 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
5637 (unsigned long)host);
5638
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005639 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
5640 (unsigned long)host);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305641 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005642 /* Setup DMA */
Subhash Jadavani190657c2011-05-02 18:10:40 +05305643 ret = msmsdcc_init_dma(host);
5644 if (ret)
5645 goto ioremap_free;
5646 } else {
5647 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07005648 host->dma.crci = -1;
Subhash Jadavani190657c2011-05-02 18:10:40 +05305649 }
San Mehat9d2bd732009-09-22 16:44:22 -07005650
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005651 /*
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305652 * Setup SDCC bus voter clock.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005653 */
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305654 host->bus_clk = clk_get(&pdev->dev, "bus_clk");
5655 if (!IS_ERR_OR_NULL(host->bus_clk)) {
5656 /* Vote for max. clk rate for max. performance */
5657 ret = clk_set_rate(host->bus_clk, INT_MAX);
5658 if (ret)
5659 goto bus_clk_put;
5660 ret = clk_prepare_enable(host->bus_clk);
5661 if (ret)
5662 goto bus_clk_put;
San Mehat9d2bd732009-09-22 16:44:22 -07005663 }
5664
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005665 /*
5666 * Setup main peripheral bus clock
5667 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07005668 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005669 if (!IS_ERR(host->pclk)) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305670 ret = clk_prepare_enable(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005671 if (ret)
5672 goto pclk_put;
5673
5674 host->pclk_rate = clk_get_rate(host->pclk);
5675 }
5676
5677 /*
5678 * Setup SDC MMC clock
5679 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07005680 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07005681 if (IS_ERR(host->clk)) {
5682 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005683 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07005684 }
5685
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005686 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
Sahitya Tummala514d9ed2011-05-02 18:07:01 +05305687 if (ret) {
5688 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
5689 goto clk_put;
5690 }
5691
Asutosh Dasf5298c32012-04-03 14:51:47 +05305692 ret = clk_prepare_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07005693 if (ret)
5694 goto clk_put;
5695
San Mehat9d2bd732009-09-22 16:44:22 -07005696 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05305697 if (!host->clk_rate)
5698 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05305699
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305700 set_default_hw_caps(host);
5701
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05305702 /*
5703 * Set the register write delay according to min. clock frequency
5704 * supported and update later when the host->clk_rate changes.
5705 */
5706 host->reg_write_delay =
5707 (1 + ((3 * USEC_PER_SEC) /
5708 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005709
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305710 atomic_set(&host->clks_on, 1);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05305711 /* Apply Hard reset to SDCC to put it in power on default state */
5712 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005713
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005714#define MSM_MMC_DEFAULT_CPUDMA_LATENCY 200 /* usecs */
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305715 /* pm qos request to prevent apps idle power collapse */
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005716 if (host->plat->cpu_dma_latency)
5717 host->cpu_dma_latency = host->plat->cpu_dma_latency;
5718 else
5719 host->cpu_dma_latency = MSM_MMC_DEFAULT_CPUDMA_LATENCY;
5720 pm_qos_add_request(&host->pm_qos_req_dma,
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305721 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
5722
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305723 ret = msmsdcc_msm_bus_register(host);
5724 if (ret)
5725 goto pm_qos_remove;
5726
5727 if (host->msm_bus_vote.client_handle)
5728 INIT_DELAYED_WORK(&host->msm_bus_vote.vote_work,
5729 msmsdcc_msm_bus_work);
5730
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005731 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07005732 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005733 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07005734 goto clk_disable;
5735 }
5736
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005737
5738 /* Clocks has to be running before accessing SPS/DML HW blocks */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305739 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005740 /* Initialize SPS */
5741 ret = msmsdcc_sps_init(host);
5742 if (ret)
5743 goto vreg_deinit;
5744 /* Initialize DML */
5745 ret = msmsdcc_dml_init(host);
5746 if (ret)
5747 goto sps_exit;
5748 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05305749 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07005750
San Mehat9d2bd732009-09-22 16:44:22 -07005751 /*
5752 * Setup MMC host structure
5753 */
5754 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005755 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
5756 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005757 mmc->ocr_avail = plat->ocr_mask;
Sujit Reddy Thumma0e05f022012-06-11 19:44:18 +05305758 mmc->clkgate_delay = MSM_MMC_CLK_GATE_DELAY;
5759
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005760 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
5761 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07005762 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05305763 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
Asutosh Dasebd7d092012-07-09 19:08:26 +05305764 mmc->caps |= MMC_CAP_HW_RESET;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05305765 /*
5766 * If we send the CMD23 before multi block write/read command
5767 * then we need not to send CMD12 at the end of the transfer.
5768 * If we don't send the CMD12 then only way to detect the PROG_DONE
5769 * status is to use the AUTO_PROG_DONE status provided by SDCC4
5770 * controller. So let's enable the CMD23 for SDCC4 only.
5771 */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305772 if (!plat->disable_cmd23 && is_auto_prog_done(host))
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05305773 mmc->caps |= MMC_CAP_CMD23;
San Mehat9d2bd732009-09-22 16:44:22 -07005774
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005775 mmc->caps |= plat->uhs_caps;
Devin Kim9ccbff52012-07-16 20:55:14 -07005776 mmc->caps2 |= plat->uhs_caps2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005777 /*
5778 * XPC controls the maximum current in the default speed mode of SDXC
5779 * card. XPC=0 means 100mA (max.) but speed class is not supported.
5780 * XPC=1 means 150mA (max.) and speed class is supported.
5781 */
5782 if (plat->xpc_cap)
5783 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
5784 MMC_CAP_SET_XPC_180);
5785
Maya Erez231dd082012-11-28 23:55:57 +02005786
5787 /* packed write */
5788 mmc->caps2 |= plat->packed_write;
5789
Subhash Jadavani6bb34a82012-04-18 13:18:40 +05305790 mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
Yaniv Gardi14098552012-06-04 10:56:03 +03005791 mmc->caps2 |= MMC_CAP2_SANITIZE;
Maya Erezd0ed5ae2012-11-01 21:39:00 +02005792 mmc->caps2 |= MMC_CAP2_INIT_BKOPS;
Yaniv Gardi14098552012-06-04 10:56:03 +03005793
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005794 if (plat->nonremovable)
5795 mmc->caps |= MMC_CAP_NONREMOVABLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005796 mmc->caps |= MMC_CAP_SDIO_IRQ;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005797
5798 if (plat->is_sdio_al_client)
5799 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07005800
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305801 mmc->max_segs = msmsdcc_get_nr_sg(host);
5802 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
5803 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07005804
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305805 mmc->max_req_size = MMC_MAX_REQ_SIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07005806 mmc->max_seg_size = mmc->max_req_size;
5807
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005808 writel_relaxed(0, host->base + MMCIMASK0);
5809 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05305810 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005811
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005812 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
5813 mb();
5814 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07005815
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005816 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
5817 DRIVER_NAME " (cmd)", host);
5818 if (ret)
5819 goto dml_exit;
5820
5821 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
5822 DRIVER_NAME " (pio)", host);
5823 if (ret)
5824 goto irq_free;
5825
5826 /*
5827 * Enable SDCC IRQ only when host is powered on. Otherwise, this
5828 * IRQ is un-necessarily being monitored by MPM (Modem power
5829 * management block) during idle-power collapse. The MPM will be
5830 * configured to monitor the DATA1 GPIO line with level-low trigger
5831 * and thus depending on the GPIO status, it prevents TCXO shutdown
5832 * during idle-power collapse.
5833 */
5834 disable_irq(core_irqres->start);
5835 host->sdcc_irq_disabled = 1;
5836
5837 if (plat->sdiowakeup_irq) {
5838 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5839 mmc_hostname(mmc));
5840 ret = request_irq(plat->sdiowakeup_irq,
5841 msmsdcc_platform_sdiowakeup_irq,
5842 IRQF_SHARED | IRQF_TRIGGER_LOW,
5843 DRIVER_NAME "sdiowakeup", host);
5844 if (ret) {
5845 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
5846 plat->sdiowakeup_irq, ret);
5847 goto pio_irq_free;
5848 } else {
5849 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305850 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005851 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305852 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005853 }
5854 spin_unlock_irqrestore(&host->lock, flags);
5855 }
5856 }
5857
Subhash Jadavanic9b85752012-04-13 11:16:49 +05305858 if (host->plat->mpm_sdiowakeup_int) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005859 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5860 mmc_hostname(mmc));
5861 }
5862
5863 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
5864 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005865 /*
5866 * Setup card detect change
5867 */
5868
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305869 if (!plat->status_gpio)
5870 plat->status_gpio = -ENOENT;
5871 if (!plat->wpswitch_gpio)
5872 plat->wpswitch_gpio = -ENOENT;
5873
5874 if (plat->status || gpio_is_valid(plat->status_gpio)) {
Krishna Konda941604a2012-01-10 17:46:34 -08005875 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005876 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08005877 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005878 host->oldstat = msmsdcc_slot_status(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005879
Krishna Konda941604a2012-01-10 17:46:34 -08005880 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005881 }
San Mehat9d2bd732009-09-22 16:44:22 -07005882
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005883 if (plat->status_irq) {
5884 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07005885 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005886 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07005887 DRIVER_NAME " (slot)",
5888 host);
5889 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005890 pr_err("Unable to get slot IRQ %d (%d)\n",
5891 plat->status_irq, ret);
5892 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005893 }
5894 } else if (plat->register_status_notify) {
5895 plat->register_status_notify(msmsdcc_status_notify_cb, host);
5896 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005897 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07005898 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005899
5900 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005901
5902 ret = pm_runtime_set_active(&(pdev)->dev);
5903 if (ret < 0)
5904 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
5905 __func__, ret);
5906 /*
5907 * There is no notion of suspend/resume for SD/MMC/SDIO
5908 * cards. So host can be suspended/resumed with out
5909 * worrying about its children.
5910 */
5911 pm_suspend_ignore_children(&(pdev)->dev, true);
5912
5913 /*
5914 * MMC/SD/SDIO bus suspend/resume operations are defined
5915 * only for the slots that will be used for non-removable
5916 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
5917 * defined. Otherwise, they simply become card removal and
5918 * insertion events during suspend and resume respectively.
5919 * Hence, enable run-time PM only for slots for which bus
5920 * suspend/resume operations are defined.
5921 */
5922#ifdef CONFIG_MMC_UNSAFE_RESUME
5923 /*
5924 * If this capability is set, MMC core will enable/disable host
5925 * for every claim/release operation on a host. We use this
5926 * notification to increment/decrement runtime pm usage count.
5927 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005928 pm_runtime_enable(&(pdev)->dev);
5929#else
5930 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005931 pm_runtime_enable(&(pdev)->dev);
5932 }
5933#endif
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305934 host->idle_tout_ms = MSM_MMC_DEFAULT_IDLE_TIMEOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005935 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
5936 (unsigned long)host);
5937
San Mehat9d2bd732009-09-22 16:44:22 -07005938 mmc_add_host(mmc);
5939
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005940#ifdef CONFIG_HAS_EARLYSUSPEND
5941 host->early_suspend.suspend = msmsdcc_early_suspend;
5942 host->early_suspend.resume = msmsdcc_late_resume;
5943 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
5944 register_early_suspend(&host->early_suspend);
5945#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005946
Krishna Konda25786ec2011-07-25 16:21:36 -07005947 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
5948 " dmacrcri %d\n", mmc_hostname(mmc),
5949 (unsigned long long)core_memres->start,
5950 (unsigned int) core_irqres->start,
5951 (unsigned int) plat->status_irq, host->dma.channel,
5952 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005953
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305954 pr_info("%s: Controller capabilities: 0x%.8x\n",
5955 mmc_hostname(mmc), host->hw_caps);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005956 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
5957 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
5958 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
5959 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
5960 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
5961 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
5962 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
5963 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
5964 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
5965 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
5966 host->eject);
5967 pr_info("%s: Power save feature enable = %d\n",
5968 mmc_hostname(mmc), msmsdcc_pwrsave);
5969
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305970 if (is_dma_mode(host) && host->dma.channel != -1
Krishna Konda25786ec2011-07-25 16:21:36 -07005971 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005972 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005973 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005974 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005975 mmc_hostname(mmc), host->dma.cmd_busaddr,
5976 host->dma.cmdptr_busaddr);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305977 } else if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005978 pr_info("%s: SPS-BAM data transfer mode available\n",
5979 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005980 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005981 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005982
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005983#if defined(CONFIG_DEBUG_FS)
5984 msmsdcc_dbg_createhost(host);
5985#endif
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305986
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305987 host->max_bus_bw.show = show_sdcc_to_mem_max_bus_bw;
5988 host->max_bus_bw.store = store_sdcc_to_mem_max_bus_bw;
5989 sysfs_attr_init(&host->max_bus_bw.attr);
5990 host->max_bus_bw.attr.name = "max_bus_bw";
5991 host->max_bus_bw.attr.mode = S_IRUGO | S_IWUSR;
5992 ret = device_create_file(&pdev->dev, &host->max_bus_bw);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305993 if (ret)
5994 goto platform_irq_free;
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305995
5996 if (!plat->status_irq) {
5997 host->polling.show = show_polling;
5998 host->polling.store = store_polling;
5999 sysfs_attr_init(&host->polling.attr);
6000 host->polling.attr.name = "polling";
6001 host->polling.attr.mode = S_IRUGO | S_IWUSR;
6002 ret = device_create_file(&pdev->dev, &host->polling);
6003 if (ret)
6004 goto remove_max_bus_bw_file;
6005 }
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306006 host->idle_timeout.show = show_idle_timeout;
6007 host->idle_timeout.store = store_idle_timeout;
6008 sysfs_attr_init(&host->idle_timeout.attr);
6009 host->idle_timeout.attr.name = "idle_timeout";
6010 host->idle_timeout.attr.mode = S_IRUGO | S_IWUSR;
6011 ret = device_create_file(&pdev->dev, &host->idle_timeout);
6012 if (ret)
6013 goto remove_polling_file;
San Mehat9d2bd732009-09-22 16:44:22 -07006014 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006015
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306016 remove_polling_file:
6017 if (!plat->status_irq)
6018 device_remove_file(&pdev->dev, &host->polling);
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306019 remove_max_bus_bw_file:
6020 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006021 platform_irq_free:
6022 del_timer_sync(&host->req_tout_timer);
6023 pm_runtime_disable(&(pdev)->dev);
6024 pm_runtime_set_suspended(&(pdev)->dev);
6025
6026 if (plat->status_irq)
6027 free_irq(plat->status_irq, host);
6028 sdiowakeup_irq_free:
6029 wake_lock_destroy(&host->sdio_suspend_wlock);
6030 if (plat->sdiowakeup_irq)
6031 free_irq(plat->sdiowakeup_irq, host);
6032 pio_irq_free:
6033 if (plat->sdiowakeup_irq)
6034 wake_lock_destroy(&host->sdio_wlock);
6035 free_irq(core_irqres->start, host);
6036 irq_free:
6037 free_irq(core_irqres->start, host);
6038 dml_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306039 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006040 msmsdcc_dml_exit(host);
6041 sps_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306042 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006043 msmsdcc_sps_exit(host);
6044 vreg_deinit:
6045 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07006046 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006047 clk_disable(host->clk);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306048 msmsdcc_msm_bus_unregister(host);
6049 pm_qos_remove:
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006050 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306051 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07006052 clk_put:
6053 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006054 pclk_disable:
6055 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05306056 clk_disable_unprepare(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07006057 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006058 if (!IS_ERR(host->pclk))
6059 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05306060 if (!IS_ERR_OR_NULL(host->bus_clk))
6061 clk_disable_unprepare(host->bus_clk);
6062 bus_clk_put:
6063 if (!IS_ERR_OR_NULL(host->bus_clk))
6064 clk_put(host->bus_clk);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306065 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006066 if (host->dmares)
6067 dma_free_coherent(NULL,
6068 sizeof(struct msmsdcc_nc_dmadata),
6069 host->dma.nc, host->dma.nc_busaddr);
6070 }
6071 ioremap_free:
Sahitya Tummaladce7c752011-05-02 18:06:05 +05306072 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07006073 host_free:
6074 mmc_free_host(mmc);
6075 out:
6076 return ret;
6077}
6078
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006079static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07006080{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006081 struct mmc_host *mmc = mmc_get_drvdata(pdev);
6082 struct mmc_platform_data *plat;
6083 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07006084
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006085 if (!mmc)
6086 return -ENXIO;
6087
6088 if (pm_runtime_suspended(&(pdev)->dev))
6089 pm_runtime_resume(&(pdev)->dev);
6090
6091 host = mmc_priv(mmc);
6092
6093 DBG(host, "Removing SDCC device = %d\n", pdev->id);
6094 plat = host->plat;
6095
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306096 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006097 if (!plat->status_irq)
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306098 device_remove_file(&pdev->dev, &host->polling);
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306099 device_remove_file(&pdev->dev, &host->idle_timeout);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006100
6101 del_timer_sync(&host->req_tout_timer);
6102 tasklet_kill(&host->dma_tlet);
6103 tasklet_kill(&host->sps.tlet);
6104 mmc_remove_host(mmc);
6105
6106 if (plat->status_irq)
6107 free_irq(plat->status_irq, host);
6108
6109 wake_lock_destroy(&host->sdio_suspend_wlock);
6110 if (plat->sdiowakeup_irq) {
6111 wake_lock_destroy(&host->sdio_wlock);
6112 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
6113 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07006114 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006115
6116 free_irq(host->core_irqres->start, host);
6117 free_irq(host->core_irqres->start, host);
6118
6119 clk_put(host->clk);
6120 if (!IS_ERR(host->pclk))
6121 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05306122 if (!IS_ERR_OR_NULL(host->bus_clk))
6123 clk_put(host->bus_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006124
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006125 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306126 pm_qos_remove_request(&host->pm_qos_req_dma);
6127
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306128 if (host->msm_bus_vote.client_handle) {
6129 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
6130 msmsdcc_msm_bus_unregister(host);
6131 }
6132
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006133 msmsdcc_vreg_init(host, false);
6134
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306135 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006136 if (host->dmares)
6137 dma_free_coherent(NULL,
6138 sizeof(struct msmsdcc_nc_dmadata),
6139 host->dma.nc, host->dma.nc_busaddr);
6140 }
6141
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306142 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006143 msmsdcc_dml_exit(host);
6144 msmsdcc_sps_exit(host);
6145 }
6146
6147 iounmap(host->base);
6148 mmc_free_host(mmc);
6149
6150#ifdef CONFIG_HAS_EARLYSUSPEND
6151 unregister_early_suspend(&host->early_suspend);
6152#endif
6153 pm_runtime_disable(&(pdev)->dev);
6154 pm_runtime_set_suspended(&(pdev)->dev);
6155
6156 return 0;
6157}
6158
6159#ifdef CONFIG_MSM_SDIO_AL
6160int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
6161{
6162 struct msmsdcc_host *host = mmc_priv(mmc);
6163 unsigned long flags;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306164 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006165
Asutosh Dasf5298c32012-04-03 14:51:47 +05306166 mutex_lock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006167 spin_lock_irqsave(&host->lock, flags);
6168 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
6169 enable ? "En" : "Dis");
6170
6171 if (enable) {
6172 if (!host->sdcc_irq_disabled) {
6173 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05306174 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006175 host->sdcc_irq_disabled = 1;
6176 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306177 rc = msmsdcc_setup_clocks(host, false);
6178 if (rc)
6179 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006180
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05306181 if (host->plat->sdio_lpm_gpio_setup &&
6182 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006183 spin_unlock_irqrestore(&host->lock, flags);
6184 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
6185 spin_lock_irqsave(&host->lock, flags);
6186 host->sdio_gpio_lpm = 1;
6187 }
6188
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306189 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006190 msmsdcc_enable_irq_wake(host);
6191 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306192 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006193 }
6194 } else {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306195 rc = msmsdcc_setup_clocks(host, true);
6196 if (rc)
6197 goto out;
6198
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306199 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006200 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306201 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006202 msmsdcc_disable_irq_wake(host);
6203 }
6204
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05306205 if (host->plat->sdio_lpm_gpio_setup &&
6206 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006207 spin_unlock_irqrestore(&host->lock, flags);
6208 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
6209 spin_lock_irqsave(&host->lock, flags);
6210 host->sdio_gpio_lpm = 0;
6211 }
6212
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306213 if (host->sdcc_irq_disabled && atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006214 writel_relaxed(host->mci_irqenable,
6215 host->base + MMCIMASK0);
6216 mb();
6217 enable_irq(host->core_irqres->start);
6218 host->sdcc_irq_disabled = 0;
6219 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006220 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306221out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006222 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05306223 mutex_unlock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306224 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006225}
6226#else
6227int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
6228{
6229 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07006230}
6231#endif
6232
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006233#ifdef CONFIG_PM
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306234#ifdef CONFIG_MMC_CLKGATE
6235static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6236{
6237 struct mmc_host *mmc = host->mmc;
6238 unsigned long flags;
6239
6240 mmc_host_clk_hold(mmc);
6241 spin_lock_irqsave(&mmc->clk_lock, flags);
6242 mmc->clk_old = mmc->ios.clock;
6243 mmc->ios.clock = 0;
6244 mmc->clk_gated = true;
6245 spin_unlock_irqrestore(&mmc->clk_lock, flags);
6246 mmc_set_ios(mmc);
6247 mmc_host_clk_release(mmc);
6248}
6249
6250static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6251{
6252 struct mmc_host *mmc = host->mmc;
6253
6254 mmc_host_clk_hold(mmc);
6255 mmc->ios.clock = host->clk_rate;
6256 mmc_set_ios(mmc);
6257 mmc_host_clk_release(mmc);
6258}
6259#else
6260static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6261{
6262 struct mmc_host *mmc = host->mmc;
6263
6264 mmc->ios.clock = 0;
6265 mmc_set_ios(mmc);
6266}
6267
6268static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6269{
6270 struct mmc_host *mmc = host->mmc;
6271
6272 mmc->ios.clock = host->clk_rate;
6273 mmc_set_ios(mmc);
6274}
6275#endif
6276
San Mehat9d2bd732009-09-22 16:44:22 -07006277static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006278msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006279{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006280 struct mmc_host *mmc = dev_get_drvdata(dev);
6281 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006282 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306283 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07006284
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306285 if (host->plat->is_sdio_al_client) {
6286 rc = 0;
6287 goto out;
San Mehat9d2bd732009-09-22 16:44:22 -07006288 }
San Mehat9d2bd732009-09-22 16:44:22 -07006289
Sahitya Tummala7661a452011-07-18 13:28:35 +05306290 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006291 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006292 host->sdcc_suspending = 1;
6293 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07006294
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006295 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006296 * MMC core thinks that host is disabled by now since
6297 * runtime suspend is scheduled after msmsdcc_disable()
6298 * is called. Thus, MMC core will try to enable the host
6299 * while suspending it. This results in a synchronous
6300 * runtime resume request while in runtime suspending
6301 * context and hence inorder to complete this resume
6302 * requet, it will wait for suspend to be complete,
6303 * but runtime suspend also can not proceed further
6304 * until the host is resumed. Thus, it leads to a hang.
6305 * Hence, increase the pm usage count before suspending
6306 * the host so that any resume requests after this will
6307 * simple become pm usage counter increment operations.
6308 */
6309 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306310 /* If there is pending detect work abort runtime suspend */
6311 if (unlikely(work_busy(&mmc->detect.work)))
6312 rc = -EAGAIN;
6313 else
6314 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006315 pm_runtime_put_noidle(dev);
6316
6317 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306318 spin_lock_irqsave(&host->lock, flags);
6319 host->sdcc_suspended = true;
6320 spin_unlock_irqrestore(&host->lock, flags);
6321 if (mmc->card && mmc_card_sdio(mmc->card) &&
6322 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006323 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306324 * If SDIO function driver doesn't want
6325 * to power off the card, atleast turn off
6326 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006327 */
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306328 msmsdcc_gate_clock(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006329 }
6330 }
6331 host->sdcc_suspending = 0;
6332 mmc->suspend_task = NULL;
6333 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
6334 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006335 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306336 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306337out:
6338 /* set bus bandwidth to 0 immediately */
6339 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
San Mehat9d2bd732009-09-22 16:44:22 -07006340 return rc;
6341}
6342
6343static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006344msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006345{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006346 struct mmc_host *mmc = dev_get_drvdata(dev);
6347 struct msmsdcc_host *host = mmc_priv(mmc);
6348 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07006349
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006350 if (host->plat->is_sdio_al_client)
6351 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07006352
Sahitya Tummala7661a452011-07-18 13:28:35 +05306353 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006354 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306355 if (mmc->card && mmc_card_sdio(mmc->card) &&
6356 mmc_card_keep_power(mmc)) {
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306357 msmsdcc_ungate_clock(host);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05306358 }
San Mehat9d2bd732009-09-22 16:44:22 -07006359
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006360 mmc_resume_host(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006361
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006362 /*
6363 * FIXME: Clearing of flags must be handled in clients
6364 * resume handler.
6365 */
6366 spin_lock_irqsave(&host->lock, flags);
6367 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306368 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006369 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07006370
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006371 /*
6372 * After resuming the host wait for sometime so that
6373 * the SDIO work will be processed.
6374 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306375 if (mmc->card && mmc_card_sdio(mmc->card)) {
Subhash Jadavanic9b85752012-04-13 11:16:49 +05306376 if ((host->plat->mpm_sdiowakeup_int ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006377 host->plat->sdiowakeup_irq) &&
6378 wake_lock_active(&host->sdio_wlock))
6379 wake_lock_timeout(&host->sdio_wlock, 1);
6380 }
6381
6382 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006383 }
Subhash Jadavani1371d192012-08-16 18:46:57 +05306384 host->pending_resume = false;
Sahitya Tummala7661a452011-07-18 13:28:35 +05306385 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006386 return 0;
6387}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006388
6389static int msmsdcc_runtime_idle(struct device *dev)
6390{
6391 struct mmc_host *mmc = dev_get_drvdata(dev);
6392 struct msmsdcc_host *host = mmc_priv(mmc);
6393
6394 if (host->plat->is_sdio_al_client)
6395 return 0;
6396
6397 /* Idle timeout is not configurable for now */
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306398 pm_schedule_suspend(dev, host->idle_tout_ms);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006399
6400 return -EAGAIN;
6401}
6402
6403static int msmsdcc_pm_suspend(struct device *dev)
6404{
6405 struct mmc_host *mmc = dev_get_drvdata(dev);
6406 struct msmsdcc_host *host = mmc_priv(mmc);
6407 int rc = 0;
6408
6409 if (host->plat->is_sdio_al_client)
6410 return 0;
6411
6412
6413 if (host->plat->status_irq)
6414 disable_irq(host->plat->status_irq);
6415
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006416 if (!pm_runtime_suspended(dev))
6417 rc = msmsdcc_runtime_suspend(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006418
6419 return rc;
6420}
6421
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306422static int msmsdcc_suspend_noirq(struct device *dev)
6423{
6424 struct mmc_host *mmc = dev_get_drvdata(dev);
6425 struct msmsdcc_host *host = mmc_priv(mmc);
6426 int rc = 0;
6427
6428 /*
6429 * After platform suspend there may be active request
6430 * which might have enabled clocks. For example, in SDIO
6431 * case, ksdioirq thread might have scheduled after sdcc
6432 * suspend but before system freeze. In that case abort
6433 * suspend and retry instead of keeping the clocks on
6434 * during suspend and not allowing TCXO.
6435 */
6436
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306437 if (atomic_read(&host->clks_on) && !host->plat->is_sdio_al_client) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306438 pr_warn("%s: clocks are on after suspend, aborting system "
6439 "suspend\n", mmc_hostname(mmc));
6440 rc = -EAGAIN;
6441 }
6442
6443 return rc;
6444}
6445
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006446static int msmsdcc_pm_resume(struct device *dev)
6447{
6448 struct mmc_host *mmc = dev_get_drvdata(dev);
6449 struct msmsdcc_host *host = mmc_priv(mmc);
6450 int rc = 0;
6451
6452 if (host->plat->is_sdio_al_client)
6453 return 0;
6454
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006455 if (mmc->card && mmc_card_sdio(mmc->card))
Sahitya Tummalafb486372011-09-02 19:01:49 +05306456 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavani1371d192012-08-16 18:46:57 +05306457 /*
6458 * As runtime PM is enabled before calling the device's platform resume
6459 * callback, we use the pm_runtime_suspended API to know if SDCC is
6460 * really runtime suspended or not and set the pending_resume flag only
6461 * if its not runtime suspended.
6462 */
6463 else if (!pm_runtime_suspended(dev))
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006464 host->pending_resume = true;
6465
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006466 if (host->plat->status_irq) {
6467 msmsdcc_check_status((unsigned long)host);
6468 enable_irq(host->plat->status_irq);
6469 }
6470
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006471 return rc;
6472}
6473
Daniel Walker08ecfde2010-06-23 12:32:20 -07006474#else
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006475static int msmsdcc_runtime_suspend(struct device *dev)
6476{
6477 return 0;
6478}
6479static int msmsdcc_runtime_idle(struct device *dev)
6480{
6481 return 0;
6482}
6483static int msmsdcc_pm_suspend(struct device *dev)
6484{
6485 return 0;
6486}
6487static int msmsdcc_pm_resume(struct device *dev)
6488{
6489 return 0;
6490}
6491static int msmsdcc_suspend_noirq(struct device *dev)
6492{
6493 return 0;
6494}
6495static int msmsdcc_runtime_resume(struct device *dev)
6496{
6497 return 0;
6498}
Daniel Walker08ecfde2010-06-23 12:32:20 -07006499#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006500
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006501static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
6502 .runtime_suspend = msmsdcc_runtime_suspend,
6503 .runtime_resume = msmsdcc_runtime_resume,
6504 .runtime_idle = msmsdcc_runtime_idle,
6505 .suspend = msmsdcc_pm_suspend,
6506 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306507 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006508};
6509
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306510static const struct of_device_id msmsdcc_dt_match[] = {
6511 {.compatible = "qcom,msm-sdcc"},
6512
6513};
6514MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
6515
San Mehat9d2bd732009-09-22 16:44:22 -07006516static struct platform_driver msmsdcc_driver = {
6517 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006518 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07006519 .driver = {
6520 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006521 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306522 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07006523 },
6524};
6525
6526static int __init msmsdcc_init(void)
6527{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006528#if defined(CONFIG_DEBUG_FS)
6529 int ret = 0;
6530 ret = msmsdcc_dbg_init();
6531 if (ret) {
6532 pr_err("Failed to create debug fs dir \n");
6533 return ret;
6534 }
6535#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006536 return platform_driver_register(&msmsdcc_driver);
6537}
San Mehat9d2bd732009-09-22 16:44:22 -07006538
San Mehat9d2bd732009-09-22 16:44:22 -07006539static void __exit msmsdcc_exit(void)
6540{
6541 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006542
6543#if defined(CONFIG_DEBUG_FS)
6544 debugfs_remove(debugfs_file);
6545 debugfs_remove(debugfs_dir);
6546#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006547}
6548
6549module_init(msmsdcc_init);
6550module_exit(msmsdcc_exit);
6551
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006552MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07006553MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006554
6555#if defined(CONFIG_DEBUG_FS)
6556
6557static int
6558msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
6559{
6560 file->private_data = inode->i_private;
6561 return 0;
6562}
6563
6564static ssize_t
6565msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
6566 size_t count, loff_t *ppos)
6567{
6568 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08006569 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006570 int max, i;
6571
6572 i = 0;
6573 max = sizeof(buf) - 1;
6574
6575 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
6576 host->curr.cmd, host->curr.data);
6577 if (host->curr.cmd) {
6578 struct mmc_command *cmd = host->curr.cmd;
6579
6580 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
6581 cmd->opcode, cmd->arg, cmd->flags);
6582 }
6583 if (host->curr.data) {
6584 struct mmc_data *data = host->curr.data;
6585 i += scnprintf(buf + i, max - i,
6586 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
6587 data->timeout_ns, data->timeout_clks,
6588 data->blksz, data->blocks, data->error,
6589 data->flags);
6590 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
6591 host->curr.xfer_size, host->curr.xfer_remain,
6592 host->curr.data_xfered, host->dma.sg);
6593 }
6594
6595 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
6596}
6597
6598static const struct file_operations msmsdcc_dbg_state_ops = {
6599 .read = msmsdcc_dbg_state_read,
6600 .open = msmsdcc_dbg_state_open,
6601};
6602
6603static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
6604{
6605 if (debugfs_dir) {
6606 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
6607 0644, debugfs_dir, host,
6608 &msmsdcc_dbg_state_ops);
6609 }
6610}
6611
6612static int __init msmsdcc_dbg_init(void)
6613{
6614 int err;
6615
6616 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
6617 if (IS_ERR(debugfs_dir)) {
6618 err = PTR_ERR(debugfs_dir);
6619 debugfs_dir = NULL;
6620 return err;
6621 }
6622
6623 return 0;
6624}
6625#endif