blob: b5736858c63a7555fc79b0464d6803d279723fdc [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);
Sujit Reddy Thumma565c4312012-11-17 13:03:27 +0530460 msmsdcc_reset_and_restore(host);
461 host->pending_dpsm_reset = false;
462 goto out;
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530463 }
464 }
465 }
466
467 writel_relaxed(0, host->base + MMCIDATACTRL);
468 msmsdcc_sync_reg_wr(host); /* Allow the DPSM to be reset */
469 host->pending_dpsm_reset = false;
470out:
471 return;
472}
473
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700474static int
San Mehat9d2bd732009-09-22 16:44:22 -0700475msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
476{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700477 int retval = 0;
478
San Mehat9d2bd732009-09-22 16:44:22 -0700479 BUG_ON(host->curr.data);
480
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700481 del_timer(&host->req_tout_timer);
San Mehat9d2bd732009-09-22 16:44:22 -0700482
483 if (mrq->data)
484 mrq->data->bytes_xfered = host->curr.data_xfered;
485 if (mrq->cmd->error == -ETIMEDOUT)
486 mdelay(5);
487
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530488 msmsdcc_reset_dpsm(host);
489
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530490 /* Clear current request information as current request has ended */
491 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
492
San Mehat9d2bd732009-09-22 16:44:22 -0700493 /*
494 * Need to drop the host lock here; mmc_request_done may call
495 * back into the driver...
496 */
497 spin_unlock(&host->lock);
498 mmc_request_done(host->mmc, mrq);
499 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700500
501 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700502}
503
504static void
505msmsdcc_stop_data(struct msmsdcc_host *host)
506{
San Mehat9d2bd732009-09-22 16:44:22 -0700507 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530508 host->curr.got_dataend = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +0530509 host->curr.wait_for_auto_prog_done = false;
510 host->curr.got_auto_prog_done = false;
San Mehat9d2bd732009-09-22 16:44:22 -0700511}
512
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700513static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700514{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700515 return host->core_memres->start + MMCIFIFO;
516}
517
518static inline unsigned int msmsdcc_get_min_sup_clk_rate(
519 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530520
Subhash Jadavanidd432952012-03-28 11:25:56 +0530521static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700522{
523 mb();
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530524 if (!is_wait_for_reg_write(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +0530525 udelay(host->reg_write_delay);
526 else if (readl_relaxed(host->base + MCI_STATUS2) &
527 MCI_MCLK_REG_WR_ACTIVE) {
528 ktime_t start, diff;
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530529
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530530 start = ktime_get();
531 while (readl_relaxed(host->base + MCI_STATUS2) &
532 MCI_MCLK_REG_WR_ACTIVE) {
533 diff = ktime_sub(ktime_get(), start);
534 /* poll for max. 1 ms */
535 if (ktime_to_us(diff) > 1000) {
536 pr_warning("%s: previous reg. write is"
537 " still active\n",
538 mmc_hostname(host->mmc));
539 break;
540 }
541 }
542 }
San Mehat9d2bd732009-09-22 16:44:22 -0700543}
544
Subhash Jadavanidd432952012-03-28 11:25:56 +0530545static inline void msmsdcc_delay(struct msmsdcc_host *host)
546{
547 udelay(host->reg_write_delay);
548
San Mehat9d2bd732009-09-22 16:44:22 -0700549}
550
San Mehat56a8b5b2009-11-21 12:29:46 -0800551static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700552msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
553{
554 writel_relaxed(arg, host->base + MMCIARGUMENT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700555 writel_relaxed(c, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530556 /*
557 * As after sending the command, we don't write any of the
558 * controller registers and just wait for the
559 * CMD_RESPOND_END/CMD_SENT/Command failure notication
560 * from Controller.
561 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700562 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800563}
564
565static void
566msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
567{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700568 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800569
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700570 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
571 writel_relaxed((unsigned int)host->curr.xfer_size,
572 host->base + MMCIDATALENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700573 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530574 msmsdcc_sync_reg_wr(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800575
San Mehat6ac9ea62009-12-02 17:24:58 -0800576 if (host->cmd_cmd) {
577 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700578 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800579 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800580}
581
San Mehat9d2bd732009-09-22 16:44:22 -0700582static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530583msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700584{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530585 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700586 unsigned long flags;
587 struct mmc_request *mrq;
588
589 spin_lock_irqsave(&host->lock, flags);
590 mrq = host->curr.mrq;
591 BUG_ON(!mrq);
592
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530593 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700594 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700595 goto out;
596 }
597
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530598 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700599 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700600 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700601 } else {
602 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530603 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700604 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530605 mmc_hostname(host->mmc), host->dma.result);
606 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700607 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530608 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530609 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700610 host->dma.err.flush[0], host->dma.err.flush[1],
611 host->dma.err.flush[2], host->dma.err.flush[3],
612 host->dma.err.flush[4],
613 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530614 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700615 if (!mrq->data->error)
616 mrq->data->error = -EIO;
617 }
Asutosh Dasaccacd42012-03-08 14:33:17 +0530618 if (!mrq->data->host_cookie)
619 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
620 host->dma.num_ents, host->dma.dir);
San Mehat9d2bd732009-09-22 16:44:22 -0700621
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700622 if (host->curr.user_pages) {
623 struct scatterlist *sg = host->dma.sg;
624 int i;
625
626 for (i = 0; i < host->dma.num_ents; i++, sg++)
627 flush_dcache_page(sg_page(sg));
628 }
San Mehat9d2bd732009-09-22 16:44:22 -0700629
San Mehat9d2bd732009-09-22 16:44:22 -0700630 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800631 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700632
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530633 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
634 (host->curr.wait_for_auto_prog_done &&
635 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700636 /*
637 * If we've already gotten our DATAEND / DATABLKEND
638 * for this request, then complete it through here.
639 */
San Mehat9d2bd732009-09-22 16:44:22 -0700640
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700641 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700642 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700643 host->curr.xfer_remain -= host->curr.xfer_size;
644 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700645 if (host->dummy_52_needed) {
San Mehat9d2bd732009-09-22 16:44:22 -0700646 mrq->data->bytes_xfered = host->curr.data_xfered;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700647 host->dummy_52_sent = 1;
648 msmsdcc_start_command(host, &dummy52cmd,
649 MCI_CPSM_PROGENA);
650 goto out;
651 }
652 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530653 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530654 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700655 mrq->data->bytes_xfered = host->curr.data_xfered;
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530656 msmsdcc_reset_dpsm(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700657 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530658 /*
659 * Clear current request information as current
660 * request has ended
661 */
662 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
San Mehat9d2bd732009-09-22 16:44:22 -0700663 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700664
San Mehat9d2bd732009-09-22 16:44:22 -0700665 mmc_request_done(host->mmc, mrq);
666 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530667 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
668 || !mrq->sbc)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700669 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530670 }
San Mehat9d2bd732009-09-22 16:44:22 -0700671 }
672
673out:
674 spin_unlock_irqrestore(&host->lock, flags);
675 return;
676}
677
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700678#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
679/**
680 * Callback notification from SPS driver
681 *
682 * This callback function gets triggered called from
683 * SPS driver when requested SPS data transfer is
684 * completed.
685 *
686 * SPS driver invokes this callback in BAM irq context so
687 * SDCC driver schedule a tasklet for further processing
688 * this callback notification at later point of time in
689 * tasklet context and immediately returns control back
690 * to SPS driver.
691 *
692 * @nofity - Pointer to sps event notify sturcture
693 *
694 */
695static void
696msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
697{
698 struct msmsdcc_host *host =
699 (struct msmsdcc_host *)
700 ((struct sps_event_notify *)notify)->user;
701
702 host->sps.notify = *notify;
703 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
704 mmc_hostname(host->mmc), __func__, notify->event_id,
705 notify->data.transfer.iovec.addr,
706 notify->data.transfer.iovec.size,
707 notify->data.transfer.iovec.flags);
708 /* Schedule a tasklet for completing data transfer */
709 tasklet_schedule(&host->sps.tlet);
710}
711
712/**
713 * Tasklet handler for processing SPS callback event
714 *
715 * This function processing SPS event notification and
716 * checks if the SPS transfer is completed or not and
717 * then accordingly notifies status to MMC core layer.
718 *
719 * This function is called in tasklet context.
720 *
721 * @data - Pointer to sdcc driver data
722 *
723 */
724static void msmsdcc_sps_complete_tlet(unsigned long data)
725{
726 unsigned long flags;
727 int i, rc;
728 u32 data_xfered = 0;
729 struct mmc_request *mrq;
730 struct sps_iovec iovec;
731 struct sps_pipe *sps_pipe_handle;
732 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
733 struct sps_event_notify *notify = &host->sps.notify;
734
735 spin_lock_irqsave(&host->lock, flags);
736 if (host->sps.dir == DMA_FROM_DEVICE)
737 sps_pipe_handle = host->sps.prod.pipe_handle;
738 else
739 sps_pipe_handle = host->sps.cons.pipe_handle;
740 mrq = host->curr.mrq;
741
742 if (!mrq) {
743 spin_unlock_irqrestore(&host->lock, flags);
744 return;
745 }
746
747 pr_debug("%s: %s: sps event_id=%d\n",
748 mmc_hostname(host->mmc), __func__,
749 notify->event_id);
750
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700751 /*
752 * Got End of transfer event!!! Check if all of the data
753 * has been transferred?
754 */
755 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
756 rc = sps_get_iovec(sps_pipe_handle, &iovec);
757 if (rc) {
758 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
759 mmc_hostname(host->mmc), __func__, rc, i);
760 break;
761 }
762 data_xfered += iovec.size;
763 }
764
765 if (data_xfered == host->curr.xfer_size) {
766 host->curr.data_xfered = host->curr.xfer_size;
767 host->curr.xfer_remain -= host->curr.xfer_size;
768 pr_debug("%s: Data xfer success. data_xfered=0x%x",
769 mmc_hostname(host->mmc),
770 host->curr.xfer_size);
771 } else {
772 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
773 " xfer_size=%d", mmc_hostname(host->mmc),
774 data_xfered, host->curr.xfer_size);
775 msmsdcc_reset_and_restore(host);
776 if (!mrq->data->error)
777 mrq->data->error = -EIO;
778 }
779
780 /* Unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +0530781 if (!mrq->data->host_cookie)
782 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
783 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700784 host->sps.sg = NULL;
785 host->sps.busy = 0;
786
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530787 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
788 (host->curr.wait_for_auto_prog_done &&
789 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700790 /*
791 * If we've already gotten our DATAEND / DATABLKEND
792 * for this request, then complete it through here.
793 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700794
795 if (!mrq->data->error) {
796 host->curr.data_xfered = host->curr.xfer_size;
797 host->curr.xfer_remain -= host->curr.xfer_size;
798 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700799 if (host->dummy_52_needed) {
800 mrq->data->bytes_xfered = host->curr.data_xfered;
801 host->dummy_52_sent = 1;
802 msmsdcc_start_command(host, &dummy52cmd,
803 MCI_CPSM_PROGENA);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700804 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700805 return;
806 }
807 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530808 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530809 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700810 mrq->data->bytes_xfered = host->curr.data_xfered;
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530811 msmsdcc_reset_dpsm(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700812 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530813 /*
814 * Clear current request information as current
815 * request has ended
816 */
817 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700818 spin_unlock_irqrestore(&host->lock, flags);
819
820 mmc_request_done(host->mmc, mrq);
821 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530822 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
823 || !mrq->sbc)) {
824 msmsdcc_start_command(host, mrq->data->stop, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700825 }
826 }
827 spin_unlock_irqrestore(&host->lock, flags);
828}
829
830/**
831 * Exit from current SPS data transfer
832 *
833 * This function exits from current SPS data transfer.
834 *
835 * This function should be called when error condition
836 * is encountered during data transfer.
837 *
838 * @host - Pointer to sdcc host structure
839 *
840 */
841static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
842{
843 struct mmc_request *mrq;
844
845 mrq = host->curr.mrq;
846 BUG_ON(!mrq);
847
848 msmsdcc_reset_and_restore(host);
849 if (!mrq->data->error)
850 mrq->data->error = -EIO;
851
852 /* Unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +0530853 if (!mrq->data->host_cookie)
854 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
855 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700856
857 host->sps.sg = NULL;
858 host->sps.busy = 0;
859 if (host->curr.data)
860 msmsdcc_stop_data(host);
861
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530862 if (!mrq->data->stop || mrq->cmd->error ||
863 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700864 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530865 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
866 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700867 msmsdcc_start_command(host, mrq->data->stop, 0);
868
869}
870#else
871static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
872static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
873static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
874#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
875
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530876static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700877
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530878static void
879msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
880 unsigned int result,
881 struct msm_dmov_errdata *err)
882{
883 struct msmsdcc_dma_data *dma_data =
884 container_of(cmd, struct msmsdcc_dma_data, hdr);
885 struct msmsdcc_host *host = dma_data->host;
886
887 dma_data->result = result;
888 if (err)
889 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
890
891 tasklet_schedule(&host->dma_tlet);
892}
893
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530894static bool msmsdcc_is_dma_possible(struct msmsdcc_host *host,
895 struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700896{
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530897 bool ret = true;
898 u32 xfer_size = data->blksz * data->blocks;
San Mehat9d2bd732009-09-22 16:44:22 -0700899
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530900 if (is_sps_mode(host)) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530901 /*
902 * BAM Mode: Fall back on PIO if size is less
903 * than or equal to SPS_MIN_XFER_SIZE bytes.
904 */
905 if (xfer_size <= SPS_MIN_XFER_SIZE)
906 ret = false;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530907 } else if (is_dma_mode(host)) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530908 /*
909 * ADM Mode: Fall back on PIO if size is less than FIFO size
910 * or not integer multiple of FIFO size
911 */
912 if (xfer_size % MCI_FIFOSIZE)
913 ret = false;
914 } else {
915 /* PIO Mode */
916 ret = false;
917 }
918
919 return ret;
San Mehat9d2bd732009-09-22 16:44:22 -0700920}
921
922static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
923{
924 struct msmsdcc_nc_dmadata *nc;
925 dmov_box *box;
926 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700927 unsigned int n;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530928 int i, err = 0, box_cmd_cnt = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700929 struct scatterlist *sg = data->sg;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530930 unsigned int len, offset;
San Mehat9d2bd732009-09-22 16:44:22 -0700931
Krishna Konda25786ec2011-07-25 16:21:36 -0700932 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700933 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700934
Krishna Konda25786ec2011-07-25 16:21:36 -0700935 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
San Mehat9d2bd732009-09-22 16:44:22 -0700936
937 host->dma.sg = data->sg;
938 host->dma.num_ents = data->sg_len;
939
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530940 /* Prevent memory corruption */
941 BUG_ON(host->dma.num_ents > msmsdcc_get_nr_sg(host));
San Mehat56a8b5b2009-11-21 12:29:46 -0800942
San Mehat9d2bd732009-09-22 16:44:22 -0700943 nc = host->dma.nc;
944
San Mehat9d2bd732009-09-22 16:44:22 -0700945 if (data->flags & MMC_DATA_READ)
946 host->dma.dir = DMA_FROM_DEVICE;
947 else
948 host->dma.dir = DMA_TO_DEVICE;
949
Asutosh Dasaccacd42012-03-08 14:33:17 +0530950 if (!data->host_cookie) {
951 n = msmsdcc_prep_xfer(host, data);
952 if (unlikely(n < 0)) {
953 host->dma.sg = NULL;
954 host->dma.num_ents = 0;
955 return -ENOMEM;
956 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800957 }
San Mehat9d2bd732009-09-22 16:44:22 -0700958
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530959 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
960 host->curr.user_pages = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700961 box = &nc->cmd[0];
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530962 for (i = 0; i < host->dma.num_ents; i++) {
963 len = sg_dma_len(sg);
964 offset = 0;
965
966 do {
967 /* Check if we can do DMA */
968 if (!len || (box_cmd_cnt >= MMC_MAX_DMA_CMDS)) {
969 err = -ENOTSUPP;
970 goto unmap;
971 }
972
973 box->cmd = CMD_MODE_BOX;
974
975 if (len >= MMC_MAX_DMA_BOX_LENGTH) {
976 len = MMC_MAX_DMA_BOX_LENGTH;
977 len -= len % data->blksz;
978 }
979 rows = (len % MCI_FIFOSIZE) ?
980 (len / MCI_FIFOSIZE) + 1 :
981 (len / MCI_FIFOSIZE);
982
983 if (data->flags & MMC_DATA_READ) {
984 box->src_row_addr = msmsdcc_fifo_addr(host);
985 box->dst_row_addr = sg_dma_address(sg) + offset;
986 box->src_dst_len = (MCI_FIFOSIZE << 16) |
987 (MCI_FIFOSIZE);
988 box->row_offset = MCI_FIFOSIZE;
989 box->num_rows = rows * ((1 << 16) + 1);
990 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
991 } else {
992 box->src_row_addr = sg_dma_address(sg) + offset;
993 box->dst_row_addr = msmsdcc_fifo_addr(host);
994 box->src_dst_len = (MCI_FIFOSIZE << 16) |
995 (MCI_FIFOSIZE);
996 box->row_offset = (MCI_FIFOSIZE << 16);
997 box->num_rows = rows * ((1 << 16) + 1);
998 box->cmd |= CMD_DST_CRCI(host->dma.crci);
999 }
1000
1001 offset += len;
1002 len = sg_dma_len(sg) - offset;
1003 box++;
1004 box_cmd_cnt++;
1005 } while (len);
1006 sg++;
1007 }
1008 /* Mark last command */
1009 box--;
1010 box->cmd |= CMD_LC;
San Mehat9d2bd732009-09-22 16:44:22 -07001011
1012 /* location of command block must be 64 bit aligned */
1013 BUG_ON(host->dma.cmd_busaddr & 0x07);
1014
1015 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
1016 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
1017 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
1018 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
1019
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05301020 /* Flush all data to memory before starting dma */
1021 mb();
1022
1023unmap:
1024 if (err) {
Asutosh Dasaccacd42012-03-08 14:33:17 +05301025 if (!data->host_cookie)
1026 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
1027 host->dma.num_ents, host->dma.dir);
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05301028 pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
1029 mmc_hostname(host->mmc), err);
San Mehat9d2bd732009-09-22 16:44:22 -07001030 }
1031
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05301032 return err;
San Mehat9d2bd732009-09-22 16:44:22 -07001033}
1034
Asutosh Dasaccacd42012-03-08 14:33:17 +05301035static int msmsdcc_prep_xfer(struct msmsdcc_host *host,
1036 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -08001037{
Asutosh Dasaccacd42012-03-08 14:33:17 +05301038 int rc = 0;
1039 unsigned int dir;
1040
1041 /* Prevent memory corruption */
1042 BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
1043
1044 if (data->flags & MMC_DATA_READ)
1045 dir = DMA_FROM_DEVICE;
1046 else
1047 dir = DMA_TO_DEVICE;
1048
1049 /* Make sg buffers DMA ready */
1050 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
1051 dir);
1052
1053 if (unlikely(rc != data->sg_len)) {
1054 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
1055 mmc_hostname(host->mmc), rc);
1056 rc = -ENOMEM;
1057 goto dma_map_err;
1058 }
1059
1060 pr_debug("%s: %s: %s: sg_len=%d\n",
1061 mmc_hostname(host->mmc), __func__,
1062 dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
1063 data->sg_len);
1064
1065 goto out;
1066
1067dma_map_err:
1068 dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
1069 data->flags);
1070out:
1071 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07001072}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001073#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
1074/**
1075 * Submits data transfer request to SPS driver
1076 *
1077 * This function make sg (scatter gather) data buffers
1078 * DMA ready and then submits them to SPS driver for
1079 * transfer.
1080 *
1081 * @host - Pointer to sdcc host structure
1082 * @data - Pointer to mmc_data structure
1083 *
1084 * @return 0 if success else negative value
1085 */
1086static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
Asutosh Dasaccacd42012-03-08 14:33:17 +05301087 struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -07001088{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001089 int rc = 0;
1090 u32 flags;
1091 int i;
1092 u32 addr, len, data_cnt;
1093 struct scatterlist *sg = data->sg;
1094 struct sps_pipe *sps_pipe_handle;
1095
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001096 host->sps.sg = data->sg;
1097 host->sps.num_ents = data->sg_len;
1098 host->sps.xfer_req_cnt = 0;
1099 if (data->flags & MMC_DATA_READ) {
1100 host->sps.dir = DMA_FROM_DEVICE;
1101 sps_pipe_handle = host->sps.prod.pipe_handle;
1102 } else {
1103 host->sps.dir = DMA_TO_DEVICE;
1104 sps_pipe_handle = host->sps.cons.pipe_handle;
1105 }
1106
Asutosh Dasaccacd42012-03-08 14:33:17 +05301107 if (!data->host_cookie) {
1108 rc = msmsdcc_prep_xfer(host, data);
1109 if (unlikely(rc < 0)) {
1110 host->dma.sg = NULL;
1111 host->dma.num_ents = 0;
1112 goto out;
1113 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001114 }
1115
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001116 for (i = 0; i < data->sg_len; i++) {
1117 /*
1118 * Check if this is the last buffer to transfer?
1119 * If yes then set the INT and EOT flags.
1120 */
1121 len = sg_dma_len(sg);
1122 addr = sg_dma_address(sg);
1123 flags = 0;
1124 while (len > 0) {
1125 if (len > SPS_MAX_DESC_SIZE) {
1126 data_cnt = SPS_MAX_DESC_SIZE;
1127 } else {
1128 data_cnt = len;
1129 if (i == data->sg_len - 1)
1130 flags = SPS_IOVEC_FLAG_INT |
1131 SPS_IOVEC_FLAG_EOT;
1132 }
1133 rc = sps_transfer_one(sps_pipe_handle, addr,
1134 data_cnt, host, flags);
1135 if (rc) {
1136 pr_err("%s: sps_transfer_one() error! rc=%d,"
1137 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
1138 mmc_hostname(host->mmc), rc,
1139 (u32)sps_pipe_handle, (u32)sg, i);
1140 goto dma_map_err;
1141 }
1142 addr += data_cnt;
1143 len -= data_cnt;
1144 host->sps.xfer_req_cnt++;
1145 }
1146 sg++;
1147 }
1148 goto out;
1149
1150dma_map_err:
1151 /* unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +05301152 if (!data->host_cookie)
1153 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
1154 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001155out:
1156 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07001157}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001158#else
1159static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
1160 struct mmc_data *data) { return 0; }
1161#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -07001162
1163static void
San Mehat56a8b5b2009-11-21 12:29:46 -08001164msmsdcc_start_command_deferred(struct msmsdcc_host *host,
1165 struct mmc_command *cmd, u32 *c)
1166{
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301167 DBG(host, "op %02x arg %08x flags %08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001168 cmd->opcode, cmd->arg, cmd->flags);
1169
San Mehat56a8b5b2009-11-21 12:29:46 -08001170 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
1171
1172 if (cmd->flags & MMC_RSP_PRESENT) {
1173 if (cmd->flags & MMC_RSP_136)
1174 *c |= MCI_CPSM_LONGRSP;
1175 *c |= MCI_CPSM_RESPONSE;
1176 }
1177
1178 if (/*interrupt*/0)
1179 *c |= MCI_CPSM_INTERRUPT;
1180
Asutosh Das05049132012-05-09 12:38:15 +05301181 /* DAT_CMD bit should be set for all ADTC */
1182 if (mmc_cmd_type(cmd) == MMC_CMD_ADTC)
San Mehat56a8b5b2009-11-21 12:29:46 -08001183 *c |= MCI_CSPM_DATCMD;
1184
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001185 /* Check if AUTO CMD19 is required or not? */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301186 if (host->tuning_needed &&
1187 !(host->mmc->ios.timing == MMC_TIMING_MMC_HS200)) {
1188
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301189 /*
1190 * For open ended block read operation (without CMD23),
1191 * AUTO_CMD19 bit should be set while sending the READ command.
1192 * For close ended block read operation (with CMD23),
1193 * AUTO_CMD19 bit should be set while sending CMD23.
1194 */
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301195 if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
1196 host->curr.mrq->cmd->opcode ==
1197 MMC_READ_MULTIPLE_BLOCK) ||
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301198 (!host->curr.mrq->sbc &&
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301199 (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
1200 cmd->opcode == MMC_READ_MULTIPLE_BLOCK))) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301201 msmsdcc_enable_cdr_cm_sdc4_dll(host);
1202 *c |= MCI_CSPM_AUTO_CMD19;
1203 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001204 }
1205
Subhash Jadavanif97d2992012-07-13 14:47:47 +05301206 if (cmd->mrq->data && (cmd->mrq->data->flags & MMC_DATA_READ))
1207 writel_relaxed((readl_relaxed(host->base +
1208 MCI_DLL_CONFIG) | MCI_CDR_EN),
1209 host->base + MCI_DLL_CONFIG);
1210 else
1211 /* Clear CDR_EN bit for non read operations */
1212 writel_relaxed((readl_relaxed(host->base +
1213 MCI_DLL_CONFIG) & ~MCI_CDR_EN),
1214 host->base + MCI_DLL_CONFIG);
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05301215
Sujit Reddy Thumma02868752012-06-25 17:22:56 +05301216 if (((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) ||
1217 (cmd->opcode == MMC_SEND_STATUS &&
1218 !(cmd->flags & MMC_CMD_ADTC))) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301219 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001220 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301221 }
1222
San Mehat56a8b5b2009-11-21 12:29:46 -08001223 if (cmd == cmd->mrq->stop)
1224 *c |= MCI_CSPM_MCIABORT;
1225
San Mehat56a8b5b2009-11-21 12:29:46 -08001226 if (host->curr.cmd != NULL) {
Girish K Sa3c76eb2011-10-11 11:44:09 +05301227 pr_err("%s: Overlapping command requests\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001228 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -08001229 }
1230 host->curr.cmd = cmd;
1231}
1232
1233static void
1234msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1235 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001236{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301237 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001238 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001239 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001240 unsigned int pio_irqmask = 0;
1241
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301242 BUG_ON(!data->sg);
1243 BUG_ON(!data->sg_len);
1244
San Mehat9d2bd732009-09-22 16:44:22 -07001245 host->curr.data = data;
1246 host->curr.xfer_size = data->blksz * data->blocks;
1247 host->curr.xfer_remain = host->curr.xfer_size;
1248 host->curr.data_xfered = 0;
1249 host->curr.got_dataend = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301250 host->curr.got_auto_prog_done = false;
San Mehat9d2bd732009-09-22 16:44:22 -07001251
San Mehat9d2bd732009-09-22 16:44:22 -07001252 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1253
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301254 if (host->curr.wait_for_auto_prog_done)
1255 datactrl |= MCI_AUTO_PROG_DONE;
San Mehat9d2bd732009-09-22 16:44:22 -07001256
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05301257 if (msmsdcc_is_dma_possible(host, data)) {
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301258 if (is_dma_mode(host) && !msmsdcc_config_dma(host, data)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001259 datactrl |= MCI_DPSM_DMAENABLE;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301260 } else if (is_sps_mode(host)) {
Krishna Kondad337ddd2012-08-19 11:16:39 -07001261 if (!msmsdcc_sps_start_xfer(host, data)) {
1262 /* Now kick start DML transfer */
1263 mb();
1264 msmsdcc_dml_start_xfer(host, data);
1265 datactrl |= MCI_DPSM_DMAENABLE;
1266 host->sps.busy = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001267 }
1268 }
1269 }
1270
1271 /* Is data transfer in PIO mode required? */
1272 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001273 if (data->flags & MMC_DATA_READ) {
1274 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1275 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1276 pio_irqmask |= MCI_RXDATAAVLBLMASK;
1277 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001278 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1279 MCI_TXFIFOEMPTYMASK;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001280
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001281 msmsdcc_sg_start(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001282 }
1283
1284 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301285 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
Subhash Jadavanif5277752011-10-12 16:47:52 +05301286 else if (host->curr.use_wr_data_pend)
1287 datactrl |= MCI_DATA_PEND;
San Mehat9d2bd732009-09-22 16:44:22 -07001288
San Mehat56a8b5b2009-11-21 12:29:46 -08001289 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001290 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001291 timeout = data->timeout_clks + (unsigned int)clks*2 ;
Subhash Jadavani63540362012-06-12 14:56:04 +05301292 WARN(!timeout,
1293 "%s: data timeout is zero. timeout_ns=0x%x, timeout_clks=0x%x\n",
1294 mmc_hostname(host->mmc), data->timeout_ns, data->timeout_clks);
San Mehat9d2bd732009-09-22 16:44:22 -07001295
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301296 if (is_dma_mode(host) && (datactrl & MCI_DPSM_DMAENABLE)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001297 /* Use ADM (Application Data Mover) HW for Data transfer */
1298 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001299 host->cmd_timeout = timeout;
1300 host->cmd_pio_irqmask = pio_irqmask;
1301 host->cmd_datactrl = datactrl;
1302 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001303
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001304 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1305 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001306 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001307
1308 if (cmd) {
1309 msmsdcc_start_command_deferred(host, cmd, &c);
1310 host->cmd_c = c;
1311 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001312 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1313 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1314 host->base + MMCIMASK0);
1315 mb();
1316 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001317 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001318 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001319 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001320
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001321 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001322
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001323 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1324 (~(MCI_IRQ_PIO))) | pio_irqmask,
1325 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001326 writel_relaxed(datactrl, base + MMCIDATACTRL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001327
1328 if (cmd) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05301329 /* Delay between data/command */
1330 msmsdcc_sync_reg_wr(host);
San Mehat56a8b5b2009-11-21 12:29:46 -08001331 /* Daisy-chain the command if requested */
1332 msmsdcc_start_command(host, cmd, c);
Subhash Jadavanidd432952012-03-28 11:25:56 +05301333 } else {
1334 /*
1335 * We don't need delay after writing to DATA_CTRL
1336 * register if we are not writing to CMD register
1337 * immediately after this. As we already have delay
1338 * before sending the command, we just need mb() here.
1339 */
1340 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001341 }
San Mehat9d2bd732009-09-22 16:44:22 -07001342 }
1343}
1344
1345static void
1346msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1347{
San Mehat56a8b5b2009-11-21 12:29:46 -08001348 msmsdcc_start_command_deferred(host, cmd, &c);
1349 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001350}
1351
1352static void
1353msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1354 unsigned int status)
1355{
1356 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001357 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
Subhash Jadavanib30c9822012-03-27 18:03:16 +05301358 || data->mrq->cmd->opcode == MMC_BUS_TEST_R
1359 || data->mrq->cmd->opcode ==
1360 MMC_SEND_TUNING_BLOCK_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001361 pr_err("%s: Data CRC error\n",
1362 mmc_hostname(host->mmc));
1363 pr_err("%s: opcode 0x%.8x\n", __func__,
1364 data->mrq->cmd->opcode);
1365 pr_err("%s: blksz %d, blocks %d\n", __func__,
1366 data->blksz, data->blocks);
1367 data->error = -EILSEQ;
1368 }
San Mehat9d2bd732009-09-22 16:44:22 -07001369 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001370 /* CRC is optional for the bus test commands, not all
1371 * cards respond back with CRC. However controller
1372 * waits for the CRC and times out. Hence ignore the
1373 * data timeouts during the Bustest.
1374 */
1375 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1376 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301377 pr_err("%s: CMD%d: Data timeout\n",
1378 mmc_hostname(host->mmc),
1379 data->mrq->cmd->opcode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001380 data->error = -ETIMEDOUT;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301381 msmsdcc_dump_sdcc_state(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001382 }
San Mehat9d2bd732009-09-22 16:44:22 -07001383 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001384 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001385 data->error = -EIO;
1386 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001387 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001388 data->error = -EIO;
1389 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001390 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001391 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001392 data->error = -EIO;
1393 }
San Mehat9d2bd732009-09-22 16:44:22 -07001394
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001395 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001396 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001397 host->dummy_52_needed = 0;
1398}
San Mehat9d2bd732009-09-22 16:44:22 -07001399
1400static int
1401msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1402{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001403 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001404 uint32_t *ptr = (uint32_t *) buffer;
1405 int count = 0;
1406
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301407 if (remain % 4)
1408 remain = ((remain >> 2) + 1) << 2;
1409
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001410 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1411
1412 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001413 ptr++;
1414 count += sizeof(uint32_t);
1415
1416 remain -= sizeof(uint32_t);
1417 if (remain == 0)
1418 break;
1419 }
1420 return count;
1421}
1422
1423static int
1424msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001425 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001426{
1427 void __iomem *base = host->base;
1428 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001429 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001430
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001431 while (readl_relaxed(base + MMCISTATUS) &
1432 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1433 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001434
San Mehat9d2bd732009-09-22 16:44:22 -07001435 count = min(remain, maxcnt);
1436
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301437 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1438 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001439 ptr += count;
1440 remain -= count;
1441
1442 if (remain == 0)
1443 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001444 }
1445 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001446
1447 return ptr - buffer;
1448}
1449
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001450/*
1451 * Copy up to a word (4 bytes) between a scatterlist
1452 * and a temporary bounce buffer when the word lies across
1453 * two pages. The temporary buffer can then be read to/
1454 * written from the FIFO once.
1455 */
1456static void _msmsdcc_sg_consume_word(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -07001457{
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001458 struct msmsdcc_pio_data *pio = &host->pio;
1459 unsigned int bytes_avail;
1460
1461 if (host->curr.data->flags & MMC_DATA_READ)
1462 memcpy(pio->sg_miter.addr, pio->bounce_buf,
1463 pio->bounce_buf_len);
1464 else
1465 memcpy(pio->bounce_buf, pio->sg_miter.addr,
1466 pio->bounce_buf_len);
1467
1468 while (pio->bounce_buf_len != 4) {
1469 if (!sg_miter_next(&pio->sg_miter))
1470 break;
1471 bytes_avail = min_t(unsigned int, pio->sg_miter.length,
1472 4 - pio->bounce_buf_len);
1473 if (host->curr.data->flags & MMC_DATA_READ)
1474 memcpy(pio->sg_miter.addr,
1475 &pio->bounce_buf[pio->bounce_buf_len],
1476 bytes_avail);
1477 else
1478 memcpy(&pio->bounce_buf[pio->bounce_buf_len],
1479 pio->sg_miter.addr, bytes_avail);
1480
1481 pio->sg_miter.consumed = bytes_avail;
1482 pio->bounce_buf_len += bytes_avail;
San Mehat9d2bd732009-09-22 16:44:22 -07001483 }
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001484}
1485
1486/*
1487 * Use sg_miter_next to return as many 4-byte aligned
1488 * chunks as possible, using a temporary 4 byte buffer
1489 * for alignment if necessary
1490 */
1491static int msmsdcc_sg_next(struct msmsdcc_host *host, char **buf, int *len)
1492{
1493 struct msmsdcc_pio_data *pio = &host->pio;
1494 unsigned int length, rlength;
1495 char *buffer;
1496
1497 if (!sg_miter_next(&pio->sg_miter))
1498 return 0;
1499
1500 buffer = pio->sg_miter.addr;
1501 length = pio->sg_miter.length;
1502
1503 if (length < host->curr.xfer_remain) {
1504 rlength = round_down(length, 4);
1505 if (rlength) {
1506 /*
1507 * We have a 4-byte aligned chunk.
1508 * The rounding will be reflected by
1509 * a call to msmsdcc_sg_consumed
1510 */
1511 length = rlength;
1512 goto sg_next_end;
1513 }
1514 /*
1515 * We have a length less than 4 bytes. Check to
1516 * see if more buffer is available, and combine
1517 * to make 4 bytes if possible.
1518 */
1519 pio->bounce_buf_len = length;
1520 memset(pio->bounce_buf, 0, 4);
1521
1522 /*
1523 * On a read, get 4 bytes from FIFO, and distribute
1524 * (4-bouce_buf_len) bytes into consecutive
1525 * sgl buffers when msmsdcc_sg_consumed is called
1526 */
1527 if (host->curr.data->flags & MMC_DATA_READ) {
1528 buffer = pio->bounce_buf;
1529 length = 4;
1530 goto sg_next_end;
1531 } else {
1532 _msmsdcc_sg_consume_word(host);
1533 buffer = pio->bounce_buf;
1534 length = pio->bounce_buf_len;
1535 }
1536 }
1537
1538sg_next_end:
1539 *buf = buffer;
1540 *len = length;
1541 return 1;
1542}
1543
1544/*
1545 * Update sg_miter.consumed based on how many bytes were
1546 * consumed. If the bounce buffer was used to read from FIFO,
1547 * redistribute into sgls.
1548 */
1549static void msmsdcc_sg_consumed(struct msmsdcc_host *host,
1550 unsigned int length)
1551{
1552 struct msmsdcc_pio_data *pio = &host->pio;
1553
1554 if (host->curr.data->flags & MMC_DATA_READ) {
1555 if (length > pio->sg_miter.consumed)
1556 /*
1557 * consumed 4 bytes, but sgl
1558 * describes < 4 bytes
1559 */
1560 _msmsdcc_sg_consume_word(host);
1561 else
1562 pio->sg_miter.consumed = length;
1563 } else
1564 if (length < pio->sg_miter.consumed)
1565 pio->sg_miter.consumed = length;
1566}
1567
1568static void msmsdcc_sg_start(struct msmsdcc_host *host)
1569{
1570 unsigned int sg_miter_flags = SG_MITER_ATOMIC;
1571
1572 host->pio.bounce_buf_len = 0;
1573
1574 if (host->curr.data->flags & MMC_DATA_READ)
1575 sg_miter_flags |= SG_MITER_TO_SG;
1576 else
1577 sg_miter_flags |= SG_MITER_FROM_SG;
1578
1579 sg_miter_start(&host->pio.sg_miter, host->curr.data->sg,
1580 host->curr.data->sg_len, sg_miter_flags);
1581}
1582
1583static void msmsdcc_sg_stop(struct msmsdcc_host *host)
1584{
1585 sg_miter_stop(&host->pio.sg_miter);
San Mehat9d2bd732009-09-22 16:44:22 -07001586}
1587
San Mehat1cd22962010-02-03 12:59:29 -08001588static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001589msmsdcc_pio_irq(int irq, void *dev_id)
1590{
1591 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001592 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001593 uint32_t status;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001594 unsigned long flags;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001595 unsigned int remain;
1596 char *buffer;
San Mehat9d2bd732009-09-22 16:44:22 -07001597
Murali Palnati36448a42011-09-02 15:06:18 +05301598 spin_lock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301599
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001600 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001601
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001602 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301603 (MCI_IRQ_PIO)) == 0) {
1604 spin_unlock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301605 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301606 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001607#if IRQ_DEBUG
1608 msmsdcc_print_status(host, "irq1-r", status);
1609#endif
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001610 local_irq_save(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001611
1612 do {
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001613 unsigned int len;
San Mehat9d2bd732009-09-22 16:44:22 -07001614
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001615 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1616 | MCI_RXDATAAVLBL)))
1617 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001618
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001619 if (!msmsdcc_sg_next(host, &buffer, &remain))
1620 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001621
San Mehat9d2bd732009-09-22 16:44:22 -07001622 len = 0;
1623 if (status & MCI_RXACTIVE)
1624 len = msmsdcc_pio_read(host, buffer, remain);
1625 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001626 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001627
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301628 /* len might have aligned to 32bits above */
1629 if (len > remain)
1630 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001631
San Mehat9d2bd732009-09-22 16:44:22 -07001632 host->curr.xfer_remain -= len;
1633 host->curr.data_xfered += len;
1634 remain -= len;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001635 msmsdcc_sg_consumed(host, len);
San Mehat9d2bd732009-09-22 16:44:22 -07001636
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001637 if (remain) /* Done with this page? */
1638 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001639
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001640 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001641 } while (1);
1642
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001643 msmsdcc_sg_stop(host);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001644 local_irq_restore(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001645
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001646 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1647 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1648 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1649 host->base + MMCIMASK0);
1650 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301651 /*
1652 * back to back write to MASK0 register don't need
1653 * synchronization delay.
1654 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001655 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1656 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1657 }
1658 mb();
1659 } else if (!host->curr.xfer_remain) {
1660 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1661 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1662 mb();
1663 }
San Mehat9d2bd732009-09-22 16:44:22 -07001664
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001665 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001666
1667 return IRQ_HANDLED;
1668}
1669
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001670static void
1671msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1672
1673static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1674 struct mmc_data *data)
1675{
1676 u32 loop_cnt = 0;
1677
1678 /*
1679 * For read commands with data less than fifo size, it is possible to
1680 * get DATAEND first and RXDATA_AVAIL might be set later because of
1681 * synchronization delay through the asynchronous RX FIFO. Thus, for
1682 * such cases, even after DATAEND interrupt is received software
1683 * should poll for RXDATA_AVAIL until the requested data is read out
1684 * of FIFO. This change is needed to get around this abnormal but
1685 * sometimes expected behavior of SDCC3 controller.
1686 *
1687 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1688 * after the data is loaded into RX FIFO. This would amount to less
1689 * than a microsecond and thus looping for 1000 times is good enough
1690 * for that delay.
1691 */
1692 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1693 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1694 spin_unlock(&host->lock);
1695 msmsdcc_pio_irq(1, host);
1696 spin_lock(&host->lock);
1697 }
1698 }
1699 if (loop_cnt == 1000) {
1700 pr_info("%s: Timed out while polling for Rx Data\n",
1701 mmc_hostname(host->mmc));
1702 data->error = -ETIMEDOUT;
1703 msmsdcc_reset_and_restore(host);
1704 }
1705}
1706
San Mehat9d2bd732009-09-22 16:44:22 -07001707static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1708{
1709 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001710
1711 host->curr.cmd = NULL;
subhashj8046ae12012-05-02 12:14:52 +05301712 if (mmc_resp_type(cmd))
1713 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1714 /*
1715 * Read rest of the response registers only if
1716 * long response is expected for this command
1717 */
1718 if (mmc_resp_type(cmd) & MMC_RSP_136) {
1719 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1720 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1721 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
1722 }
San Mehat9d2bd732009-09-22 16:44:22 -07001723
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001724 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301725 pr_debug("%s: CMD%d: Command timeout\n",
1726 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001727 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001728 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301729 !host->tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301730 pr_err("%s: CMD%d: Command CRC error\n",
1731 mmc_hostname(host->mmc), cmd->opcode);
1732 msmsdcc_dump_sdcc_state(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001733 cmd->error = -EILSEQ;
1734 }
1735
Subhash Jadavani8706ced2012-05-25 16:09:21 +05301736 if (!cmd->error) {
1737 if (cmd->cmd_timeout_ms > host->curr.req_tout_ms) {
1738 host->curr.req_tout_ms = cmd->cmd_timeout_ms;
1739 mod_timer(&host->req_tout_timer, (jiffies +
1740 msecs_to_jiffies(host->curr.req_tout_ms)));
1741 }
1742 }
1743
San Mehat9d2bd732009-09-22 16:44:22 -07001744 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001745 if (host->curr.data && host->dma.sg &&
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301746 is_dma_mode(host))
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001747 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001748 else if (host->curr.data && host->sps.sg &&
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301749 is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001750 /* Stop current SPS transfer */
1751 msmsdcc_sps_exit_curr_xfer(host);
1752 }
San Mehat9d2bd732009-09-22 16:44:22 -07001753 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301754 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001755 msmsdcc_stop_data(host);
1756 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301757 } else { /* host->data == NULL */
1758 if (!cmd->error && host->prog_enable) {
1759 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001760 host->prog_enable = 0;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301761 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001762 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301763 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301764 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301765 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301766 host->curr.wait_for_auto_prog_done = false;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001767 if (host->dummy_52_needed)
1768 host->dummy_52_needed = 0;
1769 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001770 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301771 msmsdcc_request_end(host, cmd->mrq);
1772 }
1773 }
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301774 } else if (cmd->data) {
Subhash Jadavanif5277752011-10-12 16:47:52 +05301775 if (cmd == host->curr.mrq->sbc)
1776 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1777 else if ((cmd->data->flags & MMC_DATA_WRITE) &&
1778 !host->curr.use_wr_data_pend)
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301779 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001780 }
1781}
1782
San Mehat9d2bd732009-09-22 16:44:22 -07001783static irqreturn_t
1784msmsdcc_irq(int irq, void *dev_id)
1785{
1786 struct msmsdcc_host *host = dev_id;
Pratibhasagar Vbe4e3132012-09-20 19:46:11 +05301787 struct mmc_host *mmc = host->mmc;
San Mehat9d2bd732009-09-22 16:44:22 -07001788 u32 status;
1789 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001790 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001791
1792 spin_lock(&host->lock);
1793
1794 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001795 struct mmc_command *cmd;
1796 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001797
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001798 if (timer) {
1799 timer = 0;
1800 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001801 }
San Mehat9d2bd732009-09-22 16:44:22 -07001802
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05301803 if (!atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001804 pr_debug("%s: %s: SDIO async irq received\n",
1805 mmc_hostname(host->mmc), __func__);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301806
1807 /*
1808 * Only async interrupt can come when clocks are off,
1809 * disable further interrupts and enable them when
1810 * clocks are on.
1811 */
1812 if (!host->sdcc_irq_disabled) {
1813 disable_irq_nosync(irq);
1814 host->sdcc_irq_disabled = 1;
1815 }
1816
1817 /*
1818 * If mmc_card_wake_sdio_irq() is set, mmc core layer
1819 * will take care of signaling sdio irq during
1820 * mmc_sdio_resume().
1821 */
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301822 if (host->sdcc_suspended) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301823 /*
1824 * This is a wakeup interrupt so hold wakelock
1825 * until SDCC resume is handled.
1826 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001827 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301828 } else {
Pratibhasagar Vbe4e3132012-09-20 19:46:11 +05301829 if (!mmc->card || !mmc_card_sdio(mmc->card)) {
1830 WARN(1, "%s: SDCC core interrupt received for non-SDIO cards when SDCC clocks are off\n",
1831 mmc_hostname(mmc));
1832 ret = 1;
1833 break;
1834 }
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301835 spin_unlock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301836 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301837 spin_lock(&host->lock);
1838 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301839 ret = 1;
1840 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001841 }
1842
1843 status = readl_relaxed(host->base + MMCISTATUS);
1844
1845 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1846 (~(MCI_IRQ_PIO))) == 0)
San Mehat9d2bd732009-09-22 16:44:22 -07001847 break;
1848
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001849#if IRQ_DEBUG
1850 msmsdcc_print_status(host, "irq0-r", status);
1851#endif
1852 status &= readl_relaxed(host->base + MMCIMASK0);
1853 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301854 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301855 if (host->clk_rate <=
1856 msmsdcc_get_min_sup_clk_rate(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +05301857 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001858#if IRQ_DEBUG
1859 msmsdcc_print_status(host, "irq0-p", status);
1860#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001861
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001862 if (status & MCI_SDIOINTROPE) {
Pratibhasagar Vbe4e3132012-09-20 19:46:11 +05301863 if (!mmc->card || mmc_card_sdio(mmc->card)) {
1864 WARN(1, "%s: SDIO interrupt received for non-SDIO card\n",
1865 mmc_hostname(mmc));
1866 ret = 1;
1867 break;
1868 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001869 if (host->sdcc_suspending)
1870 wake_lock(&host->sdio_suspend_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301871 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001872 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301873 spin_lock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001874 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001875 data = host->curr.data;
1876
1877 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001878 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1879 MCI_CMDTIMEOUT)) {
1880 if (status & MCI_CMDTIMEOUT)
1881 pr_debug("%s: dummy CMD52 timeout\n",
1882 mmc_hostname(host->mmc));
1883 if (status & MCI_CMDCRCFAIL)
1884 pr_debug("%s: dummy CMD52 CRC failed\n",
1885 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001886 host->dummy_52_sent = 0;
1887 host->dummy_52_needed = 0;
1888 if (data) {
1889 msmsdcc_stop_data(host);
1890 msmsdcc_request_end(host, data->mrq);
1891 }
1892 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001893 spin_unlock(&host->lock);
1894 return IRQ_HANDLED;
1895 }
1896 break;
1897 }
1898
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001899 /*
1900 * Check for proper command response
1901 */
1902 cmd = host->curr.cmd;
1903 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1904 MCI_CMDTIMEOUT | MCI_PROGDONE |
1905 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1906 msmsdcc_do_cmdirq(host, status);
1907 }
1908
Sathish Ambley081d7842011-11-29 11:19:41 -08001909 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001910 /* Check for data errors */
1911 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1912 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1913 msmsdcc_data_err(host, data, status);
1914 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301915 if (host->dma.sg && is_dma_mode(host))
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001916 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301917 else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001918 /* Stop current SPS transfer */
1919 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301920 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001921 msmsdcc_reset_and_restore(host);
1922 if (host->curr.data)
1923 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301924 if (!data->stop || (host->curr.mrq->sbc
1925 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001926 timer |=
1927 msmsdcc_request_end(host,
1928 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301929 else if ((host->curr.mrq->sbc
1930 && data->error) ||
1931 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001932 msmsdcc_start_command(host,
1933 data->stop,
1934 0);
1935 timer = 1;
1936 }
1937 }
1938 }
1939
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301940 /* Check for prog done */
1941 if (host->curr.wait_for_auto_prog_done &&
1942 (status & MCI_PROGDONE))
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301943 host->curr.got_auto_prog_done = true;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301944
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001945 /* Check for data done */
1946 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1947 host->curr.got_dataend = 1;
1948
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301949 if (host->curr.got_dataend &&
1950 (!host->curr.wait_for_auto_prog_done ||
1951 (host->curr.wait_for_auto_prog_done &&
1952 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001953 /*
1954 * If DMA is still in progress, we complete
1955 * via the completion handler
1956 */
1957 if (!host->dma.busy && !host->sps.busy) {
1958 /*
1959 * There appears to be an issue in the
1960 * controller where if you request a
1961 * small block transfer (< fifo size),
1962 * you may get your DATAEND/DATABLKEND
1963 * irq without the PIO data irq.
1964 *
1965 * Check to see if theres still data
1966 * to be read, and simulate a PIO irq.
1967 */
1968 if (data->flags & MMC_DATA_READ)
1969 msmsdcc_wait_for_rxdata(host,
1970 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001971 if (!data->error) {
1972 host->curr.data_xfered =
1973 host->curr.xfer_size;
1974 host->curr.xfer_remain -=
1975 host->curr.xfer_size;
1976 }
1977
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001978 if (!host->dummy_52_needed) {
1979 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301980 if (!data->stop ||
1981 (host->curr.mrq->sbc
1982 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001983 msmsdcc_request_end(
1984 host,
1985 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301986 else if ((host->curr.mrq->sbc
1987 && data->error) ||
1988 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001989 msmsdcc_start_command(
1990 host,
1991 data->stop, 0);
1992 timer = 1;
1993 }
1994 } else {
1995 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001996 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001997 &dummy52cmd,
1998 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001999 }
2000 }
2001 }
2002 }
2003
San Mehat9d2bd732009-09-22 16:44:22 -07002004 ret = 1;
2005 } while (status);
2006
2007 spin_unlock(&host->lock);
2008
San Mehat9d2bd732009-09-22 16:44:22 -07002009 return IRQ_RETVAL(ret);
2010}
2011
2012static void
Asutosh Dasaccacd42012-03-08 14:33:17 +05302013msmsdcc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
2014 bool is_first_request)
2015{
2016 struct msmsdcc_host *host = mmc_priv(mmc);
2017 struct mmc_data *data = mrq->data;
2018 int rc = 0;
2019
2020 if (unlikely(!data)) {
2021 pr_err("%s: %s cannot prepare null data\n", mmc_hostname(mmc),
2022 __func__);
2023 return;
2024 }
2025 if (unlikely(data->host_cookie)) {
2026 /* Very wrong */
2027 data->host_cookie = 0;
2028 pr_err("%s: %s Request reposted for prepare\n",
2029 mmc_hostname(mmc), __func__);
2030 return;
2031 }
2032
2033 if (!msmsdcc_is_dma_possible(host, data))
2034 return;
2035
2036 rc = msmsdcc_prep_xfer(host, data);
2037 if (unlikely(rc < 0)) {
2038 data->host_cookie = 0;
2039 return;
2040 }
2041
2042 data->host_cookie = 1;
2043}
2044
2045static void
2046msmsdcc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, int err)
2047{
2048 struct msmsdcc_host *host = mmc_priv(mmc);
2049 unsigned int dir;
2050 struct mmc_data *data = mrq->data;
2051
2052 if (unlikely(!data)) {
2053 pr_err("%s: %s cannot cleanup null data\n", mmc_hostname(mmc),
2054 __func__);
2055 return;
2056 }
2057 if (data->flags & MMC_DATA_READ)
2058 dir = DMA_FROM_DEVICE;
2059 else
2060 dir = DMA_TO_DEVICE;
2061
2062 if (data->host_cookie)
2063 dma_unmap_sg(mmc_dev(host->mmc), data->sg,
2064 data->sg_len, dir);
2065
2066 data->host_cookie = 0;
2067}
2068
2069static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002070msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
2071{
Subhash Jadavanif5277752011-10-12 16:47:52 +05302072 if (mrq->data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002073 /* Queue/read data, daisy-chain command when data starts */
Subhash Jadavanif5277752011-10-12 16:47:52 +05302074 if ((mrq->data->flags & MMC_DATA_READ) ||
2075 host->curr.use_wr_data_pend)
2076 msmsdcc_start_data(host, mrq->data,
2077 mrq->sbc ? mrq->sbc : mrq->cmd,
2078 0);
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302079 else
Subhash Jadavanif5277752011-10-12 16:47:52 +05302080 msmsdcc_start_command(host,
2081 mrq->sbc ? mrq->sbc : mrq->cmd,
2082 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002083 } else {
2084 msmsdcc_start_command(host, mrq->cmd, 0);
2085 }
2086}
2087
2088static void
San Mehat9d2bd732009-09-22 16:44:22 -07002089msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
2090{
2091 struct msmsdcc_host *host = mmc_priv(mmc);
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302092 unsigned long flags;
Maya Erezb7a086f2012-11-29 00:37:36 +02002093 int retries = 5;
San Mehat9d2bd732009-09-22 16:44:22 -07002094
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002095 /*
2096 * Get the SDIO AL client out of LPM.
2097 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002098 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002099 if (host->plat->is_sdio_al_client)
2100 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002101
Maya Erezb7a086f2012-11-29 00:37:36 +02002102 /* check if sps bam needs to be reset */
2103 if (is_sps_mode(host) && host->sps.reset_bam) {
2104 while (retries) {
2105 if (!msmsdcc_bam_dml_reset_and_restore(host))
2106 break;
2107 pr_err("%s: msmsdcc_bam_dml_reset_and_restore returned error. %d attempts left.\n",
2108 mmc_hostname(host->mmc), --retries);
2109 }
Subhash Jadavanib5b07742011-08-29 17:48:07 +05302110 }
San Mehat9d2bd732009-09-22 16:44:22 -07002111
2112 spin_lock_irqsave(&host->lock, flags);
2113
San Mehat9d2bd732009-09-22 16:44:22 -07002114 if (host->eject) {
2115 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
2116 mrq->cmd->error = 0;
2117 mrq->data->bytes_xfered = mrq->data->blksz *
2118 mrq->data->blocks;
2119 } else
2120 mrq->cmd->error = -ENOMEDIUM;
2121
2122 spin_unlock_irqrestore(&host->lock, flags);
2123 mmc_request_done(mmc, mrq);
2124 return;
2125 }
2126
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302127 /*
subhashjf181c292012-05-02 13:07:40 +05302128 * Don't start the request if SDCC is not in proper state to handle it
2129 */
Maya Erezb7a086f2012-11-29 00:37:36 +02002130 if (!host->pwr || !atomic_read(&host->clks_on) ||
2131 host->sdcc_irq_disabled ||
2132 host->sps.reset_bam) {
subhashjf181c292012-05-02 13:07:40 +05302133 WARN(1, "%s: %s: SDCC is in bad state. don't process"
2134 " new request (CMD%d)\n", mmc_hostname(host->mmc),
2135 __func__, mrq->cmd->opcode);
2136 msmsdcc_dump_sdcc_state(host);
2137 mrq->cmd->error = -EIO;
2138 if (mrq->data) {
2139 mrq->data->error = -EIO;
2140 mrq->data->bytes_xfered = 0;
2141 }
2142 spin_unlock_irqrestore(&host->lock, flags);
2143 mmc_request_done(mmc, mrq);
2144 return;
2145 }
2146
2147 WARN(host->curr.mrq, "%s: %s: New request (CMD%d) received while"
2148 " other request (CMD%d) is in progress\n",
2149 mmc_hostname(host->mmc), __func__,
2150 mrq->cmd->opcode, host->curr.mrq->cmd->opcode);
2151
2152 /*
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302153 * Set timeout value to 10 secs (or more in case of buggy cards)
2154 */
2155 if ((mmc->card) && (mmc->card->quirks & MMC_QUIRK_INAND_DATA_TIMEOUT))
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302156 host->curr.req_tout_ms = 20000;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302157 else
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302158 host->curr.req_tout_ms = MSM_MMC_REQ_TIMEOUT;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302159 /*
2160 * Kick the software request timeout timer here with the timeout
2161 * value identified above
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302162 */
2163 mod_timer(&host->req_tout_timer,
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302164 (jiffies +
2165 msecs_to_jiffies(host->curr.req_tout_ms)));
San Mehat9d2bd732009-09-22 16:44:22 -07002166
San Mehat9d2bd732009-09-22 16:44:22 -07002167 host->curr.mrq = mrq;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302168 if (mrq->sbc) {
2169 mrq->sbc->mrq = mrq;
2170 mrq->sbc->data = mrq->data;
2171 }
2172
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302173 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05302174 if (is_auto_prog_done(host)) {
Sujit Reddy Thummab8e83692012-07-17 15:08:13 +05302175 /*
2176 * Auto-prog done will be enabled for following cases:
2177 * mrq->sbc | mrq->stop
2178 * _____________|________________
2179 * True | Don't care
2180 * False | False (CMD24, ACMD25 use case)
2181 */
2182 if (mrq->sbc || !mrq->stop)
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302183 host->curr.wait_for_auto_prog_done = true;
2184 } else {
2185 if ((mrq->cmd->opcode == SD_IO_RW_EXTENDED) ||
2186 (mrq->cmd->opcode == 54))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002187 host->dummy_52_needed = 1;
2188 }
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302189
Subhash Jadavanif5277752011-10-12 16:47:52 +05302190 if ((mrq->cmd->opcode == MMC_WRITE_BLOCK) ||
2191 (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK))
2192 host->curr.use_wr_data_pend = true;
San Mehat9d2bd732009-09-22 16:44:22 -07002193 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302194
Subhash Jadavanif5277752011-10-12 16:47:52 +05302195 msmsdcc_request_start(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302196
San Mehat9d2bd732009-09-22 16:44:22 -07002197 spin_unlock_irqrestore(&host->lock, flags);
2198}
2199
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002200static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
2201 int min_uV, int max_uV)
2202{
2203 int rc = 0;
2204
2205 if (vreg->set_voltage_sup) {
2206 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
2207 if (rc) {
2208 pr_err("%s: regulator_set_voltage(%s) failed."
2209 " min_uV=%d, max_uV=%d, rc=%d\n",
2210 __func__, vreg->name, min_uV, max_uV, rc);
2211 }
2212 }
2213
2214 return rc;
2215}
2216
Subhash Jadavanibf09d802012-08-11 18:11:57 +05302217static inline int msmsdcc_vreg_get_voltage(struct msm_mmc_reg_data *vreg)
2218{
2219 int rc = 0;
2220
2221 rc = regulator_get_voltage(vreg->reg);
2222 if (rc < 0)
2223 pr_err("%s: regulator_get_voltage(%s) failed. rc=%d\n",
2224 __func__, vreg->name, rc);
2225
2226 return rc;
2227}
2228
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002229static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
2230 int uA_load)
2231{
2232 int rc = 0;
2233
Krishna Kondafea60182011-11-01 16:01:34 -07002234 /* regulators that do not support regulator_set_voltage also
2235 do not support regulator_set_optimum_mode */
2236 if (vreg->set_voltage_sup) {
2237 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
2238 if (rc < 0)
2239 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
2240 "uA_load=%d) failed. rc=%d\n", __func__,
2241 vreg->name, uA_load, rc);
2242 else
2243 /* regulator_set_optimum_mode() can return non zero
2244 * value even for success case.
2245 */
2246 rc = 0;
2247 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002248
2249 return rc;
2250}
2251
2252static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
2253 struct device *dev)
2254{
2255 int rc = 0;
2256
2257 /* check if regulator is already initialized? */
2258 if (vreg->reg)
2259 goto out;
2260
2261 /* Get the regulator handle */
2262 vreg->reg = regulator_get(dev, vreg->name);
2263 if (IS_ERR(vreg->reg)) {
2264 rc = PTR_ERR(vreg->reg);
2265 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
2266 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002267 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002268 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002269
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05302270 if (regulator_count_voltages(vreg->reg) > 0) {
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002271 vreg->set_voltage_sup = 1;
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05302272 /* sanity check */
2273 if (!vreg->high_vol_level || !vreg->hpm_uA) {
2274 pr_err("%s: %s invalid constraints specified\n",
2275 __func__, vreg->name);
2276 rc = -EINVAL;
2277 }
2278 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002279
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002280out:
2281 return rc;
2282}
2283
2284static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
2285{
2286 if (vreg->reg)
2287 regulator_put(vreg->reg);
2288}
2289
2290/* This init function should be called only once for each SDCC slot */
2291static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
2292{
2293 int rc = 0;
2294 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302295 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vdd_io_reg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002296 struct device *dev = mmc_dev(host->mmc);
2297
2298 curr_slot = host->plat->vreg_data;
2299 if (!curr_slot)
2300 goto out;
2301
2302 curr_vdd_reg = curr_slot->vdd_data;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302303 curr_vdd_io_reg = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002304
2305 if (is_init) {
2306 /*
2307 * Get the regulator handle from voltage regulator framework
2308 * and then try to set the voltage level for the regulator
2309 */
2310 if (curr_vdd_reg) {
2311 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
2312 if (rc)
2313 goto out;
2314 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302315 if (curr_vdd_io_reg) {
2316 rc = msmsdcc_vreg_init_reg(curr_vdd_io_reg, dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002317 if (rc)
2318 goto vdd_reg_deinit;
2319 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002320 rc = msmsdcc_vreg_reset(host);
2321 if (rc)
2322 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
2323 host->pdev_id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002324 goto out;
2325 } else {
2326 /* Deregister all regulators from regulator framework */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302327 goto vdd_io_reg_deinit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002328 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302329vdd_io_reg_deinit:
2330 if (curr_vdd_io_reg)
2331 msmsdcc_vreg_deinit_reg(curr_vdd_io_reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002332vdd_reg_deinit:
2333 if (curr_vdd_reg)
2334 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2335out:
2336 return rc;
2337}
2338
2339static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2340{
2341 int rc = 0;
2342
Subhash Jadavanicc922692011-08-01 23:05:01 +05302343 /* Put regulator in HPM (high power mode) */
2344 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2345 if (rc < 0)
2346 goto out;
2347
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002348 if (!vreg->is_enabled) {
2349 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302350 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2351 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002352 if (rc)
2353 goto out;
2354
2355 rc = regulator_enable(vreg->reg);
2356 if (rc) {
2357 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2358 __func__, vreg->name, rc);
2359 goto out;
2360 }
2361 vreg->is_enabled = true;
2362 }
2363
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002364out:
2365 return rc;
2366}
2367
Krishna Konda3c4142d2012-06-27 11:01:56 -07002368static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg, bool is_init)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002369{
2370 int rc = 0;
2371
2372 /* Never disable regulator marked as always_on */
2373 if (vreg->is_enabled && !vreg->always_on) {
2374 rc = regulator_disable(vreg->reg);
2375 if (rc) {
2376 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2377 __func__, vreg->name, rc);
2378 goto out;
2379 }
2380 vreg->is_enabled = false;
2381
2382 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2383 if (rc < 0)
2384 goto out;
2385
2386 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302387 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002388 if (rc)
2389 goto out;
Krishna Konda3c4142d2012-06-27 11:01:56 -07002390 } else if (vreg->is_enabled && vreg->always_on) {
2391 if (!is_init && vreg->lpm_sup) {
2392 /* Put always_on regulator in LPM (low power mode) */
2393 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2394 if (rc < 0)
2395 goto out;
2396 } else if (is_init && vreg->reset_at_init) {
2397 /**
2398 * The regulator might not actually be disabled if it
2399 * is shared and in use by other drivers.
2400 */
2401 rc = regulator_disable(vreg->reg);
2402 if (rc) {
2403 pr_err("%s: regulator_disable(%s) failed at " \
2404 "bootup. rc=%d\n", __func__,
2405 vreg->name, rc);
2406 goto out;
2407 }
2408 vreg->is_enabled = false;
2409 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002410 }
2411out:
2412 return rc;
2413}
2414
Krishna Konda3c4142d2012-06-27 11:01:56 -07002415static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable,
2416 bool is_init)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002417{
2418 int rc = 0, i;
2419 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302420 struct msm_mmc_reg_data *vreg_table[2];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002421
2422 curr_slot = host->plat->vreg_data;
Asutosh Dasebd7d092012-07-09 19:08:26 +05302423 if (!curr_slot) {
2424 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002425 goto out;
Asutosh Dasebd7d092012-07-09 19:08:26 +05302426 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002427
Subhash Jadavani937c7502012-06-01 15:34:46 +05302428 vreg_table[0] = curr_slot->vdd_data;
2429 vreg_table[1] = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002430
2431 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2432 if (vreg_table[i]) {
2433 if (enable)
2434 rc = msmsdcc_vreg_enable(vreg_table[i]);
2435 else
Krishna Konda3c4142d2012-06-27 11:01:56 -07002436 rc = msmsdcc_vreg_disable(vreg_table[i],
2437 is_init);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002438 if (rc)
2439 goto out;
2440 }
2441 }
2442out:
2443 return rc;
2444}
2445
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002446/*
2447 * Reset vreg by ensuring it is off during probe. A call
2448 * to enable vreg is needed to balance disable vreg
2449 */
2450static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2451{
2452 int rc;
2453
Krishna Konda3c4142d2012-06-27 11:01:56 -07002454 rc = msmsdcc_setup_vreg(host, 1, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002455 if (rc)
2456 return rc;
Krishna Konda3c4142d2012-06-27 11:01:56 -07002457 rc = msmsdcc_setup_vreg(host, 0, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002458 return rc;
2459}
2460
Subhash Jadavani937c7502012-06-01 15:34:46 +05302461enum vdd_io_level {
2462 /* set vdd_io_data->low_vol_level */
2463 VDD_IO_LOW,
2464 /* set vdd_io_data->high_vol_level */
2465 VDD_IO_HIGH,
2466 /*
2467 * set whatever there in voltage_level (third argument) of
2468 * msmsdcc_set_vdd_io_vol() function.
2469 */
2470 VDD_IO_SET_LEVEL,
2471};
2472
Subhash Jadavanibf09d802012-08-11 18:11:57 +05302473/*
2474 * This function returns the current VDD IO voltage level.
2475 * Returns negative value if it fails to read the voltage level
2476 * Returns 0 if regulator was disabled or if VDD_IO (and VDD)
2477 * regulator were not defined for host.
2478 */
2479static int msmsdcc_get_vdd_io_vol(struct msmsdcc_host *host)
2480{
2481 int rc = 0;
2482
2483 if (host->plat->vreg_data) {
2484 struct msm_mmc_reg_data *io_reg =
2485 host->plat->vreg_data->vdd_io_data;
2486
2487 /*
2488 * If vdd_io is not defined, then we can consider that
2489 * IO voltage is same as VDD.
2490 */
2491 if (!io_reg)
2492 io_reg = host->plat->vreg_data->vdd_data;
2493
2494 if (io_reg && io_reg->is_enabled)
2495 rc = msmsdcc_vreg_get_voltage(io_reg);
2496 }
2497
2498 return rc;
2499}
2500
2501/*
2502 * This function updates the IO pad power switch bit in MCI_CLK register
2503 * based on currrent IO pad voltage level.
2504 * NOTE: This function assumes that host lock was not taken by caller.
2505 */
2506static void msmsdcc_update_io_pad_pwr_switch(struct msmsdcc_host *host)
2507{
2508 int rc = 0;
2509 unsigned long flags;
2510
2511 if (!is_io_pad_pwr_switch(host))
2512 return;
2513
2514 rc = msmsdcc_get_vdd_io_vol(host);
2515
2516 spin_lock_irqsave(&host->lock, flags);
2517 /*
2518 * Dual voltage pad is the SDCC's (chipset) functionality and not all
2519 * the SDCC instances support the dual voltage pads.
2520 * For dual-voltage pad (1.8v/3.3v), SW should set IO_PAD_PWR_SWITCH
2521 * bit before using the pads in 1.8V mode.
2522 * For regular, not dual-voltage pads (including eMMC 1.2v/1.8v pads),
2523 * IO_PAD_PWR_SWITCH bit is a don't care.
2524 * But we don't have an option to know (by reading some SDCC register)
2525 * that a particular SDCC instance supports dual voltage pads or not,
2526 * so we simply set the IO_PAD_PWR_SWITCH bit for low voltage IO
2527 * (1.8v/1.2v). For regular (not dual-voltage pads), this bit value
2528 * is anyway ignored.
2529 */
2530 if (rc > 0 && rc < 2700000)
2531 host->io_pad_pwr_switch = 1;
2532 else
2533 host->io_pad_pwr_switch = 0;
2534
2535 if (atomic_read(&host->clks_on)) {
2536 if (host->io_pad_pwr_switch)
2537 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2538 IO_PAD_PWR_SWITCH),
2539 host->base + MMCICLOCK);
2540 else
2541 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) &
2542 ~IO_PAD_PWR_SWITCH),
2543 host->base + MMCICLOCK);
2544 msmsdcc_sync_reg_wr(host);
2545 }
2546 spin_unlock_irqrestore(&host->lock, flags);
2547}
2548
Subhash Jadavani937c7502012-06-01 15:34:46 +05302549static int msmsdcc_set_vdd_io_vol(struct msmsdcc_host *host,
2550 enum vdd_io_level level,
2551 unsigned int voltage_level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002552{
2553 int rc = 0;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302554 int set_level;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002555
2556 if (host->plat->vreg_data) {
Subhash Jadavani937c7502012-06-01 15:34:46 +05302557 struct msm_mmc_reg_data *vdd_io_reg =
2558 host->plat->vreg_data->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002559
Subhash Jadavani937c7502012-06-01 15:34:46 +05302560 if (vdd_io_reg && vdd_io_reg->is_enabled) {
2561 switch (level) {
2562 case VDD_IO_LOW:
2563 set_level = vdd_io_reg->low_vol_level;
2564 break;
2565 case VDD_IO_HIGH:
2566 set_level = vdd_io_reg->high_vol_level;
2567 break;
2568 case VDD_IO_SET_LEVEL:
2569 set_level = voltage_level;
2570 break;
2571 default:
2572 pr_err("%s: %s: invalid argument level = %d",
2573 mmc_hostname(host->mmc), __func__,
2574 level);
2575 rc = -EINVAL;
2576 goto out;
2577 }
2578 rc = msmsdcc_vreg_set_voltage(vdd_io_reg,
2579 set_level, set_level);
2580 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002581 }
2582
Subhash Jadavani937c7502012-06-01 15:34:46 +05302583out:
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302584 return rc;
2585}
2586
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002587static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2588{
2589 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2590 return 1;
2591 return 0;
2592}
2593
Asutosh Dasf5298c32012-04-03 14:51:47 +05302594/*
2595 * Any function calling msmsdcc_setup_clocks must
2596 * acquire clk_mutex. May sleep.
2597 */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302598static int msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002599{
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302600 int rc = 0;
2601
2602 if (enable && !atomic_read(&host->clks_on)) {
2603 if (!IS_ERR_OR_NULL(host->bus_clk)) {
2604 rc = clk_prepare_enable(host->bus_clk);
2605 if (rc) {
2606 pr_err("%s: %s: failed to enable the bus-clock with error %d\n",
2607 mmc_hostname(host->mmc), __func__, rc);
2608 goto out;
2609 }
2610 }
2611 if (!IS_ERR(host->pclk)) {
2612 rc = clk_prepare_enable(host->pclk);
2613 if (rc) {
2614 pr_err("%s: %s: failed to enable the pclk with error %d\n",
2615 mmc_hostname(host->mmc), __func__, rc);
2616 goto disable_bus;
2617 }
2618 }
2619 rc = clk_prepare_enable(host->clk);
2620 if (rc) {
2621 pr_err("%s: %s: failed to enable the host-clk with error %d\n",
2622 mmc_hostname(host->mmc), __func__, rc);
2623 goto disable_pclk;
2624 }
Subhash Jadavanidd432952012-03-28 11:25:56 +05302625 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302626 msmsdcc_delay(host);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302627 atomic_set(&host->clks_on, 1);
2628 } else if (!enable && atomic_read(&host->clks_on)) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05302629 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302630 msmsdcc_delay(host);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302631 clk_disable_unprepare(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002632 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302633 clk_disable_unprepare(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05302634 if (!IS_ERR_OR_NULL(host->bus_clk))
2635 clk_disable_unprepare(host->bus_clk);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302636 atomic_set(&host->clks_on, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002637 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302638 goto out;
2639
2640disable_pclk:
2641 if (!IS_ERR_OR_NULL(host->pclk))
2642 clk_disable_unprepare(host->pclk);
2643disable_bus:
2644 if (!IS_ERR_OR_NULL(host->bus_clk))
2645 clk_disable_unprepare(host->bus_clk);
2646out:
2647 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002648}
2649
2650static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2651 unsigned int req_clk)
2652{
2653 unsigned int sel_clk = -1;
2654
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302655 if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
2656 sel_clk = msmsdcc_get_min_sup_clk_rate(host);
2657 goto out;
2658 }
2659
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002660 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2661 unsigned char cnt;
2662
2663 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2664 if (host->plat->sup_clk_table[cnt] > req_clk)
2665 break;
2666 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2667 sel_clk = host->plat->sup_clk_table[cnt];
2668 break;
2669 } else
2670 sel_clk = host->plat->sup_clk_table[cnt];
2671 }
2672 } else {
2673 if ((req_clk < host->plat->msmsdcc_fmax) &&
2674 (req_clk > host->plat->msmsdcc_fmid))
2675 sel_clk = host->plat->msmsdcc_fmid;
2676 else
2677 sel_clk = req_clk;
2678 }
2679
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302680out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002681 return sel_clk;
2682}
2683
2684static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2685 struct msmsdcc_host *host)
2686{
2687 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2688 return host->plat->sup_clk_table[0];
2689 else
2690 return host->plat->msmsdcc_fmin;
2691}
2692
2693static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2694 struct msmsdcc_host *host)
2695{
2696 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2697 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2698 else
2699 return host->plat->msmsdcc_fmax;
2700}
2701
2702static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302703{
2704 struct msm_mmc_gpio_data *curr;
2705 int i, rc = 0;
2706
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002707 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302708 for (i = 0; i < curr->size; i++) {
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05302709 if (!gpio_is_valid(curr->gpio[i].no)) {
2710 rc = -EINVAL;
2711 pr_err("%s: Invalid gpio = %d\n",
2712 mmc_hostname(host->mmc), curr->gpio[i].no);
2713 goto free_gpios;
2714 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302715 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002716 if (curr->gpio[i].is_always_on &&
2717 curr->gpio[i].is_enabled)
2718 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302719 rc = gpio_request(curr->gpio[i].no,
2720 curr->gpio[i].name);
2721 if (rc) {
2722 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2723 mmc_hostname(host->mmc),
2724 curr->gpio[i].no,
2725 curr->gpio[i].name, rc);
2726 goto free_gpios;
2727 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002728 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302729 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002730 if (curr->gpio[i].is_always_on)
2731 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302732 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002733 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302734 }
2735 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002736 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302737
2738free_gpios:
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05302739 for (i--; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302740 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002741 curr->gpio[i].is_enabled = false;
2742 }
2743out:
2744 return rc;
2745}
2746
2747static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2748{
2749 struct msm_mmc_pad_data *curr;
2750 int i;
2751
2752 curr = host->plat->pin_data->pad_data;
2753 for (i = 0; i < curr->drv->size; i++) {
2754 if (enable)
2755 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2756 curr->drv->on[i].val);
2757 else
2758 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2759 curr->drv->off[i].val);
2760 }
2761
2762 for (i = 0; i < curr->pull->size; i++) {
2763 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002764 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002765 curr->pull->on[i].val);
2766 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002767 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002768 curr->pull->off[i].val);
2769 }
2770
2771 return 0;
2772}
2773
2774static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2775{
2776 int rc = 0;
2777
2778 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2779 return 0;
2780
2781 if (host->plat->pin_data->is_gpio)
2782 rc = msmsdcc_setup_gpio(host, enable);
2783 else
2784 rc = msmsdcc_setup_pad(host, enable);
2785
2786 if (!rc)
2787 host->plat->pin_data->cfg_sts = enable;
2788
2789 return rc;
2790}
2791
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302792static int msmsdcc_cfg_mpm_sdiowakeup(struct msmsdcc_host *host,
2793 unsigned mode)
2794{
2795 int ret = 0;
2796 unsigned int pin = host->plat->mpm_sdiowakeup_int;
2797
2798 if (!pin)
2799 return 0;
2800
2801 switch (mode) {
2802 case SDC_DAT1_DISABLE:
2803 ret = msm_mpm_enable_pin(pin, 0);
2804 break;
2805 case SDC_DAT1_ENABLE:
2806 ret = msm_mpm_set_pin_type(pin, IRQ_TYPE_LEVEL_LOW);
2807 ret = msm_mpm_enable_pin(pin, 1);
2808 break;
2809 case SDC_DAT1_ENWAKE:
2810 ret = msm_mpm_set_pin_wake(pin, 1);
2811 break;
2812 case SDC_DAT1_DISWAKE:
2813 ret = msm_mpm_set_pin_wake(pin, 0);
2814 break;
2815 default:
2816 ret = -EINVAL;
2817 break;
2818 }
2819
2820 return ret;
2821}
2822
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302823static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2824{
2825 u32 pwr = 0;
2826 int ret = 0;
2827 struct mmc_host *mmc = host->mmc;
2828
2829 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2830 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2831 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
Krishna Konda3c4142d2012-06-27 11:01:56 -07002832 ret = msmsdcc_setup_vreg(host, !!ios->vdd, false);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302833
2834 if (ret) {
2835 pr_err("%s: Failed to setup voltage regulators\n",
2836 mmc_hostname(host->mmc));
2837 goto out;
2838 }
2839
2840 switch (ios->power_mode) {
2841 case MMC_POWER_OFF:
2842 pwr = MCI_PWR_OFF;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302843 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302844 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05302845 * If VDD IO rail is always on, set low voltage for VDD
2846 * IO rail when slot is not in use (like when card is not
2847 * present or during system suspend).
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302848 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302849 msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Subhash Jadavanibf09d802012-08-11 18:11:57 +05302850 msmsdcc_update_io_pad_pwr_switch(host);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302851 msmsdcc_setup_pins(host, false);
Pratibhasagar Vbe4e3132012-09-20 19:46:11 +05302852 /*
2853 * Reset the mask to prevent hitting any pending interrupts
2854 * after powering up the card again.
2855 */
2856 if (atomic_read(&host->clks_on)) {
2857 writel_relaxed(0, host->base + MMCIMASK0);
2858 mb();
2859 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302860 break;
2861 case MMC_POWER_UP:
2862 /* writing PWR_UP bit is redundant */
2863 pwr = MCI_PWR_UP;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302864 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302865
Subhash Jadavani937c7502012-06-01 15:34:46 +05302866 msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Subhash Jadavanibf09d802012-08-11 18:11:57 +05302867 msmsdcc_update_io_pad_pwr_switch(host);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302868 msmsdcc_setup_pins(host, true);
2869 break;
2870 case MMC_POWER_ON:
2871 pwr = MCI_PWR_ON;
2872 break;
2873 }
2874
2875out:
2876 return pwr;
2877}
2878
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002879static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2880{
2881 unsigned int wakeup_irq;
2882
2883 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2884 host->plat->sdiowakeup_irq :
2885 host->core_irqres->start;
2886
2887 if (!host->irq_wake_enabled) {
2888 enable_irq_wake(wakeup_irq);
2889 host->irq_wake_enabled = true;
2890 }
2891}
2892
2893static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2894{
2895 unsigned int wakeup_irq;
2896
2897 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2898 host->plat->sdiowakeup_irq :
2899 host->core_irqres->start;
2900
2901 if (host->irq_wake_enabled) {
2902 disable_irq_wake(wakeup_irq);
2903 host->irq_wake_enabled = false;
2904 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302905}
2906
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05302907/* Returns required bandwidth in Bytes per Sec */
2908static unsigned int msmsdcc_get_bw_required(struct msmsdcc_host *host,
2909 struct mmc_ios *ios)
2910{
2911 unsigned int bw;
2912
2913 bw = host->clk_rate;
2914 /*
2915 * For DDR mode, SDCC controller clock will be at
2916 * the double rate than the actual clock that goes to card.
2917 */
2918 if (ios->bus_width == MMC_BUS_WIDTH_4)
2919 bw /= 2;
2920 else if (ios->bus_width == MMC_BUS_WIDTH_1)
2921 bw /= 8;
2922
2923 return bw;
2924}
2925
2926static int msmsdcc_msm_bus_get_vote_for_bw(struct msmsdcc_host *host,
2927 unsigned int bw)
2928{
2929 unsigned int *table = host->plat->msm_bus_voting_data->bw_vecs;
2930 unsigned int size = host->plat->msm_bus_voting_data->bw_vecs_size;
2931 int i;
2932
2933 if (host->msm_bus_vote.is_max_bw_needed && bw)
2934 return host->msm_bus_vote.max_bw_vote;
2935
2936 for (i = 0; i < size; i++) {
2937 if (bw <= table[i])
2938 break;
2939 }
2940
2941 if (i && (i == size))
2942 i--;
2943
2944 return i;
2945}
2946
2947static int msmsdcc_msm_bus_register(struct msmsdcc_host *host)
2948{
2949 int rc = 0;
2950 struct msm_bus_scale_pdata *use_cases;
2951
2952 if (host->plat->msm_bus_voting_data &&
2953 host->plat->msm_bus_voting_data->use_cases &&
2954 host->plat->msm_bus_voting_data->bw_vecs &&
2955 host->plat->msm_bus_voting_data->bw_vecs_size) {
2956 use_cases = host->plat->msm_bus_voting_data->use_cases;
2957 host->msm_bus_vote.client_handle =
2958 msm_bus_scale_register_client(use_cases);
2959 } else {
2960 return 0;
2961 }
2962
2963 if (!host->msm_bus_vote.client_handle) {
2964 pr_err("%s: msm_bus_scale_register_client() failed\n",
2965 mmc_hostname(host->mmc));
2966 rc = -EFAULT;
2967 } else {
2968 /* cache the vote index for minimum and maximum bandwidth */
2969 host->msm_bus_vote.min_bw_vote =
2970 msmsdcc_msm_bus_get_vote_for_bw(host, 0);
2971 host->msm_bus_vote.max_bw_vote =
2972 msmsdcc_msm_bus_get_vote_for_bw(host, UINT_MAX);
2973 }
2974
2975 return rc;
2976}
2977
2978static void msmsdcc_msm_bus_unregister(struct msmsdcc_host *host)
2979{
2980 if (host->msm_bus_vote.client_handle)
2981 msm_bus_scale_unregister_client(
2982 host->msm_bus_vote.client_handle);
2983}
2984
2985/*
2986 * This function must be called with host lock acquired.
2987 * Caller of this function should also ensure that msm bus client
2988 * handle is not null.
2989 */
2990static inline int msmsdcc_msm_bus_set_vote(struct msmsdcc_host *host,
2991 int vote,
2992 unsigned long flags)
2993{
2994 int rc = 0;
2995
2996 if (vote != host->msm_bus_vote.curr_vote) {
2997 spin_unlock_irqrestore(&host->lock, flags);
2998 rc = msm_bus_scale_client_update_request(
2999 host->msm_bus_vote.client_handle, vote);
3000 if (rc)
3001 pr_err("%s: msm_bus_scale_client_update_request() failed."
3002 " bus_client_handle=0x%x, vote=%d, err=%d\n",
3003 mmc_hostname(host->mmc),
3004 host->msm_bus_vote.client_handle, vote, rc);
3005 spin_lock_irqsave(&host->lock, flags);
3006 if (!rc)
3007 host->msm_bus_vote.curr_vote = vote;
3008 }
3009
3010 return rc;
3011}
3012
3013/*
3014 * Internal work. Work to set 0 bandwidth for msm bus.
3015 */
3016static void msmsdcc_msm_bus_work(struct work_struct *work)
3017{
3018 struct msmsdcc_host *host = container_of(work,
3019 struct msmsdcc_host,
3020 msm_bus_vote.vote_work.work);
3021 unsigned long flags;
3022
3023 if (!host->msm_bus_vote.client_handle)
3024 return;
3025
3026 spin_lock_irqsave(&host->lock, flags);
3027 /* don't vote for 0 bandwidth if any request is in progress */
3028 if (!host->curr.mrq)
3029 msmsdcc_msm_bus_set_vote(host,
3030 host->msm_bus_vote.min_bw_vote, flags);
3031 else
3032 pr_warning("%s: %s: SDCC transfer in progress. skipping"
3033 " bus voting to 0 bandwidth\n",
3034 mmc_hostname(host->mmc), __func__);
3035 spin_unlock_irqrestore(&host->lock, flags);
3036}
3037
3038/*
3039 * This function cancels any scheduled delayed work
3040 * and sets the bus vote based on ios argument.
3041 * If "ios" argument is NULL, bandwidth required is 0 else
3042 * calculate the bandwidth based on ios parameters.
3043 */
3044static void msmsdcc_msm_bus_cancel_work_and_set_vote(
3045 struct msmsdcc_host *host,
3046 struct mmc_ios *ios)
3047{
3048 unsigned long flags;
3049 unsigned int bw;
3050 int vote;
3051
3052 if (!host->msm_bus_vote.client_handle)
3053 return;
3054
3055 bw = ios ? msmsdcc_get_bw_required(host, ios) : 0;
3056
3057 cancel_delayed_work_sync(&host->msm_bus_vote.vote_work);
3058 spin_lock_irqsave(&host->lock, flags);
3059 vote = msmsdcc_msm_bus_get_vote_for_bw(host, bw);
3060 msmsdcc_msm_bus_set_vote(host, vote, flags);
3061 spin_unlock_irqrestore(&host->lock, flags);
3062}
3063
3064/* This function queues a work which will set the bandwidth requiement to 0 */
3065static void msmsdcc_msm_bus_queue_work(struct msmsdcc_host *host)
3066{
3067 unsigned long flags;
3068
3069 if (!host->msm_bus_vote.client_handle)
3070 return;
3071
3072 spin_lock_irqsave(&host->lock, flags);
3073 if (host->msm_bus_vote.min_bw_vote != host->msm_bus_vote.curr_vote)
3074 queue_delayed_work(system_nrt_wq,
3075 &host->msm_bus_vote.vote_work,
3076 msecs_to_jiffies(MSM_MMC_BUS_VOTING_DELAY));
3077 spin_unlock_irqrestore(&host->lock, flags);
3078}
3079
San Mehat9d2bd732009-09-22 16:44:22 -07003080static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303081msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
3082{
3083 struct mmc_host *mmc = host->mmc;
3084
3085 /*
3086 * SDIO_AL clients has different mechanism of handling LPM through
3087 * sdio_al driver itself. The sdio wakeup interrupt is configured as
3088 * part of that. Here, we are interested only in clients like WLAN.
3089 */
3090 if (!(mmc->card && mmc_card_sdio(mmc->card))
3091 || host->plat->is_sdio_al_client)
3092 goto out;
3093
3094 if (!host->sdcc_suspended) {
3095 /*
3096 * When MSM is not in power collapse and we
3097 * are disabling clocks, enable bit 22 in MASK0
3098 * to handle asynchronous SDIO interrupts.
3099 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05303100 if (enable_wakeup_irq) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303101 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303102 mb();
3103 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303104 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303105 msmsdcc_sync_reg_wr(host);
3106 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303107 goto out;
3108 } else if (!mmc_card_wake_sdio_irq(mmc)) {
3109 /*
3110 * Wakeup MSM only if SDIO function drivers set
3111 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
3112 */
3113 goto out;
3114 }
3115
3116 if (enable_wakeup_irq) {
3117 if (!host->plat->sdiowakeup_irq) {
3118 /*
3119 * When there is no gpio line that can be configured
3120 * as wakeup interrupt handle it by configuring
3121 * asynchronous sdio interrupts and DAT1 line.
3122 */
3123 writel_relaxed(MCI_SDIOINTMASK,
3124 host->base + MMCIMASK0);
3125 mb();
Subhash Jadavanic9b85752012-04-13 11:16:49 +05303126 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303127 /* configure sdcc core interrupt as wakeup interrupt */
3128 msmsdcc_enable_irq_wake(host);
3129 } else {
3130 /* Let gpio line handle wakeup interrupt */
3131 writel_relaxed(0, host->base + MMCIMASK0);
3132 mb();
3133 if (host->sdio_wakeupirq_disabled) {
3134 host->sdio_wakeupirq_disabled = 0;
3135 /* configure gpio line as wakeup interrupt */
3136 msmsdcc_enable_irq_wake(host);
3137 enable_irq(host->plat->sdiowakeup_irq);
3138 }
3139 }
3140 } else {
3141 if (!host->plat->sdiowakeup_irq) {
3142 /*
3143 * We may not have cleared bit 22 in the interrupt
3144 * handler as the clocks might be off at that time.
3145 */
3146 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303147 msmsdcc_sync_reg_wr(host);
Subhash Jadavanic9b85752012-04-13 11:16:49 +05303148 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303149 msmsdcc_disable_irq_wake(host);
3150 } else if (!host->sdio_wakeupirq_disabled) {
3151 disable_irq_nosync(host->plat->sdiowakeup_irq);
3152 msmsdcc_disable_irq_wake(host);
3153 host->sdio_wakeupirq_disabled = 1;
3154 }
3155 }
3156out:
3157 return;
San Mehat9d2bd732009-09-22 16:44:22 -07003158}
3159
3160static void
3161msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
3162{
3163 struct msmsdcc_host *host = mmc_priv(mmc);
3164 u32 clk = 0, pwr = 0;
3165 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08003166 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003167 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07003168
Sahitya Tummala7a892482011-01-18 11:22:49 +05303169
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303170 /*
3171 * Disable SDCC core interrupt until set_ios is completed.
3172 * This avoids any race conditions with interrupt raised
3173 * when turning on/off the clocks. One possible
3174 * scenario is SDIO operational interrupt while the clock
3175 * is turned off.
Asutosh Dasf5298c32012-04-03 14:51:47 +05303176 * host->lock is being released intermittently below.
3177 * Thus, prevent concurrent access to host.
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303178 */
3179
Asutosh Dasf5298c32012-04-03 14:51:47 +05303180 mutex_lock(&host->clk_mutex);
3181 DBG(host, "ios->clock = %u\n", ios->clock);
San Mehat9d2bd732009-09-22 16:44:22 -07003182 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303183 if (!host->sdcc_irq_disabled) {
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05303184 disable_irq_nosync(host->core_irqres->start);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303185 host->sdcc_irq_disabled = 1;
3186 }
San Mehatd0719e52009-12-03 10:58:54 -08003187 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07003188
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05303189 /* Make sure sdcc core irq is synchronized */
3190 synchronize_irq(host->core_irqres->start);
3191
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303192 pwr = msmsdcc_setup_pwr(host, ios);
3193
3194 spin_lock_irqsave(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07003195 if (ios->clock) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303196 spin_unlock_irqrestore(&host->lock, flags);
3197 rc = msmsdcc_setup_clocks(host, true);
3198 if (rc)
3199 goto out;
3200 spin_lock_irqsave(&host->lock, flags);
3201 writel_relaxed(host->mci_irqenable, host->base + MMCIMASK0);
3202 mb();
3203 msmsdcc_cfg_sdio_wakeup(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003204 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303205
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003206 /*
3207 * For DDR50 mode, controller needs clock rate to be
3208 * double than what is required on the SD card CLK pin.
Subhash Jadavani2226d262012-10-09 20:01:56 +05303209 *
3210 * Setting DDR timing mode in controller before setting the
3211 * clock rate will make sure that card don't see the double
3212 * clock rate even for very small duration. Some eMMC
3213 * cards seems to lock up if they see clock frequency > 52MHz.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003214 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05303215 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Subhash Jadavani2226d262012-10-09 20:01:56 +05303216 u32 clk;
3217
3218 clk = readl_relaxed(host->base + MMCICLOCK);
3219 clk &= ~(0x7 << 14); /* clear SELECT_IN field */
3220 clk |= (3 << 14); /* set DDR timing mode */
3221 writel_relaxed(clk, host->base + MMCICLOCK);
3222 msmsdcc_sync_reg_wr(host);
3223
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003224 /*
3225 * Make sure that we don't double the clock if
3226 * doubled clock rate is already set
3227 */
3228 if (!host->ddr_doubled_clk_rate ||
3229 (host->ddr_doubled_clk_rate &&
3230 (host->ddr_doubled_clk_rate != ios->clock))) {
3231 host->ddr_doubled_clk_rate =
3232 msmsdcc_get_sup_clk_rate(
3233 host, (ios->clock * 2));
3234 clock = host->ddr_doubled_clk_rate;
3235 }
3236 } else {
3237 host->ddr_doubled_clk_rate = 0;
3238 }
3239
3240 if (clock != host->clk_rate) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05303241 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003242 rc = clk_set_rate(host->clk, clock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303243 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003244 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303245 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003246 mmc_hostname(mmc), clock);
3247 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303248 host->reg_write_delay =
3249 (1 + ((3 * USEC_PER_SEC) /
3250 (host->clk_rate ? host->clk_rate :
3251 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003252 }
3253 /*
3254 * give atleast 2 MCLK cycles delay for clocks
3255 * and SDCC core to stabilize
3256 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05303257 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003258 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003259 clk |= MCI_CLK_ENABLE;
3260 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003261 if (ios->bus_width == MMC_BUS_WIDTH_8)
3262 clk |= MCI_CLK_WIDEBUS_8;
3263 else if (ios->bus_width == MMC_BUS_WIDTH_4)
3264 clk |= MCI_CLK_WIDEBUS_4;
3265 else
3266 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07003267
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003268 if (msmsdcc_is_pwrsave(host))
3269 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07003270
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003271 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07003272
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003273 host->tuning_needed = 0;
3274 /*
3275 * Select the controller timing mode according
3276 * to current bus speed mode
3277 */
Subhash Jadavanif97d2992012-07-13 14:47:47 +05303278 if (host->clk_rate > (100 * 1000 * 1000) &&
3279 (ios->timing == MMC_TIMING_UHS_SDR104 ||
3280 ios->timing == MMC_TIMING_MMC_HS200)) {
3281 /* Card clock frequency must be > 100MHz to enable tuning */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003282 clk |= (4 << 14);
3283 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05303284 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003285 clk |= (3 << 14);
3286 } else {
3287 clk |= (2 << 14); /* feedback clock */
San Mehat9d2bd732009-09-22 16:44:22 -07003288 }
3289
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003290 /* Select free running MCLK as input clock of cm_dll_sdc4 */
3291 clk |= (2 << 23);
San Mehat9d2bd732009-09-22 16:44:22 -07003292
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003293 if (host->io_pad_pwr_switch)
3294 clk |= IO_PAD_PWR_SWITCH;
3295
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303296 /* Don't write into registers if clocks are disabled */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303297 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303298 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
3299 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303300 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003301 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303302 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
3303 host->pwr = pwr;
3304 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303305 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003306 }
San Mehat9d2bd732009-09-22 16:44:22 -07003307 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003308
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303309 if (!(clk & MCI_CLK_ENABLE) && atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303310 msmsdcc_cfg_sdio_wakeup(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303311 spin_unlock_irqrestore(&host->lock, flags);
3312 /*
3313 * May get a wake-up interrupt the instant we disable the
3314 * clocks. This would disable the wake-up interrupt.
3315 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003316 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303317 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003318 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303319
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303320 if (host->tuning_in_progress)
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303321 WARN(!atomic_read(&host->clks_on),
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303322 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303323
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303324 /* Let interrupts be disabled if the host is powered off */
3325 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
3326 enable_irq(host->core_irqres->start);
3327 host->sdcc_irq_disabled = 0;
3328 }
San Mehat4adbbcc2009-11-08 13:00:37 -08003329 spin_unlock_irqrestore(&host->lock, flags);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303330out:
Asutosh Dasf5298c32012-04-03 14:51:47 +05303331 mutex_unlock(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07003332}
3333
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003334int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
3335{
3336 struct msmsdcc_host *host = mmc_priv(mmc);
3337 u32 clk;
3338
3339 clk = readl_relaxed(host->base + MMCICLOCK);
3340 pr_debug("Changing to pwr_save=%d", pwrsave);
3341 if (pwrsave && msmsdcc_is_pwrsave(host))
3342 clk |= MCI_CLK_PWRSAVE;
3343 else
3344 clk &= ~MCI_CLK_PWRSAVE;
3345 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303346 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003347
3348 return 0;
3349}
3350
3351static int msmsdcc_get_ro(struct mmc_host *mmc)
3352{
3353 int status = -ENOSYS;
3354 struct msmsdcc_host *host = mmc_priv(mmc);
3355
3356 if (host->plat->wpswitch) {
3357 status = host->plat->wpswitch(mmc_dev(mmc));
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05303358 } else if (gpio_is_valid(host->plat->wpswitch_gpio)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003359 status = gpio_request(host->plat->wpswitch_gpio,
3360 "SD_WP_Switch");
3361 if (status) {
3362 pr_err("%s: %s: Failed to request GPIO %d\n",
3363 mmc_hostname(mmc), __func__,
3364 host->plat->wpswitch_gpio);
3365 } else {
3366 status = gpio_direction_input(
3367 host->plat->wpswitch_gpio);
3368 if (!status) {
3369 /*
3370 * Wait for atleast 300ms as debounce
3371 * time for GPIO input to stabilize.
3372 */
3373 msleep(300);
3374 status = gpio_get_value_cansleep(
3375 host->plat->wpswitch_gpio);
Sujit Reddy Thumma8f912ea2012-06-22 16:18:43 +05303376 status ^= !host->plat->is_wpswitch_active_low;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003377 }
3378 gpio_free(host->plat->wpswitch_gpio);
3379 }
3380 }
3381
3382 if (status < 0)
3383 status = -ENOSYS;
3384 pr_debug("%s: Card read-only status %d\n", __func__, status);
3385
3386 return status;
San Mehat9d2bd732009-09-22 16:44:22 -07003387}
3388
3389static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
3390{
3391 struct msmsdcc_host *host = mmc_priv(mmc);
3392 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003393
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303394 /*
3395 * We may come here with clocks turned off in that case don't
3396 * attempt to write into MASK0 register. While turning on the
3397 * clocks mci_irqenable will be written to MASK0 register.
3398 */
San Mehat9d2bd732009-09-22 16:44:22 -07003399
3400 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003401 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003402 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303403 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303404 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003405 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303406 mb();
3407 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003408 } else {
3409 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303410 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303411 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003412 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303413 mb();
3414 }
San Mehat9d2bd732009-09-22 16:44:22 -07003415 }
3416 spin_unlock_irqrestore(&host->lock, flags);
3417}
3418
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003419#ifdef CONFIG_PM_RUNTIME
subhashj245831e2012-04-30 18:46:17 +05303420static void msmsdcc_print_rpm_info(struct msmsdcc_host *host)
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003421{
subhashj245831e2012-04-30 18:46:17 +05303422 struct device *dev = mmc_dev(host->mmc);
3423
Subhash Jadavani1371d192012-08-16 18:46:57 +05303424 pr_info("%s: PM: sdcc_suspended=%d, pending_resume=%d, sdcc_suspending=%d\n",
3425 mmc_hostname(host->mmc), host->sdcc_suspended,
3426 host->pending_resume, host->sdcc_suspending);
subhashj245831e2012-04-30 18:46:17 +05303427 pr_info("%s: RPM: runtime_status=%d, usage_count=%d,"
3428 " is_suspended=%d, disable_depth=%d, runtime_error=%d,"
3429 " request_pending=%d, request=%d\n",
3430 mmc_hostname(host->mmc), dev->power.runtime_status,
3431 atomic_read(&dev->power.usage_count),
3432 dev->power.is_suspended, dev->power.disable_depth,
3433 dev->power.runtime_error, dev->power.request_pending,
3434 dev->power.request);
3435}
3436
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003437static int msmsdcc_enable(struct mmc_host *mmc)
3438{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003439 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003440 struct device *dev = mmc->parent;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003441 struct msmsdcc_host *host = mmc_priv(mmc);
3442
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303443 msmsdcc_pm_qos_update_latency(host, 1);
3444
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003445 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303446 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003447
Subhash Jadavani1371d192012-08-16 18:46:57 +05303448 if (host->sdcc_suspended && host->pending_resume) {
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003449 host->pending_resume = false;
3450 pm_runtime_get_noresume(dev);
3451 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303452 goto skip_get_sync;
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003453 }
3454
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303455 if (dev->power.runtime_status == RPM_SUSPENDING) {
3456 if (mmc->suspend_task == current) {
3457 pm_runtime_get_noresume(dev);
3458 goto out;
3459 }
Sujit Reddy Thumma112bd752012-06-20 12:29:45 +05303460 } else if (dev->power.runtime_status == RPM_RESUMING) {
3461 pm_runtime_get_noresume(dev);
3462 goto out;
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303463 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003464
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303465 rc = pm_runtime_get_sync(dev);
3466
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303467skip_get_sync:
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303468 if (rc < 0) {
Subhash Jadavani1371d192012-08-16 18:46:57 +05303469 WARN(1, "%s: %s: failed with error %d\n", mmc_hostname(mmc),
3470 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303471 msmsdcc_print_rpm_info(host);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303472 return rc;
3473 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303474out:
3475 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303476 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003477}
3478
Steve Mucklef132c6c2012-06-06 18:30:57 -07003479static int msmsdcc_disable(struct mmc_host *mmc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003480{
3481 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303482 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003483
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303484 msmsdcc_pm_qos_update_latency(host, 0);
3485
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303486 if (mmc->card && mmc_card_sdio(mmc->card)) {
3487 rc = 0;
3488 goto out;
3489 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303490
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303491 if (host->plat->disable_runtime_pm)
3492 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003493
3494 rc = pm_runtime_put_sync(mmc->parent);
3495
Subhash Jadavani1371d192012-08-16 18:46:57 +05303496 if (rc < 0) {
3497 WARN(1, "%s: %s: failed with error %d\n", mmc_hostname(mmc),
3498 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303499 msmsdcc_print_rpm_info(host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003500 return rc;
3501 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303502
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303503out:
3504 msmsdcc_msm_bus_queue_work(host);
3505 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003506}
3507#else
subhashj245831e2012-04-30 18:46:17 +05303508static void msmsdcc_print_rpm_info(struct msmsdcc_host *host) {}
3509
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303510static int msmsdcc_enable(struct mmc_host *mmc)
3511{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003512 struct device *dev = mmc->parent;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303513 struct msmsdcc_host *host = mmc_priv(mmc);
Sujit Reddy Thumma7f5051c2012-05-04 10:14:07 +05303514 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303515
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303516 msmsdcc_pm_qos_update_latency(host, 1);
3517
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303518 if (mmc->card && mmc_card_sdio(mmc->card)) {
3519 rc = 0;
3520 goto out;
3521 }
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003522
3523 if (host->sdcc_suspended && host->pending_resume) {
3524 host->pending_resume = false;
3525 rc = msmsdcc_runtime_resume(dev);
3526 goto out;
3527 }
3528
Asutosh Dasf5298c32012-04-03 14:51:47 +05303529 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303530 rc = msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303531 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303532
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003533out:
3534 if (rc < 0) {
3535 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3536 __func__, rc);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303537 msmsdcc_pm_qos_update_latency(host, 0);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003538 return rc;
3539 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303540 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303541 return 0;
3542}
3543
Steve Mucklef132c6c2012-06-06 18:30:57 -07003544static int msmsdcc_disable(struct mmc_host *mmc)
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303545{
3546 struct msmsdcc_host *host = mmc_priv(mmc);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303547 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303548
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303549 msmsdcc_pm_qos_update_latency(host, 0);
3550
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303551 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303552 goto out;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303553
Asutosh Dasf5298c32012-04-03 14:51:47 +05303554 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303555 rc = msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303556 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303557
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303558 if (rc) {
3559 msmsdcc_pm_qos_update_latency(host, 1);
3560 return rc;
3561 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303562out:
3563 msmsdcc_msm_bus_queue_work(host);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303564 return rc;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303565}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003566#endif
3567
Subhash Jadavani937c7502012-06-01 15:34:46 +05303568static int msmsdcc_switch_io_voltage(struct mmc_host *mmc,
3569 struct mmc_ios *ios)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003570{
3571 struct msmsdcc_host *host = mmc_priv(mmc);
3572 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303573 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003574
Subhash Jadavani937c7502012-06-01 15:34:46 +05303575 switch (ios->signal_voltage) {
3576 case MMC_SIGNAL_VOLTAGE_330:
3577 /* Set VDD IO to high voltage range (2.7v - 3.6v) */
3578 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Subhash Jadavanibf09d802012-08-11 18:11:57 +05303579 if (!rc)
3580 msmsdcc_update_io_pad_pwr_switch(host);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303581 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303582 case MMC_SIGNAL_VOLTAGE_180:
3583 break;
3584 case MMC_SIGNAL_VOLTAGE_120:
3585 /*
3586 * For eMMC cards, VDD_IO voltage range must be changed
3587 * only if it operates in HS200 SDR 1.2V mode or in
3588 * DDR 1.2V mode.
3589 */
3590 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_SET_LEVEL, 1200000);
Subhash Jadavanibf09d802012-08-11 18:11:57 +05303591 if (!rc)
3592 msmsdcc_update_io_pad_pwr_switch(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003593 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303594 default:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003595 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303596 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003597 goto out;
3598 }
San Mehat9d2bd732009-09-22 16:44:22 -07003599
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003600 /*
3601 * If we are here means voltage switch from high voltage to
3602 * low voltage is required
3603 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303604 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003605
3606 /*
3607 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
3608 * register until they become all zeros.
3609 */
3610 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303611 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003612 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
3613 mmc_hostname(mmc), __func__);
3614 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07003615 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003616
3617 /* Stop SD CLK output. */
3618 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3619 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303620 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003621 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003622
3623 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05303624 * Switch VDD Io from high voltage range (2.7v - 3.6v) to
3625 * low voltage range (1.7v - 1.95v).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003626 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303627 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303628 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003629 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003630
Subhash Jadavanibf09d802012-08-11 18:11:57 +05303631 msmsdcc_update_io_pad_pwr_switch(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003632
3633 /* Wait 5 ms for the voltage regulater in the card to become stable. */
3634 usleep_range(5000, 5500);
3635
3636 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303637 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003638 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3639 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303640 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003641 spin_unlock_irqrestore(&host->lock, flags);
3642
3643 /*
3644 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
3645 * don't become all ones within 1 ms then a Voltage Switch
3646 * sequence has failed and a power cycle to the card is required.
3647 * Otherwise Voltage Switch sequence is completed successfully.
3648 */
3649 usleep_range(1000, 1500);
3650
3651 spin_lock_irqsave(&host->lock, flags);
3652 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
3653 != (0xF << 1)) {
3654 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
3655 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303656 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003657 goto out_unlock;
3658 }
3659
3660out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303661 /* Enable PWRSAVE */
3662 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3663 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303664 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003665 spin_unlock_irqrestore(&host->lock, flags);
3666out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303667 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003668}
3669
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303670static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003671{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003672 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003673
3674 /* Program the MCLK value to MCLK_FREQ bit field */
3675 if (host->clk_rate <= 112000000)
3676 mclk_freq = 0;
3677 else if (host->clk_rate <= 125000000)
3678 mclk_freq = 1;
3679 else if (host->clk_rate <= 137000000)
3680 mclk_freq = 2;
3681 else if (host->clk_rate <= 150000000)
3682 mclk_freq = 3;
3683 else if (host->clk_rate <= 162000000)
3684 mclk_freq = 4;
3685 else if (host->clk_rate <= 175000000)
3686 mclk_freq = 5;
3687 else if (host->clk_rate <= 187000000)
3688 mclk_freq = 6;
3689 else if (host->clk_rate <= 200000000)
3690 mclk_freq = 7;
3691
3692 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3693 & ~(7 << 24)) | (mclk_freq << 24)),
3694 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003695}
3696
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303697/* Initialize the DLL (Programmable Delay Line ) */
3698static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003699{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003700 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303701 unsigned long flags;
3702 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003703
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303704 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003705 /*
3706 * Make sure that clock is always enabled when DLL
3707 * tuning is in progress. Keeping PWRSAVE ON may
3708 * turn off the clock. So let's disable the PWRSAVE
3709 * here and re-enable it once tuning is completed.
3710 */
3711 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3712 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303713 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303714
3715 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3716 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3717 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3718
3719 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3720 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3721 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3722
3723 msmsdcc_cm_sdc4_dll_set_freq(host);
3724
3725 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3726 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3727 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3728
3729 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3730 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3731 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3732
3733 /* Set DLL_EN bit to 1. */
3734 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3735 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3736
3737 /* Set CK_OUT_EN bit to 1. */
3738 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3739 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3740
3741 wait_cnt = 50;
3742 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3743 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3744 /* max. wait for 50us sec for LOCK bit to be set */
3745 if (--wait_cnt == 0) {
3746 pr_err("%s: %s: DLL failed to LOCK\n",
3747 mmc_hostname(host->mmc), __func__);
3748 rc = -ETIMEDOUT;
3749 goto out;
3750 }
3751 /* wait for 1us before polling again */
3752 udelay(1);
3753 }
3754
3755out:
3756 /* re-enable PWRSAVE */
3757 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3758 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303759 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303760 spin_unlock_irqrestore(&host->lock, flags);
3761
3762 return rc;
3763}
3764
3765static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3766 u8 poll)
3767{
3768 int rc = 0;
3769 u32 wait_cnt = 50;
3770 u8 ck_out_en = 0;
3771
3772 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3773 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3774 MCI_CK_OUT_EN);
3775
3776 while (ck_out_en != poll) {
3777 if (--wait_cnt == 0) {
3778 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3779 mmc_hostname(host->mmc), __func__, poll);
3780 rc = -ETIMEDOUT;
3781 goto out;
3782 }
3783 udelay(1);
3784
3785 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3786 MCI_CK_OUT_EN);
3787 }
3788out:
3789 return rc;
3790}
3791
3792/*
3793 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3794 * calibration sequence. This function should be called before
3795 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3796 * commands (CMD17/CMD18).
3797 *
3798 * This function gets called when host spinlock acquired.
3799 */
3800static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3801{
3802 int rc = 0;
3803 u32 config;
3804
3805 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3806 config |= MCI_CDR_EN;
3807 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3808 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3809
3810 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3811 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3812 if (rc)
3813 goto err_out;
3814
3815 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3816 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3817 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3818
3819 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3820 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3821 if (rc)
3822 goto err_out;
3823
3824 goto out;
3825
3826err_out:
3827 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3828out:
3829 return rc;
3830}
3831
3832static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3833 u8 phase)
3834{
3835 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303836 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3837 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3838 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303839 unsigned long flags;
3840 u32 config;
3841
3842 spin_lock_irqsave(&host->lock, flags);
3843
3844 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3845 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3846 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3847 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3848
3849 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3850 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3851 if (rc)
3852 goto err_out;
3853
3854 /*
3855 * Write the selected DLL clock output phase (0 ... 15)
3856 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
3857 */
3858 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3859 & ~(0xF << 20))
3860 | (grey_coded_phase_table[phase] << 20)),
3861 host->base + MCI_DLL_CONFIG);
3862
3863 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3864 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3865 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3866
3867 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3868 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3869 if (rc)
3870 goto err_out;
3871
3872 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3873 config |= MCI_CDR_EN;
3874 config &= ~MCI_CDR_EXT_EN;
3875 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3876 goto out;
3877
3878err_out:
3879 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3880 mmc_hostname(host->mmc), __func__, phase);
3881out:
3882 spin_unlock_irqrestore(&host->lock, flags);
3883 return rc;
3884}
3885
3886/*
3887 * Find out the greatest range of consecuitive selected
3888 * DLL clock output phases that can be used as sampling
3889 * setting for SD3.0 UHS-I card read operation (in SDR104
3890 * timing mode) or for eMMC4.5 card read operation (in HS200
3891 * timing mode).
3892 * Select the 3/4 of the range and configure the DLL with the
3893 * selected DLL clock output phase.
3894*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303895static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303896 u8 *phase_table, u8 total_phases)
3897{
Subhash Jadavani6159c622012-03-15 19:05:55 +05303898 #define MAX_PHASES 16
Subhash Jadavani34187042012-03-02 10:59:49 +05303899 int ret;
Subhash Jadavani6159c622012-03-15 19:05:55 +05303900 u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
3901 u8 phases_per_row[MAX_PHASES] = {0};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303902 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303903 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3904 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303905
Subhash Jadavani6159c622012-03-15 19:05:55 +05303906 if (!total_phases || (total_phases > MAX_PHASES)) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303907 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3908 mmc_hostname(host->mmc), __func__, total_phases);
3909 return -EINVAL;
3910 }
3911
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303912 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303913 ranges[row_index][col_index] = phase_table[cnt];
3914 phases_per_row[row_index] += 1;
3915 col_index++;
3916
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303917 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303918 continue;
3919 /* check if next phase in phase_table is consecutive or not */
3920 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3921 row_index++;
3922 col_index = 0;
3923 }
3924 }
3925
Subhash Jadavani6159c622012-03-15 19:05:55 +05303926 if (row_index >= MAX_PHASES)
3927 return -EINVAL;
3928
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303929 /* Check if phase-0 is present in first valid window? */
3930 if (!ranges[0][0]) {
3931 phase_0_found = true;
3932 phase_0_raw_index = 0;
3933 /* Check if cycle exist between 2 valid windows */
3934 for (cnt = 1; cnt <= row_index; cnt++) {
3935 if (phases_per_row[cnt]) {
Subhash Jadavani6159c622012-03-15 19:05:55 +05303936 for (i = 0; i < phases_per_row[cnt]; i++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303937 if (ranges[cnt][i] == 15) {
3938 phase_15_found = true;
3939 phase_15_raw_index = cnt;
3940 break;
3941 }
3942 }
3943 }
3944 }
3945 }
3946
3947 /* If 2 valid windows form cycle then merge them as single window */
3948 if (phase_0_found && phase_15_found) {
3949 /* number of phases in raw where phase 0 is present */
3950 u8 phases_0 = phases_per_row[phase_0_raw_index];
3951 /* number of phases in raw where phase 15 is present */
3952 u8 phases_15 = phases_per_row[phase_15_raw_index];
3953
Subhash Jadavani6159c622012-03-15 19:05:55 +05303954 if (phases_0 + phases_15 >= MAX_PHASES)
3955 /*
3956 * If there are more than 1 phase windows then total
3957 * number of phases in both the windows should not be
3958 * more than or equal to MAX_PHASES.
3959 */
3960 return -EINVAL;
3961
3962 /* Merge 2 cyclic windows */
3963 i = phases_15;
3964 for (cnt = 0; cnt < phases_0; cnt++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303965 ranges[phase_15_raw_index][i] =
3966 ranges[phase_0_raw_index][cnt];
Subhash Jadavani6159c622012-03-15 19:05:55 +05303967 if (++i >= MAX_PHASES)
3968 break;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303969 }
Subhash Jadavani6159c622012-03-15 19:05:55 +05303970
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303971 phases_per_row[phase_0_raw_index] = 0;
3972 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
3973 }
3974
3975 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303976 if (phases_per_row[cnt] > curr_max) {
3977 curr_max = phases_per_row[cnt];
3978 selected_row_index = cnt;
3979 }
3980 }
3981
Subhash Jadavani6159c622012-03-15 19:05:55 +05303982 i = ((curr_max * 3) / 4);
3983 if (i)
3984 i--;
3985
Subhash Jadavani34187042012-03-02 10:59:49 +05303986 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303987
Subhash Jadavani6159c622012-03-15 19:05:55 +05303988 if (ret >= MAX_PHASES) {
3989 ret = -EINVAL;
3990 pr_err("%s: %s: invalid phase selected=%d\n",
3991 mmc_hostname(host->mmc), __func__, ret);
3992 }
3993
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303994 return ret;
3995}
3996
Girish K Sa3f41692012-02-29 12:00:09 +05303997static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303998{
3999 int rc = 0;
4000 struct msmsdcc_host *host = mmc_priv(mmc);
4001 unsigned long flags;
4002 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304003 const u32 *tuning_block_pattern = tuning_block_64;
4004 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304005
4006 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
4007
4008 /* Tuning is only required for SDR104 modes */
4009 if (!host->tuning_needed) {
4010 rc = 0;
4011 goto exit;
4012 }
4013
4014 spin_lock_irqsave(&host->lock, flags);
4015 WARN(!host->pwr, "SDCC power is turned off\n");
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304016 WARN(!atomic_read(&host->clks_on), "SDCC clocks are turned off\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304017 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
4018
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304019 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304020 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
4021 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
4022 tuning_block_pattern = tuning_block_128;
4023 size = sizeof(tuning_block_128);
4024 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304025 spin_unlock_irqrestore(&host->lock, flags);
4026
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004027 /* first of all reset the tuning block */
4028 rc = msmsdcc_init_cm_sdc4_dll(host);
4029 if (rc)
4030 goto out;
4031
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304032 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004033 if (!data_buf) {
4034 rc = -ENOMEM;
4035 goto out;
4036 }
4037
4038 phase = 0;
4039 do {
4040 struct mmc_command cmd = {0};
4041 struct mmc_data data = {0};
4042 struct mmc_request mrq = {
4043 .cmd = &cmd,
4044 .data = &data
4045 };
4046 struct scatterlist sg;
4047
4048 /* set the phase in delay line hw block */
4049 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
4050 if (rc)
4051 goto kfree;
4052
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304053 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004054 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
4055
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304056 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004057 data.blocks = 1;
4058 data.flags = MMC_DATA_READ;
4059 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
4060
4061 data.sg = &sg;
4062 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304063 sg_init_one(&sg, data_buf, size);
4064 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004065 mmc_wait_for_req(mmc, &mrq);
4066
4067 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304068 !memcmp(data_buf, tuning_block_pattern, size)) {
4069 /* tuning is successful at this tuning point */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004070 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304071 pr_debug("%s: %s: found good phase = %d\n",
4072 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004073 }
4074 } while (++phase < 16);
4075
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004076 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05304077 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304078 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05304079 if (rc < 0)
4080 goto kfree;
4081 else
4082 phase = (u8)rc;
4083
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004084 /*
4085 * Finally set the selected phase in delay
4086 * line hw block.
4087 */
4088 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
4089 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304090 goto kfree;
4091 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
4092 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004093 } else {
4094 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304095 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004096 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304097 msmsdcc_dump_sdcc_state(host);
4098 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004099 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004100
4101kfree:
4102 kfree(data_buf);
4103out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304104 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304105 host->tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304106 spin_unlock_irqrestore(&host->lock, flags);
4107exit:
4108 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004109 return rc;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04004110}
4111
Asutosh Dasebd7d092012-07-09 19:08:26 +05304112/*
4113 * Work around of the unavailability of a power_reset functionality in SD cards
4114 * by turning the OFF & back ON the regulators supplying the SD card.
4115 */
4116void msmsdcc_hw_reset(struct mmc_host *mmc)
4117{
4118 struct mmc_card *card = mmc->card;
4119 struct msmsdcc_host *host = mmc_priv(mmc);
4120 int rc;
4121
4122 /* Write-protection bits would be lost on a hardware reset in emmc */
4123 if (!card || !mmc_card_sd(card))
4124 return;
4125
4126 /*
4127 * Continuing on failing to disable regulator would lead to a panic
4128 * anyway, since the commands would fail and console would be flooded
4129 * with prints, eventually leading to a watchdog bark
4130 */
4131 rc = msmsdcc_setup_vreg(host, false, false);
4132 if (rc) {
4133 pr_err("%s: %s disable regulator: failed: %d\n",
4134 mmc_hostname(mmc), __func__, rc);
4135 BUG_ON(rc);
4136 }
4137
4138 /* 10ms delay for the supply to reach the desired voltage level */
4139 usleep_range(10000, 12000);
4140
4141 /*
4142 * Continuing on failing to enable regulator would lead to a panic
4143 * anyway, since the commands would fail and console would be flooded
4144 * with prints, eventually leading to a watchdog bark
4145 */
4146 rc = msmsdcc_setup_vreg(host, true, false);
4147 if (rc) {
4148 pr_err("%s: %s enable regulator: failed: %d\n",
4149 mmc_hostname(mmc), __func__, rc);
4150 BUG_ON(rc);
4151 }
4152
4153 /* 10ms delay for the supply to reach the desired voltage level */
4154 usleep_range(10000, 12000);
4155}
4156
San Mehat9d2bd732009-09-22 16:44:22 -07004157static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004158 .enable = msmsdcc_enable,
4159 .disable = msmsdcc_disable,
Asutosh Dasaccacd42012-03-08 14:33:17 +05304160 .pre_req = msmsdcc_pre_req,
4161 .post_req = msmsdcc_post_req,
San Mehat9d2bd732009-09-22 16:44:22 -07004162 .request = msmsdcc_request,
4163 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004164 .get_ro = msmsdcc_get_ro,
San Mehat9d2bd732009-09-22 16:44:22 -07004165 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Subhash Jadavani937c7502012-06-01 15:34:46 +05304166 .start_signal_voltage_switch = msmsdcc_switch_io_voltage,
Asutosh Dasebd7d092012-07-09 19:08:26 +05304167 .execute_tuning = msmsdcc_execute_tuning,
4168 .hw_reset = msmsdcc_hw_reset,
San Mehat9d2bd732009-09-22 16:44:22 -07004169};
4170
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004171static unsigned int
4172msmsdcc_slot_status(struct msmsdcc_host *host)
4173{
4174 int status;
4175 unsigned int gpio_no = host->plat->status_gpio;
4176
4177 status = gpio_request(gpio_no, "SD_HW_Detect");
4178 if (status) {
4179 pr_err("%s: %s: Failed to request GPIO %d\n",
4180 mmc_hostname(host->mmc), __func__, gpio_no);
4181 } else {
4182 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08004183 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08004184 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08004185 if (host->plat->is_status_gpio_active_low)
4186 status = !status;
4187 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004188 gpio_free(gpio_no);
4189 }
4190 return status;
4191}
4192
San Mehat9d2bd732009-09-22 16:44:22 -07004193static void
4194msmsdcc_check_status(unsigned long data)
4195{
4196 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4197 unsigned int status;
4198
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05304199 if (host->plat->status || gpio_is_valid(host->plat->status_gpio)) {
Krishna Konda941604a2012-01-10 17:46:34 -08004200 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004201 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004202 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004203 status = msmsdcc_slot_status(host);
4204
Krishna Konda941604a2012-01-10 17:46:34 -08004205 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08004206
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004207 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08004208 if (host->plat->status)
4209 pr_info("%s: Slot status change detected "
4210 "(%d -> %d)\n",
4211 mmc_hostname(host->mmc),
4212 host->oldstat, status);
4213 else if (host->plat->is_status_gpio_active_low)
4214 pr_info("%s: Slot status change detected "
4215 "(%d -> %d) and the card detect GPIO"
4216 " is ACTIVE_LOW\n",
4217 mmc_hostname(host->mmc),
4218 host->oldstat, status);
4219 else
4220 pr_info("%s: Slot status change detected "
4221 "(%d -> %d) and the card detect GPIO"
4222 " is ACTIVE_HIGH\n",
4223 mmc_hostname(host->mmc),
4224 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07004225 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004226 }
4227 host->oldstat = status;
4228 } else {
4229 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07004230 }
San Mehat9d2bd732009-09-22 16:44:22 -07004231}
4232
4233static irqreturn_t
4234msmsdcc_platform_status_irq(int irq, void *dev_id)
4235{
4236 struct msmsdcc_host *host = dev_id;
4237
Girish K Sa3c76eb2011-10-11 11:44:09 +05304238 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07004239 msmsdcc_check_status((unsigned long) host);
4240 return IRQ_HANDLED;
4241}
4242
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004243static irqreturn_t
4244msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
4245{
4246 struct msmsdcc_host *host = dev_id;
4247
4248 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
4249 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304250 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004251 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304252 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004253 wake_lock(&host->sdio_wlock);
4254 msmsdcc_disable_irq_wake(host);
4255 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304256 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004257 }
4258 if (host->plat->is_sdio_al_client) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004259 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304260 spin_unlock(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304261 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304262 goto out_unlocked;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004263 }
4264 spin_unlock(&host->lock);
4265
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304266out_unlocked:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004267 return IRQ_HANDLED;
4268}
4269
San Mehat9d2bd732009-09-22 16:44:22 -07004270static void
4271msmsdcc_status_notify_cb(int card_present, void *dev_id)
4272{
4273 struct msmsdcc_host *host = dev_id;
4274
Girish K Sa3c76eb2011-10-11 11:44:09 +05304275 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07004276 card_present);
4277 msmsdcc_check_status((unsigned long) host);
4278}
4279
San Mehat9d2bd732009-09-22 16:44:22 -07004280static int
4281msmsdcc_init_dma(struct msmsdcc_host *host)
4282{
4283 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
4284 host->dma.host = host;
4285 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004286 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004287
4288 if (!host->dmares)
4289 return -ENODEV;
4290
4291 host->dma.nc = dma_alloc_coherent(NULL,
4292 sizeof(struct msmsdcc_nc_dmadata),
4293 &host->dma.nc_busaddr,
4294 GFP_KERNEL);
4295 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004296 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07004297 return -ENOMEM;
4298 }
4299 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
4300 host->dma.cmd_busaddr = host->dma.nc_busaddr;
4301 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
4302 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
4303 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07004304 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07004305
4306 return 0;
4307}
4308
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004309#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
4310/**
4311 * Allocate and Connect a SDCC peripheral's SPS endpoint
4312 *
4313 * This function allocates endpoint context and
4314 * connect it with memory endpoint by calling
4315 * appropriate SPS driver APIs.
4316 *
4317 * Also registers a SPS callback function with
4318 * SPS driver
4319 *
4320 * This function should only be called once typically
4321 * during driver probe.
4322 *
4323 * @host - Pointer to sdcc host structure
4324 * @ep - Pointer to sps endpoint data structure
4325 * @is_produce - 1 means Producer endpoint
4326 * 0 means Consumer endpoint
4327 *
4328 * @return - 0 if successful else negative value.
4329 *
4330 */
4331static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
4332 struct msmsdcc_sps_ep_conn_data *ep,
4333 bool is_producer)
4334{
4335 int rc = 0;
4336 struct sps_pipe *sps_pipe_handle;
4337 struct sps_connect *sps_config = &ep->config;
4338 struct sps_register_event *sps_event = &ep->event;
4339
4340 /* Allocate endpoint context */
4341 sps_pipe_handle = sps_alloc_endpoint();
4342 if (!sps_pipe_handle) {
4343 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
4344 mmc_hostname(host->mmc), is_producer);
4345 rc = -ENOMEM;
4346 goto out;
4347 }
4348
4349 /* Get default connection configuration for an endpoint */
4350 rc = sps_get_config(sps_pipe_handle, sps_config);
4351 if (rc) {
4352 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
4353 " rc=%d", mmc_hostname(host->mmc),
4354 (u32)sps_pipe_handle, rc);
4355 goto get_config_err;
4356 }
4357
4358 /* Modify the default connection configuration */
4359 if (is_producer) {
4360 /*
4361 * For SDCC producer transfer, source should be
4362 * SDCC peripheral where as destination should
4363 * be system memory.
4364 */
4365 sps_config->source = host->sps.bam_handle;
4366 sps_config->destination = SPS_DEV_HANDLE_MEM;
4367 /* Producer pipe will handle this connection */
4368 sps_config->mode = SPS_MODE_SRC;
4369 sps_config->options =
4370 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4371 } else {
4372 /*
4373 * For SDCC consumer transfer, source should be
4374 * system memory where as destination should
4375 * SDCC peripheral
4376 */
4377 sps_config->source = SPS_DEV_HANDLE_MEM;
4378 sps_config->destination = host->sps.bam_handle;
4379 sps_config->mode = SPS_MODE_DEST;
4380 sps_config->options =
4381 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4382 }
4383
4384 /* Producer pipe index */
4385 sps_config->src_pipe_index = host->sps.src_pipe_index;
4386 /* Consumer pipe index */
4387 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
4388 /*
4389 * This event thresold value is only significant for BAM-to-BAM
4390 * transfer. It's ignored for BAM-to-System mode transfer.
4391 */
4392 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304393
4394 /* Allocate maximum descriptor fifo size */
4395 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
4396 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004397 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
4398 sps_config->desc.size,
4399 &sps_config->desc.phys_base,
4400 GFP_KERNEL);
4401
Pratibhasagar V00b94332011-10-18 14:57:27 +05304402 if (!sps_config->desc.base) {
4403 rc = -ENOMEM;
4404 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
4405 , mmc_hostname(host->mmc));
4406 goto get_config_err;
4407 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004408 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
4409
4410 /* Establish connection between peripheral and memory endpoint */
4411 rc = sps_connect(sps_pipe_handle, sps_config);
4412 if (rc) {
4413 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4414 " rc=%d", mmc_hostname(host->mmc),
4415 (u32)sps_pipe_handle, rc);
4416 goto sps_connect_err;
4417 }
4418
4419 sps_event->mode = SPS_TRIGGER_CALLBACK;
4420 sps_event->options = SPS_O_EOT;
4421 sps_event->callback = msmsdcc_sps_complete_cb;
4422 sps_event->xfer_done = NULL;
4423 sps_event->user = (void *)host;
4424
4425 /* Register callback event for EOT (End of transfer) event. */
4426 rc = sps_register_event(sps_pipe_handle, sps_event);
4427 if (rc) {
4428 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4429 " rc=%d", mmc_hostname(host->mmc),
4430 (u32)sps_pipe_handle, rc);
4431 goto reg_event_err;
4432 }
4433 /* Now save the sps pipe handle */
4434 ep->pipe_handle = sps_pipe_handle;
4435 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
4436 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
4437 __func__, is_producer ? "READ" : "WRITE",
4438 (u32)sps_pipe_handle, sps_config->desc.phys_base);
4439 goto out;
4440
4441reg_event_err:
4442 sps_disconnect(sps_pipe_handle);
4443sps_connect_err:
4444 dma_free_coherent(mmc_dev(host->mmc),
4445 sps_config->desc.size,
4446 sps_config->desc.base,
4447 sps_config->desc.phys_base);
4448get_config_err:
4449 sps_free_endpoint(sps_pipe_handle);
4450out:
4451 return rc;
4452}
4453
4454/**
4455 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
4456 *
4457 * This function disconnect endpoint and deallocates
4458 * endpoint context.
4459 *
4460 * This function should only be called once typically
4461 * during driver remove.
4462 *
4463 * @host - Pointer to sdcc host structure
4464 * @ep - Pointer to sps endpoint data structure
4465 *
4466 */
4467static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
4468 struct msmsdcc_sps_ep_conn_data *ep)
4469{
4470 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4471 struct sps_connect *sps_config = &ep->config;
4472 struct sps_register_event *sps_event = &ep->event;
4473
4474 sps_event->xfer_done = NULL;
4475 sps_event->callback = NULL;
4476 sps_register_event(sps_pipe_handle, sps_event);
4477 sps_disconnect(sps_pipe_handle);
4478 dma_free_coherent(mmc_dev(host->mmc),
4479 sps_config->desc.size,
4480 sps_config->desc.base,
4481 sps_config->desc.phys_base);
4482 sps_free_endpoint(sps_pipe_handle);
4483}
4484
4485/**
4486 * Reset SDCC peripheral's SPS endpoint
4487 *
4488 * This function disconnects an endpoint.
4489 *
4490 * This function should be called for reseting
4491 * SPS endpoint when data transfer error is
4492 * encountered during data transfer. This
4493 * can be considered as soft reset to endpoint.
4494 *
4495 * This function should only be called if
4496 * msmsdcc_sps_init() is already called.
4497 *
4498 * @host - Pointer to sdcc host structure
4499 * @ep - Pointer to sps endpoint data structure
4500 *
4501 * @return - 0 if successful else negative value.
4502 */
4503static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
4504 struct msmsdcc_sps_ep_conn_data *ep)
4505{
4506 int rc = 0;
4507 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4508
4509 rc = sps_disconnect(sps_pipe_handle);
4510 if (rc) {
4511 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
4512 " rc=%d", mmc_hostname(host->mmc), __func__,
4513 (u32)sps_pipe_handle, rc);
4514 goto out;
4515 }
4516 out:
4517 return rc;
4518}
4519
4520/**
4521 * Restore SDCC peripheral's SPS endpoint
4522 *
4523 * This function connects an endpoint.
4524 *
4525 * This function should be called for restoring
4526 * SPS endpoint after data transfer error is
4527 * encountered during data transfer. This
4528 * can be considered as soft reset to endpoint.
4529 *
4530 * This function should only be called if
4531 * msmsdcc_sps_reset_ep() is called before.
4532 *
4533 * @host - Pointer to sdcc host structure
4534 * @ep - Pointer to sps endpoint data structure
4535 *
4536 * @return - 0 if successful else negative value.
4537 */
4538static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
4539 struct msmsdcc_sps_ep_conn_data *ep)
4540{
4541 int rc = 0;
4542 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4543 struct sps_connect *sps_config = &ep->config;
4544 struct sps_register_event *sps_event = &ep->event;
4545
4546 /* Establish connection between peripheral and memory endpoint */
4547 rc = sps_connect(sps_pipe_handle, sps_config);
4548 if (rc) {
4549 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
4550 " rc=%d", mmc_hostname(host->mmc), __func__,
4551 (u32)sps_pipe_handle, rc);
4552 goto out;
4553 }
4554
4555 /* Register callback event for EOT (End of transfer) event. */
4556 rc = sps_register_event(sps_pipe_handle, sps_event);
4557 if (rc) {
4558 pr_err("%s: %s: sps_register_event() failed!!!"
4559 " pipe_handle=0x%x, rc=%d",
4560 mmc_hostname(host->mmc), __func__,
4561 (u32)sps_pipe_handle, rc);
4562 goto reg_event_err;
4563 }
4564 goto out;
4565
4566reg_event_err:
4567 sps_disconnect(sps_pipe_handle);
4568out:
4569 return rc;
4570}
4571
4572/**
Krishna Konda5af8f972012-05-14 16:15:24 -07004573 * Handle BAM device's global error condition
4574 *
4575 * This is an error handler for the SDCC bam device
4576 *
4577 * This function is registered as a callback with SPS-BAM
4578 * driver and will called in case there are an errors for
4579 * the SDCC BAM deivce. Any error conditions in the BAM
4580 * device are global and will be result in this function
4581 * being called once per device.
4582 *
4583 * This function will be called from the sps driver's
4584 * interrupt context.
4585 *
4586 * @sps_cb_case - indicates what error it is
4587 * @user - Pointer to sdcc host structure
4588 */
4589static void
4590msmsdcc_sps_bam_global_irq_cb(enum sps_callback_case sps_cb_case, void *user)
4591{
4592 struct msmsdcc_host *host = (struct msmsdcc_host *)user;
4593 struct mmc_request *mrq;
4594 unsigned long flags;
4595 int32_t error = 0;
4596
4597 BUG_ON(!host);
4598 BUG_ON(!is_sps_mode(host));
4599
4600 if (sps_cb_case == SPS_CALLBACK_BAM_ERROR_IRQ) {
Maya Erezb7a086f2012-11-29 00:37:36 +02004601 /* Reset all endpoints along with resetting bam. */
4602 host->sps.reset_bam = true;
Krishna Konda5af8f972012-05-14 16:15:24 -07004603
4604 pr_err("%s: BAM Global ERROR IRQ happened\n",
4605 mmc_hostname(host->mmc));
4606 error = EAGAIN;
4607 } else if (sps_cb_case == SPS_CALLBACK_BAM_HRESP_ERR_IRQ) {
4608 /**
4609 * This means that there was an AHB access error and
4610 * the address we are trying to read/write is something
4611 * we dont have priviliges to do so.
4612 */
4613 pr_err("%s: BAM HRESP_ERR_IRQ happened\n",
4614 mmc_hostname(host->mmc));
4615 error = EACCES;
4616 } else {
4617 /**
4618 * This should not have happened ideally. If this happens
4619 * there is some seriously wrong.
4620 */
4621 pr_err("%s: BAM global IRQ callback received, type:%d\n",
4622 mmc_hostname(host->mmc), (u32) sps_cb_case);
4623 error = EIO;
4624 }
4625
4626 spin_lock_irqsave(&host->lock, flags);
4627
4628 mrq = host->curr.mrq;
4629
4630 if (mrq && mrq->cmd) {
4631 msmsdcc_dump_sdcc_state(host);
4632
4633 if (!mrq->cmd->error)
4634 mrq->cmd->error = -error;
4635 if (host->curr.data) {
4636 if (mrq->data && !mrq->data->error)
4637 mrq->data->error = -error;
4638 host->curr.data_xfered = 0;
4639 if (host->sps.sg && is_sps_mode(host)) {
4640 /* Stop current SPS transfer */
4641 msmsdcc_sps_exit_curr_xfer(host);
4642 } else {
4643 /* this condition should not have happened */
4644 pr_err("%s: something is seriously wrong. "\
4645 "Funtion: %s, line: %d\n",
4646 mmc_hostname(host->mmc),
4647 __func__, __LINE__);
4648 }
4649 } else {
4650 /* this condition should not have happened */
4651 pr_err("%s: something is seriously wrong. Funtion: "\
4652 "%s, line: %d\n", mmc_hostname(host->mmc),
4653 __func__, __LINE__);
4654 }
4655 }
4656 spin_unlock_irqrestore(&host->lock, flags);
4657}
4658
4659/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004660 * Initialize SPS HW connected with SDCC core
4661 *
4662 * This function register BAM HW resources with
4663 * SPS driver and then initialize 2 SPS endpoints
4664 *
4665 * This function should only be called once typically
4666 * during driver probe.
4667 *
4668 * @host - Pointer to sdcc host structure
4669 *
4670 * @return - 0 if successful else negative value.
4671 *
4672 */
4673static int msmsdcc_sps_init(struct msmsdcc_host *host)
4674{
4675 int rc = 0;
4676 struct sps_bam_props bam = {0};
4677
4678 host->bam_base = ioremap(host->bam_memres->start,
4679 resource_size(host->bam_memres));
4680 if (!host->bam_base) {
4681 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
4682 " size=0x%x", mmc_hostname(host->mmc),
4683 host->bam_memres->start,
4684 (host->bam_memres->end -
4685 host->bam_memres->start));
4686 rc = -ENOMEM;
4687 goto out;
4688 }
4689
4690 bam.phys_addr = host->bam_memres->start;
4691 bam.virt_addr = host->bam_base;
4692 /*
4693 * This event thresold value is only significant for BAM-to-BAM
4694 * transfer. It's ignored for BAM-to-System mode transfer.
4695 */
4696 bam.event_threshold = 0x10; /* Pipe event threshold */
4697 /*
4698 * This threshold controls when the BAM publish
4699 * the descriptor size on the sideband interface.
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304700 * SPS HW will be used for data transfer size even
4701 * less than SDCC FIFO size. So let's set BAM summing
4702 * thresold to SPS_MIN_XFER_SIZE bytes.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004703 */
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304704 bam.summing_threshold = SPS_MIN_XFER_SIZE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004705 /* SPS driver wll handle the SDCC BAM IRQ */
4706 bam.irq = (u32)host->bam_irqres->start;
4707 bam.manage = SPS_BAM_MGR_LOCAL;
Krishna Konda5af8f972012-05-14 16:15:24 -07004708 bam.callback = msmsdcc_sps_bam_global_irq_cb;
4709 bam.user = (void *)host;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004710
4711 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
4712 (u32)bam.phys_addr);
4713 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
4714 (u32)bam.virt_addr);
4715
4716 /* Register SDCC Peripheral BAM device to SPS driver */
4717 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
4718 if (rc) {
4719 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
4720 mmc_hostname(host->mmc), rc);
4721 goto reg_bam_err;
4722 }
4723 pr_info("%s: BAM device registered. bam_handle=0x%x",
4724 mmc_hostname(host->mmc), host->sps.bam_handle);
4725
4726 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
4727 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
4728
4729 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
4730 SPS_PROD_PERIPHERAL);
4731 if (rc)
4732 goto sps_reset_err;
4733 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
4734 SPS_CONS_PERIPHERAL);
4735 if (rc)
4736 goto cons_conn_err;
4737
4738 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
4739 mmc_hostname(host->mmc),
4740 (unsigned long long)host->bam_memres->start,
4741 (unsigned int)host->bam_irqres->start);
4742 goto out;
4743
4744cons_conn_err:
4745 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4746sps_reset_err:
4747 sps_deregister_bam_device(host->sps.bam_handle);
4748reg_bam_err:
4749 iounmap(host->bam_base);
4750out:
4751 return rc;
4752}
4753
4754/**
4755 * De-initialize SPS HW connected with SDCC core
4756 *
4757 * This function deinitialize SPS endpoints and then
4758 * deregisters BAM resources from SPS driver.
4759 *
4760 * This function should only be called once typically
4761 * during driver remove.
4762 *
4763 * @host - Pointer to sdcc host structure
4764 *
4765 */
4766static void msmsdcc_sps_exit(struct msmsdcc_host *host)
4767{
4768 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
4769 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4770 sps_deregister_bam_device(host->sps.bam_handle);
4771 iounmap(host->bam_base);
4772}
4773#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
4774
4775static ssize_t
4776show_polling(struct device *dev, struct device_attribute *attr, char *buf)
4777{
4778 struct mmc_host *mmc = dev_get_drvdata(dev);
4779 struct msmsdcc_host *host = mmc_priv(mmc);
4780 int poll;
4781 unsigned long flags;
4782
4783 spin_lock_irqsave(&host->lock, flags);
4784 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
4785 spin_unlock_irqrestore(&host->lock, flags);
4786
4787 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
4788}
4789
4790static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05304791store_polling(struct device *dev, struct device_attribute *attr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004792 const char *buf, size_t count)
4793{
4794 struct mmc_host *mmc = dev_get_drvdata(dev);
4795 struct msmsdcc_host *host = mmc_priv(mmc);
4796 int value;
4797 unsigned long flags;
4798
4799 sscanf(buf, "%d", &value);
4800
4801 spin_lock_irqsave(&host->lock, flags);
4802 if (value) {
4803 mmc->caps |= MMC_CAP_NEEDS_POLL;
4804 mmc_detect_change(host->mmc, 0);
4805 } else {
4806 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4807 }
4808#ifdef CONFIG_HAS_EARLYSUSPEND
4809 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
4810#endif
4811 spin_unlock_irqrestore(&host->lock, flags);
4812 return count;
4813}
4814
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304815static ssize_t
4816show_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
4817 char *buf)
4818{
4819 struct mmc_host *mmc = dev_get_drvdata(dev);
4820 struct msmsdcc_host *host = mmc_priv(mmc);
4821
4822 return snprintf(buf, PAGE_SIZE, "%u\n",
4823 host->msm_bus_vote.is_max_bw_needed);
4824}
4825
4826static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05304827store_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304828 const char *buf, size_t count)
4829{
4830 struct mmc_host *mmc = dev_get_drvdata(dev);
4831 struct msmsdcc_host *host = mmc_priv(mmc);
4832 uint32_t value;
4833 unsigned long flags;
4834
4835 if (!kstrtou32(buf, 0, &value)) {
4836 spin_lock_irqsave(&host->lock, flags);
4837 host->msm_bus_vote.is_max_bw_needed = !!value;
4838 spin_unlock_irqrestore(&host->lock, flags);
4839 }
4840
4841 return count;
4842}
4843
Pratibhasagar V13d1d032012-07-09 20:12:38 +05304844static ssize_t
4845show_idle_timeout(struct device *dev, struct device_attribute *attr,
4846 char *buf)
4847{
4848 struct mmc_host *mmc = dev_get_drvdata(dev);
4849 struct msmsdcc_host *host = mmc_priv(mmc);
4850
4851 return snprintf(buf, PAGE_SIZE, "%u (Min 5 sec)\n",
4852 host->idle_tout_ms / 1000);
4853}
4854
4855static ssize_t
4856store_idle_timeout(struct device *dev, struct device_attribute *attr,
4857 const char *buf, size_t count)
4858{
4859 struct mmc_host *mmc = dev_get_drvdata(dev);
4860 struct msmsdcc_host *host = mmc_priv(mmc);
4861 unsigned int long flags;
4862 int timeout; /* in secs */
4863
4864 if (!kstrtou32(buf, 0, &timeout)
4865 && (timeout > MSM_MMC_DEFAULT_IDLE_TIMEOUT / 1000)) {
4866 spin_lock_irqsave(&host->lock, flags);
4867 host->idle_tout_ms = timeout * 1000;
4868 spin_unlock_irqrestore(&host->lock, flags);
4869 }
4870 return count;
4871}
4872
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004873#ifdef CONFIG_HAS_EARLYSUSPEND
4874static void msmsdcc_early_suspend(struct early_suspend *h)
4875{
4876 struct msmsdcc_host *host =
4877 container_of(h, struct msmsdcc_host, early_suspend);
4878 unsigned long flags;
4879
4880 spin_lock_irqsave(&host->lock, flags);
4881 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
4882 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4883 spin_unlock_irqrestore(&host->lock, flags);
4884};
4885static void msmsdcc_late_resume(struct early_suspend *h)
4886{
4887 struct msmsdcc_host *host =
4888 container_of(h, struct msmsdcc_host, early_suspend);
4889 unsigned long flags;
4890
4891 if (host->polling_enabled) {
4892 spin_lock_irqsave(&host->lock, flags);
4893 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
4894 mmc_detect_change(host->mmc, 0);
4895 spin_unlock_irqrestore(&host->lock, flags);
4896 }
4897};
4898#endif
4899
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304900static void msmsdcc_print_regs(const char *name, void __iomem *base,
4901 u32 phys_base, unsigned int no_of_regs)
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304902{
4903 unsigned int i;
4904
4905 if (!base)
4906 return;
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304907
4908 pr_info("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
4909 " =====\n", name, phys_base, (u32)base);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304910 for (i = 0; i < no_of_regs; i = i + 4) {
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304911 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
4912 (u32)readl_relaxed(base + i*4),
4913 (u32)readl_relaxed(base + ((i+1)*4)),
4914 (u32)readl_relaxed(base + ((i+2)*4)),
4915 (u32)readl_relaxed(base + ((i+3)*4)));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304916 }
4917}
4918
4919static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
4920{
4921 /* Dump current state of SDCC clocks, power and irq */
4922 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304923 (host->pwr ? "ON" : "OFF"));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304924 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304925 mmc_hostname(host->mmc),
4926 (atomic_read(&host->clks_on) ? "ON" : "OFF"),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304927 (u32)clk_get_rate(host->clk));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304928 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
4929 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
4930
4931 /* Now dump SDCC registers. Don't print FIFO registers */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304932 if (atomic_read(&host->clks_on))
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304933 msmsdcc_print_regs("SDCC-CORE", host->base,
4934 host->core_memres->start, 28);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304935
4936 if (host->curr.data) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304937 if (!msmsdcc_is_dma_possible(host, host->curr.data))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304938 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304939 else if (is_dma_mode(host))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304940 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
4941 mmc_hostname(host->mmc), host->dma.busy,
4942 host->dma.channel, host->dma.crci);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304943 else if (is_sps_mode(host)) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304944 if (host->sps.busy && atomic_read(&host->clks_on))
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304945 msmsdcc_print_regs("SDCC-DML", host->dml_base,
4946 host->dml_memres->start,
4947 16);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304948 pr_info("%s: SPS mode: busy=%d\n",
4949 mmc_hostname(host->mmc), host->sps.busy);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304950 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304951
4952 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
4953 mmc_hostname(host->mmc), host->curr.xfer_size,
4954 host->curr.data_xfered, host->curr.xfer_remain);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304955 }
4956
Maya Erezb7a086f2012-11-29 00:37:36 +02004957 if (host->sps.reset_bam)
4958 pr_err("%s: SPS BAM reset failed: sps reset_bam=%d\n",
4959 mmc_hostname(host->mmc), host->sps.reset_bam);
4960
4961 pr_err("%s: got_dataend=%d, prog_enable=%d,"
Subhash Jadavani8706ced2012-05-25 16:09:21 +05304962 " wait_for_auto_prog_done=%d, got_auto_prog_done=%d,"
4963 " req_tout_ms=%d\n", mmc_hostname(host->mmc),
4964 host->curr.got_dataend, host->prog_enable,
4965 host->curr.wait_for_auto_prog_done,
4966 host->curr.got_auto_prog_done, host->curr.req_tout_ms);
subhashj245831e2012-04-30 18:46:17 +05304967 msmsdcc_print_rpm_info(host);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304968}
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304969
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004970static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
4971{
4972 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4973 struct mmc_request *mrq;
4974 unsigned long flags;
4975
4976 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004977 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004978 pr_info("%s: %s: dummy CMD52 timeout\n",
4979 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004980 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004981 }
4982
4983 mrq = host->curr.mrq;
4984
4985 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304986 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
4987 mrq->cmd->opcode);
4988 msmsdcc_dump_sdcc_state(host);
4989
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004990 if (!mrq->cmd->error)
4991 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304992 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004993 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004994 if (mrq->data && !mrq->data->error)
4995 mrq->data->error = -ETIMEDOUT;
4996 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304997 if (host->dma.sg && is_dma_mode(host)) {
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07004998 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304999 } else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005000 /* Stop current SPS transfer */
5001 msmsdcc_sps_exit_curr_xfer(host);
5002 } else {
5003 msmsdcc_reset_and_restore(host);
5004 msmsdcc_stop_data(host);
5005 if (mrq->data && mrq->data->stop)
5006 msmsdcc_start_command(host,
5007 mrq->data->stop, 0);
5008 else
5009 msmsdcc_request_end(host, mrq);
5010 }
5011 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05305012 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05305013 host->curr.wait_for_auto_prog_done = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005014 msmsdcc_reset_and_restore(host);
5015 msmsdcc_request_end(host, mrq);
5016 }
5017 }
5018 spin_unlock_irqrestore(&host->lock, flags);
5019}
5020
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305021/*
5022 * msmsdcc_dt_get_array - Wrapper fn to read an array of 32 bit integers
5023 *
5024 * @dev: device node from which the property value is to be read.
5025 * @prop_name: name of the property to be searched.
5026 * @out_array: filled array returned to caller
5027 * @len: filled array size returned to caller
5028 * @size: expected size of the array
5029 *
5030 * If expected "size" doesn't match with "len" an error is returned. If
5031 * expected size is zero, the length of actual array is returned provided
5032 * return value is zero.
5033 *
5034 * RETURNS:
5035 * zero on success, negative error if failed.
5036 */
5037static int msmsdcc_dt_get_array(struct device *dev, const char *prop_name,
5038 u32 **out_array, int *len, int size)
5039{
5040 int ret = 0;
5041 u32 *array = NULL;
5042 struct device_node *np = dev->of_node;
5043
5044 if (of_get_property(np, prop_name, len)) {
5045 size_t sz;
5046 sz = *len = *len / sizeof(*array);
5047
5048 if (sz > 0 && !(size > 0 && (sz != size))) {
5049 array = devm_kzalloc(dev, sz * sizeof(*array),
5050 GFP_KERNEL);
5051 if (!array) {
5052 dev_err(dev, "%s: no memory\n", prop_name);
5053 ret = -ENOMEM;
5054 goto out;
5055 }
5056
5057 ret = of_property_read_u32_array(np, prop_name,
5058 array, sz);
5059 if (ret < 0) {
5060 dev_err(dev, "%s: error reading array %d\n",
5061 prop_name, ret);
5062 goto out;
5063 }
5064 } else {
5065 dev_err(dev, "%s invalid size\n", prop_name);
5066 ret = -EINVAL;
5067 goto out;
5068 }
5069 } else {
5070 dev_err(dev, "%s not specified\n", prop_name);
5071 ret = -EINVAL;
5072 goto out;
5073 }
5074 *out_array = array;
5075out:
5076 if (ret)
5077 *len = 0;
5078 return ret;
5079}
5080
5081static int msmsdcc_dt_get_pad_pull_info(struct device *dev, int id,
5082 struct msm_mmc_pad_pull_data **pad_pull_data)
5083{
5084 int ret = 0, base = 0, len, i;
5085 u32 *tmp;
5086 struct msm_mmc_pad_pull_data *pull_data;
5087 struct msm_mmc_pad_pull *pull;
5088
5089 switch (id) {
5090 case 1:
5091 base = TLMM_PULL_SDC1_CLK;
5092 break;
5093 case 2:
5094 base = TLMM_PULL_SDC2_CLK;
5095 break;
5096 case 3:
5097 base = TLMM_PULL_SDC3_CLK;
5098 break;
5099 case 4:
5100 base = TLMM_PULL_SDC4_CLK;
5101 break;
5102 default:
5103 dev_err(dev, "%s: Invalid slot id\n", __func__);
5104 ret = -EINVAL;
5105 goto err;
5106 }
5107
5108 pull_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_pull_data),
5109 GFP_KERNEL);
5110 if (!pull_data) {
5111 dev_err(dev, "No memory msm_mmc_pad_pull_data\n");
5112 ret = -ENOMEM;
5113 goto err;
5114 }
5115 pull_data->size = 3; /* array size for clk, cmd, data */
5116
5117 /* Allocate on, off configs for clk, cmd, data */
5118 pull = devm_kzalloc(dev, 2 * pull_data->size *\
5119 sizeof(struct msm_mmc_pad_pull), GFP_KERNEL);
5120 if (!pull) {
5121 dev_err(dev, "No memory for msm_mmc_pad_pull\n");
5122 ret = -ENOMEM;
5123 goto err;
5124 }
5125 pull_data->on = pull;
5126 pull_data->off = pull + pull_data->size;
5127
5128 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-pull-on",
5129 &tmp, &len, pull_data->size);
5130 if (!ret) {
5131 for (i = 0; i < len; i++) {
5132 pull_data->on[i].no = base + i;
5133 pull_data->on[i].val = tmp[i];
5134 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5135 i, pull_data->on[i].val);
5136 }
5137 } else {
5138 goto err;
5139 }
5140
5141 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-pull-off",
5142 &tmp, &len, pull_data->size);
5143 if (!ret) {
5144 for (i = 0; i < len; i++) {
5145 pull_data->off[i].no = base + i;
5146 pull_data->off[i].val = tmp[i];
5147 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5148 i, pull_data->off[i].val);
5149 }
5150 } else {
5151 goto err;
5152 }
5153
5154 *pad_pull_data = pull_data;
5155err:
5156 return ret;
5157}
5158
5159static int msmsdcc_dt_get_pad_drv_info(struct device *dev, int id,
5160 struct msm_mmc_pad_drv_data **pad_drv_data)
5161{
5162 int ret = 0, base = 0, len, i;
5163 u32 *tmp;
5164 struct msm_mmc_pad_drv_data *drv_data;
5165 struct msm_mmc_pad_drv *drv;
5166
5167 switch (id) {
5168 case 1:
5169 base = TLMM_HDRV_SDC1_CLK;
5170 break;
5171 case 2:
5172 base = TLMM_HDRV_SDC2_CLK;
5173 break;
5174 case 3:
5175 base = TLMM_HDRV_SDC3_CLK;
5176 break;
5177 case 4:
5178 base = TLMM_HDRV_SDC4_CLK;
5179 break;
5180 default:
5181 dev_err(dev, "%s: Invalid slot id\n", __func__);
5182 ret = -EINVAL;
5183 goto err;
5184 }
5185
5186 drv_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_drv_data),
5187 GFP_KERNEL);
5188 if (!drv_data) {
5189 dev_err(dev, "No memory for msm_mmc_pad_drv_data\n");
5190 ret = -ENOMEM;
5191 goto err;
5192 }
5193 drv_data->size = 3; /* array size for clk, cmd, data */
5194
5195 /* Allocate on, off configs for clk, cmd, data */
5196 drv = devm_kzalloc(dev, 2 * drv_data->size *\
5197 sizeof(struct msm_mmc_pad_drv), GFP_KERNEL);
5198 if (!drv) {
5199 dev_err(dev, "No memory msm_mmc_pad_drv\n");
5200 ret = -ENOMEM;
5201 goto err;
5202 }
5203 drv_data->on = drv;
5204 drv_data->off = drv + drv_data->size;
5205
5206 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-drv-on",
5207 &tmp, &len, drv_data->size);
5208 if (!ret) {
5209 for (i = 0; i < len; i++) {
5210 drv_data->on[i].no = base + i;
5211 drv_data->on[i].val = tmp[i];
5212 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5213 i, drv_data->on[i].val);
5214 }
5215 } else {
5216 goto err;
5217 }
5218
5219 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-drv-off",
5220 &tmp, &len, drv_data->size);
5221 if (!ret) {
5222 for (i = 0; i < len; i++) {
5223 drv_data->off[i].no = base + i;
5224 drv_data->off[i].val = tmp[i];
5225 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5226 i, drv_data->off[i].val);
5227 }
5228 } else {
5229 goto err;
5230 }
5231
5232 *pad_drv_data = drv_data;
5233err:
5234 return ret;
5235}
5236
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305237static void msmsdcc_dt_get_cd_wp_gpio(struct device *dev,
5238 struct mmc_platform_data *pdata)
5239{
5240 enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
5241 struct device_node *np = dev->of_node;
5242
5243 pdata->status_gpio = of_get_named_gpio_flags(np,
5244 "cd-gpios", 0, &flags);
5245 if (gpio_is_valid(pdata->status_gpio)) {
5246 pdata->status_irq = gpio_to_irq(pdata->status_gpio);
5247 pdata->is_status_gpio_active_low = flags & OF_GPIO_ACTIVE_LOW;
5248 }
5249
5250 pdata->wpswitch_gpio = of_get_named_gpio_flags(np,
5251 "wp-gpios", 0, &flags);
5252 if (gpio_is_valid(pdata->wpswitch_gpio))
5253 pdata->is_wpswitch_active_low = flags & OF_GPIO_ACTIVE_LOW;
5254}
5255
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305256static int msmsdcc_dt_parse_gpio_info(struct device *dev,
5257 struct mmc_platform_data *pdata)
5258{
5259 int ret = 0, id = 0, cnt, i;
5260 struct msm_mmc_pin_data *pin_data;
5261 struct device_node *np = dev->of_node;
5262
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305263 msmsdcc_dt_get_cd_wp_gpio(dev, pdata);
5264
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305265 pin_data = devm_kzalloc(dev, sizeof(*pin_data), GFP_KERNEL);
5266 if (!pin_data) {
5267 dev_err(dev, "No memory for pin_data\n");
5268 ret = -ENOMEM;
5269 goto err;
5270 }
5271
5272 cnt = of_gpio_count(np);
5273 if (cnt > 0) {
5274 pin_data->is_gpio = true;
5275
5276 pin_data->gpio_data = devm_kzalloc(dev,
5277 sizeof(struct msm_mmc_gpio_data), GFP_KERNEL);
5278 if (!pin_data->gpio_data) {
5279 dev_err(dev, "No memory for gpio_data\n");
5280 ret = -ENOMEM;
5281 goto err;
5282 }
5283 pin_data->gpio_data->size = cnt;
5284 pin_data->gpio_data->gpio = devm_kzalloc(dev,
5285 cnt * sizeof(struct msm_mmc_gpio), GFP_KERNEL);
5286 if (!pin_data->gpio_data->gpio) {
5287 dev_err(dev, "No memory for gpio\n");
5288 ret = -ENOMEM;
5289 goto err;
5290 }
5291
5292 for (i = 0; i < cnt; i++) {
5293 const char *name = NULL;
5294 char result[32];
5295 pin_data->gpio_data->gpio[i].no = of_get_gpio(np, i);
5296 of_property_read_string_index(np,
5297 "qcom,sdcc-gpio-names", i, &name);
5298
5299 snprintf(result, 32, "%s-%s",
5300 dev_name(dev), name ? name : "?");
5301 pin_data->gpio_data->gpio[i].name = result;
5302 dev_dbg(dev, "%s: gpio[%s] = %d\n", __func__,
5303 pin_data->gpio_data->gpio[i].name,
5304 pin_data->gpio_data->gpio[i].no);
5305 }
5306 } else {
5307 pin_data->pad_data = devm_kzalloc(dev,
5308 sizeof(struct msm_mmc_pad_data), GFP_KERNEL);
5309 if (!pin_data->pad_data) {
5310 dev_err(dev, "No memory for pin_data->pad_data\n");
5311 ret = -ENOMEM;
5312 goto err;
5313 }
5314
5315 of_property_read_u32(np, "cell-index", &id);
5316
5317 ret = msmsdcc_dt_get_pad_pull_info(dev, id,
5318 &pin_data->pad_data->pull);
5319 if (ret)
5320 goto err;
5321 ret = msmsdcc_dt_get_pad_drv_info(dev, id,
5322 &pin_data->pad_data->drv);
5323 if (ret)
5324 goto err;
5325 }
5326
5327 pdata->pin_data = pin_data;
5328err:
5329 if (ret)
5330 dev_err(dev, "%s failed with err %d\n", __func__, ret);
5331 return ret;
5332}
5333
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305334#define MAX_PROP_SIZE 32
5335static int msmsdcc_dt_parse_vreg_info(struct device *dev,
5336 struct msm_mmc_reg_data **vreg_data, const char *vreg_name)
5337{
5338 int len, ret = 0;
5339 const __be32 *prop;
5340 char prop_name[MAX_PROP_SIZE];
5341 struct msm_mmc_reg_data *vreg;
5342 struct device_node *np = dev->of_node;
5343
5344 snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", vreg_name);
5345 if (of_parse_phandle(np, prop_name, 0)) {
5346 vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
5347 if (!vreg) {
5348 dev_err(dev, "No memory for vreg: %s\n", vreg_name);
5349 ret = -ENOMEM;
5350 goto err;
5351 }
5352
5353 vreg->name = vreg_name;
5354
5355 snprintf(prop_name, MAX_PROP_SIZE,
5356 "qcom,sdcc-%s-always_on", vreg_name);
5357 if (of_get_property(np, prop_name, NULL))
5358 vreg->always_on = true;
5359
5360 snprintf(prop_name, MAX_PROP_SIZE,
5361 "qcom,sdcc-%s-lpm_sup", vreg_name);
5362 if (of_get_property(np, prop_name, NULL))
5363 vreg->lpm_sup = true;
5364
5365 snprintf(prop_name, MAX_PROP_SIZE,
5366 "qcom,sdcc-%s-voltage_level", vreg_name);
5367 prop = of_get_property(np, prop_name, &len);
5368 if (!prop || (len != (2 * sizeof(__be32)))) {
5369 dev_warn(dev, "%s %s property\n",
5370 prop ? "invalid format" : "no", prop_name);
5371 } else {
5372 vreg->low_vol_level = be32_to_cpup(&prop[0]);
5373 vreg->high_vol_level = be32_to_cpup(&prop[1]);
5374 }
5375
5376 snprintf(prop_name, MAX_PROP_SIZE,
5377 "qcom,sdcc-%s-current_level", vreg_name);
5378 prop = of_get_property(np, prop_name, &len);
5379 if (!prop || (len != (2 * sizeof(__be32)))) {
5380 dev_warn(dev, "%s %s property\n",
5381 prop ? "invalid format" : "no", prop_name);
5382 } else {
5383 vreg->lpm_uA = be32_to_cpup(&prop[0]);
5384 vreg->hpm_uA = be32_to_cpup(&prop[1]);
5385 }
5386
5387 *vreg_data = vreg;
5388 dev_dbg(dev, "%s: %s %s vol=[%d %d]uV, curr=[%d %d]uA\n",
5389 vreg->name, vreg->always_on ? "always_on," : "",
5390 vreg->lpm_sup ? "lpm_sup," : "", vreg->low_vol_level,
5391 vreg->high_vol_level, vreg->lpm_uA, vreg->hpm_uA);
5392 }
5393
5394err:
5395 return ret;
5396}
5397
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305398static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
5399{
5400 int i, ret;
5401 struct mmc_platform_data *pdata;
5402 struct device_node *np = dev->of_node;
Devin Kim9ccbff52012-07-16 20:55:14 -07005403 u32 bus_width = 0, current_limit = 0;
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305404 u32 *clk_table, *sup_voltages;
Devin Kim9ccbff52012-07-16 20:55:14 -07005405 int clk_table_len, sup_volt_len, len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305406
5407 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
5408 if (!pdata) {
5409 dev_err(dev, "could not allocate memory for platform data\n");
5410 goto err;
5411 }
5412
5413 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
5414 if (bus_width == 8) {
5415 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
5416 } else if (bus_width == 4) {
5417 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
5418 } else {
5419 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
5420 pdata->mmc_bus_width = 0;
5421 }
5422
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305423 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-sup-voltages",
5424 &sup_voltages, &sup_volt_len, 0);
5425 if (!ret) {
5426 for (i = 0; i < sup_volt_len; i += 2) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305427 u32 mask;
5428
5429 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
5430 sup_voltages[i + 1]);
5431 if (!mask)
5432 dev_err(dev, "Invalide voltage range %d\n", i);
5433 pdata->ocr_mask |= mask;
5434 }
5435 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305436 }
5437
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305438 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-clk-rates",
5439 &clk_table, &clk_table_len, 0);
5440 if (!ret) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305441 pdata->sup_clk_table = clk_table;
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305442 pdata->sup_clk_cnt = clk_table_len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305443 }
5444
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305445 pdata->vreg_data = devm_kzalloc(dev,
5446 sizeof(struct msm_mmc_slot_reg_data), GFP_KERNEL);
5447 if (!pdata->vreg_data) {
5448 dev_err(dev, "could not allocate memory for vreg_data\n");
5449 goto err;
5450 }
5451
5452 if (msmsdcc_dt_parse_vreg_info(dev,
5453 &pdata->vreg_data->vdd_data, "vdd"))
5454 goto err;
5455
5456 if (msmsdcc_dt_parse_vreg_info(dev,
5457 &pdata->vreg_data->vdd_io_data, "vdd-io"))
5458 goto err;
5459
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305460 if (msmsdcc_dt_parse_gpio_info(dev, pdata))
5461 goto err;
5462
Devin Kim9ccbff52012-07-16 20:55:14 -07005463 len = of_property_count_strings(np, "qcom,sdcc-bus-speed-mode");
5464
5465 for (i = 0; i < len; i++) {
5466 const char *name = NULL;
5467
5468 of_property_read_string_index(np,
5469 "qcom,sdcc-bus-speed-mode", i, &name);
5470 if (!name)
5471 continue;
5472
5473 if (!strncmp(name, "SDR12", sizeof("SDR12")))
5474 pdata->uhs_caps |= MMC_CAP_UHS_SDR12;
5475 else if (!strncmp(name, "SDR25", sizeof("SDR25")))
5476 pdata->uhs_caps |= MMC_CAP_UHS_SDR25;
5477 else if (!strncmp(name, "SDR50", sizeof("SDR50")))
5478 pdata->uhs_caps |= MMC_CAP_UHS_SDR50;
5479 else if (!strncmp(name, "DDR50", sizeof("DDR50")))
5480 pdata->uhs_caps |= MMC_CAP_UHS_DDR50;
5481 else if (!strncmp(name, "SDR104", sizeof("SDR104")))
5482 pdata->uhs_caps |= MMC_CAP_UHS_SDR104;
5483 else if (!strncmp(name, "HS200_1p8v", sizeof("HS200_1p8v")))
5484 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_8V_SDR;
5485 else if (!strncmp(name, "HS200_1p2v", sizeof("HS200_1p2v")))
5486 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_2V_SDR;
5487 else if (!strncmp(name, "DDR_1p8v", sizeof("DDR_1p8v")))
5488 pdata->uhs_caps |= MMC_CAP_1_8V_DDR
5489 | MMC_CAP_UHS_DDR50;
5490 else if (!strncmp(name, "DDR_1p2v", sizeof("DDR_1p2v")))
5491 pdata->uhs_caps |= MMC_CAP_1_2V_DDR
5492 | MMC_CAP_UHS_DDR50;
5493 }
5494
5495 of_property_read_u32(np, "qcom,sdcc-current-limit", &current_limit);
5496 if (current_limit == 800)
5497 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_800;
5498 else if (current_limit == 600)
5499 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_600;
5500 else if (current_limit == 400)
5501 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_400;
5502 else if (current_limit == 200)
5503 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_200;
5504
5505 if (of_get_property(np, "qcom,sdcc-xpc", NULL))
5506 pdata->xpc_cap = true;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305507 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
5508 pdata->nonremovable = true;
5509 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
5510 pdata->disable_cmd23 = true;
5511
5512 return pdata;
5513err:
5514 return NULL;
5515}
5516
San Mehat9d2bd732009-09-22 16:44:22 -07005517static int
5518msmsdcc_probe(struct platform_device *pdev)
5519{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305520 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07005521 struct msmsdcc_host *host;
5522 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005523 unsigned long flags;
5524 struct resource *core_irqres = NULL;
5525 struct resource *bam_irqres = NULL;
5526 struct resource *core_memres = NULL;
5527 struct resource *dml_memres = NULL;
5528 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07005529 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07005530 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05305531 int ret = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07005532
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305533 if (pdev->dev.of_node) {
5534 plat = msmsdcc_populate_pdata(&pdev->dev);
5535 of_property_read_u32((&pdev->dev)->of_node,
5536 "cell-index", &pdev->id);
5537 } else {
5538 plat = pdev->dev.platform_data;
5539 }
San Mehat9d2bd732009-09-22 16:44:22 -07005540
5541 /* must have platform data */
5542 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005543 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005544 ret = -EINVAL;
5545 goto out;
5546 }
5547
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005548 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07005549 return -EINVAL;
5550
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305551 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
5552 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
5553 return -EINVAL;
5554 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005555
San Mehat9d2bd732009-09-22 16:44:22 -07005556 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005557 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005558 return -ENXIO;
5559 }
5560
Sujit Reddy Thumma1dfac2c2012-07-30 10:15:39 +05305561 core_memres = platform_get_resource_byname(pdev,
5562 IORESOURCE_MEM, "core_mem");
5563 bam_memres = platform_get_resource_byname(pdev,
5564 IORESOURCE_MEM, "bam_mem");
5565 dml_memres = platform_get_resource_byname(pdev,
5566 IORESOURCE_MEM, "dml_mem");
5567 core_irqres = platform_get_resource_byname(pdev,
5568 IORESOURCE_IRQ, "core_irq");
5569 bam_irqres = platform_get_resource_byname(pdev,
5570 IORESOURCE_IRQ, "bam_irq");
5571 dmares = platform_get_resource_byname(pdev,
5572 IORESOURCE_DMA, "dma_chnl");
5573 dma_crci_res = platform_get_resource_byname(pdev,
5574 IORESOURCE_DMA, "dma_crci");
San Mehat9d2bd732009-09-22 16:44:22 -07005575
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005576 if (!core_irqres || !core_memres) {
5577 pr_err("%s: Invalid sdcc core resource\n", __func__);
5578 return -ENXIO;
5579 }
5580
5581 /*
5582 * Both BAM and DML memory resource should be preset.
5583 * BAM IRQ resource should also be present.
5584 */
5585 if ((bam_memres && !dml_memres) ||
5586 (!bam_memres && dml_memres) ||
5587 ((bam_memres && dml_memres) && !bam_irqres)) {
5588 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005589 return -ENXIO;
5590 }
5591
5592 /*
5593 * Setup our host structure
5594 */
San Mehat9d2bd732009-09-22 16:44:22 -07005595 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
5596 if (!mmc) {
5597 ret = -ENOMEM;
5598 goto out;
5599 }
5600
5601 host = mmc_priv(mmc);
5602 host->pdev_id = pdev->id;
5603 host->plat = plat;
5604 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08005605 host->curr.cmd = NULL;
Sahitya Tummala19207f02011-05-02 18:10:01 +05305606
Sahitya Tummalad9df3272011-08-19 16:50:46 +05305607 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305608 set_hw_caps(host, MSMSDCC_SPS_BAM_SUP);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005609 else if (dmares)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305610 set_hw_caps(host, MSMSDCC_DMA_SUP);
San Mehat9d2bd732009-09-22 16:44:22 -07005611
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005612 host->base = ioremap(core_memres->start,
5613 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07005614 if (!host->base) {
5615 ret = -ENOMEM;
Sahitya Tummaladce7c752011-05-02 18:06:05 +05305616 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005617 }
5618
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005619 host->core_irqres = core_irqres;
5620 host->bam_irqres = bam_irqres;
5621 host->core_memres = core_memres;
5622 host->dml_memres = dml_memres;
5623 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07005624 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07005625 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07005626 spin_lock_init(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305627 mutex_init(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07005628
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005629#ifdef CONFIG_MMC_EMBEDDED_SDIO
5630 if (plat->embedded_sdio)
5631 mmc_set_embedded_sdio_data(mmc,
5632 &plat->embedded_sdio->cis,
5633 &plat->embedded_sdio->cccr,
5634 plat->embedded_sdio->funcs,
5635 plat->embedded_sdio->num_funcs);
5636#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005637
Sahitya Tummala62612cf2010-12-08 15:03:03 +05305638 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
5639 (unsigned long)host);
5640
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005641 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
5642 (unsigned long)host);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305643 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005644 /* Setup DMA */
Subhash Jadavani190657c2011-05-02 18:10:40 +05305645 ret = msmsdcc_init_dma(host);
5646 if (ret)
5647 goto ioremap_free;
5648 } else {
5649 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07005650 host->dma.crci = -1;
Subhash Jadavani190657c2011-05-02 18:10:40 +05305651 }
San Mehat9d2bd732009-09-22 16:44:22 -07005652
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005653 /*
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305654 * Setup SDCC bus voter clock.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005655 */
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305656 host->bus_clk = clk_get(&pdev->dev, "bus_clk");
5657 if (!IS_ERR_OR_NULL(host->bus_clk)) {
5658 /* Vote for max. clk rate for max. performance */
5659 ret = clk_set_rate(host->bus_clk, INT_MAX);
5660 if (ret)
5661 goto bus_clk_put;
5662 ret = clk_prepare_enable(host->bus_clk);
5663 if (ret)
5664 goto bus_clk_put;
San Mehat9d2bd732009-09-22 16:44:22 -07005665 }
5666
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005667 /*
5668 * Setup main peripheral bus clock
5669 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07005670 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005671 if (!IS_ERR(host->pclk)) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305672 ret = clk_prepare_enable(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005673 if (ret)
5674 goto pclk_put;
5675
5676 host->pclk_rate = clk_get_rate(host->pclk);
5677 }
5678
5679 /*
5680 * Setup SDC MMC clock
5681 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07005682 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07005683 if (IS_ERR(host->clk)) {
5684 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005685 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07005686 }
5687
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005688 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
Sahitya Tummala514d9ed2011-05-02 18:07:01 +05305689 if (ret) {
5690 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
5691 goto clk_put;
5692 }
5693
Asutosh Dasf5298c32012-04-03 14:51:47 +05305694 ret = clk_prepare_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07005695 if (ret)
5696 goto clk_put;
5697
San Mehat9d2bd732009-09-22 16:44:22 -07005698 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05305699 if (!host->clk_rate)
5700 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05305701
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305702 set_default_hw_caps(host);
5703
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05305704 /*
5705 * Set the register write delay according to min. clock frequency
5706 * supported and update later when the host->clk_rate changes.
5707 */
5708 host->reg_write_delay =
5709 (1 + ((3 * USEC_PER_SEC) /
5710 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005711
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305712 atomic_set(&host->clks_on, 1);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05305713 /* Apply Hard reset to SDCC to put it in power on default state */
5714 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005715
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005716#define MSM_MMC_DEFAULT_CPUDMA_LATENCY 200 /* usecs */
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305717 /* pm qos request to prevent apps idle power collapse */
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005718 if (host->plat->cpu_dma_latency)
5719 host->cpu_dma_latency = host->plat->cpu_dma_latency;
5720 else
5721 host->cpu_dma_latency = MSM_MMC_DEFAULT_CPUDMA_LATENCY;
5722 pm_qos_add_request(&host->pm_qos_req_dma,
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305723 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
5724
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305725 ret = msmsdcc_msm_bus_register(host);
5726 if (ret)
5727 goto pm_qos_remove;
5728
5729 if (host->msm_bus_vote.client_handle)
5730 INIT_DELAYED_WORK(&host->msm_bus_vote.vote_work,
5731 msmsdcc_msm_bus_work);
5732
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005733 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07005734 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005735 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07005736 goto clk_disable;
5737 }
5738
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005739
5740 /* Clocks has to be running before accessing SPS/DML HW blocks */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305741 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005742 /* Initialize SPS */
5743 ret = msmsdcc_sps_init(host);
5744 if (ret)
5745 goto vreg_deinit;
5746 /* Initialize DML */
5747 ret = msmsdcc_dml_init(host);
5748 if (ret)
5749 goto sps_exit;
5750 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05305751 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07005752
San Mehat9d2bd732009-09-22 16:44:22 -07005753 /*
5754 * Setup MMC host structure
5755 */
5756 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005757 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
5758 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005759 mmc->ocr_avail = plat->ocr_mask;
Sujit Reddy Thumma0e05f022012-06-11 19:44:18 +05305760 mmc->clkgate_delay = MSM_MMC_CLK_GATE_DELAY;
5761
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005762 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
5763 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07005764 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05305765 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
Asutosh Dasebd7d092012-07-09 19:08:26 +05305766 mmc->caps |= MMC_CAP_HW_RESET;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05305767 /*
5768 * If we send the CMD23 before multi block write/read command
5769 * then we need not to send CMD12 at the end of the transfer.
5770 * If we don't send the CMD12 then only way to detect the PROG_DONE
5771 * status is to use the AUTO_PROG_DONE status provided by SDCC4
5772 * controller. So let's enable the CMD23 for SDCC4 only.
5773 */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305774 if (!plat->disable_cmd23 && is_auto_prog_done(host))
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05305775 mmc->caps |= MMC_CAP_CMD23;
San Mehat9d2bd732009-09-22 16:44:22 -07005776
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005777 mmc->caps |= plat->uhs_caps;
Devin Kim9ccbff52012-07-16 20:55:14 -07005778 mmc->caps2 |= plat->uhs_caps2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005779 /*
5780 * XPC controls the maximum current in the default speed mode of SDXC
5781 * card. XPC=0 means 100mA (max.) but speed class is not supported.
5782 * XPC=1 means 150mA (max.) and speed class is supported.
5783 */
5784 if (plat->xpc_cap)
5785 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
5786 MMC_CAP_SET_XPC_180);
5787
Maya Erez231dd082012-11-28 23:55:57 +02005788
5789 /* packed write */
5790 mmc->caps2 |= plat->packed_write;
5791
Subhash Jadavani6bb34a82012-04-18 13:18:40 +05305792 mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
Yaniv Gardi14098552012-06-04 10:56:03 +03005793 mmc->caps2 |= MMC_CAP2_SANITIZE;
Maya Erezd0ed5ae2012-11-01 21:39:00 +02005794 mmc->caps2 |= MMC_CAP2_INIT_BKOPS;
Tatyana Brokhman139eabf2012-10-15 22:43:35 +02005795 mmc->caps2 |= MMC_CAP2_POWEROFF_NOTIFY;
Yaniv Gardi14098552012-06-04 10:56:03 +03005796
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005797 if (plat->nonremovable)
5798 mmc->caps |= MMC_CAP_NONREMOVABLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005799 mmc->caps |= MMC_CAP_SDIO_IRQ;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005800
5801 if (plat->is_sdio_al_client)
5802 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07005803
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305804 mmc->max_segs = msmsdcc_get_nr_sg(host);
5805 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
5806 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07005807
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305808 mmc->max_req_size = MMC_MAX_REQ_SIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07005809 mmc->max_seg_size = mmc->max_req_size;
5810
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005811 writel_relaxed(0, host->base + MMCIMASK0);
5812 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05305813 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005814
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005815 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
5816 mb();
5817 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07005818
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005819 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
5820 DRIVER_NAME " (cmd)", host);
5821 if (ret)
5822 goto dml_exit;
5823
5824 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
5825 DRIVER_NAME " (pio)", host);
5826 if (ret)
5827 goto irq_free;
5828
5829 /*
5830 * Enable SDCC IRQ only when host is powered on. Otherwise, this
5831 * IRQ is un-necessarily being monitored by MPM (Modem power
5832 * management block) during idle-power collapse. The MPM will be
5833 * configured to monitor the DATA1 GPIO line with level-low trigger
5834 * and thus depending on the GPIO status, it prevents TCXO shutdown
5835 * during idle-power collapse.
5836 */
5837 disable_irq(core_irqres->start);
5838 host->sdcc_irq_disabled = 1;
5839
5840 if (plat->sdiowakeup_irq) {
5841 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5842 mmc_hostname(mmc));
5843 ret = request_irq(plat->sdiowakeup_irq,
5844 msmsdcc_platform_sdiowakeup_irq,
5845 IRQF_SHARED | IRQF_TRIGGER_LOW,
5846 DRIVER_NAME "sdiowakeup", host);
5847 if (ret) {
5848 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
5849 plat->sdiowakeup_irq, ret);
5850 goto pio_irq_free;
5851 } else {
5852 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305853 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005854 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305855 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005856 }
5857 spin_unlock_irqrestore(&host->lock, flags);
5858 }
5859 }
5860
Subhash Jadavanic9b85752012-04-13 11:16:49 +05305861 if (host->plat->mpm_sdiowakeup_int) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005862 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5863 mmc_hostname(mmc));
5864 }
5865
5866 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
5867 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005868 /*
5869 * Setup card detect change
5870 */
5871
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305872 if (!plat->status_gpio)
5873 plat->status_gpio = -ENOENT;
5874 if (!plat->wpswitch_gpio)
5875 plat->wpswitch_gpio = -ENOENT;
5876
5877 if (plat->status || gpio_is_valid(plat->status_gpio)) {
Krishna Konda941604a2012-01-10 17:46:34 -08005878 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005879 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08005880 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005881 host->oldstat = msmsdcc_slot_status(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005882
Krishna Konda941604a2012-01-10 17:46:34 -08005883 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005884 }
San Mehat9d2bd732009-09-22 16:44:22 -07005885
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005886 if (plat->status_irq) {
5887 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07005888 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005889 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07005890 DRIVER_NAME " (slot)",
5891 host);
5892 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005893 pr_err("Unable to get slot IRQ %d (%d)\n",
5894 plat->status_irq, ret);
5895 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005896 }
5897 } else if (plat->register_status_notify) {
5898 plat->register_status_notify(msmsdcc_status_notify_cb, host);
5899 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005900 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07005901 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005902
5903 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005904
5905 ret = pm_runtime_set_active(&(pdev)->dev);
5906 if (ret < 0)
5907 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
5908 __func__, ret);
5909 /*
5910 * There is no notion of suspend/resume for SD/MMC/SDIO
5911 * cards. So host can be suspended/resumed with out
5912 * worrying about its children.
5913 */
5914 pm_suspend_ignore_children(&(pdev)->dev, true);
5915
5916 /*
5917 * MMC/SD/SDIO bus suspend/resume operations are defined
5918 * only for the slots that will be used for non-removable
5919 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
5920 * defined. Otherwise, they simply become card removal and
5921 * insertion events during suspend and resume respectively.
5922 * Hence, enable run-time PM only for slots for which bus
5923 * suspend/resume operations are defined.
5924 */
5925#ifdef CONFIG_MMC_UNSAFE_RESUME
5926 /*
5927 * If this capability is set, MMC core will enable/disable host
5928 * for every claim/release operation on a host. We use this
5929 * notification to increment/decrement runtime pm usage count.
5930 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005931 pm_runtime_enable(&(pdev)->dev);
5932#else
5933 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005934 pm_runtime_enable(&(pdev)->dev);
5935 }
5936#endif
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305937 host->idle_tout_ms = MSM_MMC_DEFAULT_IDLE_TIMEOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005938 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
5939 (unsigned long)host);
5940
San Mehat9d2bd732009-09-22 16:44:22 -07005941 mmc_add_host(mmc);
5942
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005943#ifdef CONFIG_HAS_EARLYSUSPEND
5944 host->early_suspend.suspend = msmsdcc_early_suspend;
5945 host->early_suspend.resume = msmsdcc_late_resume;
5946 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
5947 register_early_suspend(&host->early_suspend);
5948#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005949
Krishna Konda25786ec2011-07-25 16:21:36 -07005950 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
5951 " dmacrcri %d\n", mmc_hostname(mmc),
5952 (unsigned long long)core_memres->start,
5953 (unsigned int) core_irqres->start,
5954 (unsigned int) plat->status_irq, host->dma.channel,
5955 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005956
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305957 pr_info("%s: Controller capabilities: 0x%.8x\n",
5958 mmc_hostname(mmc), host->hw_caps);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005959 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
5960 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
5961 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
5962 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
5963 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
5964 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
5965 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
5966 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
5967 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
5968 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
5969 host->eject);
5970 pr_info("%s: Power save feature enable = %d\n",
5971 mmc_hostname(mmc), msmsdcc_pwrsave);
5972
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305973 if (is_dma_mode(host) && host->dma.channel != -1
Krishna Konda25786ec2011-07-25 16:21:36 -07005974 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005975 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005976 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005977 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005978 mmc_hostname(mmc), host->dma.cmd_busaddr,
5979 host->dma.cmdptr_busaddr);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305980 } else if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005981 pr_info("%s: SPS-BAM data transfer mode available\n",
5982 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005983 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005984 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005985
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005986#if defined(CONFIG_DEBUG_FS)
5987 msmsdcc_dbg_createhost(host);
5988#endif
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305989
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305990 host->max_bus_bw.show = show_sdcc_to_mem_max_bus_bw;
5991 host->max_bus_bw.store = store_sdcc_to_mem_max_bus_bw;
5992 sysfs_attr_init(&host->max_bus_bw.attr);
5993 host->max_bus_bw.attr.name = "max_bus_bw";
5994 host->max_bus_bw.attr.mode = S_IRUGO | S_IWUSR;
5995 ret = device_create_file(&pdev->dev, &host->max_bus_bw);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305996 if (ret)
5997 goto platform_irq_free;
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305998
5999 if (!plat->status_irq) {
6000 host->polling.show = show_polling;
6001 host->polling.store = store_polling;
6002 sysfs_attr_init(&host->polling.attr);
6003 host->polling.attr.name = "polling";
6004 host->polling.attr.mode = S_IRUGO | S_IWUSR;
6005 ret = device_create_file(&pdev->dev, &host->polling);
6006 if (ret)
6007 goto remove_max_bus_bw_file;
6008 }
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306009 host->idle_timeout.show = show_idle_timeout;
6010 host->idle_timeout.store = store_idle_timeout;
6011 sysfs_attr_init(&host->idle_timeout.attr);
6012 host->idle_timeout.attr.name = "idle_timeout";
6013 host->idle_timeout.attr.mode = S_IRUGO | S_IWUSR;
6014 ret = device_create_file(&pdev->dev, &host->idle_timeout);
6015 if (ret)
6016 goto remove_polling_file;
San Mehat9d2bd732009-09-22 16:44:22 -07006017 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006018
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306019 remove_polling_file:
6020 if (!plat->status_irq)
6021 device_remove_file(&pdev->dev, &host->polling);
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306022 remove_max_bus_bw_file:
6023 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006024 platform_irq_free:
6025 del_timer_sync(&host->req_tout_timer);
6026 pm_runtime_disable(&(pdev)->dev);
6027 pm_runtime_set_suspended(&(pdev)->dev);
6028
6029 if (plat->status_irq)
6030 free_irq(plat->status_irq, host);
6031 sdiowakeup_irq_free:
6032 wake_lock_destroy(&host->sdio_suspend_wlock);
6033 if (plat->sdiowakeup_irq)
6034 free_irq(plat->sdiowakeup_irq, host);
6035 pio_irq_free:
6036 if (plat->sdiowakeup_irq)
6037 wake_lock_destroy(&host->sdio_wlock);
6038 free_irq(core_irqres->start, host);
6039 irq_free:
6040 free_irq(core_irqres->start, host);
6041 dml_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306042 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006043 msmsdcc_dml_exit(host);
6044 sps_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306045 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006046 msmsdcc_sps_exit(host);
6047 vreg_deinit:
6048 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07006049 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006050 clk_disable(host->clk);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306051 msmsdcc_msm_bus_unregister(host);
6052 pm_qos_remove:
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006053 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306054 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07006055 clk_put:
6056 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006057 pclk_disable:
6058 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05306059 clk_disable_unprepare(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07006060 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006061 if (!IS_ERR(host->pclk))
6062 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05306063 if (!IS_ERR_OR_NULL(host->bus_clk))
6064 clk_disable_unprepare(host->bus_clk);
6065 bus_clk_put:
6066 if (!IS_ERR_OR_NULL(host->bus_clk))
6067 clk_put(host->bus_clk);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306068 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006069 if (host->dmares)
6070 dma_free_coherent(NULL,
6071 sizeof(struct msmsdcc_nc_dmadata),
6072 host->dma.nc, host->dma.nc_busaddr);
6073 }
6074 ioremap_free:
Sahitya Tummaladce7c752011-05-02 18:06:05 +05306075 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07006076 host_free:
6077 mmc_free_host(mmc);
6078 out:
6079 return ret;
6080}
6081
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006082static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07006083{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006084 struct mmc_host *mmc = mmc_get_drvdata(pdev);
6085 struct mmc_platform_data *plat;
6086 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07006087
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006088 if (!mmc)
6089 return -ENXIO;
6090
6091 if (pm_runtime_suspended(&(pdev)->dev))
6092 pm_runtime_resume(&(pdev)->dev);
6093
6094 host = mmc_priv(mmc);
6095
6096 DBG(host, "Removing SDCC device = %d\n", pdev->id);
6097 plat = host->plat;
6098
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306099 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006100 if (!plat->status_irq)
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306101 device_remove_file(&pdev->dev, &host->polling);
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306102 device_remove_file(&pdev->dev, &host->idle_timeout);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006103
6104 del_timer_sync(&host->req_tout_timer);
6105 tasklet_kill(&host->dma_tlet);
6106 tasklet_kill(&host->sps.tlet);
6107 mmc_remove_host(mmc);
6108
6109 if (plat->status_irq)
6110 free_irq(plat->status_irq, host);
6111
6112 wake_lock_destroy(&host->sdio_suspend_wlock);
6113 if (plat->sdiowakeup_irq) {
6114 wake_lock_destroy(&host->sdio_wlock);
6115 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
6116 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07006117 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006118
6119 free_irq(host->core_irqres->start, host);
6120 free_irq(host->core_irqres->start, host);
6121
6122 clk_put(host->clk);
6123 if (!IS_ERR(host->pclk))
6124 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05306125 if (!IS_ERR_OR_NULL(host->bus_clk))
6126 clk_put(host->bus_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006127
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006128 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306129 pm_qos_remove_request(&host->pm_qos_req_dma);
6130
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306131 if (host->msm_bus_vote.client_handle) {
6132 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
6133 msmsdcc_msm_bus_unregister(host);
6134 }
6135
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006136 msmsdcc_vreg_init(host, false);
6137
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306138 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006139 if (host->dmares)
6140 dma_free_coherent(NULL,
6141 sizeof(struct msmsdcc_nc_dmadata),
6142 host->dma.nc, host->dma.nc_busaddr);
6143 }
6144
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306145 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006146 msmsdcc_dml_exit(host);
6147 msmsdcc_sps_exit(host);
6148 }
6149
6150 iounmap(host->base);
6151 mmc_free_host(mmc);
6152
6153#ifdef CONFIG_HAS_EARLYSUSPEND
6154 unregister_early_suspend(&host->early_suspend);
6155#endif
6156 pm_runtime_disable(&(pdev)->dev);
6157 pm_runtime_set_suspended(&(pdev)->dev);
6158
6159 return 0;
6160}
6161
6162#ifdef CONFIG_MSM_SDIO_AL
6163int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
6164{
6165 struct msmsdcc_host *host = mmc_priv(mmc);
6166 unsigned long flags;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306167 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006168
Asutosh Dasf5298c32012-04-03 14:51:47 +05306169 mutex_lock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006170 spin_lock_irqsave(&host->lock, flags);
6171 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
6172 enable ? "En" : "Dis");
6173
6174 if (enable) {
6175 if (!host->sdcc_irq_disabled) {
6176 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05306177 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006178 host->sdcc_irq_disabled = 1;
6179 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306180 rc = msmsdcc_setup_clocks(host, false);
6181 if (rc)
6182 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006183
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05306184 if (host->plat->sdio_lpm_gpio_setup &&
6185 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006186 spin_unlock_irqrestore(&host->lock, flags);
6187 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
6188 spin_lock_irqsave(&host->lock, flags);
6189 host->sdio_gpio_lpm = 1;
6190 }
6191
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306192 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006193 msmsdcc_enable_irq_wake(host);
6194 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306195 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006196 }
6197 } else {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306198 rc = msmsdcc_setup_clocks(host, true);
6199 if (rc)
6200 goto out;
6201
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306202 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006203 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306204 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006205 msmsdcc_disable_irq_wake(host);
6206 }
6207
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05306208 if (host->plat->sdio_lpm_gpio_setup &&
6209 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006210 spin_unlock_irqrestore(&host->lock, flags);
6211 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
6212 spin_lock_irqsave(&host->lock, flags);
6213 host->sdio_gpio_lpm = 0;
6214 }
6215
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306216 if (host->sdcc_irq_disabled && atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006217 writel_relaxed(host->mci_irqenable,
6218 host->base + MMCIMASK0);
6219 mb();
6220 enable_irq(host->core_irqres->start);
6221 host->sdcc_irq_disabled = 0;
6222 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006223 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306224out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006225 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05306226 mutex_unlock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306227 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006228}
6229#else
6230int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
6231{
6232 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07006233}
6234#endif
6235
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006236#ifdef CONFIG_PM
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306237#ifdef CONFIG_MMC_CLKGATE
6238static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6239{
6240 struct mmc_host *mmc = host->mmc;
6241 unsigned long flags;
6242
6243 mmc_host_clk_hold(mmc);
6244 spin_lock_irqsave(&mmc->clk_lock, flags);
6245 mmc->clk_old = mmc->ios.clock;
6246 mmc->ios.clock = 0;
6247 mmc->clk_gated = true;
6248 spin_unlock_irqrestore(&mmc->clk_lock, flags);
6249 mmc_set_ios(mmc);
6250 mmc_host_clk_release(mmc);
6251}
6252
6253static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6254{
6255 struct mmc_host *mmc = host->mmc;
6256
6257 mmc_host_clk_hold(mmc);
6258 mmc->ios.clock = host->clk_rate;
6259 mmc_set_ios(mmc);
6260 mmc_host_clk_release(mmc);
6261}
6262#else
6263static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6264{
6265 struct mmc_host *mmc = host->mmc;
6266
6267 mmc->ios.clock = 0;
6268 mmc_set_ios(mmc);
6269}
6270
6271static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6272{
6273 struct mmc_host *mmc = host->mmc;
6274
6275 mmc->ios.clock = host->clk_rate;
6276 mmc_set_ios(mmc);
6277}
6278#endif
6279
San Mehat9d2bd732009-09-22 16:44:22 -07006280static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006281msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006282{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006283 struct mmc_host *mmc = dev_get_drvdata(dev);
6284 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006285 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306286 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07006287
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306288 if (host->plat->is_sdio_al_client) {
6289 rc = 0;
6290 goto out;
San Mehat9d2bd732009-09-22 16:44:22 -07006291 }
San Mehat9d2bd732009-09-22 16:44:22 -07006292
Sahitya Tummala7661a452011-07-18 13:28:35 +05306293 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006294 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006295 host->sdcc_suspending = 1;
6296 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07006297
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006298 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006299 * MMC core thinks that host is disabled by now since
6300 * runtime suspend is scheduled after msmsdcc_disable()
6301 * is called. Thus, MMC core will try to enable the host
6302 * while suspending it. This results in a synchronous
6303 * runtime resume request while in runtime suspending
6304 * context and hence inorder to complete this resume
6305 * requet, it will wait for suspend to be complete,
6306 * but runtime suspend also can not proceed further
6307 * until the host is resumed. Thus, it leads to a hang.
6308 * Hence, increase the pm usage count before suspending
6309 * the host so that any resume requests after this will
6310 * simple become pm usage counter increment operations.
6311 */
6312 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306313 /* If there is pending detect work abort runtime suspend */
6314 if (unlikely(work_busy(&mmc->detect.work)))
6315 rc = -EAGAIN;
6316 else
6317 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006318 pm_runtime_put_noidle(dev);
6319
6320 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306321 spin_lock_irqsave(&host->lock, flags);
6322 host->sdcc_suspended = true;
6323 spin_unlock_irqrestore(&host->lock, flags);
6324 if (mmc->card && mmc_card_sdio(mmc->card) &&
6325 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006326 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306327 * If SDIO function driver doesn't want
6328 * to power off the card, atleast turn off
6329 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006330 */
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306331 msmsdcc_gate_clock(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006332 }
6333 }
6334 host->sdcc_suspending = 0;
6335 mmc->suspend_task = NULL;
6336 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
6337 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006338 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306339 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306340out:
6341 /* set bus bandwidth to 0 immediately */
6342 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
San Mehat9d2bd732009-09-22 16:44:22 -07006343 return rc;
6344}
6345
6346static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006347msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006348{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006349 struct mmc_host *mmc = dev_get_drvdata(dev);
6350 struct msmsdcc_host *host = mmc_priv(mmc);
6351 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07006352
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006353 if (host->plat->is_sdio_al_client)
6354 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07006355
Sahitya Tummala7661a452011-07-18 13:28:35 +05306356 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006357 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306358 if (mmc->card && mmc_card_sdio(mmc->card) &&
6359 mmc_card_keep_power(mmc)) {
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306360 msmsdcc_ungate_clock(host);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05306361 }
San Mehat9d2bd732009-09-22 16:44:22 -07006362
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006363 mmc_resume_host(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006364
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006365 /*
6366 * FIXME: Clearing of flags must be handled in clients
6367 * resume handler.
6368 */
6369 spin_lock_irqsave(&host->lock, flags);
6370 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306371 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006372 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07006373
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006374 /*
6375 * After resuming the host wait for sometime so that
6376 * the SDIO work will be processed.
6377 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306378 if (mmc->card && mmc_card_sdio(mmc->card)) {
Subhash Jadavanic9b85752012-04-13 11:16:49 +05306379 if ((host->plat->mpm_sdiowakeup_int ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006380 host->plat->sdiowakeup_irq) &&
6381 wake_lock_active(&host->sdio_wlock))
6382 wake_lock_timeout(&host->sdio_wlock, 1);
6383 }
6384
6385 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006386 }
Subhash Jadavani1371d192012-08-16 18:46:57 +05306387 host->pending_resume = false;
Sahitya Tummala7661a452011-07-18 13:28:35 +05306388 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006389 return 0;
6390}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006391
6392static int msmsdcc_runtime_idle(struct device *dev)
6393{
6394 struct mmc_host *mmc = dev_get_drvdata(dev);
6395 struct msmsdcc_host *host = mmc_priv(mmc);
6396
6397 if (host->plat->is_sdio_al_client)
6398 return 0;
6399
6400 /* Idle timeout is not configurable for now */
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306401 pm_schedule_suspend(dev, host->idle_tout_ms);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006402
6403 return -EAGAIN;
6404}
6405
6406static int msmsdcc_pm_suspend(struct device *dev)
6407{
6408 struct mmc_host *mmc = dev_get_drvdata(dev);
6409 struct msmsdcc_host *host = mmc_priv(mmc);
6410 int rc = 0;
6411
6412 if (host->plat->is_sdio_al_client)
6413 return 0;
6414
6415
6416 if (host->plat->status_irq)
6417 disable_irq(host->plat->status_irq);
6418
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006419 if (!pm_runtime_suspended(dev))
6420 rc = msmsdcc_runtime_suspend(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006421
6422 return rc;
6423}
6424
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306425static int msmsdcc_suspend_noirq(struct device *dev)
6426{
6427 struct mmc_host *mmc = dev_get_drvdata(dev);
6428 struct msmsdcc_host *host = mmc_priv(mmc);
6429 int rc = 0;
6430
6431 /*
6432 * After platform suspend there may be active request
6433 * which might have enabled clocks. For example, in SDIO
6434 * case, ksdioirq thread might have scheduled after sdcc
6435 * suspend but before system freeze. In that case abort
6436 * suspend and retry instead of keeping the clocks on
6437 * during suspend and not allowing TCXO.
6438 */
6439
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306440 if (atomic_read(&host->clks_on) && !host->plat->is_sdio_al_client) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306441 pr_warn("%s: clocks are on after suspend, aborting system "
6442 "suspend\n", mmc_hostname(mmc));
6443 rc = -EAGAIN;
6444 }
6445
6446 return rc;
6447}
6448
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006449static int msmsdcc_pm_resume(struct device *dev)
6450{
6451 struct mmc_host *mmc = dev_get_drvdata(dev);
6452 struct msmsdcc_host *host = mmc_priv(mmc);
6453 int rc = 0;
6454
6455 if (host->plat->is_sdio_al_client)
6456 return 0;
6457
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006458 if (mmc->card && mmc_card_sdio(mmc->card))
Sahitya Tummalafb486372011-09-02 19:01:49 +05306459 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavani1371d192012-08-16 18:46:57 +05306460 /*
6461 * As runtime PM is enabled before calling the device's platform resume
6462 * callback, we use the pm_runtime_suspended API to know if SDCC is
6463 * really runtime suspended or not and set the pending_resume flag only
6464 * if its not runtime suspended.
6465 */
6466 else if (!pm_runtime_suspended(dev))
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006467 host->pending_resume = true;
6468
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006469 if (host->plat->status_irq) {
6470 msmsdcc_check_status((unsigned long)host);
6471 enable_irq(host->plat->status_irq);
6472 }
6473
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006474 return rc;
6475}
6476
Daniel Walker08ecfde2010-06-23 12:32:20 -07006477#else
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006478static int msmsdcc_runtime_suspend(struct device *dev)
6479{
6480 return 0;
6481}
6482static int msmsdcc_runtime_idle(struct device *dev)
6483{
6484 return 0;
6485}
6486static int msmsdcc_pm_suspend(struct device *dev)
6487{
6488 return 0;
6489}
6490static int msmsdcc_pm_resume(struct device *dev)
6491{
6492 return 0;
6493}
6494static int msmsdcc_suspend_noirq(struct device *dev)
6495{
6496 return 0;
6497}
6498static int msmsdcc_runtime_resume(struct device *dev)
6499{
6500 return 0;
6501}
Daniel Walker08ecfde2010-06-23 12:32:20 -07006502#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006503
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006504static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
6505 .runtime_suspend = msmsdcc_runtime_suspend,
6506 .runtime_resume = msmsdcc_runtime_resume,
6507 .runtime_idle = msmsdcc_runtime_idle,
6508 .suspend = msmsdcc_pm_suspend,
6509 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306510 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006511};
6512
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306513static const struct of_device_id msmsdcc_dt_match[] = {
6514 {.compatible = "qcom,msm-sdcc"},
6515
6516};
6517MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
6518
San Mehat9d2bd732009-09-22 16:44:22 -07006519static struct platform_driver msmsdcc_driver = {
6520 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006521 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07006522 .driver = {
6523 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006524 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306525 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07006526 },
6527};
6528
6529static int __init msmsdcc_init(void)
6530{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006531#if defined(CONFIG_DEBUG_FS)
6532 int ret = 0;
6533 ret = msmsdcc_dbg_init();
6534 if (ret) {
6535 pr_err("Failed to create debug fs dir \n");
6536 return ret;
6537 }
6538#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006539 return platform_driver_register(&msmsdcc_driver);
6540}
San Mehat9d2bd732009-09-22 16:44:22 -07006541
San Mehat9d2bd732009-09-22 16:44:22 -07006542static void __exit msmsdcc_exit(void)
6543{
6544 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006545
6546#if defined(CONFIG_DEBUG_FS)
6547 debugfs_remove(debugfs_file);
6548 debugfs_remove(debugfs_dir);
6549#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006550}
6551
6552module_init(msmsdcc_init);
6553module_exit(msmsdcc_exit);
6554
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006555MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07006556MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006557
6558#if defined(CONFIG_DEBUG_FS)
6559
6560static int
6561msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
6562{
6563 file->private_data = inode->i_private;
6564 return 0;
6565}
6566
6567static ssize_t
6568msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
6569 size_t count, loff_t *ppos)
6570{
6571 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08006572 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006573 int max, i;
6574
6575 i = 0;
6576 max = sizeof(buf) - 1;
6577
6578 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
6579 host->curr.cmd, host->curr.data);
6580 if (host->curr.cmd) {
6581 struct mmc_command *cmd = host->curr.cmd;
6582
6583 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
6584 cmd->opcode, cmd->arg, cmd->flags);
6585 }
6586 if (host->curr.data) {
6587 struct mmc_data *data = host->curr.data;
6588 i += scnprintf(buf + i, max - i,
6589 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
6590 data->timeout_ns, data->timeout_clks,
6591 data->blksz, data->blocks, data->error,
6592 data->flags);
6593 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
6594 host->curr.xfer_size, host->curr.xfer_remain,
6595 host->curr.data_xfered, host->dma.sg);
6596 }
6597
6598 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
6599}
6600
6601static const struct file_operations msmsdcc_dbg_state_ops = {
6602 .read = msmsdcc_dbg_state_read,
6603 .open = msmsdcc_dbg_state_open,
6604};
6605
6606static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
6607{
6608 if (debugfs_dir) {
6609 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
6610 0644, debugfs_dir, host,
6611 &msmsdcc_dbg_state_ops);
6612 }
6613}
6614
6615static int __init msmsdcc_dbg_init(void)
6616{
6617 int err;
6618
6619 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
6620 if (IS_ERR(debugfs_dir)) {
6621 err = PTR_ERR(debugfs_dir);
6622 debugfs_dir = NULL;
6623 return err;
6624 }
6625
6626 return 0;
6627}
6628#endif