blob: 0938305860897f8b5276443ad67f6ed44d50f968 [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.
Duy Truonge833aca2013-02-12 13:35:08 -08006 * Copyright (c) 2009-2012, The Linux Foundation. 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);
Maya Erez00d7be62013-02-05 13:19:52 +0200161static bool msmsdcc_is_wait_for_auto_prog_done(struct msmsdcc_host *host,
162 struct mmc_request *mrq);
163static bool msmsdcc_is_wait_for_prog_done(struct msmsdcc_host *host,
164 struct mmc_request *mrq);
San Mehat9d2bd732009-09-22 16:44:22 -0700165
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530166static inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530167{
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530168 unsigned short ret = NR_SG;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530169
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530170 if (is_sps_mode(host)) {
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +0530171 ret = SPS_MAX_DESCS;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530172 } else { /* DMA or PIO mode */
173 if (NR_SG > MAX_NR_SG_DMA_PIO)
174 ret = MAX_NR_SG_DMA_PIO;
175 }
176
177 return ret;
178}
179
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530180/* Prevent idle power collapse(pc) while operating in peripheral mode */
181static void msmsdcc_pm_qos_update_latency(struct msmsdcc_host *host, int vote)
182{
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -0700183 if (!host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530184 return;
185
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530186 if (vote)
187 pm_qos_update_request(&host->pm_qos_req_dma,
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -0700188 host->cpu_dma_latency);
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530189 else
190 pm_qos_update_request(&host->pm_qos_req_dma,
191 PM_QOS_DEFAULT_VALUE);
192}
193
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700194#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
195static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
196 struct msmsdcc_sps_ep_conn_data *ep);
197static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
198 struct msmsdcc_sps_ep_conn_data *ep);
199#else
200static inline int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
201 struct msmsdcc_sps_ep_conn_data *ep,
202 bool is_producer) { return 0; }
203static inline void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
204 struct msmsdcc_sps_ep_conn_data *ep) { }
205static inline int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
206 struct msmsdcc_sps_ep_conn_data *ep)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530207{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700208 return 0;
209}
210static inline int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
211 struct msmsdcc_sps_ep_conn_data *ep)
212{
213 return 0;
214}
215static inline int msmsdcc_sps_init(struct msmsdcc_host *host) { return 0; }
216static inline void msmsdcc_sps_exit(struct msmsdcc_host *host) {}
217#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530218
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700219/**
Maya Erezb7a086f2012-11-29 00:37:36 +0200220 * Apply reset
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530221 *
Maya Erezb7a086f2012-11-29 00:37:36 +0200222 * This function resets SPS BAM and DML cores.
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530223 *
224 * This function should be called to recover from error
225 * conditions encountered during CMD/DATA tranfsers with card.
226 *
227 * @host - Pointer to driver's host structure
228 *
229 */
Maya Erezb7a086f2012-11-29 00:37:36 +0200230static int msmsdcc_bam_dml_reset_and_restore(struct msmsdcc_host *host)
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530231{
232 int rc;
233
234 /* Reset all SDCC BAM pipes */
235 rc = msmsdcc_sps_reset_ep(host, &host->sps.prod);
Maya Erezb7a086f2012-11-29 00:37:36 +0200236 if (rc) {
237 pr_err("%s: msmsdcc_sps_reset_ep(prod) error=%d\n",
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530238 mmc_hostname(host->mmc), rc);
Maya Erezb7a086f2012-11-29 00:37:36 +0200239 goto out;
240 }
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530241
Maya Erezb7a086f2012-11-29 00:37:36 +0200242 rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
243 if (rc) {
244 pr_err("%s: msmsdcc_sps_reset_ep(cons) error=%d\n",
Krishna Konda5af8f972012-05-14 16:15:24 -0700245 mmc_hostname(host->mmc), rc);
Maya Erezb7a086f2012-11-29 00:37:36 +0200246 goto out;
247 }
248
249 /* Reset BAM */
250 rc = sps_device_reset(host->sps.bam_handle);
251 if (rc) {
252 pr_err("%s: sps_device_reset error=%d\n",
253 mmc_hostname(host->mmc), rc);
254 goto out;
Krishna Konda5af8f972012-05-14 16:15:24 -0700255 }
256
Sujit Reddy Thumma96838fe2013-02-10 17:01:30 +0530257 memset(host->sps.prod.config.desc.base, 0x00,
258 host->sps.prod.config.desc.size);
259 memset(host->sps.cons.config.desc.base, 0x00,
260 host->sps.cons.config.desc.size);
261
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530262 /* Restore all BAM pipes connections */
263 rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
Maya Erezb7a086f2012-11-29 00:37:36 +0200264 if (rc) {
265 pr_err("%s: msmsdcc_sps_restore_ep(prod) error=%d\n",
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530266 mmc_hostname(host->mmc), rc);
Maya Erezb7a086f2012-11-29 00:37:36 +0200267 goto out;
268 }
269
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530270 rc = msmsdcc_sps_restore_ep(host, &host->sps.cons);
Sujit Reddy Thumma8ce39122012-12-27 17:24:45 +0530271 if (rc) {
Maya Erezb7a086f2012-11-29 00:37:36 +0200272 pr_err("%s: msmsdcc_sps_restore_ep(cons) error=%d\n",
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530273 mmc_hostname(host->mmc), rc);
Sujit Reddy Thumma8ce39122012-12-27 17:24:45 +0530274 goto out;
275 }
276
277 /* Reset and init DML */
278 rc = msmsdcc_dml_init(host);
279 if (rc)
280 pr_err("%s: msmsdcc_dml_init error=%d\n",
281 mmc_hostname(host->mmc), rc);
Maya Erezb7a086f2012-11-29 00:37:36 +0200282
283out:
Sujit Reddy Thumma8ce39122012-12-27 17:24:45 +0530284 if (!rc)
285 host->sps.reset_bam = false;
Maya Erezb7a086f2012-11-29 00:37:36 +0200286 return rc;
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530287}
288
289/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700290 * Apply soft reset
291 *
Maya Erezb7a086f2012-11-29 00:37:36 +0200292 * This function applies soft reset to SDCC core.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700293 *
294 * This function should be called to recover from error
295 * conditions encountered with CMD/DATA tranfsers with card.
296 *
297 * Soft reset should only be used with SDCC controller v4.
298 *
299 * @host - Pointer to driver's host structure
300 *
301 */
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530302static void msmsdcc_soft_reset(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700303{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700304 /*
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530305 * Reset controller state machines without resetting
306 * configuration registers (MCI_POWER, MCI_CLK, MCI_INT_MASKn).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700307 */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530308 if (is_sw_reset_save_config(host)) {
309 ktime_t start;
310
311 writel_relaxed(readl_relaxed(host->base + MMCIPOWER)
312 | MCI_SW_RST_CFG, host->base + MMCIPOWER);
313 msmsdcc_sync_reg_wr(host);
314
315 start = ktime_get();
316 while (readl_relaxed(host->base + MMCIPOWER) & MCI_SW_RST_CFG) {
317 /*
318 * SW reset can take upto 10HCLK + 15MCLK cycles.
319 * Calculating based on min clk rates (hclk = 27MHz,
320 * mclk = 400KHz) it comes to ~40us. Let's poll for
321 * max. 1ms for reset completion.
322 */
323 if (ktime_to_us(ktime_sub(ktime_get(), start)) > 1000) {
324 pr_err("%s: %s failed\n",
325 mmc_hostname(host->mmc), __func__);
326 BUG();
327 }
328 }
329 } else {
330 writel_relaxed(0, host->base + MMCICOMMAND);
331 msmsdcc_sync_reg_wr(host);
332 writel_relaxed(0, host->base + MMCIDATACTRL);
333 msmsdcc_sync_reg_wr(host);
334 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530335}
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530336
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530337static void msmsdcc_hard_reset(struct msmsdcc_host *host)
338{
339 int ret;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530340
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530341 /*
342 * Reset SDCC controller to power on default state.
343 * Don't issue a reset request to clock control block if
344 * SDCC controller itself can support hard reset.
345 */
346 if (is_sw_hard_reset(host)) {
347 ktime_t start;
348
349 writel_relaxed(readl_relaxed(host->base + MMCIPOWER)
350 | MCI_SW_RST, host->base + MMCIPOWER);
351 msmsdcc_sync_reg_wr(host);
352
353 start = ktime_get();
354 while (readl_relaxed(host->base + MMCIPOWER) & MCI_SW_RST) {
355 /*
356 * See comment in msmsdcc_soft_reset() on choosing 1ms
357 * poll timeout.
358 */
359 if (ktime_to_us(ktime_sub(ktime_get(), start)) > 1000) {
360 pr_err("%s: %s failed\n",
361 mmc_hostname(host->mmc), __func__);
362 BUG();
363 }
364 }
365 } else {
366 ret = clk_reset(host->clk, CLK_RESET_ASSERT);
367 if (ret)
368 pr_err("%s: Clock assert failed at %u Hz" \
369 " with err %d\n", mmc_hostname(host->mmc),
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530370 host->clk_rate, ret);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530371
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530372 ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
373 if (ret)
374 pr_err("%s: Clock deassert failed at %u Hz" \
375 " with err %d\n", mmc_hostname(host->mmc),
376 host->clk_rate, ret);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530377
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530378 mb();
379 /* Give some delay for clock reset to propogate to controller */
380 msmsdcc_delay(host);
381 }
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530382}
383
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700384static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
385{
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530386 if (is_soft_reset(host)) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530387 msmsdcc_soft_reset(host);
388
389 pr_debug("%s: Applied soft reset to Controller\n",
390 mmc_hostname(host->mmc));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700391 } else {
392 /* Give Clock reset (hard reset) to controller */
393 u32 mci_clk = 0;
394 u32 mci_mask0 = 0;
Sujit Reddy Thumma96838fe2013-02-10 17:01:30 +0530395 u32 dll_config = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700396
397 /* Save the controller state */
398 mci_clk = readl_relaxed(host->base + MMCICLOCK);
399 mci_mask0 = readl_relaxed(host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +0530400 host->pwr = readl_relaxed(host->base + MMCIPOWER);
Sujit Reddy Thumma96838fe2013-02-10 17:01:30 +0530401 if (host->tuning_needed)
402 dll_config = readl_relaxed(host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700403 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700404
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530405 msmsdcc_hard_reset(host);
Sujit Reddy Thumma96838fe2013-02-10 17:01:30 +0530406 pr_debug("%s: Applied hard reset to controller\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700407 mmc_hostname(host->mmc));
408
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700409 /* Restore the contoller state */
410 writel_relaxed(host->pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530411 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700412 writel_relaxed(mci_clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530413 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700414 writel_relaxed(mci_mask0, host->base + MMCIMASK0);
Sujit Reddy Thumma96838fe2013-02-10 17:01:30 +0530415 if (host->tuning_needed)
416 writel_relaxed(dll_config, host->base + MCI_DLL_CONFIG);
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
Sujit Reddy Thumma96838fe2013-02-10 17:01:30 +0530420 if (is_sps_mode(host))
421 /*
422 * delay the SPS BAM reset in thread context as
423 * sps_connect/sps_disconnect APIs can be called
424 * only from non-atomic context.
425 */
426 host->sps.reset_bam = true;
427
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700428 if (host->dummy_52_needed)
429 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700430}
431
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530432static void msmsdcc_reset_dpsm(struct msmsdcc_host *host)
433{
434 struct mmc_request *mrq = host->curr.mrq;
435
Maya Erez00d7be62013-02-05 13:19:52 +0200436 if (!mrq || !mrq->cmd || !mrq->data)
437 goto out;
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530438
439 /*
Maya Erez00d7be62013-02-05 13:19:52 +0200440 * If we have not waited for the prog done for write transfer then
441 * perform the DPSM reset without polling for TXACTIVE.
442 * Otherwise, we poll here unnecessarily as TXACTIVE will not be
443 * deasserted until DAT0 (Busy line) goes high.
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530444 */
Maya Erez00d7be62013-02-05 13:19:52 +0200445 if (mrq->data->flags & MMC_DATA_WRITE) {
446 if (!msmsdcc_is_wait_for_prog_done(host, mrq)) {
447 if (is_wait_for_tx_rx_active(host) &&
448 !is_auto_prog_done(host))
449 pr_warning("%s: %s: AUTO_PROG_DONE capability is must\n",
450 mmc_hostname(host->mmc), __func__);
451 goto no_polling;
452 }
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530453 }
454
455 /* Make sure h/w (TX/RX) is inactive before resetting DPSM */
456 if (is_wait_for_tx_rx_active(host)) {
457 ktime_t start = ktime_get();
458
459 while (readl_relaxed(host->base + MMCISTATUS) &
460 (MCI_TXACTIVE | MCI_RXACTIVE)) {
461 /*
462 * TX/RX active bits may be asserted for 4HCLK + 4MCLK
463 * cycles (~11us) after data transfer due to clock mux
464 * switching delays. Let's poll for 1ms and panic if
465 * still active.
466 */
467 if (ktime_to_us(ktime_sub(ktime_get(), start)) > 1000) {
468 pr_err("%s: %s still active\n",
469 mmc_hostname(host->mmc),
470 readl_relaxed(host->base + MMCISTATUS)
471 & MCI_TXACTIVE ? "TX" : "RX");
472 msmsdcc_dump_sdcc_state(host);
Sujit Reddy Thumma565c4312012-11-17 13:03:27 +0530473 msmsdcc_reset_and_restore(host);
Sujit Reddy Thumma565c4312012-11-17 13:03:27 +0530474 goto out;
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530475 }
476 }
477 }
478
Maya Erez00d7be62013-02-05 13:19:52 +0200479no_polling:
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530480 writel_relaxed(0, host->base + MMCIDATACTRL);
481 msmsdcc_sync_reg_wr(host); /* Allow the DPSM to be reset */
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530482out:
483 return;
484}
485
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700486static int
San Mehat9d2bd732009-09-22 16:44:22 -0700487msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
488{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700489 int retval = 0;
490
San Mehat9d2bd732009-09-22 16:44:22 -0700491 BUG_ON(host->curr.data);
492
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700493 del_timer(&host->req_tout_timer);
San Mehat9d2bd732009-09-22 16:44:22 -0700494
495 if (mrq->data)
496 mrq->data->bytes_xfered = host->curr.data_xfered;
497 if (mrq->cmd->error == -ETIMEDOUT)
498 mdelay(5);
499
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530500 msmsdcc_reset_dpsm(host);
501
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530502 /* Clear current request information as current request has ended */
503 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
504
San Mehat9d2bd732009-09-22 16:44:22 -0700505 /*
506 * Need to drop the host lock here; mmc_request_done may call
507 * back into the driver...
508 */
509 spin_unlock(&host->lock);
510 mmc_request_done(host->mmc, mrq);
511 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700512
513 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700514}
515
516static void
517msmsdcc_stop_data(struct msmsdcc_host *host)
518{
San Mehat9d2bd732009-09-22 16:44:22 -0700519 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530520 host->curr.got_dataend = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +0530521 host->curr.wait_for_auto_prog_done = false;
522 host->curr.got_auto_prog_done = false;
San Mehat9d2bd732009-09-22 16:44:22 -0700523}
524
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700525static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700526{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700527 return host->core_memres->start + MMCIFIFO;
528}
529
530static inline unsigned int msmsdcc_get_min_sup_clk_rate(
531 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530532
Subhash Jadavanidd432952012-03-28 11:25:56 +0530533static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700534{
535 mb();
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530536 if (!is_wait_for_reg_write(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +0530537 udelay(host->reg_write_delay);
538 else if (readl_relaxed(host->base + MCI_STATUS2) &
539 MCI_MCLK_REG_WR_ACTIVE) {
540 ktime_t start, diff;
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530541
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530542 start = ktime_get();
543 while (readl_relaxed(host->base + MCI_STATUS2) &
544 MCI_MCLK_REG_WR_ACTIVE) {
545 diff = ktime_sub(ktime_get(), start);
546 /* poll for max. 1 ms */
547 if (ktime_to_us(diff) > 1000) {
548 pr_warning("%s: previous reg. write is"
549 " still active\n",
550 mmc_hostname(host->mmc));
551 break;
552 }
553 }
554 }
San Mehat9d2bd732009-09-22 16:44:22 -0700555}
556
Subhash Jadavanidd432952012-03-28 11:25:56 +0530557static inline void msmsdcc_delay(struct msmsdcc_host *host)
558{
559 udelay(host->reg_write_delay);
560
San Mehat9d2bd732009-09-22 16:44:22 -0700561}
562
San Mehat56a8b5b2009-11-21 12:29:46 -0800563static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700564msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
565{
566 writel_relaxed(arg, host->base + MMCIARGUMENT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700567 writel_relaxed(c, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530568 /*
569 * As after sending the command, we don't write any of the
570 * controller registers and just wait for the
571 * CMD_RESPOND_END/CMD_SENT/Command failure notication
572 * from Controller.
573 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700574 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800575}
576
577static void
578msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
579{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700580 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800581
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700582 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
583 writel_relaxed((unsigned int)host->curr.xfer_size,
584 host->base + MMCIDATALENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700585 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530586 msmsdcc_sync_reg_wr(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800587
San Mehat6ac9ea62009-12-02 17:24:58 -0800588 if (host->cmd_cmd) {
589 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700590 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800591 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800592}
593
San Mehat9d2bd732009-09-22 16:44:22 -0700594static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530595msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700596{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530597 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700598 unsigned long flags;
599 struct mmc_request *mrq;
600
601 spin_lock_irqsave(&host->lock, flags);
602 mrq = host->curr.mrq;
603 BUG_ON(!mrq);
604
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530605 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700606 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700607 goto out;
608 }
609
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530610 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700611 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700612 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700613 } else {
614 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530615 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700616 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530617 mmc_hostname(host->mmc), host->dma.result);
618 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700619 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530620 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530621 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700622 host->dma.err.flush[0], host->dma.err.flush[1],
623 host->dma.err.flush[2], host->dma.err.flush[3],
624 host->dma.err.flush[4],
625 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530626 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700627 if (!mrq->data->error)
628 mrq->data->error = -EIO;
629 }
Asutosh Dasaccacd42012-03-08 14:33:17 +0530630 if (!mrq->data->host_cookie)
631 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
632 host->dma.num_ents, host->dma.dir);
San Mehat9d2bd732009-09-22 16:44:22 -0700633
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700634 if (host->curr.user_pages) {
635 struct scatterlist *sg = host->dma.sg;
636 int i;
637
638 for (i = 0; i < host->dma.num_ents; i++, sg++)
639 flush_dcache_page(sg_page(sg));
640 }
San Mehat9d2bd732009-09-22 16:44:22 -0700641
San Mehat9d2bd732009-09-22 16:44:22 -0700642 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800643 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700644
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530645 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
646 (host->curr.wait_for_auto_prog_done &&
647 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700648 /*
649 * If we've already gotten our DATAEND / DATABLKEND
650 * for this request, then complete it through here.
651 */
San Mehat9d2bd732009-09-22 16:44:22 -0700652
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700653 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700654 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700655 host->curr.xfer_remain -= host->curr.xfer_size;
656 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700657 if (host->dummy_52_needed) {
San Mehat9d2bd732009-09-22 16:44:22 -0700658 mrq->data->bytes_xfered = host->curr.data_xfered;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700659 host->dummy_52_sent = 1;
660 msmsdcc_start_command(host, &dummy52cmd,
661 MCI_CPSM_PROGENA);
662 goto out;
663 }
664 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530665 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530666 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700667 mrq->data->bytes_xfered = host->curr.data_xfered;
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530668 msmsdcc_reset_dpsm(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700669 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530670 /*
671 * Clear current request information as current
672 * request has ended
673 */
674 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
San Mehat9d2bd732009-09-22 16:44:22 -0700675 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700676
San Mehat9d2bd732009-09-22 16:44:22 -0700677 mmc_request_done(host->mmc, mrq);
678 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530679 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
680 || !mrq->sbc)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700681 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530682 }
San Mehat9d2bd732009-09-22 16:44:22 -0700683 }
684
685out:
686 spin_unlock_irqrestore(&host->lock, flags);
687 return;
688}
689
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700690#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
691/**
692 * Callback notification from SPS driver
693 *
694 * This callback function gets triggered called from
695 * SPS driver when requested SPS data transfer is
696 * completed.
697 *
698 * SPS driver invokes this callback in BAM irq context so
699 * SDCC driver schedule a tasklet for further processing
700 * this callback notification at later point of time in
701 * tasklet context and immediately returns control back
702 * to SPS driver.
703 *
704 * @nofity - Pointer to sps event notify sturcture
705 *
706 */
707static void
708msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
709{
710 struct msmsdcc_host *host =
711 (struct msmsdcc_host *)
712 ((struct sps_event_notify *)notify)->user;
713
714 host->sps.notify = *notify;
715 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
716 mmc_hostname(host->mmc), __func__, notify->event_id,
717 notify->data.transfer.iovec.addr,
718 notify->data.transfer.iovec.size,
719 notify->data.transfer.iovec.flags);
720 /* Schedule a tasklet for completing data transfer */
721 tasklet_schedule(&host->sps.tlet);
722}
723
724/**
725 * Tasklet handler for processing SPS callback event
726 *
727 * This function processing SPS event notification and
728 * checks if the SPS transfer is completed or not and
729 * then accordingly notifies status to MMC core layer.
730 *
731 * This function is called in tasklet context.
732 *
733 * @data - Pointer to sdcc driver data
734 *
735 */
736static void msmsdcc_sps_complete_tlet(unsigned long data)
737{
738 unsigned long flags;
739 int i, rc;
740 u32 data_xfered = 0;
741 struct mmc_request *mrq;
742 struct sps_iovec iovec;
743 struct sps_pipe *sps_pipe_handle;
744 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
745 struct sps_event_notify *notify = &host->sps.notify;
746
747 spin_lock_irqsave(&host->lock, flags);
748 if (host->sps.dir == DMA_FROM_DEVICE)
749 sps_pipe_handle = host->sps.prod.pipe_handle;
750 else
751 sps_pipe_handle = host->sps.cons.pipe_handle;
752 mrq = host->curr.mrq;
753
754 if (!mrq) {
755 spin_unlock_irqrestore(&host->lock, flags);
756 return;
757 }
758
759 pr_debug("%s: %s: sps event_id=%d\n",
760 mmc_hostname(host->mmc), __func__,
761 notify->event_id);
762
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700763 /*
764 * Got End of transfer event!!! Check if all of the data
765 * has been transferred?
766 */
767 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
768 rc = sps_get_iovec(sps_pipe_handle, &iovec);
769 if (rc) {
770 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
771 mmc_hostname(host->mmc), __func__, rc, i);
772 break;
773 }
774 data_xfered += iovec.size;
775 }
776
777 if (data_xfered == host->curr.xfer_size) {
778 host->curr.data_xfered = host->curr.xfer_size;
779 host->curr.xfer_remain -= host->curr.xfer_size;
780 pr_debug("%s: Data xfer success. data_xfered=0x%x",
781 mmc_hostname(host->mmc),
782 host->curr.xfer_size);
783 } else {
784 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
785 " xfer_size=%d", mmc_hostname(host->mmc),
786 data_xfered, host->curr.xfer_size);
787 msmsdcc_reset_and_restore(host);
788 if (!mrq->data->error)
789 mrq->data->error = -EIO;
790 }
791
792 /* Unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +0530793 if (!mrq->data->host_cookie)
794 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
795 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700796 host->sps.sg = NULL;
797 host->sps.busy = 0;
798
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530799 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
800 (host->curr.wait_for_auto_prog_done &&
801 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700802 /*
803 * If we've already gotten our DATAEND / DATABLKEND
804 * for this request, then complete it through here.
805 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700806
807 if (!mrq->data->error) {
808 host->curr.data_xfered = host->curr.xfer_size;
809 host->curr.xfer_remain -= host->curr.xfer_size;
810 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700811 if (host->dummy_52_needed) {
812 mrq->data->bytes_xfered = host->curr.data_xfered;
813 host->dummy_52_sent = 1;
814 msmsdcc_start_command(host, &dummy52cmd,
815 MCI_CPSM_PROGENA);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700816 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700817 return;
818 }
819 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530820 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530821 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700822 mrq->data->bytes_xfered = host->curr.data_xfered;
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530823 msmsdcc_reset_dpsm(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700824 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530825 /*
826 * Clear current request information as current
827 * request has ended
828 */
829 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700830 spin_unlock_irqrestore(&host->lock, flags);
831
832 mmc_request_done(host->mmc, mrq);
833 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530834 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
835 || !mrq->sbc)) {
836 msmsdcc_start_command(host, mrq->data->stop, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700837 }
838 }
839 spin_unlock_irqrestore(&host->lock, flags);
840}
841
842/**
843 * Exit from current SPS data transfer
844 *
845 * This function exits from current SPS data transfer.
846 *
847 * This function should be called when error condition
848 * is encountered during data transfer.
849 *
850 * @host - Pointer to sdcc host structure
851 *
852 */
853static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
854{
855 struct mmc_request *mrq;
856
857 mrq = host->curr.mrq;
858 BUG_ON(!mrq);
859
860 msmsdcc_reset_and_restore(host);
861 if (!mrq->data->error)
862 mrq->data->error = -EIO;
863
864 /* Unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +0530865 if (!mrq->data->host_cookie)
866 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
867 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700868
869 host->sps.sg = NULL;
870 host->sps.busy = 0;
871 if (host->curr.data)
872 msmsdcc_stop_data(host);
873
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530874 if (!mrq->data->stop || mrq->cmd->error ||
875 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700876 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530877 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
878 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700879 msmsdcc_start_command(host, mrq->data->stop, 0);
880
881}
882#else
883static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
884static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
885static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
886#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
887
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530888static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700889
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530890static void
891msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
892 unsigned int result,
893 struct msm_dmov_errdata *err)
894{
895 struct msmsdcc_dma_data *dma_data =
896 container_of(cmd, struct msmsdcc_dma_data, hdr);
897 struct msmsdcc_host *host = dma_data->host;
898
899 dma_data->result = result;
900 if (err)
901 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
902
903 tasklet_schedule(&host->dma_tlet);
904}
905
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530906static bool msmsdcc_is_dma_possible(struct msmsdcc_host *host,
907 struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700908{
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530909 bool ret = true;
910 u32 xfer_size = data->blksz * data->blocks;
San Mehat9d2bd732009-09-22 16:44:22 -0700911
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530912 if (is_sps_mode(host)) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530913 /*
914 * BAM Mode: Fall back on PIO if size is less
915 * than or equal to SPS_MIN_XFER_SIZE bytes.
916 */
917 if (xfer_size <= SPS_MIN_XFER_SIZE)
918 ret = false;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530919 } else if (is_dma_mode(host)) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530920 /*
921 * ADM Mode: Fall back on PIO if size is less than FIFO size
922 * or not integer multiple of FIFO size
923 */
924 if (xfer_size % MCI_FIFOSIZE)
925 ret = false;
926 } else {
927 /* PIO Mode */
928 ret = false;
929 }
930
931 return ret;
San Mehat9d2bd732009-09-22 16:44:22 -0700932}
933
934static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
935{
936 struct msmsdcc_nc_dmadata *nc;
937 dmov_box *box;
938 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700939 unsigned int n;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530940 int i, err = 0, box_cmd_cnt = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700941 struct scatterlist *sg = data->sg;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530942 unsigned int len, offset;
San Mehat9d2bd732009-09-22 16:44:22 -0700943
Krishna Konda25786ec2011-07-25 16:21:36 -0700944 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700945 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700946
Krishna Konda25786ec2011-07-25 16:21:36 -0700947 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
San Mehat9d2bd732009-09-22 16:44:22 -0700948
949 host->dma.sg = data->sg;
950 host->dma.num_ents = data->sg_len;
951
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530952 /* Prevent memory corruption */
953 BUG_ON(host->dma.num_ents > msmsdcc_get_nr_sg(host));
San Mehat56a8b5b2009-11-21 12:29:46 -0800954
San Mehat9d2bd732009-09-22 16:44:22 -0700955 nc = host->dma.nc;
956
San Mehat9d2bd732009-09-22 16:44:22 -0700957 if (data->flags & MMC_DATA_READ)
958 host->dma.dir = DMA_FROM_DEVICE;
959 else
960 host->dma.dir = DMA_TO_DEVICE;
961
Asutosh Dasaccacd42012-03-08 14:33:17 +0530962 if (!data->host_cookie) {
963 n = msmsdcc_prep_xfer(host, data);
964 if (unlikely(n < 0)) {
965 host->dma.sg = NULL;
966 host->dma.num_ents = 0;
967 return -ENOMEM;
968 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800969 }
San Mehat9d2bd732009-09-22 16:44:22 -0700970
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530971 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
972 host->curr.user_pages = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700973 box = &nc->cmd[0];
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530974 for (i = 0; i < host->dma.num_ents; i++) {
975 len = sg_dma_len(sg);
976 offset = 0;
977
978 do {
979 /* Check if we can do DMA */
980 if (!len || (box_cmd_cnt >= MMC_MAX_DMA_CMDS)) {
981 err = -ENOTSUPP;
982 goto unmap;
983 }
984
985 box->cmd = CMD_MODE_BOX;
986
987 if (len >= MMC_MAX_DMA_BOX_LENGTH) {
988 len = MMC_MAX_DMA_BOX_LENGTH;
989 len -= len % data->blksz;
990 }
991 rows = (len % MCI_FIFOSIZE) ?
992 (len / MCI_FIFOSIZE) + 1 :
993 (len / MCI_FIFOSIZE);
994
995 if (data->flags & MMC_DATA_READ) {
996 box->src_row_addr = msmsdcc_fifo_addr(host);
997 box->dst_row_addr = sg_dma_address(sg) + offset;
998 box->src_dst_len = (MCI_FIFOSIZE << 16) |
999 (MCI_FIFOSIZE);
1000 box->row_offset = MCI_FIFOSIZE;
1001 box->num_rows = rows * ((1 << 16) + 1);
1002 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
1003 } else {
1004 box->src_row_addr = sg_dma_address(sg) + offset;
1005 box->dst_row_addr = msmsdcc_fifo_addr(host);
1006 box->src_dst_len = (MCI_FIFOSIZE << 16) |
1007 (MCI_FIFOSIZE);
1008 box->row_offset = (MCI_FIFOSIZE << 16);
1009 box->num_rows = rows * ((1 << 16) + 1);
1010 box->cmd |= CMD_DST_CRCI(host->dma.crci);
1011 }
1012
1013 offset += len;
1014 len = sg_dma_len(sg) - offset;
1015 box++;
1016 box_cmd_cnt++;
1017 } while (len);
1018 sg++;
1019 }
1020 /* Mark last command */
1021 box--;
1022 box->cmd |= CMD_LC;
San Mehat9d2bd732009-09-22 16:44:22 -07001023
1024 /* location of command block must be 64 bit aligned */
1025 BUG_ON(host->dma.cmd_busaddr & 0x07);
1026
1027 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
1028 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
1029 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
1030 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
1031
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05301032 /* Flush all data to memory before starting dma */
1033 mb();
1034
1035unmap:
1036 if (err) {
Asutosh Dasaccacd42012-03-08 14:33:17 +05301037 if (!data->host_cookie)
1038 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
1039 host->dma.num_ents, host->dma.dir);
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05301040 pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
1041 mmc_hostname(host->mmc), err);
San Mehat9d2bd732009-09-22 16:44:22 -07001042 }
1043
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05301044 return err;
San Mehat9d2bd732009-09-22 16:44:22 -07001045}
1046
Asutosh Dasaccacd42012-03-08 14:33:17 +05301047static int msmsdcc_prep_xfer(struct msmsdcc_host *host,
1048 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -08001049{
Asutosh Dasaccacd42012-03-08 14:33:17 +05301050 int rc = 0;
1051 unsigned int dir;
1052
1053 /* Prevent memory corruption */
1054 BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
1055
1056 if (data->flags & MMC_DATA_READ)
1057 dir = DMA_FROM_DEVICE;
1058 else
1059 dir = DMA_TO_DEVICE;
1060
1061 /* Make sg buffers DMA ready */
1062 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
1063 dir);
1064
1065 if (unlikely(rc != data->sg_len)) {
1066 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
1067 mmc_hostname(host->mmc), rc);
1068 rc = -ENOMEM;
1069 goto dma_map_err;
1070 }
1071
1072 pr_debug("%s: %s: %s: sg_len=%d\n",
1073 mmc_hostname(host->mmc), __func__,
1074 dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
1075 data->sg_len);
1076
1077 goto out;
1078
1079dma_map_err:
1080 dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
1081 data->flags);
1082out:
1083 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07001084}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001085#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
1086/**
1087 * Submits data transfer request to SPS driver
1088 *
1089 * This function make sg (scatter gather) data buffers
1090 * DMA ready and then submits them to SPS driver for
1091 * transfer.
1092 *
1093 * @host - Pointer to sdcc host structure
1094 * @data - Pointer to mmc_data structure
1095 *
1096 * @return 0 if success else negative value
1097 */
1098static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
Asutosh Dasaccacd42012-03-08 14:33:17 +05301099 struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -07001100{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001101 int rc = 0;
1102 u32 flags;
1103 int i;
1104 u32 addr, len, data_cnt;
1105 struct scatterlist *sg = data->sg;
1106 struct sps_pipe *sps_pipe_handle;
1107
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001108 host->sps.sg = data->sg;
1109 host->sps.num_ents = data->sg_len;
1110 host->sps.xfer_req_cnt = 0;
1111 if (data->flags & MMC_DATA_READ) {
1112 host->sps.dir = DMA_FROM_DEVICE;
1113 sps_pipe_handle = host->sps.prod.pipe_handle;
1114 } else {
1115 host->sps.dir = DMA_TO_DEVICE;
1116 sps_pipe_handle = host->sps.cons.pipe_handle;
1117 }
1118
Asutosh Dasaccacd42012-03-08 14:33:17 +05301119 if (!data->host_cookie) {
1120 rc = msmsdcc_prep_xfer(host, data);
1121 if (unlikely(rc < 0)) {
1122 host->dma.sg = NULL;
1123 host->dma.num_ents = 0;
1124 goto out;
1125 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001126 }
1127
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001128 for (i = 0; i < data->sg_len; i++) {
1129 /*
1130 * Check if this is the last buffer to transfer?
1131 * If yes then set the INT and EOT flags.
1132 */
1133 len = sg_dma_len(sg);
1134 addr = sg_dma_address(sg);
1135 flags = 0;
1136 while (len > 0) {
1137 if (len > SPS_MAX_DESC_SIZE) {
1138 data_cnt = SPS_MAX_DESC_SIZE;
1139 } else {
1140 data_cnt = len;
1141 if (i == data->sg_len - 1)
1142 flags = SPS_IOVEC_FLAG_INT |
1143 SPS_IOVEC_FLAG_EOT;
1144 }
1145 rc = sps_transfer_one(sps_pipe_handle, addr,
1146 data_cnt, host, flags);
1147 if (rc) {
1148 pr_err("%s: sps_transfer_one() error! rc=%d,"
1149 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
1150 mmc_hostname(host->mmc), rc,
1151 (u32)sps_pipe_handle, (u32)sg, i);
1152 goto dma_map_err;
1153 }
1154 addr += data_cnt;
1155 len -= data_cnt;
1156 host->sps.xfer_req_cnt++;
1157 }
1158 sg++;
1159 }
1160 goto out;
1161
1162dma_map_err:
1163 /* unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +05301164 if (!data->host_cookie)
1165 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
1166 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001167out:
1168 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07001169}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001170#else
1171static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
1172 struct mmc_data *data) { return 0; }
1173#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -07001174
1175static void
San Mehat56a8b5b2009-11-21 12:29:46 -08001176msmsdcc_start_command_deferred(struct msmsdcc_host *host,
1177 struct mmc_command *cmd, u32 *c)
1178{
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301179 DBG(host, "op %02x arg %08x flags %08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001180 cmd->opcode, cmd->arg, cmd->flags);
1181
San Mehat56a8b5b2009-11-21 12:29:46 -08001182 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
1183
1184 if (cmd->flags & MMC_RSP_PRESENT) {
1185 if (cmd->flags & MMC_RSP_136)
1186 *c |= MCI_CPSM_LONGRSP;
1187 *c |= MCI_CPSM_RESPONSE;
1188 }
1189
1190 if (/*interrupt*/0)
1191 *c |= MCI_CPSM_INTERRUPT;
1192
Asutosh Das05049132012-05-09 12:38:15 +05301193 /* DAT_CMD bit should be set for all ADTC */
1194 if (mmc_cmd_type(cmd) == MMC_CMD_ADTC)
San Mehat56a8b5b2009-11-21 12:29:46 -08001195 *c |= MCI_CSPM_DATCMD;
1196
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001197 /* Check if AUTO CMD19 is required or not? */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301198 if (host->tuning_needed &&
1199 !(host->mmc->ios.timing == MMC_TIMING_MMC_HS200)) {
1200
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301201 /*
1202 * For open ended block read operation (without CMD23),
1203 * AUTO_CMD19 bit should be set while sending the READ command.
1204 * For close ended block read operation (with CMD23),
1205 * AUTO_CMD19 bit should be set while sending CMD23.
1206 */
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301207 if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
1208 host->curr.mrq->cmd->opcode ==
1209 MMC_READ_MULTIPLE_BLOCK) ||
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301210 (!host->curr.mrq->sbc &&
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301211 (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
1212 cmd->opcode == MMC_READ_MULTIPLE_BLOCK))) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301213 msmsdcc_enable_cdr_cm_sdc4_dll(host);
1214 *c |= MCI_CSPM_AUTO_CMD19;
1215 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001216 }
1217
Subhash Jadavanif97d2992012-07-13 14:47:47 +05301218 if (cmd->mrq->data && (cmd->mrq->data->flags & MMC_DATA_READ))
1219 writel_relaxed((readl_relaxed(host->base +
1220 MCI_DLL_CONFIG) | MCI_CDR_EN),
1221 host->base + MCI_DLL_CONFIG);
1222 else
1223 /* Clear CDR_EN bit for non read operations */
1224 writel_relaxed((readl_relaxed(host->base +
1225 MCI_DLL_CONFIG) & ~MCI_CDR_EN),
1226 host->base + MCI_DLL_CONFIG);
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05301227
Subhash Jadavani824c4ad2012-12-19 19:05:02 +05301228 if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301229 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001230 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301231 }
San Mehat56a8b5b2009-11-21 12:29:46 -08001232 if (cmd == cmd->mrq->stop)
1233 *c |= MCI_CSPM_MCIABORT;
1234
San Mehat56a8b5b2009-11-21 12:29:46 -08001235 if (host->curr.cmd != NULL) {
Girish K Sa3c76eb2011-10-11 11:44:09 +05301236 pr_err("%s: Overlapping command requests\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001237 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -08001238 }
1239 host->curr.cmd = cmd;
1240}
1241
1242static void
1243msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1244 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001245{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301246 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001247 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001248 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001249 unsigned int pio_irqmask = 0;
1250
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301251 BUG_ON(!data->sg);
1252 BUG_ON(!data->sg_len);
1253
San Mehat9d2bd732009-09-22 16:44:22 -07001254 host->curr.data = data;
1255 host->curr.xfer_size = data->blksz * data->blocks;
1256 host->curr.xfer_remain = host->curr.xfer_size;
1257 host->curr.data_xfered = 0;
1258 host->curr.got_dataend = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301259 host->curr.got_auto_prog_done = false;
San Mehat9d2bd732009-09-22 16:44:22 -07001260
San Mehat9d2bd732009-09-22 16:44:22 -07001261 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1262
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301263 if (host->curr.wait_for_auto_prog_done)
1264 datactrl |= MCI_AUTO_PROG_DONE;
San Mehat9d2bd732009-09-22 16:44:22 -07001265
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05301266 if (msmsdcc_is_dma_possible(host, data)) {
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301267 if (is_dma_mode(host) && !msmsdcc_config_dma(host, data)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001268 datactrl |= MCI_DPSM_DMAENABLE;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301269 } else if (is_sps_mode(host)) {
Krishna Kondad337ddd2012-08-19 11:16:39 -07001270 if (!msmsdcc_sps_start_xfer(host, data)) {
1271 /* Now kick start DML transfer */
1272 mb();
1273 msmsdcc_dml_start_xfer(host, data);
1274 datactrl |= MCI_DPSM_DMAENABLE;
1275 host->sps.busy = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001276 }
1277 }
1278 }
1279
1280 /* Is data transfer in PIO mode required? */
1281 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001282 if (data->flags & MMC_DATA_READ) {
1283 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1284 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1285 pio_irqmask |= MCI_RXDATAAVLBLMASK;
1286 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001287 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1288 MCI_TXFIFOEMPTYMASK;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001289
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001290 msmsdcc_sg_start(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001291 }
1292
1293 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301294 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
Subhash Jadavanif5277752011-10-12 16:47:52 +05301295 else if (host->curr.use_wr_data_pend)
1296 datactrl |= MCI_DATA_PEND;
San Mehat9d2bd732009-09-22 16:44:22 -07001297
San Mehat56a8b5b2009-11-21 12:29:46 -08001298 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001299 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001300 timeout = data->timeout_clks + (unsigned int)clks*2 ;
Subhash Jadavani63540362012-06-12 14:56:04 +05301301 WARN(!timeout,
1302 "%s: data timeout is zero. timeout_ns=0x%x, timeout_clks=0x%x\n",
1303 mmc_hostname(host->mmc), data->timeout_ns, data->timeout_clks);
San Mehat9d2bd732009-09-22 16:44:22 -07001304
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301305 if (is_dma_mode(host) && (datactrl & MCI_DPSM_DMAENABLE)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001306 /* Use ADM (Application Data Mover) HW for Data transfer */
1307 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001308 host->cmd_timeout = timeout;
1309 host->cmd_pio_irqmask = pio_irqmask;
1310 host->cmd_datactrl = datactrl;
1311 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001312
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001313 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1314 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001315 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001316
1317 if (cmd) {
1318 msmsdcc_start_command_deferred(host, cmd, &c);
1319 host->cmd_c = c;
1320 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001321 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1322 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1323 host->base + MMCIMASK0);
1324 mb();
1325 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001326 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001327 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001328 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001329
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001330 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001331
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001332 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1333 (~(MCI_IRQ_PIO))) | pio_irqmask,
1334 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001335 writel_relaxed(datactrl, base + MMCIDATACTRL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001336
1337 if (cmd) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05301338 /* Delay between data/command */
1339 msmsdcc_sync_reg_wr(host);
San Mehat56a8b5b2009-11-21 12:29:46 -08001340 /* Daisy-chain the command if requested */
1341 msmsdcc_start_command(host, cmd, c);
Subhash Jadavanidd432952012-03-28 11:25:56 +05301342 } else {
1343 /*
1344 * We don't need delay after writing to DATA_CTRL
1345 * register if we are not writing to CMD register
1346 * immediately after this. As we already have delay
1347 * before sending the command, we just need mb() here.
1348 */
1349 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001350 }
San Mehat9d2bd732009-09-22 16:44:22 -07001351 }
1352}
1353
1354static void
1355msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1356{
San Mehat56a8b5b2009-11-21 12:29:46 -08001357 msmsdcc_start_command_deferred(host, cmd, &c);
1358 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001359}
1360
1361static void
1362msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1363 unsigned int status)
1364{
1365 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001366 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
Subhash Jadavanib30c9822012-03-27 18:03:16 +05301367 || data->mrq->cmd->opcode == MMC_BUS_TEST_R
1368 || data->mrq->cmd->opcode ==
1369 MMC_SEND_TUNING_BLOCK_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001370 pr_err("%s: Data CRC error\n",
1371 mmc_hostname(host->mmc));
1372 pr_err("%s: opcode 0x%.8x\n", __func__,
1373 data->mrq->cmd->opcode);
1374 pr_err("%s: blksz %d, blocks %d\n", __func__,
1375 data->blksz, data->blocks);
1376 data->error = -EILSEQ;
1377 }
San Mehat9d2bd732009-09-22 16:44:22 -07001378 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001379 /* CRC is optional for the bus test commands, not all
1380 * cards respond back with CRC. However controller
1381 * waits for the CRC and times out. Hence ignore the
1382 * data timeouts during the Bustest.
1383 */
1384 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1385 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301386 pr_err("%s: CMD%d: Data timeout\n",
1387 mmc_hostname(host->mmc),
1388 data->mrq->cmd->opcode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001389 data->error = -ETIMEDOUT;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301390 msmsdcc_dump_sdcc_state(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001391 }
San Mehat9d2bd732009-09-22 16:44:22 -07001392 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001393 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001394 data->error = -EIO;
1395 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001396 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001397 data->error = -EIO;
1398 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001399 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001400 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001401 data->error = -EIO;
1402 }
San Mehat9d2bd732009-09-22 16:44:22 -07001403
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001404 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001405 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001406 host->dummy_52_needed = 0;
1407}
San Mehat9d2bd732009-09-22 16:44:22 -07001408
1409static int
1410msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1411{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001412 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001413 uint32_t *ptr = (uint32_t *) buffer;
1414 int count = 0;
1415
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301416 if (remain % 4)
1417 remain = ((remain >> 2) + 1) << 2;
1418
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001419 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1420
1421 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001422 ptr++;
1423 count += sizeof(uint32_t);
1424
1425 remain -= sizeof(uint32_t);
1426 if (remain == 0)
1427 break;
1428 }
1429 return count;
1430}
1431
1432static int
1433msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001434 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001435{
1436 void __iomem *base = host->base;
1437 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001438 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001439
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001440 while (readl_relaxed(base + MMCISTATUS) &
1441 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1442 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001443
San Mehat9d2bd732009-09-22 16:44:22 -07001444 count = min(remain, maxcnt);
1445
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301446 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1447 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001448 ptr += count;
1449 remain -= count;
1450
1451 if (remain == 0)
1452 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001453 }
1454 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001455
1456 return ptr - buffer;
1457}
1458
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001459/*
1460 * Copy up to a word (4 bytes) between a scatterlist
1461 * and a temporary bounce buffer when the word lies across
1462 * two pages. The temporary buffer can then be read to/
1463 * written from the FIFO once.
1464 */
1465static void _msmsdcc_sg_consume_word(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -07001466{
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001467 struct msmsdcc_pio_data *pio = &host->pio;
1468 unsigned int bytes_avail;
1469
1470 if (host->curr.data->flags & MMC_DATA_READ)
1471 memcpy(pio->sg_miter.addr, pio->bounce_buf,
1472 pio->bounce_buf_len);
1473 else
1474 memcpy(pio->bounce_buf, pio->sg_miter.addr,
1475 pio->bounce_buf_len);
1476
1477 while (pio->bounce_buf_len != 4) {
1478 if (!sg_miter_next(&pio->sg_miter))
1479 break;
1480 bytes_avail = min_t(unsigned int, pio->sg_miter.length,
1481 4 - pio->bounce_buf_len);
1482 if (host->curr.data->flags & MMC_DATA_READ)
1483 memcpy(pio->sg_miter.addr,
1484 &pio->bounce_buf[pio->bounce_buf_len],
1485 bytes_avail);
1486 else
1487 memcpy(&pio->bounce_buf[pio->bounce_buf_len],
1488 pio->sg_miter.addr, bytes_avail);
1489
1490 pio->sg_miter.consumed = bytes_avail;
1491 pio->bounce_buf_len += bytes_avail;
San Mehat9d2bd732009-09-22 16:44:22 -07001492 }
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001493}
1494
1495/*
1496 * Use sg_miter_next to return as many 4-byte aligned
1497 * chunks as possible, using a temporary 4 byte buffer
1498 * for alignment if necessary
1499 */
1500static int msmsdcc_sg_next(struct msmsdcc_host *host, char **buf, int *len)
1501{
1502 struct msmsdcc_pio_data *pio = &host->pio;
1503 unsigned int length, rlength;
1504 char *buffer;
1505
1506 if (!sg_miter_next(&pio->sg_miter))
1507 return 0;
1508
1509 buffer = pio->sg_miter.addr;
1510 length = pio->sg_miter.length;
1511
1512 if (length < host->curr.xfer_remain) {
1513 rlength = round_down(length, 4);
1514 if (rlength) {
1515 /*
1516 * We have a 4-byte aligned chunk.
1517 * The rounding will be reflected by
1518 * a call to msmsdcc_sg_consumed
1519 */
1520 length = rlength;
1521 goto sg_next_end;
1522 }
1523 /*
1524 * We have a length less than 4 bytes. Check to
1525 * see if more buffer is available, and combine
1526 * to make 4 bytes if possible.
1527 */
1528 pio->bounce_buf_len = length;
1529 memset(pio->bounce_buf, 0, 4);
1530
1531 /*
1532 * On a read, get 4 bytes from FIFO, and distribute
1533 * (4-bouce_buf_len) bytes into consecutive
1534 * sgl buffers when msmsdcc_sg_consumed is called
1535 */
1536 if (host->curr.data->flags & MMC_DATA_READ) {
1537 buffer = pio->bounce_buf;
1538 length = 4;
1539 goto sg_next_end;
1540 } else {
1541 _msmsdcc_sg_consume_word(host);
1542 buffer = pio->bounce_buf;
1543 length = pio->bounce_buf_len;
1544 }
1545 }
1546
1547sg_next_end:
1548 *buf = buffer;
1549 *len = length;
1550 return 1;
1551}
1552
1553/*
1554 * Update sg_miter.consumed based on how many bytes were
1555 * consumed. If the bounce buffer was used to read from FIFO,
1556 * redistribute into sgls.
1557 */
1558static void msmsdcc_sg_consumed(struct msmsdcc_host *host,
1559 unsigned int length)
1560{
1561 struct msmsdcc_pio_data *pio = &host->pio;
1562
1563 if (host->curr.data->flags & MMC_DATA_READ) {
1564 if (length > pio->sg_miter.consumed)
1565 /*
1566 * consumed 4 bytes, but sgl
1567 * describes < 4 bytes
1568 */
1569 _msmsdcc_sg_consume_word(host);
1570 else
1571 pio->sg_miter.consumed = length;
1572 } else
1573 if (length < pio->sg_miter.consumed)
1574 pio->sg_miter.consumed = length;
1575}
1576
1577static void msmsdcc_sg_start(struct msmsdcc_host *host)
1578{
1579 unsigned int sg_miter_flags = SG_MITER_ATOMIC;
1580
1581 host->pio.bounce_buf_len = 0;
1582
1583 if (host->curr.data->flags & MMC_DATA_READ)
1584 sg_miter_flags |= SG_MITER_TO_SG;
1585 else
1586 sg_miter_flags |= SG_MITER_FROM_SG;
1587
1588 sg_miter_start(&host->pio.sg_miter, host->curr.data->sg,
1589 host->curr.data->sg_len, sg_miter_flags);
1590}
1591
1592static void msmsdcc_sg_stop(struct msmsdcc_host *host)
1593{
1594 sg_miter_stop(&host->pio.sg_miter);
San Mehat9d2bd732009-09-22 16:44:22 -07001595}
1596
San Mehat1cd22962010-02-03 12:59:29 -08001597static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001598msmsdcc_pio_irq(int irq, void *dev_id)
1599{
1600 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001601 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001602 uint32_t status;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001603 unsigned long flags;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001604 unsigned int remain;
1605 char *buffer;
San Mehat9d2bd732009-09-22 16:44:22 -07001606
Murali Palnati36448a42011-09-02 15:06:18 +05301607 spin_lock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301608
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001609 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001610
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001611 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301612 (MCI_IRQ_PIO)) == 0) {
1613 spin_unlock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301614 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301615 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001616#if IRQ_DEBUG
1617 msmsdcc_print_status(host, "irq1-r", status);
1618#endif
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001619 local_irq_save(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001620
1621 do {
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001622 unsigned int len;
San Mehat9d2bd732009-09-22 16:44:22 -07001623
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001624 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1625 | MCI_RXDATAAVLBL)))
1626 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001627
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001628 if (!msmsdcc_sg_next(host, &buffer, &remain))
1629 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001630
San Mehat9d2bd732009-09-22 16:44:22 -07001631 len = 0;
1632 if (status & MCI_RXACTIVE)
1633 len = msmsdcc_pio_read(host, buffer, remain);
1634 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001635 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001636
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301637 /* len might have aligned to 32bits above */
1638 if (len > remain)
1639 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001640
San Mehat9d2bd732009-09-22 16:44:22 -07001641 host->curr.xfer_remain -= len;
1642 host->curr.data_xfered += len;
1643 remain -= len;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001644 msmsdcc_sg_consumed(host, len);
San Mehat9d2bd732009-09-22 16:44:22 -07001645
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001646 if (remain) /* Done with this page? */
1647 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001648
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001649 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001650 } while (1);
1651
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001652 msmsdcc_sg_stop(host);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001653 local_irq_restore(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001654
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001655 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1656 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1657 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1658 host->base + MMCIMASK0);
1659 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301660 /*
1661 * back to back write to MASK0 register don't need
1662 * synchronization delay.
1663 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001664 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1665 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1666 }
1667 mb();
1668 } else if (!host->curr.xfer_remain) {
1669 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1670 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1671 mb();
1672 }
San Mehat9d2bd732009-09-22 16:44:22 -07001673
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001674 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001675
1676 return IRQ_HANDLED;
1677}
1678
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001679static void
1680msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1681
1682static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1683 struct mmc_data *data)
1684{
1685 u32 loop_cnt = 0;
1686
1687 /*
1688 * For read commands with data less than fifo size, it is possible to
1689 * get DATAEND first and RXDATA_AVAIL might be set later because of
1690 * synchronization delay through the asynchronous RX FIFO. Thus, for
1691 * such cases, even after DATAEND interrupt is received software
1692 * should poll for RXDATA_AVAIL until the requested data is read out
1693 * of FIFO. This change is needed to get around this abnormal but
1694 * sometimes expected behavior of SDCC3 controller.
1695 *
1696 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1697 * after the data is loaded into RX FIFO. This would amount to less
1698 * than a microsecond and thus looping for 1000 times is good enough
1699 * for that delay.
1700 */
1701 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1702 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1703 spin_unlock(&host->lock);
1704 msmsdcc_pio_irq(1, host);
1705 spin_lock(&host->lock);
1706 }
1707 }
1708 if (loop_cnt == 1000) {
1709 pr_info("%s: Timed out while polling for Rx Data\n",
1710 mmc_hostname(host->mmc));
1711 data->error = -ETIMEDOUT;
1712 msmsdcc_reset_and_restore(host);
1713 }
1714}
1715
San Mehat9d2bd732009-09-22 16:44:22 -07001716static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1717{
1718 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001719
1720 host->curr.cmd = NULL;
subhashj8046ae12012-05-02 12:14:52 +05301721 if (mmc_resp_type(cmd))
1722 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1723 /*
1724 * Read rest of the response registers only if
1725 * long response is expected for this command
1726 */
1727 if (mmc_resp_type(cmd) & MMC_RSP_136) {
1728 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1729 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1730 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
1731 }
San Mehat9d2bd732009-09-22 16:44:22 -07001732
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001733 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301734 pr_debug("%s: CMD%d: Command timeout\n",
1735 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001736 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001737 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301738 !host->tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301739 pr_err("%s: CMD%d: Command CRC error\n",
1740 mmc_hostname(host->mmc), cmd->opcode);
1741 msmsdcc_dump_sdcc_state(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001742 cmd->error = -EILSEQ;
1743 }
1744
Subhash Jadavani8706ced2012-05-25 16:09:21 +05301745 if (!cmd->error) {
1746 if (cmd->cmd_timeout_ms > host->curr.req_tout_ms) {
1747 host->curr.req_tout_ms = cmd->cmd_timeout_ms;
1748 mod_timer(&host->req_tout_timer, (jiffies +
1749 msecs_to_jiffies(host->curr.req_tout_ms)));
1750 }
1751 }
1752
San Mehat9d2bd732009-09-22 16:44:22 -07001753 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001754 if (host->curr.data && host->dma.sg &&
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301755 is_dma_mode(host))
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001756 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001757 else if (host->curr.data && host->sps.sg &&
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301758 is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001759 /* Stop current SPS transfer */
1760 msmsdcc_sps_exit_curr_xfer(host);
1761 }
San Mehat9d2bd732009-09-22 16:44:22 -07001762 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301763 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001764 msmsdcc_stop_data(host);
1765 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301766 } else { /* host->data == NULL */
1767 if (!cmd->error && host->prog_enable) {
1768 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001769 host->prog_enable = 0;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301770 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001771 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301772 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301773 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301774 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301775 host->curr.wait_for_auto_prog_done = false;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001776 if (host->dummy_52_needed)
1777 host->dummy_52_needed = 0;
1778 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001779 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301780 msmsdcc_request_end(host, cmd->mrq);
1781 }
1782 }
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301783 } else if (cmd->data) {
Subhash Jadavanif5277752011-10-12 16:47:52 +05301784 if (cmd == host->curr.mrq->sbc)
1785 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1786 else if ((cmd->data->flags & MMC_DATA_WRITE) &&
1787 !host->curr.use_wr_data_pend)
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301788 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001789 }
1790}
1791
San Mehat9d2bd732009-09-22 16:44:22 -07001792static irqreturn_t
1793msmsdcc_irq(int irq, void *dev_id)
1794{
1795 struct msmsdcc_host *host = dev_id;
Pratibhasagar Vbe4e3132012-09-20 19:46:11 +05301796 struct mmc_host *mmc = host->mmc;
San Mehat9d2bd732009-09-22 16:44:22 -07001797 u32 status;
1798 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001799 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001800
1801 spin_lock(&host->lock);
1802
1803 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001804 struct mmc_command *cmd;
1805 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001806
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001807 if (timer) {
1808 timer = 0;
1809 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001810 }
San Mehat9d2bd732009-09-22 16:44:22 -07001811
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05301812 if (!atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001813 pr_debug("%s: %s: SDIO async irq received\n",
1814 mmc_hostname(host->mmc), __func__);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301815
1816 /*
1817 * Only async interrupt can come when clocks are off,
1818 * disable further interrupts and enable them when
1819 * clocks are on.
1820 */
1821 if (!host->sdcc_irq_disabled) {
1822 disable_irq_nosync(irq);
1823 host->sdcc_irq_disabled = 1;
1824 }
1825
1826 /*
1827 * If mmc_card_wake_sdio_irq() is set, mmc core layer
1828 * will take care of signaling sdio irq during
1829 * mmc_sdio_resume().
1830 */
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301831 if (host->sdcc_suspended) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301832 /*
1833 * This is a wakeup interrupt so hold wakelock
1834 * until SDCC resume is handled.
1835 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001836 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301837 } else {
Pratibhasagar Vbe4e3132012-09-20 19:46:11 +05301838 if (!mmc->card || !mmc_card_sdio(mmc->card)) {
1839 WARN(1, "%s: SDCC core interrupt received for non-SDIO cards when SDCC clocks are off\n",
1840 mmc_hostname(mmc));
1841 ret = 1;
1842 break;
1843 }
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301844 spin_unlock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301845 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301846 spin_lock(&host->lock);
1847 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301848 ret = 1;
1849 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001850 }
1851
1852 status = readl_relaxed(host->base + MMCISTATUS);
1853
1854 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1855 (~(MCI_IRQ_PIO))) == 0)
San Mehat9d2bd732009-09-22 16:44:22 -07001856 break;
1857
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001858#if IRQ_DEBUG
1859 msmsdcc_print_status(host, "irq0-r", status);
1860#endif
1861 status &= readl_relaxed(host->base + MMCIMASK0);
1862 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301863 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301864 if (host->clk_rate <=
1865 msmsdcc_get_min_sup_clk_rate(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +05301866 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001867#if IRQ_DEBUG
1868 msmsdcc_print_status(host, "irq0-p", status);
1869#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001870
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001871 if (status & MCI_SDIOINTROPE) {
Pratibhasagar Vbe4e3132012-09-20 19:46:11 +05301872 if (!mmc->card || mmc_card_sdio(mmc->card)) {
1873 WARN(1, "%s: SDIO interrupt received for non-SDIO card\n",
1874 mmc_hostname(mmc));
1875 ret = 1;
1876 break;
1877 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001878 if (host->sdcc_suspending)
1879 wake_lock(&host->sdio_suspend_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301880 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001881 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301882 spin_lock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001883 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001884 data = host->curr.data;
1885
1886 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001887 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1888 MCI_CMDTIMEOUT)) {
1889 if (status & MCI_CMDTIMEOUT)
1890 pr_debug("%s: dummy CMD52 timeout\n",
1891 mmc_hostname(host->mmc));
1892 if (status & MCI_CMDCRCFAIL)
1893 pr_debug("%s: dummy CMD52 CRC failed\n",
1894 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001895 host->dummy_52_sent = 0;
1896 host->dummy_52_needed = 0;
1897 if (data) {
1898 msmsdcc_stop_data(host);
1899 msmsdcc_request_end(host, data->mrq);
1900 }
1901 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001902 spin_unlock(&host->lock);
1903 return IRQ_HANDLED;
1904 }
1905 break;
1906 }
1907
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001908 /*
1909 * Check for proper command response
1910 */
1911 cmd = host->curr.cmd;
1912 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1913 MCI_CMDTIMEOUT | MCI_PROGDONE |
1914 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1915 msmsdcc_do_cmdirq(host, status);
1916 }
1917
Sathish Ambley081d7842011-11-29 11:19:41 -08001918 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001919 /* Check for data errors */
1920 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1921 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1922 msmsdcc_data_err(host, data, status);
1923 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301924 if (host->dma.sg && is_dma_mode(host))
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001925 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301926 else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001927 /* Stop current SPS transfer */
1928 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301929 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001930 msmsdcc_reset_and_restore(host);
1931 if (host->curr.data)
1932 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301933 if (!data->stop || (host->curr.mrq->sbc
1934 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001935 timer |=
1936 msmsdcc_request_end(host,
1937 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301938 else if ((host->curr.mrq->sbc
1939 && data->error) ||
1940 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001941 msmsdcc_start_command(host,
1942 data->stop,
1943 0);
1944 timer = 1;
1945 }
1946 }
1947 }
1948
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301949 /* Check for prog done */
1950 if (host->curr.wait_for_auto_prog_done &&
1951 (status & MCI_PROGDONE))
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301952 host->curr.got_auto_prog_done = true;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301953
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001954 /* Check for data done */
1955 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1956 host->curr.got_dataend = 1;
1957
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301958 if (host->curr.got_dataend &&
1959 (!host->curr.wait_for_auto_prog_done ||
1960 (host->curr.wait_for_auto_prog_done &&
1961 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001962 /*
1963 * If DMA is still in progress, we complete
1964 * via the completion handler
1965 */
1966 if (!host->dma.busy && !host->sps.busy) {
1967 /*
1968 * There appears to be an issue in the
1969 * controller where if you request a
1970 * small block transfer (< fifo size),
1971 * you may get your DATAEND/DATABLKEND
1972 * irq without the PIO data irq.
1973 *
1974 * Check to see if theres still data
1975 * to be read, and simulate a PIO irq.
1976 */
1977 if (data->flags & MMC_DATA_READ)
1978 msmsdcc_wait_for_rxdata(host,
1979 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001980 if (!data->error) {
1981 host->curr.data_xfered =
1982 host->curr.xfer_size;
1983 host->curr.xfer_remain -=
1984 host->curr.xfer_size;
1985 }
1986
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001987 if (!host->dummy_52_needed) {
1988 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301989 if (!data->stop ||
1990 (host->curr.mrq->sbc
1991 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001992 msmsdcc_request_end(
1993 host,
1994 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301995 else if ((host->curr.mrq->sbc
1996 && data->error) ||
1997 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001998 msmsdcc_start_command(
1999 host,
2000 data->stop, 0);
2001 timer = 1;
2002 }
2003 } else {
2004 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002005 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002006 &dummy52cmd,
2007 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002008 }
2009 }
2010 }
2011 }
2012
San Mehat9d2bd732009-09-22 16:44:22 -07002013 ret = 1;
2014 } while (status);
2015
2016 spin_unlock(&host->lock);
2017
San Mehat9d2bd732009-09-22 16:44:22 -07002018 return IRQ_RETVAL(ret);
2019}
2020
2021static void
Asutosh Dasaccacd42012-03-08 14:33:17 +05302022msmsdcc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
2023 bool is_first_request)
2024{
2025 struct msmsdcc_host *host = mmc_priv(mmc);
2026 struct mmc_data *data = mrq->data;
2027 int rc = 0;
2028
2029 if (unlikely(!data)) {
2030 pr_err("%s: %s cannot prepare null data\n", mmc_hostname(mmc),
2031 __func__);
2032 return;
2033 }
2034 if (unlikely(data->host_cookie)) {
2035 /* Very wrong */
2036 data->host_cookie = 0;
2037 pr_err("%s: %s Request reposted for prepare\n",
2038 mmc_hostname(mmc), __func__);
2039 return;
2040 }
2041
2042 if (!msmsdcc_is_dma_possible(host, data))
2043 return;
2044
2045 rc = msmsdcc_prep_xfer(host, data);
2046 if (unlikely(rc < 0)) {
2047 data->host_cookie = 0;
2048 return;
2049 }
2050
2051 data->host_cookie = 1;
2052}
2053
2054static void
2055msmsdcc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, int err)
2056{
2057 struct msmsdcc_host *host = mmc_priv(mmc);
2058 unsigned int dir;
2059 struct mmc_data *data = mrq->data;
2060
2061 if (unlikely(!data)) {
2062 pr_err("%s: %s cannot cleanup null data\n", mmc_hostname(mmc),
2063 __func__);
2064 return;
2065 }
2066 if (data->flags & MMC_DATA_READ)
2067 dir = DMA_FROM_DEVICE;
2068 else
2069 dir = DMA_TO_DEVICE;
2070
2071 if (data->host_cookie)
2072 dma_unmap_sg(mmc_dev(host->mmc), data->sg,
2073 data->sg_len, dir);
2074
2075 data->host_cookie = 0;
2076}
2077
2078static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002079msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
2080{
Subhash Jadavanif5277752011-10-12 16:47:52 +05302081 if (mrq->data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002082 /* Queue/read data, daisy-chain command when data starts */
Subhash Jadavanif5277752011-10-12 16:47:52 +05302083 if ((mrq->data->flags & MMC_DATA_READ) ||
2084 host->curr.use_wr_data_pend)
2085 msmsdcc_start_data(host, mrq->data,
2086 mrq->sbc ? mrq->sbc : mrq->cmd,
2087 0);
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302088 else
Subhash Jadavanif5277752011-10-12 16:47:52 +05302089 msmsdcc_start_command(host,
2090 mrq->sbc ? mrq->sbc : mrq->cmd,
2091 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002092 } else {
2093 msmsdcc_start_command(host, mrq->cmd, 0);
2094 }
2095}
2096
Maya Erez00d7be62013-02-05 13:19:52 +02002097/*
2098 * This function returns true if AUTO_PROG_DONE feature of host is
2099 * applicable for current request, returns "false" otherwise.
2100 *
2101 * NOTE: Caller should call this function only for data write operations.
2102 */
2103static bool msmsdcc_is_wait_for_auto_prog_done(struct msmsdcc_host *host,
2104 struct mmc_request *mrq)
2105{
2106 /*
2107 * Auto-prog done will be enabled for following cases:
2108 * mrq->sbc | mrq->stop
2109 * _____________|________________
2110 * True | Don't care
2111 * False | False (CMD24, ACMD25 use case)
2112 */
2113 if (is_auto_prog_done(host) && (mrq->sbc || !mrq->stop))
2114 return true;
2115
2116 return false;
2117}
2118
2119/*
2120 * This function returns true if controller can wait for prog done
2121 * for current request, returns "false" otherwise.
2122 *
2123 * NOTE: Caller should call this function only for data write operations.
2124 */
2125static bool msmsdcc_is_wait_for_prog_done(struct msmsdcc_host *host,
2126 struct mmc_request *mrq)
2127{
2128 if (msmsdcc_is_wait_for_auto_prog_done(host, mrq) || mrq->stop)
2129 return true;
2130
2131 return false;
2132}
2133
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002134static void
San Mehat9d2bd732009-09-22 16:44:22 -07002135msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
2136{
2137 struct msmsdcc_host *host = mmc_priv(mmc);
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302138 unsigned long flags;
Maya Erezb7a086f2012-11-29 00:37:36 +02002139 int retries = 5;
San Mehat9d2bd732009-09-22 16:44:22 -07002140
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002141 /*
2142 * Get the SDIO AL client out of LPM.
2143 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002144 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002145 if (host->plat->is_sdio_al_client)
2146 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002147
Maya Erezb7a086f2012-11-29 00:37:36 +02002148 /* check if sps bam needs to be reset */
2149 if (is_sps_mode(host) && host->sps.reset_bam) {
2150 while (retries) {
2151 if (!msmsdcc_bam_dml_reset_and_restore(host))
2152 break;
2153 pr_err("%s: msmsdcc_bam_dml_reset_and_restore returned error. %d attempts left.\n",
2154 mmc_hostname(host->mmc), --retries);
2155 }
Subhash Jadavanib5b07742011-08-29 17:48:07 +05302156 }
San Mehat9d2bd732009-09-22 16:44:22 -07002157
2158 spin_lock_irqsave(&host->lock, flags);
2159
San Mehat9d2bd732009-09-22 16:44:22 -07002160 if (host->eject) {
2161 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
2162 mrq->cmd->error = 0;
2163 mrq->data->bytes_xfered = mrq->data->blksz *
2164 mrq->data->blocks;
2165 } else
2166 mrq->cmd->error = -ENOMEDIUM;
2167
2168 spin_unlock_irqrestore(&host->lock, flags);
2169 mmc_request_done(mmc, mrq);
2170 return;
2171 }
2172
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302173 /*
subhashjf181c292012-05-02 13:07:40 +05302174 * Don't start the request if SDCC is not in proper state to handle it
2175 */
Maya Erezb7a086f2012-11-29 00:37:36 +02002176 if (!host->pwr || !atomic_read(&host->clks_on) ||
2177 host->sdcc_irq_disabled ||
2178 host->sps.reset_bam) {
subhashjf181c292012-05-02 13:07:40 +05302179 WARN(1, "%s: %s: SDCC is in bad state. don't process"
2180 " new request (CMD%d)\n", mmc_hostname(host->mmc),
2181 __func__, mrq->cmd->opcode);
2182 msmsdcc_dump_sdcc_state(host);
2183 mrq->cmd->error = -EIO;
2184 if (mrq->data) {
2185 mrq->data->error = -EIO;
2186 mrq->data->bytes_xfered = 0;
2187 }
2188 spin_unlock_irqrestore(&host->lock, flags);
2189 mmc_request_done(mmc, mrq);
2190 return;
2191 }
2192
2193 WARN(host->curr.mrq, "%s: %s: New request (CMD%d) received while"
2194 " other request (CMD%d) is in progress\n",
2195 mmc_hostname(host->mmc), __func__,
2196 mrq->cmd->opcode, host->curr.mrq->cmd->opcode);
2197
2198 /*
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302199 * Set timeout value to 10 secs (or more in case of buggy cards)
2200 */
2201 if ((mmc->card) && (mmc->card->quirks & MMC_QUIRK_INAND_DATA_TIMEOUT))
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302202 host->curr.req_tout_ms = 20000;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302203 else
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302204 host->curr.req_tout_ms = MSM_MMC_REQ_TIMEOUT;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302205 /*
2206 * Kick the software request timeout timer here with the timeout
2207 * value identified above
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302208 */
2209 mod_timer(&host->req_tout_timer,
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302210 (jiffies +
2211 msecs_to_jiffies(host->curr.req_tout_ms)));
San Mehat9d2bd732009-09-22 16:44:22 -07002212
San Mehat9d2bd732009-09-22 16:44:22 -07002213 host->curr.mrq = mrq;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302214 if (mrq->sbc) {
2215 mrq->sbc->mrq = mrq;
2216 mrq->sbc->data = mrq->data;
2217 }
2218
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302219 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Maya Erez00d7be62013-02-05 13:19:52 +02002220 if (msmsdcc_is_wait_for_auto_prog_done(host, mrq)) {
2221 host->curr.wait_for_auto_prog_done = true;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302222 } else {
2223 if ((mrq->cmd->opcode == SD_IO_RW_EXTENDED) ||
2224 (mrq->cmd->opcode == 54))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002225 host->dummy_52_needed = 1;
2226 }
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302227
Subhash Jadavanif5277752011-10-12 16:47:52 +05302228 if ((mrq->cmd->opcode == MMC_WRITE_BLOCK) ||
2229 (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK))
2230 host->curr.use_wr_data_pend = true;
San Mehat9d2bd732009-09-22 16:44:22 -07002231 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302232
Subhash Jadavanif5277752011-10-12 16:47:52 +05302233 msmsdcc_request_start(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302234
San Mehat9d2bd732009-09-22 16:44:22 -07002235 spin_unlock_irqrestore(&host->lock, flags);
2236}
2237
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002238static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
2239 int min_uV, int max_uV)
2240{
2241 int rc = 0;
2242
2243 if (vreg->set_voltage_sup) {
2244 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
2245 if (rc) {
2246 pr_err("%s: regulator_set_voltage(%s) failed."
2247 " min_uV=%d, max_uV=%d, rc=%d\n",
2248 __func__, vreg->name, min_uV, max_uV, rc);
2249 }
2250 }
2251
2252 return rc;
2253}
2254
Subhash Jadavanibf09d802012-08-11 18:11:57 +05302255static inline int msmsdcc_vreg_get_voltage(struct msm_mmc_reg_data *vreg)
2256{
2257 int rc = 0;
2258
2259 rc = regulator_get_voltage(vreg->reg);
2260 if (rc < 0)
2261 pr_err("%s: regulator_get_voltage(%s) failed. rc=%d\n",
2262 __func__, vreg->name, rc);
2263
2264 return rc;
2265}
2266
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002267static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
2268 int uA_load)
2269{
2270 int rc = 0;
2271
Krishna Kondafea60182011-11-01 16:01:34 -07002272 /* regulators that do not support regulator_set_voltage also
2273 do not support regulator_set_optimum_mode */
2274 if (vreg->set_voltage_sup) {
2275 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
2276 if (rc < 0)
2277 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
2278 "uA_load=%d) failed. rc=%d\n", __func__,
2279 vreg->name, uA_load, rc);
2280 else
2281 /* regulator_set_optimum_mode() can return non zero
2282 * value even for success case.
2283 */
2284 rc = 0;
2285 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002286
2287 return rc;
2288}
2289
2290static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
2291 struct device *dev)
2292{
2293 int rc = 0;
2294
2295 /* check if regulator is already initialized? */
2296 if (vreg->reg)
2297 goto out;
2298
2299 /* Get the regulator handle */
2300 vreg->reg = regulator_get(dev, vreg->name);
2301 if (IS_ERR(vreg->reg)) {
2302 rc = PTR_ERR(vreg->reg);
2303 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
2304 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002305 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002306 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002307
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05302308 if (regulator_count_voltages(vreg->reg) > 0) {
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002309 vreg->set_voltage_sup = 1;
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05302310 /* sanity check */
2311 if (!vreg->high_vol_level || !vreg->hpm_uA) {
2312 pr_err("%s: %s invalid constraints specified\n",
2313 __func__, vreg->name);
2314 rc = -EINVAL;
2315 }
2316 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002317
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002318out:
2319 return rc;
2320}
2321
2322static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
2323{
2324 if (vreg->reg)
2325 regulator_put(vreg->reg);
2326}
2327
2328/* This init function should be called only once for each SDCC slot */
2329static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
2330{
2331 int rc = 0;
2332 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302333 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vdd_io_reg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002334 struct device *dev = mmc_dev(host->mmc);
2335
2336 curr_slot = host->plat->vreg_data;
2337 if (!curr_slot)
2338 goto out;
2339
2340 curr_vdd_reg = curr_slot->vdd_data;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302341 curr_vdd_io_reg = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002342
2343 if (is_init) {
2344 /*
2345 * Get the regulator handle from voltage regulator framework
2346 * and then try to set the voltage level for the regulator
2347 */
2348 if (curr_vdd_reg) {
2349 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
2350 if (rc)
2351 goto out;
2352 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302353 if (curr_vdd_io_reg) {
2354 rc = msmsdcc_vreg_init_reg(curr_vdd_io_reg, dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002355 if (rc)
2356 goto vdd_reg_deinit;
2357 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002358 rc = msmsdcc_vreg_reset(host);
2359 if (rc)
2360 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
2361 host->pdev_id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002362 goto out;
2363 } else {
2364 /* Deregister all regulators from regulator framework */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302365 goto vdd_io_reg_deinit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002366 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302367vdd_io_reg_deinit:
2368 if (curr_vdd_io_reg)
2369 msmsdcc_vreg_deinit_reg(curr_vdd_io_reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002370vdd_reg_deinit:
2371 if (curr_vdd_reg)
2372 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2373out:
2374 return rc;
2375}
2376
2377static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2378{
2379 int rc = 0;
2380
Subhash Jadavanicc922692011-08-01 23:05:01 +05302381 /* Put regulator in HPM (high power mode) */
2382 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2383 if (rc < 0)
2384 goto out;
2385
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002386 if (!vreg->is_enabled) {
2387 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302388 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2389 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002390 if (rc)
2391 goto out;
2392
2393 rc = regulator_enable(vreg->reg);
2394 if (rc) {
2395 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2396 __func__, vreg->name, rc);
2397 goto out;
2398 }
2399 vreg->is_enabled = true;
2400 }
2401
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002402out:
2403 return rc;
2404}
2405
Krishna Konda3c4142d2012-06-27 11:01:56 -07002406static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg, bool is_init)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002407{
2408 int rc = 0;
2409
2410 /* Never disable regulator marked as always_on */
2411 if (vreg->is_enabled && !vreg->always_on) {
2412 rc = regulator_disable(vreg->reg);
2413 if (rc) {
2414 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2415 __func__, vreg->name, rc);
2416 goto out;
2417 }
2418 vreg->is_enabled = false;
2419
2420 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2421 if (rc < 0)
2422 goto out;
2423
2424 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302425 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002426 if (rc)
2427 goto out;
Krishna Konda3c4142d2012-06-27 11:01:56 -07002428 } else if (vreg->is_enabled && vreg->always_on) {
2429 if (!is_init && vreg->lpm_sup) {
2430 /* Put always_on regulator in LPM (low power mode) */
2431 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2432 if (rc < 0)
2433 goto out;
2434 } else if (is_init && vreg->reset_at_init) {
2435 /**
2436 * The regulator might not actually be disabled if it
2437 * is shared and in use by other drivers.
2438 */
2439 rc = regulator_disable(vreg->reg);
2440 if (rc) {
2441 pr_err("%s: regulator_disable(%s) failed at " \
2442 "bootup. rc=%d\n", __func__,
2443 vreg->name, rc);
2444 goto out;
2445 }
2446 vreg->is_enabled = false;
2447 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002448 }
2449out:
2450 return rc;
2451}
2452
Krishna Konda3c4142d2012-06-27 11:01:56 -07002453static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable,
2454 bool is_init)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002455{
2456 int rc = 0, i;
2457 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302458 struct msm_mmc_reg_data *vreg_table[2];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002459
2460 curr_slot = host->plat->vreg_data;
Asutosh Dasebd7d092012-07-09 19:08:26 +05302461 if (!curr_slot) {
2462 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002463 goto out;
Asutosh Dasebd7d092012-07-09 19:08:26 +05302464 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002465
Subhash Jadavani937c7502012-06-01 15:34:46 +05302466 vreg_table[0] = curr_slot->vdd_data;
2467 vreg_table[1] = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002468
2469 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2470 if (vreg_table[i]) {
2471 if (enable)
2472 rc = msmsdcc_vreg_enable(vreg_table[i]);
2473 else
Krishna Konda3c4142d2012-06-27 11:01:56 -07002474 rc = msmsdcc_vreg_disable(vreg_table[i],
2475 is_init);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002476 if (rc)
2477 goto out;
2478 }
2479 }
2480out:
2481 return rc;
2482}
2483
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002484/*
2485 * Reset vreg by ensuring it is off during probe. A call
2486 * to enable vreg is needed to balance disable vreg
2487 */
2488static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2489{
2490 int rc;
2491
Krishna Konda3c4142d2012-06-27 11:01:56 -07002492 rc = msmsdcc_setup_vreg(host, 1, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002493 if (rc)
2494 return rc;
Krishna Konda3c4142d2012-06-27 11:01:56 -07002495 rc = msmsdcc_setup_vreg(host, 0, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002496 return rc;
2497}
2498
Subhash Jadavani937c7502012-06-01 15:34:46 +05302499enum vdd_io_level {
2500 /* set vdd_io_data->low_vol_level */
2501 VDD_IO_LOW,
2502 /* set vdd_io_data->high_vol_level */
2503 VDD_IO_HIGH,
2504 /*
2505 * set whatever there in voltage_level (third argument) of
2506 * msmsdcc_set_vdd_io_vol() function.
2507 */
2508 VDD_IO_SET_LEVEL,
2509};
2510
Subhash Jadavanibf09d802012-08-11 18:11:57 +05302511/*
2512 * This function returns the current VDD IO voltage level.
2513 * Returns negative value if it fails to read the voltage level
2514 * Returns 0 if regulator was disabled or if VDD_IO (and VDD)
2515 * regulator were not defined for host.
2516 */
2517static int msmsdcc_get_vdd_io_vol(struct msmsdcc_host *host)
2518{
2519 int rc = 0;
2520
2521 if (host->plat->vreg_data) {
2522 struct msm_mmc_reg_data *io_reg =
2523 host->plat->vreg_data->vdd_io_data;
2524
2525 /*
2526 * If vdd_io is not defined, then we can consider that
2527 * IO voltage is same as VDD.
2528 */
2529 if (!io_reg)
2530 io_reg = host->plat->vreg_data->vdd_data;
2531
2532 if (io_reg && io_reg->is_enabled)
2533 rc = msmsdcc_vreg_get_voltage(io_reg);
2534 }
2535
2536 return rc;
2537}
2538
2539/*
2540 * This function updates the IO pad power switch bit in MCI_CLK register
2541 * based on currrent IO pad voltage level.
2542 * NOTE: This function assumes that host lock was not taken by caller.
2543 */
2544static void msmsdcc_update_io_pad_pwr_switch(struct msmsdcc_host *host)
2545{
2546 int rc = 0;
2547 unsigned long flags;
2548
2549 if (!is_io_pad_pwr_switch(host))
2550 return;
2551
2552 rc = msmsdcc_get_vdd_io_vol(host);
2553
2554 spin_lock_irqsave(&host->lock, flags);
2555 /*
2556 * Dual voltage pad is the SDCC's (chipset) functionality and not all
2557 * the SDCC instances support the dual voltage pads.
2558 * For dual-voltage pad (1.8v/3.3v), SW should set IO_PAD_PWR_SWITCH
2559 * bit before using the pads in 1.8V mode.
2560 * For regular, not dual-voltage pads (including eMMC 1.2v/1.8v pads),
2561 * IO_PAD_PWR_SWITCH bit is a don't care.
2562 * But we don't have an option to know (by reading some SDCC register)
2563 * that a particular SDCC instance supports dual voltage pads or not,
2564 * so we simply set the IO_PAD_PWR_SWITCH bit for low voltage IO
2565 * (1.8v/1.2v). For regular (not dual-voltage pads), this bit value
2566 * is anyway ignored.
2567 */
2568 if (rc > 0 && rc < 2700000)
2569 host->io_pad_pwr_switch = 1;
2570 else
2571 host->io_pad_pwr_switch = 0;
2572
2573 if (atomic_read(&host->clks_on)) {
2574 if (host->io_pad_pwr_switch)
2575 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2576 IO_PAD_PWR_SWITCH),
2577 host->base + MMCICLOCK);
2578 else
2579 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) &
2580 ~IO_PAD_PWR_SWITCH),
2581 host->base + MMCICLOCK);
2582 msmsdcc_sync_reg_wr(host);
2583 }
2584 spin_unlock_irqrestore(&host->lock, flags);
2585}
2586
Subhash Jadavani937c7502012-06-01 15:34:46 +05302587static int msmsdcc_set_vdd_io_vol(struct msmsdcc_host *host,
2588 enum vdd_io_level level,
2589 unsigned int voltage_level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002590{
2591 int rc = 0;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302592 int set_level;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002593
2594 if (host->plat->vreg_data) {
Subhash Jadavani937c7502012-06-01 15:34:46 +05302595 struct msm_mmc_reg_data *vdd_io_reg =
2596 host->plat->vreg_data->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002597
Subhash Jadavani937c7502012-06-01 15:34:46 +05302598 if (vdd_io_reg && vdd_io_reg->is_enabled) {
2599 switch (level) {
2600 case VDD_IO_LOW:
2601 set_level = vdd_io_reg->low_vol_level;
2602 break;
2603 case VDD_IO_HIGH:
2604 set_level = vdd_io_reg->high_vol_level;
2605 break;
2606 case VDD_IO_SET_LEVEL:
2607 set_level = voltage_level;
2608 break;
2609 default:
2610 pr_err("%s: %s: invalid argument level = %d",
2611 mmc_hostname(host->mmc), __func__,
2612 level);
2613 rc = -EINVAL;
2614 goto out;
2615 }
2616 rc = msmsdcc_vreg_set_voltage(vdd_io_reg,
2617 set_level, set_level);
2618 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002619 }
2620
Subhash Jadavani937c7502012-06-01 15:34:46 +05302621out:
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302622 return rc;
2623}
2624
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002625static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2626{
2627 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2628 return 1;
2629 return 0;
2630}
2631
Asutosh Dasf5298c32012-04-03 14:51:47 +05302632/*
2633 * Any function calling msmsdcc_setup_clocks must
2634 * acquire clk_mutex. May sleep.
2635 */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302636static int msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002637{
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302638 int rc = 0;
2639
2640 if (enable && !atomic_read(&host->clks_on)) {
2641 if (!IS_ERR_OR_NULL(host->bus_clk)) {
2642 rc = clk_prepare_enable(host->bus_clk);
2643 if (rc) {
2644 pr_err("%s: %s: failed to enable the bus-clock with error %d\n",
2645 mmc_hostname(host->mmc), __func__, rc);
2646 goto out;
2647 }
2648 }
2649 if (!IS_ERR(host->pclk)) {
2650 rc = clk_prepare_enable(host->pclk);
2651 if (rc) {
2652 pr_err("%s: %s: failed to enable the pclk with error %d\n",
2653 mmc_hostname(host->mmc), __func__, rc);
2654 goto disable_bus;
2655 }
2656 }
2657 rc = clk_prepare_enable(host->clk);
2658 if (rc) {
2659 pr_err("%s: %s: failed to enable the host-clk with error %d\n",
2660 mmc_hostname(host->mmc), __func__, rc);
2661 goto disable_pclk;
2662 }
Subhash Jadavanidd432952012-03-28 11:25:56 +05302663 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302664 msmsdcc_delay(host);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302665 atomic_set(&host->clks_on, 1);
2666 } else if (!enable && atomic_read(&host->clks_on)) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05302667 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302668 msmsdcc_delay(host);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302669 clk_disable_unprepare(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002670 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302671 clk_disable_unprepare(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05302672 if (!IS_ERR_OR_NULL(host->bus_clk))
2673 clk_disable_unprepare(host->bus_clk);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302674 atomic_set(&host->clks_on, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002675 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302676 goto out;
2677
2678disable_pclk:
2679 if (!IS_ERR_OR_NULL(host->pclk))
2680 clk_disable_unprepare(host->pclk);
2681disable_bus:
2682 if (!IS_ERR_OR_NULL(host->bus_clk))
2683 clk_disable_unprepare(host->bus_clk);
2684out:
2685 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002686}
2687
2688static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2689 unsigned int req_clk)
2690{
2691 unsigned int sel_clk = -1;
2692
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302693 if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
2694 sel_clk = msmsdcc_get_min_sup_clk_rate(host);
2695 goto out;
2696 }
2697
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002698 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2699 unsigned char cnt;
2700
2701 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2702 if (host->plat->sup_clk_table[cnt] > req_clk)
2703 break;
2704 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2705 sel_clk = host->plat->sup_clk_table[cnt];
2706 break;
2707 } else
2708 sel_clk = host->plat->sup_clk_table[cnt];
2709 }
2710 } else {
2711 if ((req_clk < host->plat->msmsdcc_fmax) &&
2712 (req_clk > host->plat->msmsdcc_fmid))
2713 sel_clk = host->plat->msmsdcc_fmid;
2714 else
2715 sel_clk = req_clk;
2716 }
2717
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302718out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002719 return sel_clk;
2720}
2721
2722static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2723 struct msmsdcc_host *host)
2724{
2725 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2726 return host->plat->sup_clk_table[0];
2727 else
2728 return host->plat->msmsdcc_fmin;
2729}
2730
2731static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2732 struct msmsdcc_host *host)
2733{
2734 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2735 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2736 else
2737 return host->plat->msmsdcc_fmax;
2738}
2739
2740static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302741{
2742 struct msm_mmc_gpio_data *curr;
2743 int i, rc = 0;
2744
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002745 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302746 for (i = 0; i < curr->size; i++) {
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05302747 if (!gpio_is_valid(curr->gpio[i].no)) {
2748 rc = -EINVAL;
2749 pr_err("%s: Invalid gpio = %d\n",
2750 mmc_hostname(host->mmc), curr->gpio[i].no);
2751 goto free_gpios;
2752 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302753 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002754 if (curr->gpio[i].is_always_on &&
2755 curr->gpio[i].is_enabled)
2756 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302757 rc = gpio_request(curr->gpio[i].no,
2758 curr->gpio[i].name);
2759 if (rc) {
2760 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2761 mmc_hostname(host->mmc),
2762 curr->gpio[i].no,
2763 curr->gpio[i].name, rc);
2764 goto free_gpios;
2765 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002766 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302767 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002768 if (curr->gpio[i].is_always_on)
2769 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302770 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002771 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302772 }
2773 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002774 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302775
2776free_gpios:
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05302777 for (i--; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302778 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002779 curr->gpio[i].is_enabled = false;
2780 }
2781out:
2782 return rc;
2783}
2784
2785static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2786{
2787 struct msm_mmc_pad_data *curr;
2788 int i;
2789
2790 curr = host->plat->pin_data->pad_data;
2791 for (i = 0; i < curr->drv->size; i++) {
2792 if (enable)
2793 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2794 curr->drv->on[i].val);
2795 else
2796 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2797 curr->drv->off[i].val);
2798 }
2799
2800 for (i = 0; i < curr->pull->size; i++) {
2801 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002802 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002803 curr->pull->on[i].val);
2804 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002805 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002806 curr->pull->off[i].val);
2807 }
2808
2809 return 0;
2810}
2811
2812static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2813{
2814 int rc = 0;
2815
2816 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2817 return 0;
2818
2819 if (host->plat->pin_data->is_gpio)
2820 rc = msmsdcc_setup_gpio(host, enable);
2821 else
2822 rc = msmsdcc_setup_pad(host, enable);
2823
2824 if (!rc)
2825 host->plat->pin_data->cfg_sts = enable;
2826
2827 return rc;
2828}
2829
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302830static int msmsdcc_cfg_mpm_sdiowakeup(struct msmsdcc_host *host,
2831 unsigned mode)
2832{
2833 int ret = 0;
2834 unsigned int pin = host->plat->mpm_sdiowakeup_int;
2835
2836 if (!pin)
2837 return 0;
2838
2839 switch (mode) {
2840 case SDC_DAT1_DISABLE:
2841 ret = msm_mpm_enable_pin(pin, 0);
2842 break;
2843 case SDC_DAT1_ENABLE:
2844 ret = msm_mpm_set_pin_type(pin, IRQ_TYPE_LEVEL_LOW);
2845 ret = msm_mpm_enable_pin(pin, 1);
2846 break;
2847 case SDC_DAT1_ENWAKE:
2848 ret = msm_mpm_set_pin_wake(pin, 1);
2849 break;
2850 case SDC_DAT1_DISWAKE:
2851 ret = msm_mpm_set_pin_wake(pin, 0);
2852 break;
2853 default:
2854 ret = -EINVAL;
2855 break;
2856 }
2857
2858 return ret;
2859}
2860
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302861static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2862{
2863 u32 pwr = 0;
2864 int ret = 0;
2865 struct mmc_host *mmc = host->mmc;
2866
2867 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2868 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2869 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
Krishna Konda3c4142d2012-06-27 11:01:56 -07002870 ret = msmsdcc_setup_vreg(host, !!ios->vdd, false);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302871
2872 if (ret) {
2873 pr_err("%s: Failed to setup voltage regulators\n",
2874 mmc_hostname(host->mmc));
2875 goto out;
2876 }
2877
2878 switch (ios->power_mode) {
2879 case MMC_POWER_OFF:
2880 pwr = MCI_PWR_OFF;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302881 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302882 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05302883 * If VDD IO rail is always on, set low voltage for VDD
2884 * IO rail when slot is not in use (like when card is not
2885 * present or during system suspend).
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302886 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302887 msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Subhash Jadavanibf09d802012-08-11 18:11:57 +05302888 msmsdcc_update_io_pad_pwr_switch(host);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302889 msmsdcc_setup_pins(host, false);
Pratibhasagar Vbe4e3132012-09-20 19:46:11 +05302890 /*
2891 * Reset the mask to prevent hitting any pending interrupts
2892 * after powering up the card again.
2893 */
2894 if (atomic_read(&host->clks_on)) {
2895 writel_relaxed(0, host->base + MMCIMASK0);
2896 mb();
2897 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302898 break;
2899 case MMC_POWER_UP:
2900 /* writing PWR_UP bit is redundant */
2901 pwr = MCI_PWR_UP;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302902 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302903
Subhash Jadavani937c7502012-06-01 15:34:46 +05302904 msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Subhash Jadavanibf09d802012-08-11 18:11:57 +05302905 msmsdcc_update_io_pad_pwr_switch(host);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302906 msmsdcc_setup_pins(host, true);
2907 break;
2908 case MMC_POWER_ON:
2909 pwr = MCI_PWR_ON;
2910 break;
2911 }
2912
2913out:
2914 return pwr;
2915}
2916
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002917static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2918{
2919 unsigned int wakeup_irq;
2920
2921 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2922 host->plat->sdiowakeup_irq :
2923 host->core_irqres->start;
2924
2925 if (!host->irq_wake_enabled) {
2926 enable_irq_wake(wakeup_irq);
2927 host->irq_wake_enabled = true;
2928 }
2929}
2930
2931static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2932{
2933 unsigned int wakeup_irq;
2934
2935 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2936 host->plat->sdiowakeup_irq :
2937 host->core_irqres->start;
2938
2939 if (host->irq_wake_enabled) {
2940 disable_irq_wake(wakeup_irq);
2941 host->irq_wake_enabled = false;
2942 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302943}
2944
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05302945/* Returns required bandwidth in Bytes per Sec */
2946static unsigned int msmsdcc_get_bw_required(struct msmsdcc_host *host,
2947 struct mmc_ios *ios)
2948{
2949 unsigned int bw;
2950
2951 bw = host->clk_rate;
2952 /*
2953 * For DDR mode, SDCC controller clock will be at
2954 * the double rate than the actual clock that goes to card.
2955 */
2956 if (ios->bus_width == MMC_BUS_WIDTH_4)
2957 bw /= 2;
2958 else if (ios->bus_width == MMC_BUS_WIDTH_1)
2959 bw /= 8;
2960
2961 return bw;
2962}
2963
2964static int msmsdcc_msm_bus_get_vote_for_bw(struct msmsdcc_host *host,
2965 unsigned int bw)
2966{
2967 unsigned int *table = host->plat->msm_bus_voting_data->bw_vecs;
2968 unsigned int size = host->plat->msm_bus_voting_data->bw_vecs_size;
2969 int i;
2970
2971 if (host->msm_bus_vote.is_max_bw_needed && bw)
2972 return host->msm_bus_vote.max_bw_vote;
2973
2974 for (i = 0; i < size; i++) {
2975 if (bw <= table[i])
2976 break;
2977 }
2978
2979 if (i && (i == size))
2980 i--;
2981
2982 return i;
2983}
2984
2985static int msmsdcc_msm_bus_register(struct msmsdcc_host *host)
2986{
2987 int rc = 0;
2988 struct msm_bus_scale_pdata *use_cases;
2989
2990 if (host->plat->msm_bus_voting_data &&
2991 host->plat->msm_bus_voting_data->use_cases &&
2992 host->plat->msm_bus_voting_data->bw_vecs &&
2993 host->plat->msm_bus_voting_data->bw_vecs_size) {
2994 use_cases = host->plat->msm_bus_voting_data->use_cases;
2995 host->msm_bus_vote.client_handle =
2996 msm_bus_scale_register_client(use_cases);
2997 } else {
2998 return 0;
2999 }
3000
3001 if (!host->msm_bus_vote.client_handle) {
3002 pr_err("%s: msm_bus_scale_register_client() failed\n",
3003 mmc_hostname(host->mmc));
3004 rc = -EFAULT;
3005 } else {
3006 /* cache the vote index for minimum and maximum bandwidth */
3007 host->msm_bus_vote.min_bw_vote =
3008 msmsdcc_msm_bus_get_vote_for_bw(host, 0);
3009 host->msm_bus_vote.max_bw_vote =
3010 msmsdcc_msm_bus_get_vote_for_bw(host, UINT_MAX);
3011 }
3012
3013 return rc;
3014}
3015
3016static void msmsdcc_msm_bus_unregister(struct msmsdcc_host *host)
3017{
3018 if (host->msm_bus_vote.client_handle)
3019 msm_bus_scale_unregister_client(
3020 host->msm_bus_vote.client_handle);
3021}
3022
3023/*
3024 * This function must be called with host lock acquired.
3025 * Caller of this function should also ensure that msm bus client
3026 * handle is not null.
3027 */
3028static inline int msmsdcc_msm_bus_set_vote(struct msmsdcc_host *host,
3029 int vote,
3030 unsigned long flags)
3031{
3032 int rc = 0;
3033
3034 if (vote != host->msm_bus_vote.curr_vote) {
3035 spin_unlock_irqrestore(&host->lock, flags);
3036 rc = msm_bus_scale_client_update_request(
3037 host->msm_bus_vote.client_handle, vote);
3038 if (rc)
3039 pr_err("%s: msm_bus_scale_client_update_request() failed."
3040 " bus_client_handle=0x%x, vote=%d, err=%d\n",
3041 mmc_hostname(host->mmc),
3042 host->msm_bus_vote.client_handle, vote, rc);
3043 spin_lock_irqsave(&host->lock, flags);
3044 if (!rc)
3045 host->msm_bus_vote.curr_vote = vote;
3046 }
3047
3048 return rc;
3049}
3050
3051/*
3052 * Internal work. Work to set 0 bandwidth for msm bus.
3053 */
3054static void msmsdcc_msm_bus_work(struct work_struct *work)
3055{
3056 struct msmsdcc_host *host = container_of(work,
3057 struct msmsdcc_host,
3058 msm_bus_vote.vote_work.work);
3059 unsigned long flags;
3060
3061 if (!host->msm_bus_vote.client_handle)
3062 return;
3063
3064 spin_lock_irqsave(&host->lock, flags);
3065 /* don't vote for 0 bandwidth if any request is in progress */
3066 if (!host->curr.mrq)
3067 msmsdcc_msm_bus_set_vote(host,
3068 host->msm_bus_vote.min_bw_vote, flags);
3069 else
3070 pr_warning("%s: %s: SDCC transfer in progress. skipping"
3071 " bus voting to 0 bandwidth\n",
3072 mmc_hostname(host->mmc), __func__);
3073 spin_unlock_irqrestore(&host->lock, flags);
3074}
3075
3076/*
3077 * This function cancels any scheduled delayed work
3078 * and sets the bus vote based on ios argument.
3079 * If "ios" argument is NULL, bandwidth required is 0 else
3080 * calculate the bandwidth based on ios parameters.
3081 */
3082static void msmsdcc_msm_bus_cancel_work_and_set_vote(
3083 struct msmsdcc_host *host,
3084 struct mmc_ios *ios)
3085{
3086 unsigned long flags;
3087 unsigned int bw;
3088 int vote;
3089
3090 if (!host->msm_bus_vote.client_handle)
3091 return;
3092
3093 bw = ios ? msmsdcc_get_bw_required(host, ios) : 0;
3094
3095 cancel_delayed_work_sync(&host->msm_bus_vote.vote_work);
3096 spin_lock_irqsave(&host->lock, flags);
3097 vote = msmsdcc_msm_bus_get_vote_for_bw(host, bw);
3098 msmsdcc_msm_bus_set_vote(host, vote, flags);
3099 spin_unlock_irqrestore(&host->lock, flags);
3100}
3101
3102/* This function queues a work which will set the bandwidth requiement to 0 */
3103static void msmsdcc_msm_bus_queue_work(struct msmsdcc_host *host)
3104{
3105 unsigned long flags;
3106
3107 if (!host->msm_bus_vote.client_handle)
3108 return;
3109
3110 spin_lock_irqsave(&host->lock, flags);
3111 if (host->msm_bus_vote.min_bw_vote != host->msm_bus_vote.curr_vote)
3112 queue_delayed_work(system_nrt_wq,
3113 &host->msm_bus_vote.vote_work,
3114 msecs_to_jiffies(MSM_MMC_BUS_VOTING_DELAY));
3115 spin_unlock_irqrestore(&host->lock, flags);
3116}
3117
San Mehat9d2bd732009-09-22 16:44:22 -07003118static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303119msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
3120{
3121 struct mmc_host *mmc = host->mmc;
3122
3123 /*
3124 * SDIO_AL clients has different mechanism of handling LPM through
3125 * sdio_al driver itself. The sdio wakeup interrupt is configured as
3126 * part of that. Here, we are interested only in clients like WLAN.
3127 */
3128 if (!(mmc->card && mmc_card_sdio(mmc->card))
3129 || host->plat->is_sdio_al_client)
3130 goto out;
3131
3132 if (!host->sdcc_suspended) {
3133 /*
3134 * When MSM is not in power collapse and we
3135 * are disabling clocks, enable bit 22 in MASK0
3136 * to handle asynchronous SDIO interrupts.
3137 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05303138 if (enable_wakeup_irq) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303139 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303140 mb();
3141 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303142 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303143 msmsdcc_sync_reg_wr(host);
3144 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303145 goto out;
3146 } else if (!mmc_card_wake_sdio_irq(mmc)) {
3147 /*
3148 * Wakeup MSM only if SDIO function drivers set
3149 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
3150 */
3151 goto out;
3152 }
3153
3154 if (enable_wakeup_irq) {
3155 if (!host->plat->sdiowakeup_irq) {
3156 /*
3157 * When there is no gpio line that can be configured
3158 * as wakeup interrupt handle it by configuring
3159 * asynchronous sdio interrupts and DAT1 line.
3160 */
3161 writel_relaxed(MCI_SDIOINTMASK,
3162 host->base + MMCIMASK0);
3163 mb();
Subhash Jadavanic9b85752012-04-13 11:16:49 +05303164 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303165 /* configure sdcc core interrupt as wakeup interrupt */
3166 msmsdcc_enable_irq_wake(host);
3167 } else {
3168 /* Let gpio line handle wakeup interrupt */
3169 writel_relaxed(0, host->base + MMCIMASK0);
3170 mb();
3171 if (host->sdio_wakeupirq_disabled) {
3172 host->sdio_wakeupirq_disabled = 0;
3173 /* configure gpio line as wakeup interrupt */
3174 msmsdcc_enable_irq_wake(host);
3175 enable_irq(host->plat->sdiowakeup_irq);
3176 }
3177 }
3178 } else {
3179 if (!host->plat->sdiowakeup_irq) {
3180 /*
3181 * We may not have cleared bit 22 in the interrupt
3182 * handler as the clocks might be off at that time.
3183 */
3184 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303185 msmsdcc_sync_reg_wr(host);
Subhash Jadavanic9b85752012-04-13 11:16:49 +05303186 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303187 msmsdcc_disable_irq_wake(host);
3188 } else if (!host->sdio_wakeupirq_disabled) {
3189 disable_irq_nosync(host->plat->sdiowakeup_irq);
3190 msmsdcc_disable_irq_wake(host);
3191 host->sdio_wakeupirq_disabled = 1;
3192 }
3193 }
3194out:
3195 return;
San Mehat9d2bd732009-09-22 16:44:22 -07003196}
3197
3198static void
3199msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
3200{
3201 struct msmsdcc_host *host = mmc_priv(mmc);
3202 u32 clk = 0, pwr = 0;
3203 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08003204 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003205 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07003206
Sahitya Tummala7a892482011-01-18 11:22:49 +05303207
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303208 /*
3209 * Disable SDCC core interrupt until set_ios is completed.
3210 * This avoids any race conditions with interrupt raised
3211 * when turning on/off the clocks. One possible
3212 * scenario is SDIO operational interrupt while the clock
3213 * is turned off.
Asutosh Dasf5298c32012-04-03 14:51:47 +05303214 * host->lock is being released intermittently below.
3215 * Thus, prevent concurrent access to host.
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303216 */
3217
Asutosh Dasf5298c32012-04-03 14:51:47 +05303218 mutex_lock(&host->clk_mutex);
3219 DBG(host, "ios->clock = %u\n", ios->clock);
San Mehat9d2bd732009-09-22 16:44:22 -07003220 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303221 if (!host->sdcc_irq_disabled) {
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05303222 disable_irq_nosync(host->core_irqres->start);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303223 host->sdcc_irq_disabled = 1;
3224 }
San Mehatd0719e52009-12-03 10:58:54 -08003225 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07003226
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05303227 /* Make sure sdcc core irq is synchronized */
3228 synchronize_irq(host->core_irqres->start);
3229
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303230 pwr = msmsdcc_setup_pwr(host, ios);
3231
3232 spin_lock_irqsave(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07003233 if (ios->clock) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303234 spin_unlock_irqrestore(&host->lock, flags);
3235 rc = msmsdcc_setup_clocks(host, true);
3236 if (rc)
3237 goto out;
3238 spin_lock_irqsave(&host->lock, flags);
3239 writel_relaxed(host->mci_irqenable, host->base + MMCIMASK0);
3240 mb();
3241 msmsdcc_cfg_sdio_wakeup(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003242 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303243
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003244 /*
3245 * For DDR50 mode, controller needs clock rate to be
3246 * double than what is required on the SD card CLK pin.
Subhash Jadavani2226d262012-10-09 20:01:56 +05303247 *
3248 * Setting DDR timing mode in controller before setting the
3249 * clock rate will make sure that card don't see the double
3250 * clock rate even for very small duration. Some eMMC
3251 * cards seems to lock up if they see clock frequency > 52MHz.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003252 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05303253 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Subhash Jadavani2226d262012-10-09 20:01:56 +05303254 u32 clk;
3255
3256 clk = readl_relaxed(host->base + MMCICLOCK);
3257 clk &= ~(0x7 << 14); /* clear SELECT_IN field */
3258 clk |= (3 << 14); /* set DDR timing mode */
3259 writel_relaxed(clk, host->base + MMCICLOCK);
3260 msmsdcc_sync_reg_wr(host);
3261
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003262 /*
3263 * Make sure that we don't double the clock if
3264 * doubled clock rate is already set
3265 */
3266 if (!host->ddr_doubled_clk_rate ||
3267 (host->ddr_doubled_clk_rate &&
3268 (host->ddr_doubled_clk_rate != ios->clock))) {
3269 host->ddr_doubled_clk_rate =
3270 msmsdcc_get_sup_clk_rate(
3271 host, (ios->clock * 2));
3272 clock = host->ddr_doubled_clk_rate;
3273 }
3274 } else {
3275 host->ddr_doubled_clk_rate = 0;
3276 }
3277
3278 if (clock != host->clk_rate) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05303279 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003280 rc = clk_set_rate(host->clk, clock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303281 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003282 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303283 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003284 mmc_hostname(mmc), clock);
3285 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303286 host->reg_write_delay =
3287 (1 + ((3 * USEC_PER_SEC) /
3288 (host->clk_rate ? host->clk_rate :
3289 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003290 }
3291 /*
3292 * give atleast 2 MCLK cycles delay for clocks
3293 * and SDCC core to stabilize
3294 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05303295 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003296 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003297 clk |= MCI_CLK_ENABLE;
3298 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003299 if (ios->bus_width == MMC_BUS_WIDTH_8)
3300 clk |= MCI_CLK_WIDEBUS_8;
3301 else if (ios->bus_width == MMC_BUS_WIDTH_4)
3302 clk |= MCI_CLK_WIDEBUS_4;
3303 else
3304 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07003305
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003306 if (msmsdcc_is_pwrsave(host))
3307 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07003308
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003309 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07003310
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003311 host->tuning_needed = 0;
3312 /*
3313 * Select the controller timing mode according
3314 * to current bus speed mode
3315 */
Subhash Jadavanif97d2992012-07-13 14:47:47 +05303316 if (host->clk_rate > (100 * 1000 * 1000) &&
3317 (ios->timing == MMC_TIMING_UHS_SDR104 ||
3318 ios->timing == MMC_TIMING_MMC_HS200)) {
3319 /* Card clock frequency must be > 100MHz to enable tuning */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003320 clk |= (4 << 14);
3321 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05303322 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003323 clk |= (3 << 14);
3324 } else {
3325 clk |= (2 << 14); /* feedback clock */
San Mehat9d2bd732009-09-22 16:44:22 -07003326 }
3327
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003328 /* Select free running MCLK as input clock of cm_dll_sdc4 */
3329 clk |= (2 << 23);
San Mehat9d2bd732009-09-22 16:44:22 -07003330
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003331 if (host->io_pad_pwr_switch)
3332 clk |= IO_PAD_PWR_SWITCH;
3333
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303334 /* Don't write into registers if clocks are disabled */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303335 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303336 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
3337 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303338 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003339 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303340 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
3341 host->pwr = pwr;
3342 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303343 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003344 }
San Mehat9d2bd732009-09-22 16:44:22 -07003345 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003346
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303347 if (!(clk & MCI_CLK_ENABLE) && atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303348 msmsdcc_cfg_sdio_wakeup(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303349 spin_unlock_irqrestore(&host->lock, flags);
3350 /*
3351 * May get a wake-up interrupt the instant we disable the
3352 * clocks. This would disable the wake-up interrupt.
3353 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003354 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303355 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003356 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303357
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303358 if (host->tuning_in_progress)
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303359 WARN(!atomic_read(&host->clks_on),
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303360 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303361
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303362 /* Let interrupts be disabled if the host is powered off */
3363 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
3364 enable_irq(host->core_irqres->start);
3365 host->sdcc_irq_disabled = 0;
3366 }
San Mehat4adbbcc2009-11-08 13:00:37 -08003367 spin_unlock_irqrestore(&host->lock, flags);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303368out:
Asutosh Dasf5298c32012-04-03 14:51:47 +05303369 mutex_unlock(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07003370}
3371
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003372int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
3373{
3374 struct msmsdcc_host *host = mmc_priv(mmc);
3375 u32 clk;
3376
3377 clk = readl_relaxed(host->base + MMCICLOCK);
3378 pr_debug("Changing to pwr_save=%d", pwrsave);
3379 if (pwrsave && msmsdcc_is_pwrsave(host))
3380 clk |= MCI_CLK_PWRSAVE;
3381 else
3382 clk &= ~MCI_CLK_PWRSAVE;
3383 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303384 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003385
3386 return 0;
3387}
3388
3389static int msmsdcc_get_ro(struct mmc_host *mmc)
3390{
3391 int status = -ENOSYS;
3392 struct msmsdcc_host *host = mmc_priv(mmc);
3393
3394 if (host->plat->wpswitch) {
3395 status = host->plat->wpswitch(mmc_dev(mmc));
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05303396 } else if (gpio_is_valid(host->plat->wpswitch_gpio)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003397 status = gpio_request(host->plat->wpswitch_gpio,
3398 "SD_WP_Switch");
3399 if (status) {
3400 pr_err("%s: %s: Failed to request GPIO %d\n",
3401 mmc_hostname(mmc), __func__,
3402 host->plat->wpswitch_gpio);
3403 } else {
3404 status = gpio_direction_input(
3405 host->plat->wpswitch_gpio);
3406 if (!status) {
3407 /*
3408 * Wait for atleast 300ms as debounce
3409 * time for GPIO input to stabilize.
3410 */
3411 msleep(300);
3412 status = gpio_get_value_cansleep(
3413 host->plat->wpswitch_gpio);
Sujit Reddy Thumma8f912ea2012-06-22 16:18:43 +05303414 status ^= !host->plat->is_wpswitch_active_low;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003415 }
3416 gpio_free(host->plat->wpswitch_gpio);
3417 }
3418 }
3419
3420 if (status < 0)
3421 status = -ENOSYS;
3422 pr_debug("%s: Card read-only status %d\n", __func__, status);
3423
3424 return status;
San Mehat9d2bd732009-09-22 16:44:22 -07003425}
3426
3427static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
3428{
3429 struct msmsdcc_host *host = mmc_priv(mmc);
3430 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003431
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303432 /*
3433 * We may come here with clocks turned off in that case don't
3434 * attempt to write into MASK0 register. While turning on the
3435 * clocks mci_irqenable will be written to MASK0 register.
3436 */
San Mehat9d2bd732009-09-22 16:44:22 -07003437
3438 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003439 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003440 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303441 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303442 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003443 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303444 mb();
3445 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003446 } else {
3447 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303448 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303449 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003450 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303451 mb();
3452 }
San Mehat9d2bd732009-09-22 16:44:22 -07003453 }
3454 spin_unlock_irqrestore(&host->lock, flags);
3455}
3456
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003457#ifdef CONFIG_PM_RUNTIME
subhashj245831e2012-04-30 18:46:17 +05303458static void msmsdcc_print_rpm_info(struct msmsdcc_host *host)
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003459{
subhashj245831e2012-04-30 18:46:17 +05303460 struct device *dev = mmc_dev(host->mmc);
3461
Subhash Jadavani1371d192012-08-16 18:46:57 +05303462 pr_info("%s: PM: sdcc_suspended=%d, pending_resume=%d, sdcc_suspending=%d\n",
3463 mmc_hostname(host->mmc), host->sdcc_suspended,
3464 host->pending_resume, host->sdcc_suspending);
subhashj245831e2012-04-30 18:46:17 +05303465 pr_info("%s: RPM: runtime_status=%d, usage_count=%d,"
3466 " is_suspended=%d, disable_depth=%d, runtime_error=%d,"
3467 " request_pending=%d, request=%d\n",
3468 mmc_hostname(host->mmc), dev->power.runtime_status,
3469 atomic_read(&dev->power.usage_count),
3470 dev->power.is_suspended, dev->power.disable_depth,
3471 dev->power.runtime_error, dev->power.request_pending,
3472 dev->power.request);
3473}
3474
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003475static int msmsdcc_enable(struct mmc_host *mmc)
3476{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003477 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003478 struct device *dev = mmc->parent;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003479 struct msmsdcc_host *host = mmc_priv(mmc);
3480
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303481 msmsdcc_pm_qos_update_latency(host, 1);
3482
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003483 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303484 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003485
Subhash Jadavani1371d192012-08-16 18:46:57 +05303486 if (host->sdcc_suspended && host->pending_resume) {
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003487 host->pending_resume = false;
3488 pm_runtime_get_noresume(dev);
3489 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303490 goto skip_get_sync;
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003491 }
3492
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303493 if (dev->power.runtime_status == RPM_SUSPENDING) {
3494 if (mmc->suspend_task == current) {
3495 pm_runtime_get_noresume(dev);
3496 goto out;
3497 }
Sujit Reddy Thumma112bd752012-06-20 12:29:45 +05303498 } else if (dev->power.runtime_status == RPM_RESUMING) {
3499 pm_runtime_get_noresume(dev);
3500 goto out;
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303501 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003502
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303503 rc = pm_runtime_get_sync(dev);
3504
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303505skip_get_sync:
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303506 if (rc < 0) {
Subhash Jadavani1371d192012-08-16 18:46:57 +05303507 WARN(1, "%s: %s: failed with error %d\n", mmc_hostname(mmc),
3508 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303509 msmsdcc_print_rpm_info(host);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303510 return rc;
3511 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303512out:
3513 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303514 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003515}
3516
Steve Mucklef132c6c2012-06-06 18:30:57 -07003517static int msmsdcc_disable(struct mmc_host *mmc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003518{
3519 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303520 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003521
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303522 msmsdcc_pm_qos_update_latency(host, 0);
3523
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303524 if (mmc->card && mmc_card_sdio(mmc->card)) {
3525 rc = 0;
3526 goto out;
3527 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303528
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303529 if (host->plat->disable_runtime_pm)
3530 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003531
3532 rc = pm_runtime_put_sync(mmc->parent);
3533
Subhash Jadavani1371d192012-08-16 18:46:57 +05303534 if (rc < 0) {
3535 WARN(1, "%s: %s: failed with error %d\n", mmc_hostname(mmc),
3536 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303537 msmsdcc_print_rpm_info(host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003538 return rc;
3539 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303540
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303541out:
3542 msmsdcc_msm_bus_queue_work(host);
3543 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003544}
3545#else
subhashj245831e2012-04-30 18:46:17 +05303546static void msmsdcc_print_rpm_info(struct msmsdcc_host *host) {}
3547
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303548static int msmsdcc_enable(struct mmc_host *mmc)
3549{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003550 struct device *dev = mmc->parent;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303551 struct msmsdcc_host *host = mmc_priv(mmc);
Sujit Reddy Thumma7f5051c2012-05-04 10:14:07 +05303552 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303553
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303554 msmsdcc_pm_qos_update_latency(host, 1);
3555
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303556 if (mmc->card && mmc_card_sdio(mmc->card)) {
3557 rc = 0;
3558 goto out;
3559 }
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003560
3561 if (host->sdcc_suspended && host->pending_resume) {
3562 host->pending_resume = false;
3563 rc = msmsdcc_runtime_resume(dev);
3564 goto out;
3565 }
3566
Asutosh Dasf5298c32012-04-03 14:51:47 +05303567 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303568 rc = msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303569 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303570
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003571out:
3572 if (rc < 0) {
3573 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3574 __func__, rc);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303575 msmsdcc_pm_qos_update_latency(host, 0);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003576 return rc;
3577 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303578 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303579 return 0;
3580}
3581
Steve Mucklef132c6c2012-06-06 18:30:57 -07003582static int msmsdcc_disable(struct mmc_host *mmc)
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303583{
3584 struct msmsdcc_host *host = mmc_priv(mmc);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303585 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303586
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303587 msmsdcc_pm_qos_update_latency(host, 0);
3588
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303589 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303590 goto out;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303591
Asutosh Dasf5298c32012-04-03 14:51:47 +05303592 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303593 rc = msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303594 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303595
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303596 if (rc) {
3597 msmsdcc_pm_qos_update_latency(host, 1);
3598 return rc;
3599 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303600out:
3601 msmsdcc_msm_bus_queue_work(host);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303602 return rc;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303603}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003604#endif
3605
Subhash Jadavani937c7502012-06-01 15:34:46 +05303606static int msmsdcc_switch_io_voltage(struct mmc_host *mmc,
3607 struct mmc_ios *ios)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003608{
3609 struct msmsdcc_host *host = mmc_priv(mmc);
3610 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303611 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003612
Subhash Jadavani937c7502012-06-01 15:34:46 +05303613 switch (ios->signal_voltage) {
3614 case MMC_SIGNAL_VOLTAGE_330:
3615 /* Set VDD IO to high voltage range (2.7v - 3.6v) */
3616 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Subhash Jadavanibf09d802012-08-11 18:11:57 +05303617 if (!rc)
3618 msmsdcc_update_io_pad_pwr_switch(host);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303619 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303620 case MMC_SIGNAL_VOLTAGE_180:
3621 break;
3622 case MMC_SIGNAL_VOLTAGE_120:
3623 /*
3624 * For eMMC cards, VDD_IO voltage range must be changed
3625 * only if it operates in HS200 SDR 1.2V mode or in
3626 * DDR 1.2V mode.
3627 */
3628 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_SET_LEVEL, 1200000);
Subhash Jadavanibf09d802012-08-11 18:11:57 +05303629 if (!rc)
3630 msmsdcc_update_io_pad_pwr_switch(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003631 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303632 default:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003633 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303634 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003635 goto out;
3636 }
San Mehat9d2bd732009-09-22 16:44:22 -07003637
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003638 /*
3639 * If we are here means voltage switch from high voltage to
3640 * low voltage is required
3641 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303642 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003643
3644 /*
3645 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
3646 * register until they become all zeros.
3647 */
3648 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303649 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003650 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
3651 mmc_hostname(mmc), __func__);
3652 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07003653 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003654
3655 /* Stop SD CLK output. */
3656 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3657 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303658 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003659 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003660
3661 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05303662 * Switch VDD Io from high voltage range (2.7v - 3.6v) to
3663 * low voltage range (1.7v - 1.95v).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003664 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303665 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303666 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003667 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003668
Subhash Jadavanibf09d802012-08-11 18:11:57 +05303669 msmsdcc_update_io_pad_pwr_switch(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003670
3671 /* Wait 5 ms for the voltage regulater in the card to become stable. */
3672 usleep_range(5000, 5500);
3673
3674 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303675 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003676 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3677 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303678 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003679 spin_unlock_irqrestore(&host->lock, flags);
3680
3681 /*
3682 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
3683 * don't become all ones within 1 ms then a Voltage Switch
3684 * sequence has failed and a power cycle to the card is required.
3685 * Otherwise Voltage Switch sequence is completed successfully.
3686 */
3687 usleep_range(1000, 1500);
3688
3689 spin_lock_irqsave(&host->lock, flags);
3690 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
3691 != (0xF << 1)) {
3692 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
3693 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303694 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003695 goto out_unlock;
3696 }
3697
3698out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303699 /* Enable PWRSAVE */
3700 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3701 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303702 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003703 spin_unlock_irqrestore(&host->lock, flags);
3704out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303705 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003706}
3707
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303708static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003709{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003710 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003711
3712 /* Program the MCLK value to MCLK_FREQ bit field */
3713 if (host->clk_rate <= 112000000)
3714 mclk_freq = 0;
3715 else if (host->clk_rate <= 125000000)
3716 mclk_freq = 1;
3717 else if (host->clk_rate <= 137000000)
3718 mclk_freq = 2;
3719 else if (host->clk_rate <= 150000000)
3720 mclk_freq = 3;
3721 else if (host->clk_rate <= 162000000)
3722 mclk_freq = 4;
3723 else if (host->clk_rate <= 175000000)
3724 mclk_freq = 5;
3725 else if (host->clk_rate <= 187000000)
3726 mclk_freq = 6;
3727 else if (host->clk_rate <= 200000000)
3728 mclk_freq = 7;
3729
3730 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3731 & ~(7 << 24)) | (mclk_freq << 24)),
3732 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003733}
3734
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303735/* Initialize the DLL (Programmable Delay Line ) */
3736static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003737{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003738 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303739 unsigned long flags;
3740 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003741
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303742 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003743 /*
3744 * Make sure that clock is always enabled when DLL
3745 * tuning is in progress. Keeping PWRSAVE ON may
3746 * turn off the clock. So let's disable the PWRSAVE
3747 * here and re-enable it once tuning is completed.
3748 */
3749 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3750 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303751 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303752
3753 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3754 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3755 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3756
3757 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3758 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3759 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3760
3761 msmsdcc_cm_sdc4_dll_set_freq(host);
3762
3763 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3764 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3765 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3766
3767 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3768 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3769 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3770
3771 /* Set DLL_EN bit to 1. */
3772 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3773 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3774
3775 /* Set CK_OUT_EN bit to 1. */
3776 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3777 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3778
3779 wait_cnt = 50;
3780 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3781 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3782 /* max. wait for 50us sec for LOCK bit to be set */
3783 if (--wait_cnt == 0) {
3784 pr_err("%s: %s: DLL failed to LOCK\n",
3785 mmc_hostname(host->mmc), __func__);
3786 rc = -ETIMEDOUT;
3787 goto out;
3788 }
3789 /* wait for 1us before polling again */
3790 udelay(1);
3791 }
3792
3793out:
3794 /* re-enable PWRSAVE */
3795 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3796 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303797 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303798 spin_unlock_irqrestore(&host->lock, flags);
3799
3800 return rc;
3801}
3802
3803static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3804 u8 poll)
3805{
3806 int rc = 0;
3807 u32 wait_cnt = 50;
3808 u8 ck_out_en = 0;
3809
3810 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3811 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3812 MCI_CK_OUT_EN);
3813
3814 while (ck_out_en != poll) {
3815 if (--wait_cnt == 0) {
3816 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3817 mmc_hostname(host->mmc), __func__, poll);
3818 rc = -ETIMEDOUT;
3819 goto out;
3820 }
3821 udelay(1);
3822
3823 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3824 MCI_CK_OUT_EN);
3825 }
3826out:
3827 return rc;
3828}
3829
3830/*
3831 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3832 * calibration sequence. This function should be called before
3833 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3834 * commands (CMD17/CMD18).
3835 *
3836 * This function gets called when host spinlock acquired.
3837 */
3838static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3839{
3840 int rc = 0;
3841 u32 config;
3842
3843 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3844 config |= MCI_CDR_EN;
3845 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3846 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3847
3848 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3849 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3850 if (rc)
3851 goto err_out;
3852
3853 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3854 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3855 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3856
3857 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3858 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3859 if (rc)
3860 goto err_out;
3861
3862 goto out;
3863
3864err_out:
3865 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3866out:
3867 return rc;
3868}
3869
3870static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3871 u8 phase)
3872{
3873 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303874 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3875 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3876 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303877 unsigned long flags;
3878 u32 config;
3879
3880 spin_lock_irqsave(&host->lock, flags);
3881
3882 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3883 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3884 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3885 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3886
3887 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3888 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3889 if (rc)
3890 goto err_out;
3891
3892 /*
3893 * Write the selected DLL clock output phase (0 ... 15)
3894 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
3895 */
3896 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3897 & ~(0xF << 20))
3898 | (grey_coded_phase_table[phase] << 20)),
3899 host->base + MCI_DLL_CONFIG);
3900
3901 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3902 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3903 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3904
3905 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3906 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3907 if (rc)
3908 goto err_out;
3909
3910 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3911 config |= MCI_CDR_EN;
3912 config &= ~MCI_CDR_EXT_EN;
3913 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3914 goto out;
3915
3916err_out:
3917 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3918 mmc_hostname(host->mmc), __func__, phase);
3919out:
3920 spin_unlock_irqrestore(&host->lock, flags);
3921 return rc;
3922}
3923
3924/*
3925 * Find out the greatest range of consecuitive selected
3926 * DLL clock output phases that can be used as sampling
3927 * setting for SD3.0 UHS-I card read operation (in SDR104
3928 * timing mode) or for eMMC4.5 card read operation (in HS200
3929 * timing mode).
3930 * Select the 3/4 of the range and configure the DLL with the
3931 * selected DLL clock output phase.
3932*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303933static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303934 u8 *phase_table, u8 total_phases)
3935{
Subhash Jadavani6159c622012-03-15 19:05:55 +05303936 #define MAX_PHASES 16
Subhash Jadavani34187042012-03-02 10:59:49 +05303937 int ret;
Subhash Jadavani6159c622012-03-15 19:05:55 +05303938 u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
3939 u8 phases_per_row[MAX_PHASES] = {0};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303940 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303941 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3942 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303943
Subhash Jadavani6159c622012-03-15 19:05:55 +05303944 if (!total_phases || (total_phases > MAX_PHASES)) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303945 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3946 mmc_hostname(host->mmc), __func__, total_phases);
3947 return -EINVAL;
3948 }
3949
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303950 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303951 ranges[row_index][col_index] = phase_table[cnt];
3952 phases_per_row[row_index] += 1;
3953 col_index++;
3954
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303955 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303956 continue;
3957 /* check if next phase in phase_table is consecutive or not */
3958 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3959 row_index++;
3960 col_index = 0;
3961 }
3962 }
3963
Subhash Jadavani6159c622012-03-15 19:05:55 +05303964 if (row_index >= MAX_PHASES)
3965 return -EINVAL;
3966
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303967 /* Check if phase-0 is present in first valid window? */
3968 if (!ranges[0][0]) {
3969 phase_0_found = true;
3970 phase_0_raw_index = 0;
3971 /* Check if cycle exist between 2 valid windows */
3972 for (cnt = 1; cnt <= row_index; cnt++) {
3973 if (phases_per_row[cnt]) {
Subhash Jadavani6159c622012-03-15 19:05:55 +05303974 for (i = 0; i < phases_per_row[cnt]; i++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303975 if (ranges[cnt][i] == 15) {
3976 phase_15_found = true;
3977 phase_15_raw_index = cnt;
3978 break;
3979 }
3980 }
3981 }
3982 }
3983 }
3984
3985 /* If 2 valid windows form cycle then merge them as single window */
3986 if (phase_0_found && phase_15_found) {
3987 /* number of phases in raw where phase 0 is present */
3988 u8 phases_0 = phases_per_row[phase_0_raw_index];
3989 /* number of phases in raw where phase 15 is present */
3990 u8 phases_15 = phases_per_row[phase_15_raw_index];
3991
Subhash Jadavani6159c622012-03-15 19:05:55 +05303992 if (phases_0 + phases_15 >= MAX_PHASES)
3993 /*
3994 * If there are more than 1 phase windows then total
3995 * number of phases in both the windows should not be
3996 * more than or equal to MAX_PHASES.
3997 */
3998 return -EINVAL;
3999
4000 /* Merge 2 cyclic windows */
4001 i = phases_15;
4002 for (cnt = 0; cnt < phases_0; cnt++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304003 ranges[phase_15_raw_index][i] =
4004 ranges[phase_0_raw_index][cnt];
Subhash Jadavani6159c622012-03-15 19:05:55 +05304005 if (++i >= MAX_PHASES)
4006 break;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304007 }
Subhash Jadavani6159c622012-03-15 19:05:55 +05304008
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304009 phases_per_row[phase_0_raw_index] = 0;
4010 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
4011 }
4012
4013 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304014 if (phases_per_row[cnt] > curr_max) {
4015 curr_max = phases_per_row[cnt];
4016 selected_row_index = cnt;
4017 }
4018 }
4019
Subhash Jadavani6159c622012-03-15 19:05:55 +05304020 i = ((curr_max * 3) / 4);
4021 if (i)
4022 i--;
4023
Subhash Jadavani34187042012-03-02 10:59:49 +05304024 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304025
Subhash Jadavani6159c622012-03-15 19:05:55 +05304026 if (ret >= MAX_PHASES) {
4027 ret = -EINVAL;
4028 pr_err("%s: %s: invalid phase selected=%d\n",
4029 mmc_hostname(host->mmc), __func__, ret);
4030 }
4031
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304032 return ret;
4033}
4034
Girish K Sa3f41692012-02-29 12:00:09 +05304035static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304036{
4037 int rc = 0;
4038 struct msmsdcc_host *host = mmc_priv(mmc);
4039 unsigned long flags;
4040 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304041 const u32 *tuning_block_pattern = tuning_block_64;
4042 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304043
4044 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
4045
4046 /* Tuning is only required for SDR104 modes */
4047 if (!host->tuning_needed) {
4048 rc = 0;
4049 goto exit;
4050 }
4051
4052 spin_lock_irqsave(&host->lock, flags);
4053 WARN(!host->pwr, "SDCC power is turned off\n");
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304054 WARN(!atomic_read(&host->clks_on), "SDCC clocks are turned off\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304055 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
4056
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304057 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304058 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
4059 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
4060 tuning_block_pattern = tuning_block_128;
4061 size = sizeof(tuning_block_128);
4062 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304063 spin_unlock_irqrestore(&host->lock, flags);
4064
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004065 /* first of all reset the tuning block */
4066 rc = msmsdcc_init_cm_sdc4_dll(host);
4067 if (rc)
4068 goto out;
4069
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304070 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004071 if (!data_buf) {
4072 rc = -ENOMEM;
4073 goto out;
4074 }
4075
4076 phase = 0;
4077 do {
4078 struct mmc_command cmd = {0};
4079 struct mmc_data data = {0};
4080 struct mmc_request mrq = {
4081 .cmd = &cmd,
4082 .data = &data
4083 };
4084 struct scatterlist sg;
4085
4086 /* set the phase in delay line hw block */
4087 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
4088 if (rc)
4089 goto kfree;
4090
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304091 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004092 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
4093
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304094 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004095 data.blocks = 1;
4096 data.flags = MMC_DATA_READ;
4097 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
4098
4099 data.sg = &sg;
4100 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304101 sg_init_one(&sg, data_buf, size);
4102 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004103 mmc_wait_for_req(mmc, &mrq);
4104
4105 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304106 !memcmp(data_buf, tuning_block_pattern, size)) {
4107 /* tuning is successful at this tuning point */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004108 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304109 pr_debug("%s: %s: found good phase = %d\n",
4110 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004111 }
4112 } while (++phase < 16);
4113
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004114 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05304115 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304116 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05304117 if (rc < 0)
4118 goto kfree;
4119 else
4120 phase = (u8)rc;
4121
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004122 /*
4123 * Finally set the selected phase in delay
4124 * line hw block.
4125 */
4126 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
4127 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304128 goto kfree;
4129 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
4130 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004131 } else {
4132 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304133 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004134 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304135 msmsdcc_dump_sdcc_state(host);
4136 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004137 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004138
4139kfree:
4140 kfree(data_buf);
4141out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304142 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304143 host->tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304144 spin_unlock_irqrestore(&host->lock, flags);
4145exit:
4146 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004147 return rc;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04004148}
4149
Asutosh Dasebd7d092012-07-09 19:08:26 +05304150/*
4151 * Work around of the unavailability of a power_reset functionality in SD cards
4152 * by turning the OFF & back ON the regulators supplying the SD card.
4153 */
4154void msmsdcc_hw_reset(struct mmc_host *mmc)
4155{
4156 struct mmc_card *card = mmc->card;
4157 struct msmsdcc_host *host = mmc_priv(mmc);
4158 int rc;
4159
4160 /* Write-protection bits would be lost on a hardware reset in emmc */
4161 if (!card || !mmc_card_sd(card))
4162 return;
4163
4164 /*
4165 * Continuing on failing to disable regulator would lead to a panic
4166 * anyway, since the commands would fail and console would be flooded
4167 * with prints, eventually leading to a watchdog bark
4168 */
4169 rc = msmsdcc_setup_vreg(host, false, false);
4170 if (rc) {
4171 pr_err("%s: %s disable regulator: failed: %d\n",
4172 mmc_hostname(mmc), __func__, rc);
4173 BUG_ON(rc);
4174 }
4175
4176 /* 10ms delay for the supply to reach the desired voltage level */
4177 usleep_range(10000, 12000);
4178
4179 /*
4180 * Continuing on failing to enable regulator would lead to a panic
4181 * anyway, since the commands would fail and console would be flooded
4182 * with prints, eventually leading to a watchdog bark
4183 */
4184 rc = msmsdcc_setup_vreg(host, true, false);
4185 if (rc) {
4186 pr_err("%s: %s enable regulator: failed: %d\n",
4187 mmc_hostname(mmc), __func__, rc);
4188 BUG_ON(rc);
4189 }
4190
4191 /* 10ms delay for the supply to reach the desired voltage level */
4192 usleep_range(10000, 12000);
4193}
4194
San Mehat9d2bd732009-09-22 16:44:22 -07004195static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004196 .enable = msmsdcc_enable,
4197 .disable = msmsdcc_disable,
Asutosh Dasaccacd42012-03-08 14:33:17 +05304198 .pre_req = msmsdcc_pre_req,
4199 .post_req = msmsdcc_post_req,
San Mehat9d2bd732009-09-22 16:44:22 -07004200 .request = msmsdcc_request,
4201 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004202 .get_ro = msmsdcc_get_ro,
San Mehat9d2bd732009-09-22 16:44:22 -07004203 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Subhash Jadavani937c7502012-06-01 15:34:46 +05304204 .start_signal_voltage_switch = msmsdcc_switch_io_voltage,
Asutosh Dasebd7d092012-07-09 19:08:26 +05304205 .execute_tuning = msmsdcc_execute_tuning,
4206 .hw_reset = msmsdcc_hw_reset,
San Mehat9d2bd732009-09-22 16:44:22 -07004207};
4208
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004209static unsigned int
4210msmsdcc_slot_status(struct msmsdcc_host *host)
4211{
4212 int status;
4213 unsigned int gpio_no = host->plat->status_gpio;
4214
4215 status = gpio_request(gpio_no, "SD_HW_Detect");
4216 if (status) {
4217 pr_err("%s: %s: Failed to request GPIO %d\n",
4218 mmc_hostname(host->mmc), __func__, gpio_no);
4219 } else {
4220 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08004221 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08004222 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08004223 if (host->plat->is_status_gpio_active_low)
4224 status = !status;
4225 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004226 gpio_free(gpio_no);
4227 }
4228 return status;
4229}
4230
San Mehat9d2bd732009-09-22 16:44:22 -07004231static void
4232msmsdcc_check_status(unsigned long data)
4233{
4234 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4235 unsigned int status;
4236
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05304237 if (host->plat->status || gpio_is_valid(host->plat->status_gpio)) {
Krishna Konda941604a2012-01-10 17:46:34 -08004238 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004239 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004240 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004241 status = msmsdcc_slot_status(host);
4242
Krishna Konda941604a2012-01-10 17:46:34 -08004243 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08004244
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004245 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08004246 if (host->plat->status)
4247 pr_info("%s: Slot status change detected "
4248 "(%d -> %d)\n",
4249 mmc_hostname(host->mmc),
4250 host->oldstat, status);
4251 else if (host->plat->is_status_gpio_active_low)
4252 pr_info("%s: Slot status change detected "
4253 "(%d -> %d) and the card detect GPIO"
4254 " is ACTIVE_LOW\n",
4255 mmc_hostname(host->mmc),
4256 host->oldstat, status);
4257 else
4258 pr_info("%s: Slot status change detected "
4259 "(%d -> %d) and the card detect GPIO"
4260 " is ACTIVE_HIGH\n",
4261 mmc_hostname(host->mmc),
4262 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07004263 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004264 }
4265 host->oldstat = status;
4266 } else {
4267 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07004268 }
San Mehat9d2bd732009-09-22 16:44:22 -07004269}
4270
4271static irqreturn_t
4272msmsdcc_platform_status_irq(int irq, void *dev_id)
4273{
4274 struct msmsdcc_host *host = dev_id;
4275
Girish K Sa3c76eb2011-10-11 11:44:09 +05304276 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07004277 msmsdcc_check_status((unsigned long) host);
4278 return IRQ_HANDLED;
4279}
4280
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004281static irqreturn_t
4282msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
4283{
4284 struct msmsdcc_host *host = dev_id;
4285
4286 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
4287 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304288 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004289 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304290 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004291 wake_lock(&host->sdio_wlock);
4292 msmsdcc_disable_irq_wake(host);
4293 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304294 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004295 }
4296 if (host->plat->is_sdio_al_client) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004297 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304298 spin_unlock(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304299 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304300 goto out_unlocked;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004301 }
4302 spin_unlock(&host->lock);
4303
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304304out_unlocked:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004305 return IRQ_HANDLED;
4306}
4307
San Mehat9d2bd732009-09-22 16:44:22 -07004308static void
4309msmsdcc_status_notify_cb(int card_present, void *dev_id)
4310{
4311 struct msmsdcc_host *host = dev_id;
4312
Girish K Sa3c76eb2011-10-11 11:44:09 +05304313 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07004314 card_present);
4315 msmsdcc_check_status((unsigned long) host);
4316}
4317
San Mehat9d2bd732009-09-22 16:44:22 -07004318static int
4319msmsdcc_init_dma(struct msmsdcc_host *host)
4320{
4321 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
4322 host->dma.host = host;
4323 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004324 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004325
4326 if (!host->dmares)
4327 return -ENODEV;
4328
4329 host->dma.nc = dma_alloc_coherent(NULL,
4330 sizeof(struct msmsdcc_nc_dmadata),
4331 &host->dma.nc_busaddr,
4332 GFP_KERNEL);
4333 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004334 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07004335 return -ENOMEM;
4336 }
4337 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
4338 host->dma.cmd_busaddr = host->dma.nc_busaddr;
4339 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
4340 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
4341 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07004342 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07004343
4344 return 0;
4345}
4346
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004347#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
4348/**
4349 * Allocate and Connect a SDCC peripheral's SPS endpoint
4350 *
4351 * This function allocates endpoint context and
4352 * connect it with memory endpoint by calling
4353 * appropriate SPS driver APIs.
4354 *
4355 * Also registers a SPS callback function with
4356 * SPS driver
4357 *
4358 * This function should only be called once typically
4359 * during driver probe.
4360 *
4361 * @host - Pointer to sdcc host structure
4362 * @ep - Pointer to sps endpoint data structure
4363 * @is_produce - 1 means Producer endpoint
4364 * 0 means Consumer endpoint
4365 *
4366 * @return - 0 if successful else negative value.
4367 *
4368 */
4369static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
4370 struct msmsdcc_sps_ep_conn_data *ep,
4371 bool is_producer)
4372{
4373 int rc = 0;
4374 struct sps_pipe *sps_pipe_handle;
4375 struct sps_connect *sps_config = &ep->config;
4376 struct sps_register_event *sps_event = &ep->event;
4377
4378 /* Allocate endpoint context */
4379 sps_pipe_handle = sps_alloc_endpoint();
4380 if (!sps_pipe_handle) {
4381 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
4382 mmc_hostname(host->mmc), is_producer);
4383 rc = -ENOMEM;
4384 goto out;
4385 }
4386
4387 /* Get default connection configuration for an endpoint */
4388 rc = sps_get_config(sps_pipe_handle, sps_config);
4389 if (rc) {
4390 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
4391 " rc=%d", mmc_hostname(host->mmc),
4392 (u32)sps_pipe_handle, rc);
4393 goto get_config_err;
4394 }
4395
4396 /* Modify the default connection configuration */
4397 if (is_producer) {
4398 /*
4399 * For SDCC producer transfer, source should be
4400 * SDCC peripheral where as destination should
4401 * be system memory.
4402 */
4403 sps_config->source = host->sps.bam_handle;
4404 sps_config->destination = SPS_DEV_HANDLE_MEM;
4405 /* Producer pipe will handle this connection */
4406 sps_config->mode = SPS_MODE_SRC;
4407 sps_config->options =
4408 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4409 } else {
4410 /*
4411 * For SDCC consumer transfer, source should be
4412 * system memory where as destination should
4413 * SDCC peripheral
4414 */
4415 sps_config->source = SPS_DEV_HANDLE_MEM;
4416 sps_config->destination = host->sps.bam_handle;
4417 sps_config->mode = SPS_MODE_DEST;
4418 sps_config->options =
4419 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4420 }
4421
4422 /* Producer pipe index */
4423 sps_config->src_pipe_index = host->sps.src_pipe_index;
4424 /* Consumer pipe index */
4425 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
4426 /*
4427 * This event thresold value is only significant for BAM-to-BAM
4428 * transfer. It's ignored for BAM-to-System mode transfer.
4429 */
4430 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304431
4432 /* Allocate maximum descriptor fifo size */
4433 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
4434 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004435 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
4436 sps_config->desc.size,
4437 &sps_config->desc.phys_base,
4438 GFP_KERNEL);
4439
Pratibhasagar V00b94332011-10-18 14:57:27 +05304440 if (!sps_config->desc.base) {
4441 rc = -ENOMEM;
4442 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
4443 , mmc_hostname(host->mmc));
4444 goto get_config_err;
4445 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004446 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
4447
4448 /* Establish connection between peripheral and memory endpoint */
4449 rc = sps_connect(sps_pipe_handle, sps_config);
4450 if (rc) {
4451 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4452 " rc=%d", mmc_hostname(host->mmc),
4453 (u32)sps_pipe_handle, rc);
4454 goto sps_connect_err;
4455 }
4456
4457 sps_event->mode = SPS_TRIGGER_CALLBACK;
4458 sps_event->options = SPS_O_EOT;
4459 sps_event->callback = msmsdcc_sps_complete_cb;
4460 sps_event->xfer_done = NULL;
4461 sps_event->user = (void *)host;
4462
4463 /* Register callback event for EOT (End of transfer) event. */
4464 rc = sps_register_event(sps_pipe_handle, sps_event);
4465 if (rc) {
4466 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4467 " rc=%d", mmc_hostname(host->mmc),
4468 (u32)sps_pipe_handle, rc);
4469 goto reg_event_err;
4470 }
4471 /* Now save the sps pipe handle */
4472 ep->pipe_handle = sps_pipe_handle;
4473 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
4474 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
4475 __func__, is_producer ? "READ" : "WRITE",
4476 (u32)sps_pipe_handle, sps_config->desc.phys_base);
4477 goto out;
4478
4479reg_event_err:
4480 sps_disconnect(sps_pipe_handle);
4481sps_connect_err:
4482 dma_free_coherent(mmc_dev(host->mmc),
4483 sps_config->desc.size,
4484 sps_config->desc.base,
4485 sps_config->desc.phys_base);
4486get_config_err:
4487 sps_free_endpoint(sps_pipe_handle);
4488out:
4489 return rc;
4490}
4491
4492/**
4493 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
4494 *
4495 * This function disconnect endpoint and deallocates
4496 * endpoint context.
4497 *
4498 * This function should only be called once typically
4499 * during driver remove.
4500 *
4501 * @host - Pointer to sdcc host structure
4502 * @ep - Pointer to sps endpoint data structure
4503 *
4504 */
4505static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
4506 struct msmsdcc_sps_ep_conn_data *ep)
4507{
4508 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4509 struct sps_connect *sps_config = &ep->config;
4510 struct sps_register_event *sps_event = &ep->event;
4511
4512 sps_event->xfer_done = NULL;
4513 sps_event->callback = NULL;
4514 sps_register_event(sps_pipe_handle, sps_event);
4515 sps_disconnect(sps_pipe_handle);
4516 dma_free_coherent(mmc_dev(host->mmc),
4517 sps_config->desc.size,
4518 sps_config->desc.base,
4519 sps_config->desc.phys_base);
4520 sps_free_endpoint(sps_pipe_handle);
4521}
4522
4523/**
4524 * Reset SDCC peripheral's SPS endpoint
4525 *
4526 * This function disconnects an endpoint.
4527 *
4528 * This function should be called for reseting
4529 * SPS endpoint when data transfer error is
4530 * encountered during data transfer. This
4531 * can be considered as soft reset to endpoint.
4532 *
4533 * This function should only be called if
4534 * msmsdcc_sps_init() is already called.
4535 *
4536 * @host - Pointer to sdcc host structure
4537 * @ep - Pointer to sps endpoint data structure
4538 *
4539 * @return - 0 if successful else negative value.
4540 */
4541static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
4542 struct msmsdcc_sps_ep_conn_data *ep)
4543{
4544 int rc = 0;
4545 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4546
4547 rc = sps_disconnect(sps_pipe_handle);
4548 if (rc) {
4549 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
4550 " rc=%d", mmc_hostname(host->mmc), __func__,
4551 (u32)sps_pipe_handle, rc);
4552 goto out;
4553 }
4554 out:
4555 return rc;
4556}
4557
4558/**
4559 * Restore SDCC peripheral's SPS endpoint
4560 *
4561 * This function connects an endpoint.
4562 *
4563 * This function should be called for restoring
4564 * SPS endpoint after data transfer error is
4565 * encountered during data transfer. This
4566 * can be considered as soft reset to endpoint.
4567 *
4568 * This function should only be called if
4569 * msmsdcc_sps_reset_ep() is called before.
4570 *
4571 * @host - Pointer to sdcc host structure
4572 * @ep - Pointer to sps endpoint data structure
4573 *
4574 * @return - 0 if successful else negative value.
4575 */
4576static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
4577 struct msmsdcc_sps_ep_conn_data *ep)
4578{
4579 int rc = 0;
4580 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4581 struct sps_connect *sps_config = &ep->config;
4582 struct sps_register_event *sps_event = &ep->event;
4583
4584 /* Establish connection between peripheral and memory endpoint */
4585 rc = sps_connect(sps_pipe_handle, sps_config);
4586 if (rc) {
4587 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
4588 " rc=%d", mmc_hostname(host->mmc), __func__,
4589 (u32)sps_pipe_handle, rc);
4590 goto out;
4591 }
4592
4593 /* Register callback event for EOT (End of transfer) event. */
4594 rc = sps_register_event(sps_pipe_handle, sps_event);
4595 if (rc) {
4596 pr_err("%s: %s: sps_register_event() failed!!!"
4597 " pipe_handle=0x%x, rc=%d",
4598 mmc_hostname(host->mmc), __func__,
4599 (u32)sps_pipe_handle, rc);
4600 goto reg_event_err;
4601 }
4602 goto out;
4603
4604reg_event_err:
4605 sps_disconnect(sps_pipe_handle);
4606out:
4607 return rc;
4608}
4609
4610/**
Krishna Konda5af8f972012-05-14 16:15:24 -07004611 * Handle BAM device's global error condition
4612 *
4613 * This is an error handler for the SDCC bam device
4614 *
4615 * This function is registered as a callback with SPS-BAM
4616 * driver and will called in case there are an errors for
4617 * the SDCC BAM deivce. Any error conditions in the BAM
4618 * device are global and will be result in this function
4619 * being called once per device.
4620 *
4621 * This function will be called from the sps driver's
4622 * interrupt context.
4623 *
4624 * @sps_cb_case - indicates what error it is
4625 * @user - Pointer to sdcc host structure
4626 */
4627static void
4628msmsdcc_sps_bam_global_irq_cb(enum sps_callback_case sps_cb_case, void *user)
4629{
4630 struct msmsdcc_host *host = (struct msmsdcc_host *)user;
4631 struct mmc_request *mrq;
4632 unsigned long flags;
4633 int32_t error = 0;
4634
4635 BUG_ON(!host);
4636 BUG_ON(!is_sps_mode(host));
4637
4638 if (sps_cb_case == SPS_CALLBACK_BAM_ERROR_IRQ) {
Maya Erezb7a086f2012-11-29 00:37:36 +02004639 /* Reset all endpoints along with resetting bam. */
4640 host->sps.reset_bam = true;
Krishna Konda5af8f972012-05-14 16:15:24 -07004641
4642 pr_err("%s: BAM Global ERROR IRQ happened\n",
4643 mmc_hostname(host->mmc));
4644 error = EAGAIN;
4645 } else if (sps_cb_case == SPS_CALLBACK_BAM_HRESP_ERR_IRQ) {
4646 /**
4647 * This means that there was an AHB access error and
4648 * the address we are trying to read/write is something
4649 * we dont have priviliges to do so.
4650 */
4651 pr_err("%s: BAM HRESP_ERR_IRQ happened\n",
4652 mmc_hostname(host->mmc));
4653 error = EACCES;
4654 } else {
4655 /**
4656 * This should not have happened ideally. If this happens
4657 * there is some seriously wrong.
4658 */
4659 pr_err("%s: BAM global IRQ callback received, type:%d\n",
4660 mmc_hostname(host->mmc), (u32) sps_cb_case);
4661 error = EIO;
4662 }
4663
4664 spin_lock_irqsave(&host->lock, flags);
4665
4666 mrq = host->curr.mrq;
4667
4668 if (mrq && mrq->cmd) {
4669 msmsdcc_dump_sdcc_state(host);
4670
4671 if (!mrq->cmd->error)
4672 mrq->cmd->error = -error;
4673 if (host->curr.data) {
4674 if (mrq->data && !mrq->data->error)
4675 mrq->data->error = -error;
4676 host->curr.data_xfered = 0;
4677 if (host->sps.sg && is_sps_mode(host)) {
4678 /* Stop current SPS transfer */
4679 msmsdcc_sps_exit_curr_xfer(host);
4680 } else {
4681 /* this condition should not have happened */
4682 pr_err("%s: something is seriously wrong. "\
4683 "Funtion: %s, line: %d\n",
4684 mmc_hostname(host->mmc),
4685 __func__, __LINE__);
4686 }
4687 } else {
4688 /* this condition should not have happened */
4689 pr_err("%s: something is seriously wrong. Funtion: "\
4690 "%s, line: %d\n", mmc_hostname(host->mmc),
4691 __func__, __LINE__);
4692 }
4693 }
4694 spin_unlock_irqrestore(&host->lock, flags);
4695}
4696
4697/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004698 * Initialize SPS HW connected with SDCC core
4699 *
4700 * This function register BAM HW resources with
4701 * SPS driver and then initialize 2 SPS endpoints
4702 *
4703 * This function should only be called once typically
4704 * during driver probe.
4705 *
4706 * @host - Pointer to sdcc host structure
4707 *
4708 * @return - 0 if successful else negative value.
4709 *
4710 */
4711static int msmsdcc_sps_init(struct msmsdcc_host *host)
4712{
4713 int rc = 0;
4714 struct sps_bam_props bam = {0};
4715
4716 host->bam_base = ioremap(host->bam_memres->start,
4717 resource_size(host->bam_memres));
4718 if (!host->bam_base) {
4719 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
4720 " size=0x%x", mmc_hostname(host->mmc),
4721 host->bam_memres->start,
4722 (host->bam_memres->end -
4723 host->bam_memres->start));
4724 rc = -ENOMEM;
4725 goto out;
4726 }
4727
4728 bam.phys_addr = host->bam_memres->start;
4729 bam.virt_addr = host->bam_base;
4730 /*
4731 * This event thresold value is only significant for BAM-to-BAM
4732 * transfer. It's ignored for BAM-to-System mode transfer.
4733 */
4734 bam.event_threshold = 0x10; /* Pipe event threshold */
4735 /*
4736 * This threshold controls when the BAM publish
4737 * the descriptor size on the sideband interface.
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304738 * SPS HW will be used for data transfer size even
4739 * less than SDCC FIFO size. So let's set BAM summing
4740 * thresold to SPS_MIN_XFER_SIZE bytes.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004741 */
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304742 bam.summing_threshold = SPS_MIN_XFER_SIZE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004743 /* SPS driver wll handle the SDCC BAM IRQ */
4744 bam.irq = (u32)host->bam_irqres->start;
4745 bam.manage = SPS_BAM_MGR_LOCAL;
Krishna Konda5af8f972012-05-14 16:15:24 -07004746 bam.callback = msmsdcc_sps_bam_global_irq_cb;
4747 bam.user = (void *)host;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004748
4749 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
4750 (u32)bam.phys_addr);
4751 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
4752 (u32)bam.virt_addr);
4753
4754 /* Register SDCC Peripheral BAM device to SPS driver */
4755 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
4756 if (rc) {
4757 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
4758 mmc_hostname(host->mmc), rc);
4759 goto reg_bam_err;
4760 }
4761 pr_info("%s: BAM device registered. bam_handle=0x%x",
4762 mmc_hostname(host->mmc), host->sps.bam_handle);
4763
4764 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
4765 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
4766
4767 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
4768 SPS_PROD_PERIPHERAL);
4769 if (rc)
4770 goto sps_reset_err;
4771 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
4772 SPS_CONS_PERIPHERAL);
4773 if (rc)
4774 goto cons_conn_err;
4775
4776 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
4777 mmc_hostname(host->mmc),
4778 (unsigned long long)host->bam_memres->start,
4779 (unsigned int)host->bam_irqres->start);
4780 goto out;
4781
4782cons_conn_err:
4783 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4784sps_reset_err:
4785 sps_deregister_bam_device(host->sps.bam_handle);
4786reg_bam_err:
4787 iounmap(host->bam_base);
4788out:
4789 return rc;
4790}
4791
4792/**
4793 * De-initialize SPS HW connected with SDCC core
4794 *
4795 * This function deinitialize SPS endpoints and then
4796 * deregisters BAM resources from SPS driver.
4797 *
4798 * This function should only be called once typically
4799 * during driver remove.
4800 *
4801 * @host - Pointer to sdcc host structure
4802 *
4803 */
4804static void msmsdcc_sps_exit(struct msmsdcc_host *host)
4805{
4806 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
4807 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4808 sps_deregister_bam_device(host->sps.bam_handle);
4809 iounmap(host->bam_base);
4810}
4811#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
4812
4813static ssize_t
4814show_polling(struct device *dev, struct device_attribute *attr, char *buf)
4815{
4816 struct mmc_host *mmc = dev_get_drvdata(dev);
4817 struct msmsdcc_host *host = mmc_priv(mmc);
4818 int poll;
4819 unsigned long flags;
4820
4821 spin_lock_irqsave(&host->lock, flags);
4822 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
4823 spin_unlock_irqrestore(&host->lock, flags);
4824
4825 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
4826}
4827
4828static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05304829store_polling(struct device *dev, struct device_attribute *attr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004830 const char *buf, size_t count)
4831{
4832 struct mmc_host *mmc = dev_get_drvdata(dev);
4833 struct msmsdcc_host *host = mmc_priv(mmc);
4834 int value;
4835 unsigned long flags;
4836
4837 sscanf(buf, "%d", &value);
4838
4839 spin_lock_irqsave(&host->lock, flags);
4840 if (value) {
4841 mmc->caps |= MMC_CAP_NEEDS_POLL;
4842 mmc_detect_change(host->mmc, 0);
4843 } else {
4844 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4845 }
4846#ifdef CONFIG_HAS_EARLYSUSPEND
4847 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
4848#endif
4849 spin_unlock_irqrestore(&host->lock, flags);
4850 return count;
4851}
4852
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304853static ssize_t
4854show_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
4855 char *buf)
4856{
4857 struct mmc_host *mmc = dev_get_drvdata(dev);
4858 struct msmsdcc_host *host = mmc_priv(mmc);
4859
4860 return snprintf(buf, PAGE_SIZE, "%u\n",
4861 host->msm_bus_vote.is_max_bw_needed);
4862}
4863
4864static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05304865store_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304866 const char *buf, size_t count)
4867{
4868 struct mmc_host *mmc = dev_get_drvdata(dev);
4869 struct msmsdcc_host *host = mmc_priv(mmc);
4870 uint32_t value;
4871 unsigned long flags;
4872
4873 if (!kstrtou32(buf, 0, &value)) {
4874 spin_lock_irqsave(&host->lock, flags);
4875 host->msm_bus_vote.is_max_bw_needed = !!value;
4876 spin_unlock_irqrestore(&host->lock, flags);
4877 }
4878
4879 return count;
4880}
4881
Pratibhasagar V13d1d032012-07-09 20:12:38 +05304882static ssize_t
4883show_idle_timeout(struct device *dev, struct device_attribute *attr,
4884 char *buf)
4885{
4886 struct mmc_host *mmc = dev_get_drvdata(dev);
4887 struct msmsdcc_host *host = mmc_priv(mmc);
4888
4889 return snprintf(buf, PAGE_SIZE, "%u (Min 5 sec)\n",
4890 host->idle_tout_ms / 1000);
4891}
4892
4893static ssize_t
4894store_idle_timeout(struct device *dev, struct device_attribute *attr,
4895 const char *buf, size_t count)
4896{
4897 struct mmc_host *mmc = dev_get_drvdata(dev);
4898 struct msmsdcc_host *host = mmc_priv(mmc);
4899 unsigned int long flags;
4900 int timeout; /* in secs */
4901
4902 if (!kstrtou32(buf, 0, &timeout)
4903 && (timeout > MSM_MMC_DEFAULT_IDLE_TIMEOUT / 1000)) {
4904 spin_lock_irqsave(&host->lock, flags);
4905 host->idle_tout_ms = timeout * 1000;
4906 spin_unlock_irqrestore(&host->lock, flags);
4907 }
4908 return count;
4909}
4910
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004911#ifdef CONFIG_HAS_EARLYSUSPEND
4912static void msmsdcc_early_suspend(struct early_suspend *h)
4913{
4914 struct msmsdcc_host *host =
4915 container_of(h, struct msmsdcc_host, early_suspend);
4916 unsigned long flags;
4917
4918 spin_lock_irqsave(&host->lock, flags);
4919 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
4920 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4921 spin_unlock_irqrestore(&host->lock, flags);
4922};
4923static void msmsdcc_late_resume(struct early_suspend *h)
4924{
4925 struct msmsdcc_host *host =
4926 container_of(h, struct msmsdcc_host, early_suspend);
4927 unsigned long flags;
4928
4929 if (host->polling_enabled) {
4930 spin_lock_irqsave(&host->lock, flags);
4931 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
4932 mmc_detect_change(host->mmc, 0);
4933 spin_unlock_irqrestore(&host->lock, flags);
4934 }
4935};
4936#endif
4937
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304938static void msmsdcc_print_regs(const char *name, void __iomem *base,
4939 u32 phys_base, unsigned int no_of_regs)
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304940{
4941 unsigned int i;
4942
4943 if (!base)
4944 return;
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304945
4946 pr_info("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
4947 " =====\n", name, phys_base, (u32)base);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304948 for (i = 0; i < no_of_regs; i = i + 4) {
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304949 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
4950 (u32)readl_relaxed(base + i*4),
4951 (u32)readl_relaxed(base + ((i+1)*4)),
4952 (u32)readl_relaxed(base + ((i+2)*4)),
4953 (u32)readl_relaxed(base + ((i+3)*4)));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304954 }
4955}
4956
4957static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
4958{
4959 /* Dump current state of SDCC clocks, power and irq */
4960 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304961 (host->pwr ? "ON" : "OFF"));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304962 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304963 mmc_hostname(host->mmc),
4964 (atomic_read(&host->clks_on) ? "ON" : "OFF"),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304965 (u32)clk_get_rate(host->clk));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304966 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
4967 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
4968
4969 /* Now dump SDCC registers. Don't print FIFO registers */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304970 if (atomic_read(&host->clks_on))
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304971 msmsdcc_print_regs("SDCC-CORE", host->base,
4972 host->core_memres->start, 28);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304973
4974 if (host->curr.data) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304975 if (!msmsdcc_is_dma_possible(host, host->curr.data))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304976 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304977 else if (is_dma_mode(host))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304978 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
4979 mmc_hostname(host->mmc), host->dma.busy,
4980 host->dma.channel, host->dma.crci);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304981 else if (is_sps_mode(host)) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304982 if (host->sps.busy && atomic_read(&host->clks_on))
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304983 msmsdcc_print_regs("SDCC-DML", host->dml_base,
4984 host->dml_memres->start,
4985 16);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304986 pr_info("%s: SPS mode: busy=%d\n",
4987 mmc_hostname(host->mmc), host->sps.busy);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304988 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304989
4990 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
4991 mmc_hostname(host->mmc), host->curr.xfer_size,
4992 host->curr.data_xfered, host->curr.xfer_remain);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304993 }
4994
Maya Erezb7a086f2012-11-29 00:37:36 +02004995 if (host->sps.reset_bam)
4996 pr_err("%s: SPS BAM reset failed: sps reset_bam=%d\n",
4997 mmc_hostname(host->mmc), host->sps.reset_bam);
4998
4999 pr_err("%s: got_dataend=%d, prog_enable=%d,"
Subhash Jadavani8706ced2012-05-25 16:09:21 +05305000 " wait_for_auto_prog_done=%d, got_auto_prog_done=%d,"
5001 " req_tout_ms=%d\n", mmc_hostname(host->mmc),
5002 host->curr.got_dataend, host->prog_enable,
5003 host->curr.wait_for_auto_prog_done,
5004 host->curr.got_auto_prog_done, host->curr.req_tout_ms);
subhashj245831e2012-04-30 18:46:17 +05305005 msmsdcc_print_rpm_info(host);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305006}
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305007
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005008static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
5009{
5010 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
5011 struct mmc_request *mrq;
5012 unsigned long flags;
5013
5014 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07005015 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005016 pr_info("%s: %s: dummy CMD52 timeout\n",
5017 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07005018 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005019 }
5020
5021 mrq = host->curr.mrq;
5022
5023 if (mrq && mrq->cmd) {
Subhash Jadavanif92ff4c2012-12-15 22:05:54 +05305024 if (!mrq->cmd->bkops_busy) {
5025 pr_info("%s: CMD%d: Request timeout\n",
5026 mmc_hostname(host->mmc), mrq->cmd->opcode);
5027 msmsdcc_dump_sdcc_state(host);
5028 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305029
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005030 if (!mrq->cmd->error)
5031 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305032 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005033 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005034 if (mrq->data && !mrq->data->error)
5035 mrq->data->error = -ETIMEDOUT;
5036 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305037 if (host->dma.sg && is_dma_mode(host)) {
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07005038 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305039 } else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005040 /* Stop current SPS transfer */
5041 msmsdcc_sps_exit_curr_xfer(host);
5042 } else {
5043 msmsdcc_reset_and_restore(host);
5044 msmsdcc_stop_data(host);
5045 if (mrq->data && mrq->data->stop)
5046 msmsdcc_start_command(host,
5047 mrq->data->stop, 0);
5048 else
5049 msmsdcc_request_end(host, mrq);
5050 }
5051 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05305052 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05305053 host->curr.wait_for_auto_prog_done = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005054 msmsdcc_reset_and_restore(host);
5055 msmsdcc_request_end(host, mrq);
5056 }
5057 }
5058 spin_unlock_irqrestore(&host->lock, flags);
5059}
5060
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305061/*
5062 * msmsdcc_dt_get_array - Wrapper fn to read an array of 32 bit integers
5063 *
5064 * @dev: device node from which the property value is to be read.
5065 * @prop_name: name of the property to be searched.
5066 * @out_array: filled array returned to caller
5067 * @len: filled array size returned to caller
5068 * @size: expected size of the array
5069 *
5070 * If expected "size" doesn't match with "len" an error is returned. If
5071 * expected size is zero, the length of actual array is returned provided
5072 * return value is zero.
5073 *
5074 * RETURNS:
5075 * zero on success, negative error if failed.
5076 */
5077static int msmsdcc_dt_get_array(struct device *dev, const char *prop_name,
5078 u32 **out_array, int *len, int size)
5079{
5080 int ret = 0;
5081 u32 *array = NULL;
5082 struct device_node *np = dev->of_node;
5083
5084 if (of_get_property(np, prop_name, len)) {
5085 size_t sz;
5086 sz = *len = *len / sizeof(*array);
5087
5088 if (sz > 0 && !(size > 0 && (sz != size))) {
5089 array = devm_kzalloc(dev, sz * sizeof(*array),
5090 GFP_KERNEL);
5091 if (!array) {
5092 dev_err(dev, "%s: no memory\n", prop_name);
5093 ret = -ENOMEM;
5094 goto out;
5095 }
5096
5097 ret = of_property_read_u32_array(np, prop_name,
5098 array, sz);
5099 if (ret < 0) {
5100 dev_err(dev, "%s: error reading array %d\n",
5101 prop_name, ret);
5102 goto out;
5103 }
5104 } else {
5105 dev_err(dev, "%s invalid size\n", prop_name);
5106 ret = -EINVAL;
5107 goto out;
5108 }
5109 } else {
5110 dev_err(dev, "%s not specified\n", prop_name);
5111 ret = -EINVAL;
5112 goto out;
5113 }
5114 *out_array = array;
5115out:
5116 if (ret)
5117 *len = 0;
5118 return ret;
5119}
5120
5121static int msmsdcc_dt_get_pad_pull_info(struct device *dev, int id,
5122 struct msm_mmc_pad_pull_data **pad_pull_data)
5123{
5124 int ret = 0, base = 0, len, i;
5125 u32 *tmp;
5126 struct msm_mmc_pad_pull_data *pull_data;
5127 struct msm_mmc_pad_pull *pull;
5128
5129 switch (id) {
5130 case 1:
5131 base = TLMM_PULL_SDC1_CLK;
5132 break;
5133 case 2:
5134 base = TLMM_PULL_SDC2_CLK;
5135 break;
5136 case 3:
5137 base = TLMM_PULL_SDC3_CLK;
5138 break;
5139 case 4:
5140 base = TLMM_PULL_SDC4_CLK;
5141 break;
5142 default:
5143 dev_err(dev, "%s: Invalid slot id\n", __func__);
5144 ret = -EINVAL;
5145 goto err;
5146 }
5147
5148 pull_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_pull_data),
5149 GFP_KERNEL);
5150 if (!pull_data) {
5151 dev_err(dev, "No memory msm_mmc_pad_pull_data\n");
5152 ret = -ENOMEM;
5153 goto err;
5154 }
5155 pull_data->size = 3; /* array size for clk, cmd, data */
5156
5157 /* Allocate on, off configs for clk, cmd, data */
5158 pull = devm_kzalloc(dev, 2 * pull_data->size *\
5159 sizeof(struct msm_mmc_pad_pull), GFP_KERNEL);
5160 if (!pull) {
5161 dev_err(dev, "No memory for msm_mmc_pad_pull\n");
5162 ret = -ENOMEM;
5163 goto err;
5164 }
5165 pull_data->on = pull;
5166 pull_data->off = pull + pull_data->size;
5167
5168 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-pull-on",
5169 &tmp, &len, pull_data->size);
5170 if (!ret) {
5171 for (i = 0; i < len; i++) {
5172 pull_data->on[i].no = base + i;
5173 pull_data->on[i].val = tmp[i];
5174 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5175 i, pull_data->on[i].val);
5176 }
5177 } else {
5178 goto err;
5179 }
5180
5181 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-pull-off",
5182 &tmp, &len, pull_data->size);
5183 if (!ret) {
5184 for (i = 0; i < len; i++) {
5185 pull_data->off[i].no = base + i;
5186 pull_data->off[i].val = tmp[i];
5187 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5188 i, pull_data->off[i].val);
5189 }
5190 } else {
5191 goto err;
5192 }
5193
5194 *pad_pull_data = pull_data;
5195err:
5196 return ret;
5197}
5198
5199static int msmsdcc_dt_get_pad_drv_info(struct device *dev, int id,
5200 struct msm_mmc_pad_drv_data **pad_drv_data)
5201{
5202 int ret = 0, base = 0, len, i;
5203 u32 *tmp;
5204 struct msm_mmc_pad_drv_data *drv_data;
5205 struct msm_mmc_pad_drv *drv;
5206
5207 switch (id) {
5208 case 1:
5209 base = TLMM_HDRV_SDC1_CLK;
5210 break;
5211 case 2:
5212 base = TLMM_HDRV_SDC2_CLK;
5213 break;
5214 case 3:
5215 base = TLMM_HDRV_SDC3_CLK;
5216 break;
5217 case 4:
5218 base = TLMM_HDRV_SDC4_CLK;
5219 break;
5220 default:
5221 dev_err(dev, "%s: Invalid slot id\n", __func__);
5222 ret = -EINVAL;
5223 goto err;
5224 }
5225
5226 drv_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_drv_data),
5227 GFP_KERNEL);
5228 if (!drv_data) {
5229 dev_err(dev, "No memory for msm_mmc_pad_drv_data\n");
5230 ret = -ENOMEM;
5231 goto err;
5232 }
5233 drv_data->size = 3; /* array size for clk, cmd, data */
5234
5235 /* Allocate on, off configs for clk, cmd, data */
5236 drv = devm_kzalloc(dev, 2 * drv_data->size *\
5237 sizeof(struct msm_mmc_pad_drv), GFP_KERNEL);
5238 if (!drv) {
5239 dev_err(dev, "No memory msm_mmc_pad_drv\n");
5240 ret = -ENOMEM;
5241 goto err;
5242 }
5243 drv_data->on = drv;
5244 drv_data->off = drv + drv_data->size;
5245
5246 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-drv-on",
5247 &tmp, &len, drv_data->size);
5248 if (!ret) {
5249 for (i = 0; i < len; i++) {
5250 drv_data->on[i].no = base + i;
5251 drv_data->on[i].val = tmp[i];
5252 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5253 i, drv_data->on[i].val);
5254 }
5255 } else {
5256 goto err;
5257 }
5258
5259 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-drv-off",
5260 &tmp, &len, drv_data->size);
5261 if (!ret) {
5262 for (i = 0; i < len; i++) {
5263 drv_data->off[i].no = base + i;
5264 drv_data->off[i].val = tmp[i];
5265 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5266 i, drv_data->off[i].val);
5267 }
5268 } else {
5269 goto err;
5270 }
5271
5272 *pad_drv_data = drv_data;
5273err:
5274 return ret;
5275}
5276
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305277static void msmsdcc_dt_get_cd_wp_gpio(struct device *dev,
5278 struct mmc_platform_data *pdata)
5279{
5280 enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
5281 struct device_node *np = dev->of_node;
5282
5283 pdata->status_gpio = of_get_named_gpio_flags(np,
5284 "cd-gpios", 0, &flags);
5285 if (gpio_is_valid(pdata->status_gpio)) {
5286 pdata->status_irq = gpio_to_irq(pdata->status_gpio);
5287 pdata->is_status_gpio_active_low = flags & OF_GPIO_ACTIVE_LOW;
5288 }
5289
5290 pdata->wpswitch_gpio = of_get_named_gpio_flags(np,
5291 "wp-gpios", 0, &flags);
5292 if (gpio_is_valid(pdata->wpswitch_gpio))
5293 pdata->is_wpswitch_active_low = flags & OF_GPIO_ACTIVE_LOW;
5294}
5295
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305296static int msmsdcc_dt_parse_gpio_info(struct device *dev,
5297 struct mmc_platform_data *pdata)
5298{
5299 int ret = 0, id = 0, cnt, i;
5300 struct msm_mmc_pin_data *pin_data;
5301 struct device_node *np = dev->of_node;
5302
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305303 msmsdcc_dt_get_cd_wp_gpio(dev, pdata);
5304
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305305 pin_data = devm_kzalloc(dev, sizeof(*pin_data), GFP_KERNEL);
5306 if (!pin_data) {
5307 dev_err(dev, "No memory for pin_data\n");
5308 ret = -ENOMEM;
5309 goto err;
5310 }
5311
5312 cnt = of_gpio_count(np);
5313 if (cnt > 0) {
5314 pin_data->is_gpio = true;
5315
5316 pin_data->gpio_data = devm_kzalloc(dev,
5317 sizeof(struct msm_mmc_gpio_data), GFP_KERNEL);
5318 if (!pin_data->gpio_data) {
5319 dev_err(dev, "No memory for gpio_data\n");
5320 ret = -ENOMEM;
5321 goto err;
5322 }
5323 pin_data->gpio_data->size = cnt;
5324 pin_data->gpio_data->gpio = devm_kzalloc(dev,
5325 cnt * sizeof(struct msm_mmc_gpio), GFP_KERNEL);
5326 if (!pin_data->gpio_data->gpio) {
5327 dev_err(dev, "No memory for gpio\n");
5328 ret = -ENOMEM;
5329 goto err;
5330 }
5331
5332 for (i = 0; i < cnt; i++) {
5333 const char *name = NULL;
5334 char result[32];
5335 pin_data->gpio_data->gpio[i].no = of_get_gpio(np, i);
5336 of_property_read_string_index(np,
5337 "qcom,sdcc-gpio-names", i, &name);
5338
5339 snprintf(result, 32, "%s-%s",
5340 dev_name(dev), name ? name : "?");
5341 pin_data->gpio_data->gpio[i].name = result;
5342 dev_dbg(dev, "%s: gpio[%s] = %d\n", __func__,
5343 pin_data->gpio_data->gpio[i].name,
5344 pin_data->gpio_data->gpio[i].no);
5345 }
5346 } else {
5347 pin_data->pad_data = devm_kzalloc(dev,
5348 sizeof(struct msm_mmc_pad_data), GFP_KERNEL);
5349 if (!pin_data->pad_data) {
5350 dev_err(dev, "No memory for pin_data->pad_data\n");
5351 ret = -ENOMEM;
5352 goto err;
5353 }
5354
5355 of_property_read_u32(np, "cell-index", &id);
5356
5357 ret = msmsdcc_dt_get_pad_pull_info(dev, id,
5358 &pin_data->pad_data->pull);
5359 if (ret)
5360 goto err;
5361 ret = msmsdcc_dt_get_pad_drv_info(dev, id,
5362 &pin_data->pad_data->drv);
5363 if (ret)
5364 goto err;
5365 }
5366
5367 pdata->pin_data = pin_data;
5368err:
5369 if (ret)
5370 dev_err(dev, "%s failed with err %d\n", __func__, ret);
5371 return ret;
5372}
5373
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305374#define MAX_PROP_SIZE 32
5375static int msmsdcc_dt_parse_vreg_info(struct device *dev,
5376 struct msm_mmc_reg_data **vreg_data, const char *vreg_name)
5377{
5378 int len, ret = 0;
5379 const __be32 *prop;
5380 char prop_name[MAX_PROP_SIZE];
5381 struct msm_mmc_reg_data *vreg;
5382 struct device_node *np = dev->of_node;
5383
5384 snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", vreg_name);
5385 if (of_parse_phandle(np, prop_name, 0)) {
5386 vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
5387 if (!vreg) {
5388 dev_err(dev, "No memory for vreg: %s\n", vreg_name);
5389 ret = -ENOMEM;
5390 goto err;
5391 }
5392
5393 vreg->name = vreg_name;
5394
5395 snprintf(prop_name, MAX_PROP_SIZE,
5396 "qcom,sdcc-%s-always_on", vreg_name);
5397 if (of_get_property(np, prop_name, NULL))
5398 vreg->always_on = true;
5399
5400 snprintf(prop_name, MAX_PROP_SIZE,
5401 "qcom,sdcc-%s-lpm_sup", vreg_name);
5402 if (of_get_property(np, prop_name, NULL))
5403 vreg->lpm_sup = true;
5404
5405 snprintf(prop_name, MAX_PROP_SIZE,
5406 "qcom,sdcc-%s-voltage_level", vreg_name);
5407 prop = of_get_property(np, prop_name, &len);
5408 if (!prop || (len != (2 * sizeof(__be32)))) {
5409 dev_warn(dev, "%s %s property\n",
5410 prop ? "invalid format" : "no", prop_name);
5411 } else {
5412 vreg->low_vol_level = be32_to_cpup(&prop[0]);
5413 vreg->high_vol_level = be32_to_cpup(&prop[1]);
5414 }
5415
5416 snprintf(prop_name, MAX_PROP_SIZE,
5417 "qcom,sdcc-%s-current_level", vreg_name);
5418 prop = of_get_property(np, prop_name, &len);
5419 if (!prop || (len != (2 * sizeof(__be32)))) {
5420 dev_warn(dev, "%s %s property\n",
5421 prop ? "invalid format" : "no", prop_name);
5422 } else {
5423 vreg->lpm_uA = be32_to_cpup(&prop[0]);
5424 vreg->hpm_uA = be32_to_cpup(&prop[1]);
5425 }
5426
5427 *vreg_data = vreg;
5428 dev_dbg(dev, "%s: %s %s vol=[%d %d]uV, curr=[%d %d]uA\n",
5429 vreg->name, vreg->always_on ? "always_on," : "",
5430 vreg->lpm_sup ? "lpm_sup," : "", vreg->low_vol_level,
5431 vreg->high_vol_level, vreg->lpm_uA, vreg->hpm_uA);
5432 }
5433
5434err:
5435 return ret;
5436}
5437
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305438static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
5439{
5440 int i, ret;
5441 struct mmc_platform_data *pdata;
5442 struct device_node *np = dev->of_node;
Devin Kim9ccbff52012-07-16 20:55:14 -07005443 u32 bus_width = 0, current_limit = 0;
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305444 u32 *clk_table, *sup_voltages;
Devin Kim9ccbff52012-07-16 20:55:14 -07005445 int clk_table_len, sup_volt_len, len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305446
5447 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
5448 if (!pdata) {
5449 dev_err(dev, "could not allocate memory for platform data\n");
5450 goto err;
5451 }
5452
5453 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
5454 if (bus_width == 8) {
5455 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
5456 } else if (bus_width == 4) {
5457 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
5458 } else {
5459 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
5460 pdata->mmc_bus_width = 0;
5461 }
5462
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305463 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-sup-voltages",
5464 &sup_voltages, &sup_volt_len, 0);
5465 if (!ret) {
5466 for (i = 0; i < sup_volt_len; i += 2) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305467 u32 mask;
5468
5469 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
5470 sup_voltages[i + 1]);
5471 if (!mask)
5472 dev_err(dev, "Invalide voltage range %d\n", i);
5473 pdata->ocr_mask |= mask;
5474 }
5475 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305476 }
5477
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305478 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-clk-rates",
5479 &clk_table, &clk_table_len, 0);
5480 if (!ret) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305481 pdata->sup_clk_table = clk_table;
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305482 pdata->sup_clk_cnt = clk_table_len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305483 }
5484
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305485 pdata->vreg_data = devm_kzalloc(dev,
5486 sizeof(struct msm_mmc_slot_reg_data), GFP_KERNEL);
5487 if (!pdata->vreg_data) {
5488 dev_err(dev, "could not allocate memory for vreg_data\n");
5489 goto err;
5490 }
5491
5492 if (msmsdcc_dt_parse_vreg_info(dev,
5493 &pdata->vreg_data->vdd_data, "vdd"))
5494 goto err;
5495
5496 if (msmsdcc_dt_parse_vreg_info(dev,
5497 &pdata->vreg_data->vdd_io_data, "vdd-io"))
5498 goto err;
5499
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305500 if (msmsdcc_dt_parse_gpio_info(dev, pdata))
5501 goto err;
5502
Devin Kim9ccbff52012-07-16 20:55:14 -07005503 len = of_property_count_strings(np, "qcom,sdcc-bus-speed-mode");
5504
5505 for (i = 0; i < len; i++) {
5506 const char *name = NULL;
5507
5508 of_property_read_string_index(np,
5509 "qcom,sdcc-bus-speed-mode", i, &name);
5510 if (!name)
5511 continue;
5512
5513 if (!strncmp(name, "SDR12", sizeof("SDR12")))
5514 pdata->uhs_caps |= MMC_CAP_UHS_SDR12;
5515 else if (!strncmp(name, "SDR25", sizeof("SDR25")))
5516 pdata->uhs_caps |= MMC_CAP_UHS_SDR25;
5517 else if (!strncmp(name, "SDR50", sizeof("SDR50")))
5518 pdata->uhs_caps |= MMC_CAP_UHS_SDR50;
5519 else if (!strncmp(name, "DDR50", sizeof("DDR50")))
5520 pdata->uhs_caps |= MMC_CAP_UHS_DDR50;
5521 else if (!strncmp(name, "SDR104", sizeof("SDR104")))
5522 pdata->uhs_caps |= MMC_CAP_UHS_SDR104;
5523 else if (!strncmp(name, "HS200_1p8v", sizeof("HS200_1p8v")))
5524 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_8V_SDR;
5525 else if (!strncmp(name, "HS200_1p2v", sizeof("HS200_1p2v")))
5526 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_2V_SDR;
5527 else if (!strncmp(name, "DDR_1p8v", sizeof("DDR_1p8v")))
5528 pdata->uhs_caps |= MMC_CAP_1_8V_DDR
5529 | MMC_CAP_UHS_DDR50;
5530 else if (!strncmp(name, "DDR_1p2v", sizeof("DDR_1p2v")))
5531 pdata->uhs_caps |= MMC_CAP_1_2V_DDR
5532 | MMC_CAP_UHS_DDR50;
5533 }
5534
5535 of_property_read_u32(np, "qcom,sdcc-current-limit", &current_limit);
5536 if (current_limit == 800)
5537 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_800;
5538 else if (current_limit == 600)
5539 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_600;
5540 else if (current_limit == 400)
5541 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_400;
5542 else if (current_limit == 200)
5543 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_200;
5544
5545 if (of_get_property(np, "qcom,sdcc-xpc", NULL))
5546 pdata->xpc_cap = true;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305547 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
5548 pdata->nonremovable = true;
5549 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
5550 pdata->disable_cmd23 = true;
5551
5552 return pdata;
5553err:
5554 return NULL;
5555}
5556
San Mehat9d2bd732009-09-22 16:44:22 -07005557static int
5558msmsdcc_probe(struct platform_device *pdev)
5559{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305560 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07005561 struct msmsdcc_host *host;
5562 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005563 unsigned long flags;
5564 struct resource *core_irqres = NULL;
5565 struct resource *bam_irqres = NULL;
5566 struct resource *core_memres = NULL;
5567 struct resource *dml_memres = NULL;
5568 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07005569 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07005570 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05305571 int ret = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07005572
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305573 if (pdev->dev.of_node) {
5574 plat = msmsdcc_populate_pdata(&pdev->dev);
5575 of_property_read_u32((&pdev->dev)->of_node,
5576 "cell-index", &pdev->id);
5577 } else {
5578 plat = pdev->dev.platform_data;
5579 }
San Mehat9d2bd732009-09-22 16:44:22 -07005580
5581 /* must have platform data */
5582 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005583 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005584 ret = -EINVAL;
5585 goto out;
5586 }
5587
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005588 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07005589 return -EINVAL;
5590
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305591 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
5592 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
5593 return -EINVAL;
5594 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005595
San Mehat9d2bd732009-09-22 16:44:22 -07005596 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005597 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005598 return -ENXIO;
5599 }
5600
Sujit Reddy Thumma1dfac2c2012-07-30 10:15:39 +05305601 core_memres = platform_get_resource_byname(pdev,
5602 IORESOURCE_MEM, "core_mem");
5603 bam_memres = platform_get_resource_byname(pdev,
5604 IORESOURCE_MEM, "bam_mem");
5605 dml_memres = platform_get_resource_byname(pdev,
5606 IORESOURCE_MEM, "dml_mem");
5607 core_irqres = platform_get_resource_byname(pdev,
5608 IORESOURCE_IRQ, "core_irq");
5609 bam_irqres = platform_get_resource_byname(pdev,
5610 IORESOURCE_IRQ, "bam_irq");
5611 dmares = platform_get_resource_byname(pdev,
5612 IORESOURCE_DMA, "dma_chnl");
5613 dma_crci_res = platform_get_resource_byname(pdev,
5614 IORESOURCE_DMA, "dma_crci");
San Mehat9d2bd732009-09-22 16:44:22 -07005615
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005616 if (!core_irqres || !core_memres) {
5617 pr_err("%s: Invalid sdcc core resource\n", __func__);
5618 return -ENXIO;
5619 }
5620
5621 /*
5622 * Both BAM and DML memory resource should be preset.
5623 * BAM IRQ resource should also be present.
5624 */
5625 if ((bam_memres && !dml_memres) ||
5626 (!bam_memres && dml_memres) ||
5627 ((bam_memres && dml_memres) && !bam_irqres)) {
5628 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005629 return -ENXIO;
5630 }
5631
5632 /*
5633 * Setup our host structure
5634 */
San Mehat9d2bd732009-09-22 16:44:22 -07005635 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
5636 if (!mmc) {
5637 ret = -ENOMEM;
5638 goto out;
5639 }
5640
5641 host = mmc_priv(mmc);
5642 host->pdev_id = pdev->id;
5643 host->plat = plat;
5644 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08005645 host->curr.cmd = NULL;
Sahitya Tummala19207f02011-05-02 18:10:01 +05305646
Sahitya Tummalad9df3272011-08-19 16:50:46 +05305647 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305648 set_hw_caps(host, MSMSDCC_SPS_BAM_SUP);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005649 else if (dmares)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305650 set_hw_caps(host, MSMSDCC_DMA_SUP);
San Mehat9d2bd732009-09-22 16:44:22 -07005651
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005652 host->base = ioremap(core_memres->start,
5653 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07005654 if (!host->base) {
5655 ret = -ENOMEM;
Sahitya Tummaladce7c752011-05-02 18:06:05 +05305656 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005657 }
5658
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005659 host->core_irqres = core_irqres;
5660 host->bam_irqres = bam_irqres;
5661 host->core_memres = core_memres;
5662 host->dml_memres = dml_memres;
5663 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07005664 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07005665 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07005666 spin_lock_init(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305667 mutex_init(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07005668
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005669#ifdef CONFIG_MMC_EMBEDDED_SDIO
5670 if (plat->embedded_sdio)
5671 mmc_set_embedded_sdio_data(mmc,
5672 &plat->embedded_sdio->cis,
5673 &plat->embedded_sdio->cccr,
5674 plat->embedded_sdio->funcs,
5675 plat->embedded_sdio->num_funcs);
5676#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005677
Sahitya Tummala62612cf2010-12-08 15:03:03 +05305678 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
5679 (unsigned long)host);
5680
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005681 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
5682 (unsigned long)host);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305683 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005684 /* Setup DMA */
Subhash Jadavani190657c2011-05-02 18:10:40 +05305685 ret = msmsdcc_init_dma(host);
5686 if (ret)
5687 goto ioremap_free;
5688 } else {
5689 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07005690 host->dma.crci = -1;
Subhash Jadavani190657c2011-05-02 18:10:40 +05305691 }
San Mehat9d2bd732009-09-22 16:44:22 -07005692
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005693 /*
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305694 * Setup SDCC bus voter clock.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005695 */
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305696 host->bus_clk = clk_get(&pdev->dev, "bus_clk");
5697 if (!IS_ERR_OR_NULL(host->bus_clk)) {
5698 /* Vote for max. clk rate for max. performance */
5699 ret = clk_set_rate(host->bus_clk, INT_MAX);
5700 if (ret)
5701 goto bus_clk_put;
5702 ret = clk_prepare_enable(host->bus_clk);
5703 if (ret)
5704 goto bus_clk_put;
San Mehat9d2bd732009-09-22 16:44:22 -07005705 }
5706
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005707 /*
5708 * Setup main peripheral bus clock
5709 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07005710 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005711 if (!IS_ERR(host->pclk)) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305712 ret = clk_prepare_enable(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005713 if (ret)
5714 goto pclk_put;
5715
5716 host->pclk_rate = clk_get_rate(host->pclk);
5717 }
5718
5719 /*
5720 * Setup SDC MMC clock
5721 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07005722 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07005723 if (IS_ERR(host->clk)) {
5724 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005725 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07005726 }
5727
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005728 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
Sahitya Tummala514d9ed2011-05-02 18:07:01 +05305729 if (ret) {
5730 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
5731 goto clk_put;
5732 }
5733
Asutosh Dasf5298c32012-04-03 14:51:47 +05305734 ret = clk_prepare_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07005735 if (ret)
5736 goto clk_put;
5737
San Mehat9d2bd732009-09-22 16:44:22 -07005738 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05305739 if (!host->clk_rate)
5740 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05305741
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305742 set_default_hw_caps(host);
5743
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05305744 /*
5745 * Set the register write delay according to min. clock frequency
5746 * supported and update later when the host->clk_rate changes.
5747 */
5748 host->reg_write_delay =
5749 (1 + ((3 * USEC_PER_SEC) /
5750 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005751
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305752 atomic_set(&host->clks_on, 1);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05305753 /* Apply Hard reset to SDCC to put it in power on default state */
5754 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005755
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005756#define MSM_MMC_DEFAULT_CPUDMA_LATENCY 200 /* usecs */
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305757 /* pm qos request to prevent apps idle power collapse */
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005758 if (host->plat->cpu_dma_latency)
5759 host->cpu_dma_latency = host->plat->cpu_dma_latency;
5760 else
5761 host->cpu_dma_latency = MSM_MMC_DEFAULT_CPUDMA_LATENCY;
5762 pm_qos_add_request(&host->pm_qos_req_dma,
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305763 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
5764
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305765 ret = msmsdcc_msm_bus_register(host);
5766 if (ret)
5767 goto pm_qos_remove;
5768
5769 if (host->msm_bus_vote.client_handle)
5770 INIT_DELAYED_WORK(&host->msm_bus_vote.vote_work,
5771 msmsdcc_msm_bus_work);
5772
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005773 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07005774 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005775 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07005776 goto clk_disable;
5777 }
5778
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005779
5780 /* Clocks has to be running before accessing SPS/DML HW blocks */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305781 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005782 /* Initialize SPS */
5783 ret = msmsdcc_sps_init(host);
5784 if (ret)
5785 goto vreg_deinit;
5786 /* Initialize DML */
5787 ret = msmsdcc_dml_init(host);
5788 if (ret)
5789 goto sps_exit;
5790 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05305791 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07005792
San Mehat9d2bd732009-09-22 16:44:22 -07005793 /*
5794 * Setup MMC host structure
5795 */
5796 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005797 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
5798 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005799 mmc->ocr_avail = plat->ocr_mask;
Sujit Reddy Thumma0e05f022012-06-11 19:44:18 +05305800 mmc->clkgate_delay = MSM_MMC_CLK_GATE_DELAY;
5801
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005802 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
5803 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07005804 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05305805 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
Asutosh Dasebd7d092012-07-09 19:08:26 +05305806 mmc->caps |= MMC_CAP_HW_RESET;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05305807 /*
5808 * If we send the CMD23 before multi block write/read command
5809 * then we need not to send CMD12 at the end of the transfer.
5810 * If we don't send the CMD12 then only way to detect the PROG_DONE
5811 * status is to use the AUTO_PROG_DONE status provided by SDCC4
5812 * controller. So let's enable the CMD23 for SDCC4 only.
5813 */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305814 if (!plat->disable_cmd23 && is_auto_prog_done(host))
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05305815 mmc->caps |= MMC_CAP_CMD23;
San Mehat9d2bd732009-09-22 16:44:22 -07005816
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005817 mmc->caps |= plat->uhs_caps;
Devin Kim9ccbff52012-07-16 20:55:14 -07005818 mmc->caps2 |= plat->uhs_caps2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005819 /*
5820 * XPC controls the maximum current in the default speed mode of SDXC
5821 * card. XPC=0 means 100mA (max.) but speed class is not supported.
5822 * XPC=1 means 150mA (max.) and speed class is supported.
5823 */
5824 if (plat->xpc_cap)
5825 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
5826 MMC_CAP_SET_XPC_180);
5827
Maya Erez231dd082012-11-28 23:55:57 +02005828
5829 /* packed write */
5830 mmc->caps2 |= plat->packed_write;
5831
Subhash Jadavani6bb34a82012-04-18 13:18:40 +05305832 mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
Yaniv Gardi14098552012-06-04 10:56:03 +03005833 mmc->caps2 |= MMC_CAP2_SANITIZE;
Maya Erezd0ed5ae2012-11-01 21:39:00 +02005834 mmc->caps2 |= MMC_CAP2_INIT_BKOPS;
Tatyana Brokhman139eabf2012-10-15 22:43:35 +02005835 mmc->caps2 |= MMC_CAP2_POWEROFF_NOTIFY;
Yaniv Gardi14098552012-06-04 10:56:03 +03005836
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005837 if (plat->nonremovable)
5838 mmc->caps |= MMC_CAP_NONREMOVABLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005839 mmc->caps |= MMC_CAP_SDIO_IRQ;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005840
5841 if (plat->is_sdio_al_client)
5842 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07005843
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305844 mmc->max_segs = msmsdcc_get_nr_sg(host);
5845 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
5846 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07005847
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305848 mmc->max_req_size = MMC_MAX_REQ_SIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07005849 mmc->max_seg_size = mmc->max_req_size;
5850
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005851 writel_relaxed(0, host->base + MMCIMASK0);
5852 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05305853 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005854
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005855 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
5856 mb();
5857 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07005858
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005859 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
5860 DRIVER_NAME " (cmd)", host);
5861 if (ret)
5862 goto dml_exit;
5863
5864 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
5865 DRIVER_NAME " (pio)", host);
5866 if (ret)
5867 goto irq_free;
5868
5869 /*
5870 * Enable SDCC IRQ only when host is powered on. Otherwise, this
5871 * IRQ is un-necessarily being monitored by MPM (Modem power
5872 * management block) during idle-power collapse. The MPM will be
5873 * configured to monitor the DATA1 GPIO line with level-low trigger
5874 * and thus depending on the GPIO status, it prevents TCXO shutdown
5875 * during idle-power collapse.
5876 */
5877 disable_irq(core_irqres->start);
5878 host->sdcc_irq_disabled = 1;
5879
5880 if (plat->sdiowakeup_irq) {
5881 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5882 mmc_hostname(mmc));
5883 ret = request_irq(plat->sdiowakeup_irq,
5884 msmsdcc_platform_sdiowakeup_irq,
5885 IRQF_SHARED | IRQF_TRIGGER_LOW,
5886 DRIVER_NAME "sdiowakeup", host);
5887 if (ret) {
5888 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
5889 plat->sdiowakeup_irq, ret);
5890 goto pio_irq_free;
5891 } else {
5892 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305893 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005894 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305895 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005896 }
5897 spin_unlock_irqrestore(&host->lock, flags);
5898 }
5899 }
5900
Subhash Jadavanic9b85752012-04-13 11:16:49 +05305901 if (host->plat->mpm_sdiowakeup_int) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005902 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5903 mmc_hostname(mmc));
5904 }
5905
5906 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
5907 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005908 /*
5909 * Setup card detect change
5910 */
5911
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305912 if (!plat->status_gpio)
5913 plat->status_gpio = -ENOENT;
5914 if (!plat->wpswitch_gpio)
5915 plat->wpswitch_gpio = -ENOENT;
5916
5917 if (plat->status || gpio_is_valid(plat->status_gpio)) {
Krishna Konda941604a2012-01-10 17:46:34 -08005918 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005919 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08005920 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005921 host->oldstat = msmsdcc_slot_status(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005922
Krishna Konda941604a2012-01-10 17:46:34 -08005923 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005924 }
San Mehat9d2bd732009-09-22 16:44:22 -07005925
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005926 if (plat->status_irq) {
5927 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07005928 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005929 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07005930 DRIVER_NAME " (slot)",
5931 host);
5932 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005933 pr_err("Unable to get slot IRQ %d (%d)\n",
5934 plat->status_irq, ret);
5935 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005936 }
5937 } else if (plat->register_status_notify) {
5938 plat->register_status_notify(msmsdcc_status_notify_cb, host);
5939 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005940 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07005941 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005942
5943 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005944
5945 ret = pm_runtime_set_active(&(pdev)->dev);
5946 if (ret < 0)
5947 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
5948 __func__, ret);
5949 /*
5950 * There is no notion of suspend/resume for SD/MMC/SDIO
5951 * cards. So host can be suspended/resumed with out
5952 * worrying about its children.
5953 */
5954 pm_suspend_ignore_children(&(pdev)->dev, true);
5955
5956 /*
5957 * MMC/SD/SDIO bus suspend/resume operations are defined
5958 * only for the slots that will be used for non-removable
5959 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
5960 * defined. Otherwise, they simply become card removal and
5961 * insertion events during suspend and resume respectively.
5962 * Hence, enable run-time PM only for slots for which bus
5963 * suspend/resume operations are defined.
5964 */
5965#ifdef CONFIG_MMC_UNSAFE_RESUME
5966 /*
5967 * If this capability is set, MMC core will enable/disable host
5968 * for every claim/release operation on a host. We use this
5969 * notification to increment/decrement runtime pm usage count.
5970 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005971 pm_runtime_enable(&(pdev)->dev);
5972#else
5973 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005974 pm_runtime_enable(&(pdev)->dev);
5975 }
5976#endif
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305977 host->idle_tout_ms = MSM_MMC_DEFAULT_IDLE_TIMEOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005978 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
5979 (unsigned long)host);
5980
San Mehat9d2bd732009-09-22 16:44:22 -07005981 mmc_add_host(mmc);
5982
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005983#ifdef CONFIG_HAS_EARLYSUSPEND
5984 host->early_suspend.suspend = msmsdcc_early_suspend;
5985 host->early_suspend.resume = msmsdcc_late_resume;
5986 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
5987 register_early_suspend(&host->early_suspend);
5988#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005989
Krishna Konda25786ec2011-07-25 16:21:36 -07005990 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
5991 " dmacrcri %d\n", mmc_hostname(mmc),
5992 (unsigned long long)core_memres->start,
5993 (unsigned int) core_irqres->start,
5994 (unsigned int) plat->status_irq, host->dma.channel,
5995 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005996
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305997 pr_info("%s: Controller capabilities: 0x%.8x\n",
5998 mmc_hostname(mmc), host->hw_caps);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005999 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
6000 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
6001 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
6002 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
6003 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
6004 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
6005 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
6006 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
6007 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
6008 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
6009 host->eject);
6010 pr_info("%s: Power save feature enable = %d\n",
6011 mmc_hostname(mmc), msmsdcc_pwrsave);
6012
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306013 if (is_dma_mode(host) && host->dma.channel != -1
Krishna Konda25786ec2011-07-25 16:21:36 -07006014 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07006015 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006016 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07006017 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006018 mmc_hostname(mmc), host->dma.cmd_busaddr,
6019 host->dma.cmdptr_busaddr);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306020 } else if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006021 pr_info("%s: SPS-BAM data transfer mode available\n",
6022 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07006023 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07006024 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07006025
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006026#if defined(CONFIG_DEBUG_FS)
6027 msmsdcc_dbg_createhost(host);
6028#endif
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306029
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306030 host->max_bus_bw.show = show_sdcc_to_mem_max_bus_bw;
6031 host->max_bus_bw.store = store_sdcc_to_mem_max_bus_bw;
6032 sysfs_attr_init(&host->max_bus_bw.attr);
6033 host->max_bus_bw.attr.name = "max_bus_bw";
6034 host->max_bus_bw.attr.mode = S_IRUGO | S_IWUSR;
6035 ret = device_create_file(&pdev->dev, &host->max_bus_bw);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306036 if (ret)
6037 goto platform_irq_free;
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306038
6039 if (!plat->status_irq) {
6040 host->polling.show = show_polling;
6041 host->polling.store = store_polling;
6042 sysfs_attr_init(&host->polling.attr);
6043 host->polling.attr.name = "polling";
6044 host->polling.attr.mode = S_IRUGO | S_IWUSR;
6045 ret = device_create_file(&pdev->dev, &host->polling);
6046 if (ret)
6047 goto remove_max_bus_bw_file;
6048 }
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306049 host->idle_timeout.show = show_idle_timeout;
6050 host->idle_timeout.store = store_idle_timeout;
6051 sysfs_attr_init(&host->idle_timeout.attr);
6052 host->idle_timeout.attr.name = "idle_timeout";
6053 host->idle_timeout.attr.mode = S_IRUGO | S_IWUSR;
6054 ret = device_create_file(&pdev->dev, &host->idle_timeout);
6055 if (ret)
6056 goto remove_polling_file;
San Mehat9d2bd732009-09-22 16:44:22 -07006057 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006058
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306059 remove_polling_file:
6060 if (!plat->status_irq)
6061 device_remove_file(&pdev->dev, &host->polling);
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306062 remove_max_bus_bw_file:
6063 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006064 platform_irq_free:
6065 del_timer_sync(&host->req_tout_timer);
6066 pm_runtime_disable(&(pdev)->dev);
6067 pm_runtime_set_suspended(&(pdev)->dev);
6068
6069 if (plat->status_irq)
6070 free_irq(plat->status_irq, host);
6071 sdiowakeup_irq_free:
6072 wake_lock_destroy(&host->sdio_suspend_wlock);
6073 if (plat->sdiowakeup_irq)
6074 free_irq(plat->sdiowakeup_irq, host);
6075 pio_irq_free:
6076 if (plat->sdiowakeup_irq)
6077 wake_lock_destroy(&host->sdio_wlock);
6078 free_irq(core_irqres->start, host);
6079 irq_free:
6080 free_irq(core_irqres->start, host);
6081 dml_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306082 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006083 msmsdcc_dml_exit(host);
6084 sps_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306085 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006086 msmsdcc_sps_exit(host);
6087 vreg_deinit:
6088 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07006089 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006090 clk_disable(host->clk);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306091 msmsdcc_msm_bus_unregister(host);
6092 pm_qos_remove:
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006093 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306094 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07006095 clk_put:
6096 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006097 pclk_disable:
6098 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05306099 clk_disable_unprepare(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07006100 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006101 if (!IS_ERR(host->pclk))
6102 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05306103 if (!IS_ERR_OR_NULL(host->bus_clk))
6104 clk_disable_unprepare(host->bus_clk);
6105 bus_clk_put:
6106 if (!IS_ERR_OR_NULL(host->bus_clk))
6107 clk_put(host->bus_clk);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306108 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006109 if (host->dmares)
6110 dma_free_coherent(NULL,
6111 sizeof(struct msmsdcc_nc_dmadata),
6112 host->dma.nc, host->dma.nc_busaddr);
6113 }
6114 ioremap_free:
Sahitya Tummaladce7c752011-05-02 18:06:05 +05306115 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07006116 host_free:
6117 mmc_free_host(mmc);
6118 out:
6119 return ret;
6120}
6121
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006122static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07006123{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006124 struct mmc_host *mmc = mmc_get_drvdata(pdev);
6125 struct mmc_platform_data *plat;
6126 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07006127
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006128 if (!mmc)
6129 return -ENXIO;
6130
6131 if (pm_runtime_suspended(&(pdev)->dev))
6132 pm_runtime_resume(&(pdev)->dev);
6133
6134 host = mmc_priv(mmc);
6135
6136 DBG(host, "Removing SDCC device = %d\n", pdev->id);
6137 plat = host->plat;
6138
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306139 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006140 if (!plat->status_irq)
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306141 device_remove_file(&pdev->dev, &host->polling);
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306142 device_remove_file(&pdev->dev, &host->idle_timeout);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006143
6144 del_timer_sync(&host->req_tout_timer);
6145 tasklet_kill(&host->dma_tlet);
6146 tasklet_kill(&host->sps.tlet);
6147 mmc_remove_host(mmc);
6148
6149 if (plat->status_irq)
6150 free_irq(plat->status_irq, host);
6151
6152 wake_lock_destroy(&host->sdio_suspend_wlock);
6153 if (plat->sdiowakeup_irq) {
6154 wake_lock_destroy(&host->sdio_wlock);
6155 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
6156 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07006157 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006158
6159 free_irq(host->core_irqres->start, host);
6160 free_irq(host->core_irqres->start, host);
6161
6162 clk_put(host->clk);
6163 if (!IS_ERR(host->pclk))
6164 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05306165 if (!IS_ERR_OR_NULL(host->bus_clk))
6166 clk_put(host->bus_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006167
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006168 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306169 pm_qos_remove_request(&host->pm_qos_req_dma);
6170
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306171 if (host->msm_bus_vote.client_handle) {
6172 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
6173 msmsdcc_msm_bus_unregister(host);
6174 }
6175
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006176 msmsdcc_vreg_init(host, false);
6177
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306178 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006179 if (host->dmares)
6180 dma_free_coherent(NULL,
6181 sizeof(struct msmsdcc_nc_dmadata),
6182 host->dma.nc, host->dma.nc_busaddr);
6183 }
6184
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306185 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006186 msmsdcc_dml_exit(host);
6187 msmsdcc_sps_exit(host);
6188 }
6189
6190 iounmap(host->base);
6191 mmc_free_host(mmc);
6192
6193#ifdef CONFIG_HAS_EARLYSUSPEND
6194 unregister_early_suspend(&host->early_suspend);
6195#endif
6196 pm_runtime_disable(&(pdev)->dev);
6197 pm_runtime_set_suspended(&(pdev)->dev);
6198
6199 return 0;
6200}
6201
6202#ifdef CONFIG_MSM_SDIO_AL
6203int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
6204{
6205 struct msmsdcc_host *host = mmc_priv(mmc);
6206 unsigned long flags;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306207 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006208
Asutosh Dasf5298c32012-04-03 14:51:47 +05306209 mutex_lock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006210 spin_lock_irqsave(&host->lock, flags);
6211 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
6212 enable ? "En" : "Dis");
6213
6214 if (enable) {
6215 if (!host->sdcc_irq_disabled) {
6216 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05306217 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006218 host->sdcc_irq_disabled = 1;
6219 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306220 rc = msmsdcc_setup_clocks(host, false);
6221 if (rc)
6222 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006223
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05306224 if (host->plat->sdio_lpm_gpio_setup &&
6225 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006226 spin_unlock_irqrestore(&host->lock, flags);
6227 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
6228 spin_lock_irqsave(&host->lock, flags);
6229 host->sdio_gpio_lpm = 1;
6230 }
6231
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306232 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006233 msmsdcc_enable_irq_wake(host);
6234 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306235 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006236 }
6237 } else {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306238 rc = msmsdcc_setup_clocks(host, true);
6239 if (rc)
6240 goto out;
6241
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306242 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006243 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306244 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006245 msmsdcc_disable_irq_wake(host);
6246 }
6247
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05306248 if (host->plat->sdio_lpm_gpio_setup &&
6249 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006250 spin_unlock_irqrestore(&host->lock, flags);
6251 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
6252 spin_lock_irqsave(&host->lock, flags);
6253 host->sdio_gpio_lpm = 0;
6254 }
6255
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306256 if (host->sdcc_irq_disabled && atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006257 writel_relaxed(host->mci_irqenable,
6258 host->base + MMCIMASK0);
6259 mb();
6260 enable_irq(host->core_irqres->start);
6261 host->sdcc_irq_disabled = 0;
6262 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006263 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306264out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006265 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05306266 mutex_unlock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306267 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006268}
6269#else
6270int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
6271{
6272 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07006273}
6274#endif
6275
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006276#ifdef CONFIG_PM
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306277#ifdef CONFIG_MMC_CLKGATE
6278static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6279{
6280 struct mmc_host *mmc = host->mmc;
6281 unsigned long flags;
6282
6283 mmc_host_clk_hold(mmc);
6284 spin_lock_irqsave(&mmc->clk_lock, flags);
6285 mmc->clk_old = mmc->ios.clock;
6286 mmc->ios.clock = 0;
6287 mmc->clk_gated = true;
6288 spin_unlock_irqrestore(&mmc->clk_lock, flags);
6289 mmc_set_ios(mmc);
6290 mmc_host_clk_release(mmc);
6291}
6292
6293static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6294{
6295 struct mmc_host *mmc = host->mmc;
6296
6297 mmc_host_clk_hold(mmc);
6298 mmc->ios.clock = host->clk_rate;
6299 mmc_set_ios(mmc);
6300 mmc_host_clk_release(mmc);
6301}
6302#else
6303static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6304{
6305 struct mmc_host *mmc = host->mmc;
6306
6307 mmc->ios.clock = 0;
6308 mmc_set_ios(mmc);
6309}
6310
6311static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6312{
6313 struct mmc_host *mmc = host->mmc;
6314
6315 mmc->ios.clock = host->clk_rate;
6316 mmc_set_ios(mmc);
6317}
6318#endif
6319
San Mehat9d2bd732009-09-22 16:44:22 -07006320static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006321msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006322{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006323 struct mmc_host *mmc = dev_get_drvdata(dev);
6324 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006325 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306326 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07006327
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306328 if (host->plat->is_sdio_al_client) {
6329 rc = 0;
6330 goto out;
San Mehat9d2bd732009-09-22 16:44:22 -07006331 }
San Mehat9d2bd732009-09-22 16:44:22 -07006332
Sahitya Tummala7661a452011-07-18 13:28:35 +05306333 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006334 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006335 host->sdcc_suspending = 1;
6336 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07006337
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006338 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006339 * MMC core thinks that host is disabled by now since
6340 * runtime suspend is scheduled after msmsdcc_disable()
6341 * is called. Thus, MMC core will try to enable the host
6342 * while suspending it. This results in a synchronous
6343 * runtime resume request while in runtime suspending
6344 * context and hence inorder to complete this resume
6345 * requet, it will wait for suspend to be complete,
6346 * but runtime suspend also can not proceed further
6347 * until the host is resumed. Thus, it leads to a hang.
6348 * Hence, increase the pm usage count before suspending
6349 * the host so that any resume requests after this will
6350 * simple become pm usage counter increment operations.
6351 */
6352 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306353 /* If there is pending detect work abort runtime suspend */
6354 if (unlikely(work_busy(&mmc->detect.work)))
6355 rc = -EAGAIN;
6356 else
6357 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006358 pm_runtime_put_noidle(dev);
6359
6360 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306361 spin_lock_irqsave(&host->lock, flags);
6362 host->sdcc_suspended = true;
6363 spin_unlock_irqrestore(&host->lock, flags);
6364 if (mmc->card && mmc_card_sdio(mmc->card) &&
6365 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006366 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306367 * If SDIO function driver doesn't want
6368 * to power off the card, atleast turn off
6369 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006370 */
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306371 msmsdcc_gate_clock(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006372 }
6373 }
6374 host->sdcc_suspending = 0;
6375 mmc->suspend_task = NULL;
6376 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
6377 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006378 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306379 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306380out:
6381 /* set bus bandwidth to 0 immediately */
6382 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
San Mehat9d2bd732009-09-22 16:44:22 -07006383 return rc;
6384}
6385
6386static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006387msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006388{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006389 struct mmc_host *mmc = dev_get_drvdata(dev);
6390 struct msmsdcc_host *host = mmc_priv(mmc);
6391 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07006392
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006393 if (host->plat->is_sdio_al_client)
6394 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07006395
Sahitya Tummala7661a452011-07-18 13:28:35 +05306396 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006397 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306398 if (mmc->card && mmc_card_sdio(mmc->card) &&
6399 mmc_card_keep_power(mmc)) {
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306400 msmsdcc_ungate_clock(host);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05306401 }
San Mehat9d2bd732009-09-22 16:44:22 -07006402
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006403 mmc_resume_host(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006404
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006405 /*
6406 * FIXME: Clearing of flags must be handled in clients
6407 * resume handler.
6408 */
6409 spin_lock_irqsave(&host->lock, flags);
6410 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306411 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006412 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07006413
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006414 /*
6415 * After resuming the host wait for sometime so that
6416 * the SDIO work will be processed.
6417 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306418 if (mmc->card && mmc_card_sdio(mmc->card)) {
Subhash Jadavanic9b85752012-04-13 11:16:49 +05306419 if ((host->plat->mpm_sdiowakeup_int ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006420 host->plat->sdiowakeup_irq) &&
6421 wake_lock_active(&host->sdio_wlock))
6422 wake_lock_timeout(&host->sdio_wlock, 1);
6423 }
6424
6425 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006426 }
Subhash Jadavani1371d192012-08-16 18:46:57 +05306427 host->pending_resume = false;
Sahitya Tummala7661a452011-07-18 13:28:35 +05306428 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006429 return 0;
6430}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006431
6432static int msmsdcc_runtime_idle(struct device *dev)
6433{
6434 struct mmc_host *mmc = dev_get_drvdata(dev);
6435 struct msmsdcc_host *host = mmc_priv(mmc);
6436
6437 if (host->plat->is_sdio_al_client)
6438 return 0;
6439
6440 /* Idle timeout is not configurable for now */
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306441 pm_schedule_suspend(dev, host->idle_tout_ms);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006442
6443 return -EAGAIN;
6444}
6445
6446static int msmsdcc_pm_suspend(struct device *dev)
6447{
6448 struct mmc_host *mmc = dev_get_drvdata(dev);
6449 struct msmsdcc_host *host = mmc_priv(mmc);
6450 int rc = 0;
6451
6452 if (host->plat->is_sdio_al_client)
6453 return 0;
6454
6455
6456 if (host->plat->status_irq)
6457 disable_irq(host->plat->status_irq);
6458
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006459 if (!pm_runtime_suspended(dev))
6460 rc = msmsdcc_runtime_suspend(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006461
6462 return rc;
6463}
6464
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306465static int msmsdcc_suspend_noirq(struct device *dev)
6466{
6467 struct mmc_host *mmc = dev_get_drvdata(dev);
6468 struct msmsdcc_host *host = mmc_priv(mmc);
6469 int rc = 0;
6470
6471 /*
6472 * After platform suspend there may be active request
6473 * which might have enabled clocks. For example, in SDIO
6474 * case, ksdioirq thread might have scheduled after sdcc
6475 * suspend but before system freeze. In that case abort
6476 * suspend and retry instead of keeping the clocks on
6477 * during suspend and not allowing TCXO.
6478 */
6479
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306480 if (atomic_read(&host->clks_on) && !host->plat->is_sdio_al_client) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306481 pr_warn("%s: clocks are on after suspend, aborting system "
6482 "suspend\n", mmc_hostname(mmc));
6483 rc = -EAGAIN;
6484 }
6485
6486 return rc;
6487}
6488
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006489static int msmsdcc_pm_resume(struct device *dev)
6490{
6491 struct mmc_host *mmc = dev_get_drvdata(dev);
6492 struct msmsdcc_host *host = mmc_priv(mmc);
6493 int rc = 0;
6494
6495 if (host->plat->is_sdio_al_client)
6496 return 0;
6497
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006498 if (mmc->card && mmc_card_sdio(mmc->card))
Sahitya Tummalafb486372011-09-02 19:01:49 +05306499 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavani1371d192012-08-16 18:46:57 +05306500 /*
6501 * As runtime PM is enabled before calling the device's platform resume
6502 * callback, we use the pm_runtime_suspended API to know if SDCC is
6503 * really runtime suspended or not and set the pending_resume flag only
6504 * if its not runtime suspended.
6505 */
6506 else if (!pm_runtime_suspended(dev))
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006507 host->pending_resume = true;
6508
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006509 if (host->plat->status_irq) {
6510 msmsdcc_check_status((unsigned long)host);
6511 enable_irq(host->plat->status_irq);
6512 }
6513
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006514 return rc;
6515}
6516
Daniel Walker08ecfde2010-06-23 12:32:20 -07006517#else
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006518static int msmsdcc_runtime_suspend(struct device *dev)
6519{
6520 return 0;
6521}
6522static int msmsdcc_runtime_idle(struct device *dev)
6523{
6524 return 0;
6525}
6526static int msmsdcc_pm_suspend(struct device *dev)
6527{
6528 return 0;
6529}
6530static int msmsdcc_pm_resume(struct device *dev)
6531{
6532 return 0;
6533}
6534static int msmsdcc_suspend_noirq(struct device *dev)
6535{
6536 return 0;
6537}
6538static int msmsdcc_runtime_resume(struct device *dev)
6539{
6540 return 0;
6541}
Daniel Walker08ecfde2010-06-23 12:32:20 -07006542#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006543
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006544static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
6545 .runtime_suspend = msmsdcc_runtime_suspend,
6546 .runtime_resume = msmsdcc_runtime_resume,
6547 .runtime_idle = msmsdcc_runtime_idle,
6548 .suspend = msmsdcc_pm_suspend,
6549 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306550 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006551};
6552
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306553static const struct of_device_id msmsdcc_dt_match[] = {
6554 {.compatible = "qcom,msm-sdcc"},
6555
6556};
6557MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
6558
San Mehat9d2bd732009-09-22 16:44:22 -07006559static struct platform_driver msmsdcc_driver = {
6560 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006561 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07006562 .driver = {
6563 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006564 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306565 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07006566 },
6567};
6568
6569static int __init msmsdcc_init(void)
6570{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006571#if defined(CONFIG_DEBUG_FS)
6572 int ret = 0;
6573 ret = msmsdcc_dbg_init();
6574 if (ret) {
6575 pr_err("Failed to create debug fs dir \n");
6576 return ret;
6577 }
6578#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006579 return platform_driver_register(&msmsdcc_driver);
6580}
San Mehat9d2bd732009-09-22 16:44:22 -07006581
San Mehat9d2bd732009-09-22 16:44:22 -07006582static void __exit msmsdcc_exit(void)
6583{
6584 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006585
6586#if defined(CONFIG_DEBUG_FS)
6587 debugfs_remove(debugfs_file);
6588 debugfs_remove(debugfs_dir);
6589#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006590}
6591
6592module_init(msmsdcc_init);
6593module_exit(msmsdcc_exit);
6594
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006595MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07006596MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006597
6598#if defined(CONFIG_DEBUG_FS)
6599
6600static int
6601msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
6602{
6603 file->private_data = inode->i_private;
6604 return 0;
6605}
6606
6607static ssize_t
6608msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
6609 size_t count, loff_t *ppos)
6610{
6611 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08006612 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006613 int max, i;
6614
6615 i = 0;
6616 max = sizeof(buf) - 1;
6617
6618 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
6619 host->curr.cmd, host->curr.data);
6620 if (host->curr.cmd) {
6621 struct mmc_command *cmd = host->curr.cmd;
6622
6623 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
6624 cmd->opcode, cmd->arg, cmd->flags);
6625 }
6626 if (host->curr.data) {
6627 struct mmc_data *data = host->curr.data;
6628 i += scnprintf(buf + i, max - i,
6629 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
6630 data->timeout_ns, data->timeout_clks,
6631 data->blksz, data->blocks, data->error,
6632 data->flags);
6633 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
6634 host->curr.xfer_size, host->curr.xfer_remain,
6635 host->curr.data_xfered, host->dma.sg);
6636 }
6637
6638 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
6639}
6640
6641static const struct file_operations msmsdcc_dbg_state_ops = {
6642 .read = msmsdcc_dbg_state_read,
6643 .open = msmsdcc_dbg_state_open,
6644};
6645
6646static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
6647{
6648 if (debugfs_dir) {
6649 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
6650 0644, debugfs_dir, host,
6651 &msmsdcc_dbg_state_ops);
6652 }
6653}
6654
6655static int __init msmsdcc_dbg_init(void)
6656{
6657 int err;
6658
6659 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
6660 if (IS_ERR(debugfs_dir)) {
6661 err = PTR_ERR(debugfs_dir);
6662 debugfs_dir = NULL;
6663 return err;
6664 }
6665
6666 return 0;
6667}
6668#endif