blob: 7a87ca9f140da0c0b11b4f8e85c7d6eff8e95b82 [file] [log] [blame]
San Mehat9d2bd732009-09-22 16:44:22 -07001/*
2 * linux/drivers/mmc/host/msm_sdcc.c - Qualcomm MSM 7X00A SDCC Driver
3 *
4 * Copyright (C) 2007 Google Inc,
5 * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
Krishna Konda941604a2012-01-10 17:46:34 -08006 * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
San Mehat9d2bd732009-09-22 16:44:22 -07007 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * Based on mmci.c
13 *
14 * Author: San Mehat (san@android.com)
15 *
16 */
17
18#include <linux/module.h>
19#include <linux/moduleparam.h>
20#include <linux/init.h>
21#include <linux/ioport.h>
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +053022#include <linux/of.h>
Sujit Reddy Thumma38459152012-06-26 00:07:59 +053023#include <linux/of_gpio.h>
San Mehat9d2bd732009-09-22 16:44:22 -070024#include <linux/device.h>
25#include <linux/interrupt.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070026#include <linux/irq.h>
San Mehat9d2bd732009-09-22 16:44:22 -070027#include <linux/delay.h>
28#include <linux/err.h>
29#include <linux/highmem.h>
30#include <linux/log2.h>
31#include <linux/mmc/host.h>
32#include <linux/mmc/card.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070033#include <linux/mmc/mmc.h>
San Mehatb3fa5792009-11-02 18:46:09 -080034#include <linux/mmc/sdio.h>
San Mehat9d2bd732009-09-22 16:44:22 -070035#include <linux/clk.h>
36#include <linux/scatterlist.h>
37#include <linux/platform_device.h>
38#include <linux/dma-mapping.h>
39#include <linux/debugfs.h>
40#include <linux/io.h>
41#include <linux/memory.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070042#include <linux/pm_runtime.h>
43#include <linux/wakelock.h>
Sahitya Tummala7a892482011-01-18 11:22:49 +053044#include <linux/gpio.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070045#include <linux/regulator/consumer.h>
46#include <linux/slab.h>
Steve Mucklef132c6c2012-06-06 18:30:57 -070047#include <linux/pm_qos.h>
San Mehat9d2bd732009-09-22 16:44:22 -070048
49#include <asm/cacheflush.h>
50#include <asm/div64.h>
51#include <asm/sizes.h>
52
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070053#include <asm/mach/mmc.h>
San Mehat9d2bd732009-09-22 16:44:22 -070054#include <mach/msm_iomap.h>
Sahitya Tummalab08bb352010-12-08 15:03:05 +053055#include <mach/clk.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070056#include <mach/dma.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070057#include <mach/sdio_al.h>
Subhash Jadavanic9b85752012-04-13 11:16:49 +053058#include <mach/mpm.h>
Subhash Jadavanibcd435f2012-04-24 18:26:49 +053059#include <mach/msm_bus.h>
San Mehat9d2bd732009-09-22 16:44:22 -070060
San Mehat9d2bd732009-09-22 16:44:22 -070061#include "msm_sdcc.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070062#include "msm_sdcc_dml.h"
San Mehat9d2bd732009-09-22 16:44:22 -070063
64#define DRIVER_NAME "msm-sdcc"
65
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070066#define DBG(host, fmt, args...) \
67 pr_debug("%s: %s: " fmt "\n", mmc_hostname(host->mmc), __func__ , args)
68
69#define IRQ_DEBUG 0
70#define SPS_SDCC_PRODUCER_PIPE_INDEX 1
71#define SPS_SDCC_CONSUMER_PIPE_INDEX 2
72#define SPS_CONS_PERIPHERAL 0
73#define SPS_PROD_PERIPHERAL 1
Subhash Jadavanie6e1b822012-03-12 18:17:58 +053074/* Use SPS only if transfer size is more than this macro */
75#define SPS_MIN_XFER_SIZE MCI_FIFOSIZE
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070076
Subhash Jadavanibcd435f2012-04-24 18:26:49 +053077#define MSM_MMC_BUS_VOTING_DELAY 200 /* msecs */
78
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070079#if defined(CONFIG_DEBUG_FS)
80static void msmsdcc_dbg_createhost(struct msmsdcc_host *);
81static struct dentry *debugfs_dir;
82static struct dentry *debugfs_file;
83static int msmsdcc_dbg_init(void);
84#endif
85
Asutosh Dasaccacd42012-03-08 14:33:17 +053086static int msmsdcc_prep_xfer(struct msmsdcc_host *host, struct mmc_data
87 *data);
88
Subhash Jadavani8766e352011-11-30 11:30:32 +053089static u64 dma_mask = DMA_BIT_MASK(32);
San Mehat9d2bd732009-09-22 16:44:22 -070090static unsigned int msmsdcc_pwrsave = 1;
San Mehat9d2bd732009-09-22 16:44:22 -070091
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070092static struct mmc_command dummy52cmd;
93static struct mmc_request dummy52mrq = {
94 .cmd = &dummy52cmd,
95 .data = NULL,
96 .stop = NULL,
97};
98static struct mmc_command dummy52cmd = {
99 .opcode = SD_IO_RW_DIRECT,
100 .flags = MMC_RSP_PRESENT,
101 .data = NULL,
102 .mrq = &dummy52mrq,
103};
104/*
105 * An array holding the Tuning pattern to compare with when
106 * executing a tuning cycle.
107 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +0530108static const u32 tuning_block_64[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700109 0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
110 0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
111 0xF0FFF0FF, 0x3CCCFC0F, 0xCFCC33CC, 0xEEFFEFFF,
112 0xFDFFFDFF, 0xFFBFFFDF, 0xFFF7FFBB, 0xDE7B7FF7
113};
San Mehat9d2bd732009-09-22 16:44:22 -0700114
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +0530115static const u32 tuning_block_128[] = {
116 0xFF00FFFF, 0x0000FFFF, 0xCCCCFFFF, 0xCCCC33CC,
117 0xCC3333CC, 0xFFFFCCCC, 0xFFFFEEFF, 0xFFEEEEFF,
118 0xFFDDFFFF, 0xDDDDFFFF, 0xBBFFFFFF, 0xBBFFFFFF,
119 0xFFFFFFBB, 0xFFFFFF77, 0x77FF7777, 0xFFEEDDBB,
120 0x00FFFFFF, 0x00FFFFFF, 0xCCFFFF00, 0xCC33CCCC,
121 0x3333CCCC, 0xFFCCCCCC, 0xFFEEFFFF, 0xEEEEFFFF,
122 0xDDFFFFFF, 0xDDFFFFFF, 0xFFFFFFDD, 0xFFFFFFBB,
123 0xFFFFBBBB, 0xFFFF77FF, 0xFF7777FF, 0xEEDDBB77
124};
San Mehat865c8062009-11-13 13:42:06 -0800125
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700126#if IRQ_DEBUG == 1
127static char *irq_status_bits[] = { "cmdcrcfail", "datcrcfail", "cmdtimeout",
128 "dattimeout", "txunderrun", "rxoverrun",
129 "cmdrespend", "cmdsent", "dataend", NULL,
130 "datablkend", "cmdactive", "txactive",
131 "rxactive", "txhalfempty", "rxhalffull",
132 "txfifofull", "rxfifofull", "txfifoempty",
133 "rxfifoempty", "txdataavlbl", "rxdataavlbl",
134 "sdiointr", "progdone", "atacmdcompl",
135 "sdiointrope", "ccstimeout", NULL, NULL,
136 NULL, NULL, NULL };
137
138static void
139msmsdcc_print_status(struct msmsdcc_host *host, char *hdr, uint32_t status)
San Mehat865c8062009-11-13 13:42:06 -0800140{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700141 int i;
San Mehat8b1c2ba2009-11-16 10:17:30 -0800142
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700143 pr_debug("%s-%s ", mmc_hostname(host->mmc), hdr);
144 for (i = 0; i < 32; i++) {
145 if (status & (1 << i))
146 pr_debug("%s ", irq_status_bits[i]);
San Mehat865c8062009-11-13 13:42:06 -0800147 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700148 pr_debug("\n");
San Mehatc7fc9372009-11-22 17:19:07 -0800149}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700150#endif
San Mehat865c8062009-11-13 13:42:06 -0800151
San Mehat9d2bd732009-09-22 16:44:22 -0700152static void
153msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
154 u32 c);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530155static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530156static inline void msmsdcc_delay(struct msmsdcc_host *host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530157static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -0800158static void msmsdcc_sg_start(struct msmsdcc_host *host);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -0800159static int msmsdcc_vreg_reset(struct msmsdcc_host *host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -0700160static int msmsdcc_runtime_resume(struct device *dev);
San Mehat9d2bd732009-09-22 16:44:22 -0700161
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530162static inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530163{
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530164 unsigned short ret = NR_SG;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530165
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530166 if (is_sps_mode(host)) {
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +0530167 ret = SPS_MAX_DESCS;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530168 } else { /* DMA or PIO mode */
169 if (NR_SG > MAX_NR_SG_DMA_PIO)
170 ret = MAX_NR_SG_DMA_PIO;
171 }
172
173 return ret;
174}
175
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530176/* Prevent idle power collapse(pc) while operating in peripheral mode */
177static void msmsdcc_pm_qos_update_latency(struct msmsdcc_host *host, int vote)
178{
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -0700179 if (!host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530180 return;
181
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530182 if (vote)
183 pm_qos_update_request(&host->pm_qos_req_dma,
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -0700184 host->cpu_dma_latency);
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530185 else
186 pm_qos_update_request(&host->pm_qos_req_dma,
187 PM_QOS_DEFAULT_VALUE);
188}
189
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700190#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
191static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
192 struct msmsdcc_sps_ep_conn_data *ep);
193static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
194 struct msmsdcc_sps_ep_conn_data *ep);
195#else
196static inline int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
197 struct msmsdcc_sps_ep_conn_data *ep,
198 bool is_producer) { return 0; }
199static inline void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
200 struct msmsdcc_sps_ep_conn_data *ep) { }
201static inline int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
202 struct msmsdcc_sps_ep_conn_data *ep)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530203{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700204 return 0;
205}
206static inline int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
207 struct msmsdcc_sps_ep_conn_data *ep)
208{
209 return 0;
210}
211static inline int msmsdcc_sps_init(struct msmsdcc_host *host) { return 0; }
212static inline void msmsdcc_sps_exit(struct msmsdcc_host *host) {}
213#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530214
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700215/**
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530216 * Apply soft reset to all SDCC BAM pipes
217 *
218 * This function applies soft reset to SDCC BAM pipe.
219 *
220 * This function should be called to recover from error
221 * conditions encountered during CMD/DATA tranfsers with card.
222 *
223 * @host - Pointer to driver's host structure
224 *
225 */
226static void msmsdcc_sps_pipes_reset_and_restore(struct msmsdcc_host *host)
227{
228 int rc;
229
230 /* Reset all SDCC BAM pipes */
231 rc = msmsdcc_sps_reset_ep(host, &host->sps.prod);
232 if (rc)
233 pr_err("%s:msmsdcc_sps_reset_ep(prod) error=%d\n",
234 mmc_hostname(host->mmc), rc);
235 rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
236 if (rc)
237 pr_err("%s:msmsdcc_sps_reset_ep(cons) error=%d\n",
238 mmc_hostname(host->mmc), rc);
239
Krishna Konda5af8f972012-05-14 16:15:24 -0700240 if (host->sps.reset_device) {
241 rc = sps_device_reset(host->sps.bam_handle);
242 if (rc)
243 pr_err("%s: sps_device_reset error=%d\n",
244 mmc_hostname(host->mmc), rc);
245 host->sps.reset_device = false;
246 }
247
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530248 /* Restore all BAM pipes connections */
249 rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
250 if (rc)
251 pr_err("%s:msmsdcc_sps_restore_ep(prod) error=%d\n",
252 mmc_hostname(host->mmc), rc);
253 rc = msmsdcc_sps_restore_ep(host, &host->sps.cons);
254 if (rc)
255 pr_err("%s:msmsdcc_sps_restore_ep(cons) error=%d\n",
256 mmc_hostname(host->mmc), rc);
257}
258
259/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700260 * Apply soft reset
261 *
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530262 * This function applies soft reset to SDCC core and DML core.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700263 *
264 * This function should be called to recover from error
265 * conditions encountered with CMD/DATA tranfsers with card.
266 *
267 * Soft reset should only be used with SDCC controller v4.
268 *
269 * @host - Pointer to driver's host structure
270 *
271 */
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530272static void msmsdcc_soft_reset(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700273{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700274 /*
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530275 * Reset controller state machines without resetting
276 * configuration registers (MCI_POWER, MCI_CLK, MCI_INT_MASKn).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700277 */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530278 if (is_sw_reset_save_config(host)) {
279 ktime_t start;
280
281 writel_relaxed(readl_relaxed(host->base + MMCIPOWER)
282 | MCI_SW_RST_CFG, host->base + MMCIPOWER);
283 msmsdcc_sync_reg_wr(host);
284
285 start = ktime_get();
286 while (readl_relaxed(host->base + MMCIPOWER) & MCI_SW_RST_CFG) {
287 /*
288 * SW reset can take upto 10HCLK + 15MCLK cycles.
289 * Calculating based on min clk rates (hclk = 27MHz,
290 * mclk = 400KHz) it comes to ~40us. Let's poll for
291 * max. 1ms for reset completion.
292 */
293 if (ktime_to_us(ktime_sub(ktime_get(), start)) > 1000) {
294 pr_err("%s: %s failed\n",
295 mmc_hostname(host->mmc), __func__);
296 BUG();
297 }
298 }
299 } else {
300 writel_relaxed(0, host->base + MMCICOMMAND);
301 msmsdcc_sync_reg_wr(host);
302 writel_relaxed(0, host->base + MMCIDATACTRL);
303 msmsdcc_sync_reg_wr(host);
304 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530305}
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530306
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530307static void msmsdcc_hard_reset(struct msmsdcc_host *host)
308{
309 int ret;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530310
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530311 /*
312 * Reset SDCC controller to power on default state.
313 * Don't issue a reset request to clock control block if
314 * SDCC controller itself can support hard reset.
315 */
316 if (is_sw_hard_reset(host)) {
317 ktime_t start;
318
319 writel_relaxed(readl_relaxed(host->base + MMCIPOWER)
320 | MCI_SW_RST, host->base + MMCIPOWER);
321 msmsdcc_sync_reg_wr(host);
322
323 start = ktime_get();
324 while (readl_relaxed(host->base + MMCIPOWER) & MCI_SW_RST) {
325 /*
326 * See comment in msmsdcc_soft_reset() on choosing 1ms
327 * poll timeout.
328 */
329 if (ktime_to_us(ktime_sub(ktime_get(), start)) > 1000) {
330 pr_err("%s: %s failed\n",
331 mmc_hostname(host->mmc), __func__);
332 BUG();
333 }
334 }
335 } else {
336 ret = clk_reset(host->clk, CLK_RESET_ASSERT);
337 if (ret)
338 pr_err("%s: Clock assert failed at %u Hz" \
339 " with err %d\n", mmc_hostname(host->mmc),
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530340 host->clk_rate, ret);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530341
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530342 ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
343 if (ret)
344 pr_err("%s: Clock deassert failed at %u Hz" \
345 " with err %d\n", mmc_hostname(host->mmc),
346 host->clk_rate, ret);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530347
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530348 mb();
349 /* Give some delay for clock reset to propogate to controller */
350 msmsdcc_delay(host);
351 }
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530352}
353
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700354static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
355{
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530356 if (is_soft_reset(host)) {
357 if (is_sps_mode(host)) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530358 /* Reset DML first */
359 msmsdcc_dml_reset(host);
360 /*
361 * delay the SPS pipe reset in thread context as
362 * sps_connect/sps_disconnect APIs can be called
363 * only from non-atomic context.
364 */
365 host->sps.pipe_reset_pending = true;
366 }
367 mb();
368 msmsdcc_soft_reset(host);
369
370 pr_debug("%s: Applied soft reset to Controller\n",
371 mmc_hostname(host->mmc));
372
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530373 if (is_sps_mode(host))
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530374 msmsdcc_dml_init(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700375 } else {
376 /* Give Clock reset (hard reset) to controller */
377 u32 mci_clk = 0;
378 u32 mci_mask0 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700379
380 /* Save the controller state */
381 mci_clk = readl_relaxed(host->base + MMCICLOCK);
382 mci_mask0 = readl_relaxed(host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +0530383 host->pwr = readl_relaxed(host->base + MMCIPOWER);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700384 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700385
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530386 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700387 pr_debug("%s: Controller has been reinitialized\n",
388 mmc_hostname(host->mmc));
389
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700390 /* Restore the contoller state */
391 writel_relaxed(host->pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530392 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700393 writel_relaxed(mci_clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530394 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700395 writel_relaxed(mci_mask0, host->base + MMCIMASK0);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530396 mb(); /* no delay required after writing to MASK0 register */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700397 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530398
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700399 if (host->dummy_52_needed)
400 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700401}
402
403static int
San Mehat9d2bd732009-09-22 16:44:22 -0700404msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
405{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700406 int retval = 0;
407
San Mehat9d2bd732009-09-22 16:44:22 -0700408 BUG_ON(host->curr.data);
409
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700410 del_timer(&host->req_tout_timer);
San Mehat9d2bd732009-09-22 16:44:22 -0700411
412 if (mrq->data)
413 mrq->data->bytes_xfered = host->curr.data_xfered;
414 if (mrq->cmd->error == -ETIMEDOUT)
415 mdelay(5);
416
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530417 /* Clear current request information as current request has ended */
418 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
419
San Mehat9d2bd732009-09-22 16:44:22 -0700420 /*
421 * Need to drop the host lock here; mmc_request_done may call
422 * back into the driver...
423 */
424 spin_unlock(&host->lock);
425 mmc_request_done(host->mmc, mrq);
426 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700427
428 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700429}
430
431static void
432msmsdcc_stop_data(struct msmsdcc_host *host)
433{
San Mehat9d2bd732009-09-22 16:44:22 -0700434 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530435 host->curr.got_dataend = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +0530436 host->curr.wait_for_auto_prog_done = false;
437 host->curr.got_auto_prog_done = false;
Krishna Konda9d1679c2012-06-04 22:44:28 -0700438 writel_relaxed(0, host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530439 msmsdcc_sync_reg_wr(host); /* Allow the DPSM to be reset */
San Mehat9d2bd732009-09-22 16:44:22 -0700440}
441
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700442static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700443{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700444 return host->core_memres->start + MMCIFIFO;
445}
446
447static inline unsigned int msmsdcc_get_min_sup_clk_rate(
448 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530449
Subhash Jadavanidd432952012-03-28 11:25:56 +0530450static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700451{
452 mb();
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530453 if (!is_wait_for_reg_write(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +0530454 udelay(host->reg_write_delay);
455 else if (readl_relaxed(host->base + MCI_STATUS2) &
456 MCI_MCLK_REG_WR_ACTIVE) {
457 ktime_t start, diff;
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530458
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530459 start = ktime_get();
460 while (readl_relaxed(host->base + MCI_STATUS2) &
461 MCI_MCLK_REG_WR_ACTIVE) {
462 diff = ktime_sub(ktime_get(), start);
463 /* poll for max. 1 ms */
464 if (ktime_to_us(diff) > 1000) {
465 pr_warning("%s: previous reg. write is"
466 " still active\n",
467 mmc_hostname(host->mmc));
468 break;
469 }
470 }
471 }
San Mehat9d2bd732009-09-22 16:44:22 -0700472}
473
Subhash Jadavanidd432952012-03-28 11:25:56 +0530474static inline void msmsdcc_delay(struct msmsdcc_host *host)
475{
476 udelay(host->reg_write_delay);
477
San Mehat9d2bd732009-09-22 16:44:22 -0700478}
479
San Mehat56a8b5b2009-11-21 12:29:46 -0800480static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700481msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
482{
483 writel_relaxed(arg, host->base + MMCIARGUMENT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700484 writel_relaxed(c, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530485 /*
486 * As after sending the command, we don't write any of the
487 * controller registers and just wait for the
488 * CMD_RESPOND_END/CMD_SENT/Command failure notication
489 * from Controller.
490 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700491 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800492}
493
494static void
495msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
496{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700497 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800498
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700499 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
500 writel_relaxed((unsigned int)host->curr.xfer_size,
501 host->base + MMCIDATALENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700502 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530503 msmsdcc_sync_reg_wr(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800504
San Mehat6ac9ea62009-12-02 17:24:58 -0800505 if (host->cmd_cmd) {
506 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700507 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800508 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800509}
510
San Mehat9d2bd732009-09-22 16:44:22 -0700511static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530512msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700513{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530514 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700515 unsigned long flags;
516 struct mmc_request *mrq;
517
518 spin_lock_irqsave(&host->lock, flags);
519 mrq = host->curr.mrq;
520 BUG_ON(!mrq);
521
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530522 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700523 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700524 goto out;
525 }
526
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530527 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700528 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700529 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700530 } else {
531 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530532 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700533 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530534 mmc_hostname(host->mmc), host->dma.result);
535 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700536 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530537 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530538 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700539 host->dma.err.flush[0], host->dma.err.flush[1],
540 host->dma.err.flush[2], host->dma.err.flush[3],
541 host->dma.err.flush[4],
542 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530543 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700544 if (!mrq->data->error)
545 mrq->data->error = -EIO;
546 }
Asutosh Dasaccacd42012-03-08 14:33:17 +0530547 if (!mrq->data->host_cookie)
548 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
549 host->dma.num_ents, host->dma.dir);
San Mehat9d2bd732009-09-22 16:44:22 -0700550
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700551 if (host->curr.user_pages) {
552 struct scatterlist *sg = host->dma.sg;
553 int i;
554
555 for (i = 0; i < host->dma.num_ents; i++, sg++)
556 flush_dcache_page(sg_page(sg));
557 }
San Mehat9d2bd732009-09-22 16:44:22 -0700558
San Mehat9d2bd732009-09-22 16:44:22 -0700559 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800560 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700561
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530562 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
563 (host->curr.wait_for_auto_prog_done &&
564 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700565 /*
566 * If we've already gotten our DATAEND / DATABLKEND
567 * for this request, then complete it through here.
568 */
San Mehat9d2bd732009-09-22 16:44:22 -0700569
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700570 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700571 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700572 host->curr.xfer_remain -= host->curr.xfer_size;
573 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700574 if (host->dummy_52_needed) {
San Mehat9d2bd732009-09-22 16:44:22 -0700575 mrq->data->bytes_xfered = host->curr.data_xfered;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700576 host->dummy_52_sent = 1;
577 msmsdcc_start_command(host, &dummy52cmd,
578 MCI_CPSM_PROGENA);
579 goto out;
580 }
581 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530582 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530583 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700584 mrq->data->bytes_xfered = host->curr.data_xfered;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700585 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530586 /*
587 * Clear current request information as current
588 * request has ended
589 */
590 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
San Mehat9d2bd732009-09-22 16:44:22 -0700591 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700592
San Mehat9d2bd732009-09-22 16:44:22 -0700593 mmc_request_done(host->mmc, mrq);
594 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530595 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
596 || !mrq->sbc)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700597 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530598 }
San Mehat9d2bd732009-09-22 16:44:22 -0700599 }
600
601out:
602 spin_unlock_irqrestore(&host->lock, flags);
603 return;
604}
605
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700606#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
607/**
608 * Callback notification from SPS driver
609 *
610 * This callback function gets triggered called from
611 * SPS driver when requested SPS data transfer is
612 * completed.
613 *
614 * SPS driver invokes this callback in BAM irq context so
615 * SDCC driver schedule a tasklet for further processing
616 * this callback notification at later point of time in
617 * tasklet context and immediately returns control back
618 * to SPS driver.
619 *
620 * @nofity - Pointer to sps event notify sturcture
621 *
622 */
623static void
624msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
625{
626 struct msmsdcc_host *host =
627 (struct msmsdcc_host *)
628 ((struct sps_event_notify *)notify)->user;
629
630 host->sps.notify = *notify;
631 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
632 mmc_hostname(host->mmc), __func__, notify->event_id,
633 notify->data.transfer.iovec.addr,
634 notify->data.transfer.iovec.size,
635 notify->data.transfer.iovec.flags);
636 /* Schedule a tasklet for completing data transfer */
637 tasklet_schedule(&host->sps.tlet);
638}
639
640/**
641 * Tasklet handler for processing SPS callback event
642 *
643 * This function processing SPS event notification and
644 * checks if the SPS transfer is completed or not and
645 * then accordingly notifies status to MMC core layer.
646 *
647 * This function is called in tasklet context.
648 *
649 * @data - Pointer to sdcc driver data
650 *
651 */
652static void msmsdcc_sps_complete_tlet(unsigned long data)
653{
654 unsigned long flags;
655 int i, rc;
656 u32 data_xfered = 0;
657 struct mmc_request *mrq;
658 struct sps_iovec iovec;
659 struct sps_pipe *sps_pipe_handle;
660 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
661 struct sps_event_notify *notify = &host->sps.notify;
662
663 spin_lock_irqsave(&host->lock, flags);
664 if (host->sps.dir == DMA_FROM_DEVICE)
665 sps_pipe_handle = host->sps.prod.pipe_handle;
666 else
667 sps_pipe_handle = host->sps.cons.pipe_handle;
668 mrq = host->curr.mrq;
669
670 if (!mrq) {
671 spin_unlock_irqrestore(&host->lock, flags);
672 return;
673 }
674
675 pr_debug("%s: %s: sps event_id=%d\n",
676 mmc_hostname(host->mmc), __func__,
677 notify->event_id);
678
679 if (msmsdcc_is_dml_busy(host)) {
680 /* oops !!! this should never happen. */
681 pr_err("%s: %s: Received SPS EOT event"
682 " but DML HW is still busy !!!\n",
683 mmc_hostname(host->mmc), __func__);
684 }
685 /*
686 * Got End of transfer event!!! Check if all of the data
687 * has been transferred?
688 */
689 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
690 rc = sps_get_iovec(sps_pipe_handle, &iovec);
691 if (rc) {
692 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
693 mmc_hostname(host->mmc), __func__, rc, i);
694 break;
695 }
696 data_xfered += iovec.size;
697 }
698
699 if (data_xfered == host->curr.xfer_size) {
700 host->curr.data_xfered = host->curr.xfer_size;
701 host->curr.xfer_remain -= host->curr.xfer_size;
702 pr_debug("%s: Data xfer success. data_xfered=0x%x",
703 mmc_hostname(host->mmc),
704 host->curr.xfer_size);
705 } else {
706 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
707 " xfer_size=%d", mmc_hostname(host->mmc),
708 data_xfered, host->curr.xfer_size);
709 msmsdcc_reset_and_restore(host);
710 if (!mrq->data->error)
711 mrq->data->error = -EIO;
712 }
713
714 /* Unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +0530715 if (!mrq->data->host_cookie)
716 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
717 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700718 host->sps.sg = NULL;
719 host->sps.busy = 0;
720
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530721 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
722 (host->curr.wait_for_auto_prog_done &&
723 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700724 /*
725 * If we've already gotten our DATAEND / DATABLKEND
726 * for this request, then complete it through here.
727 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700728
729 if (!mrq->data->error) {
730 host->curr.data_xfered = host->curr.xfer_size;
731 host->curr.xfer_remain -= host->curr.xfer_size;
732 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700733 if (host->dummy_52_needed) {
734 mrq->data->bytes_xfered = host->curr.data_xfered;
735 host->dummy_52_sent = 1;
736 msmsdcc_start_command(host, &dummy52cmd,
737 MCI_CPSM_PROGENA);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700738 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700739 return;
740 }
741 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530742 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530743 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700744 mrq->data->bytes_xfered = host->curr.data_xfered;
745 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530746 /*
747 * Clear current request information as current
748 * request has ended
749 */
750 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700751 spin_unlock_irqrestore(&host->lock, flags);
752
753 mmc_request_done(host->mmc, mrq);
754 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530755 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
756 || !mrq->sbc)) {
757 msmsdcc_start_command(host, mrq->data->stop, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700758 }
759 }
760 spin_unlock_irqrestore(&host->lock, flags);
761}
762
763/**
764 * Exit from current SPS data transfer
765 *
766 * This function exits from current SPS data transfer.
767 *
768 * This function should be called when error condition
769 * is encountered during data transfer.
770 *
771 * @host - Pointer to sdcc host structure
772 *
773 */
774static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
775{
776 struct mmc_request *mrq;
777
778 mrq = host->curr.mrq;
779 BUG_ON(!mrq);
780
781 msmsdcc_reset_and_restore(host);
782 if (!mrq->data->error)
783 mrq->data->error = -EIO;
784
785 /* Unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +0530786 if (!mrq->data->host_cookie)
787 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
788 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700789
790 host->sps.sg = NULL;
791 host->sps.busy = 0;
792 if (host->curr.data)
793 msmsdcc_stop_data(host);
794
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530795 if (!mrq->data->stop || mrq->cmd->error ||
796 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700797 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530798 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
799 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700800 msmsdcc_start_command(host, mrq->data->stop, 0);
801
802}
803#else
804static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
805static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
806static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
807#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
808
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530809static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700810
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530811static void
812msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
813 unsigned int result,
814 struct msm_dmov_errdata *err)
815{
816 struct msmsdcc_dma_data *dma_data =
817 container_of(cmd, struct msmsdcc_dma_data, hdr);
818 struct msmsdcc_host *host = dma_data->host;
819
820 dma_data->result = result;
821 if (err)
822 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
823
824 tasklet_schedule(&host->dma_tlet);
825}
826
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530827static bool msmsdcc_is_dma_possible(struct msmsdcc_host *host,
828 struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700829{
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530830 bool ret = true;
831 u32 xfer_size = data->blksz * data->blocks;
San Mehat9d2bd732009-09-22 16:44:22 -0700832
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530833 if (is_sps_mode(host)) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530834 /*
835 * BAM Mode: Fall back on PIO if size is less
836 * than or equal to SPS_MIN_XFER_SIZE bytes.
837 */
838 if (xfer_size <= SPS_MIN_XFER_SIZE)
839 ret = false;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530840 } else if (is_dma_mode(host)) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530841 /*
842 * ADM Mode: Fall back on PIO if size is less than FIFO size
843 * or not integer multiple of FIFO size
844 */
845 if (xfer_size % MCI_FIFOSIZE)
846 ret = false;
847 } else {
848 /* PIO Mode */
849 ret = false;
850 }
851
852 return ret;
San Mehat9d2bd732009-09-22 16:44:22 -0700853}
854
855static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
856{
857 struct msmsdcc_nc_dmadata *nc;
858 dmov_box *box;
859 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700860 unsigned int n;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530861 int i, err = 0, box_cmd_cnt = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700862 struct scatterlist *sg = data->sg;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530863 unsigned int len, offset;
San Mehat9d2bd732009-09-22 16:44:22 -0700864
Krishna Konda25786ec2011-07-25 16:21:36 -0700865 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700866 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700867
Krishna Konda25786ec2011-07-25 16:21:36 -0700868 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
San Mehat9d2bd732009-09-22 16:44:22 -0700869
870 host->dma.sg = data->sg;
871 host->dma.num_ents = data->sg_len;
872
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530873 /* Prevent memory corruption */
874 BUG_ON(host->dma.num_ents > msmsdcc_get_nr_sg(host));
San Mehat56a8b5b2009-11-21 12:29:46 -0800875
San Mehat9d2bd732009-09-22 16:44:22 -0700876 nc = host->dma.nc;
877
San Mehat9d2bd732009-09-22 16:44:22 -0700878 if (data->flags & MMC_DATA_READ)
879 host->dma.dir = DMA_FROM_DEVICE;
880 else
881 host->dma.dir = DMA_TO_DEVICE;
882
Asutosh Dasaccacd42012-03-08 14:33:17 +0530883 if (!data->host_cookie) {
884 n = msmsdcc_prep_xfer(host, data);
885 if (unlikely(n < 0)) {
886 host->dma.sg = NULL;
887 host->dma.num_ents = 0;
888 return -ENOMEM;
889 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800890 }
San Mehat9d2bd732009-09-22 16:44:22 -0700891
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530892 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
893 host->curr.user_pages = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700894 box = &nc->cmd[0];
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530895 for (i = 0; i < host->dma.num_ents; i++) {
896 len = sg_dma_len(sg);
897 offset = 0;
898
899 do {
900 /* Check if we can do DMA */
901 if (!len || (box_cmd_cnt >= MMC_MAX_DMA_CMDS)) {
902 err = -ENOTSUPP;
903 goto unmap;
904 }
905
906 box->cmd = CMD_MODE_BOX;
907
908 if (len >= MMC_MAX_DMA_BOX_LENGTH) {
909 len = MMC_MAX_DMA_BOX_LENGTH;
910 len -= len % data->blksz;
911 }
912 rows = (len % MCI_FIFOSIZE) ?
913 (len / MCI_FIFOSIZE) + 1 :
914 (len / MCI_FIFOSIZE);
915
916 if (data->flags & MMC_DATA_READ) {
917 box->src_row_addr = msmsdcc_fifo_addr(host);
918 box->dst_row_addr = sg_dma_address(sg) + offset;
919 box->src_dst_len = (MCI_FIFOSIZE << 16) |
920 (MCI_FIFOSIZE);
921 box->row_offset = MCI_FIFOSIZE;
922 box->num_rows = rows * ((1 << 16) + 1);
923 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
924 } else {
925 box->src_row_addr = sg_dma_address(sg) + offset;
926 box->dst_row_addr = msmsdcc_fifo_addr(host);
927 box->src_dst_len = (MCI_FIFOSIZE << 16) |
928 (MCI_FIFOSIZE);
929 box->row_offset = (MCI_FIFOSIZE << 16);
930 box->num_rows = rows * ((1 << 16) + 1);
931 box->cmd |= CMD_DST_CRCI(host->dma.crci);
932 }
933
934 offset += len;
935 len = sg_dma_len(sg) - offset;
936 box++;
937 box_cmd_cnt++;
938 } while (len);
939 sg++;
940 }
941 /* Mark last command */
942 box--;
943 box->cmd |= CMD_LC;
San Mehat9d2bd732009-09-22 16:44:22 -0700944
945 /* location of command block must be 64 bit aligned */
946 BUG_ON(host->dma.cmd_busaddr & 0x07);
947
948 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
949 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
950 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
951 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
952
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530953 /* Flush all data to memory before starting dma */
954 mb();
955
956unmap:
957 if (err) {
Asutosh Dasaccacd42012-03-08 14:33:17 +0530958 if (!data->host_cookie)
959 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
960 host->dma.num_ents, host->dma.dir);
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530961 pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
962 mmc_hostname(host->mmc), err);
San Mehat9d2bd732009-09-22 16:44:22 -0700963 }
964
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530965 return err;
San Mehat9d2bd732009-09-22 16:44:22 -0700966}
967
Asutosh Dasaccacd42012-03-08 14:33:17 +0530968static int msmsdcc_prep_xfer(struct msmsdcc_host *host,
969 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -0800970{
Asutosh Dasaccacd42012-03-08 14:33:17 +0530971 int rc = 0;
972 unsigned int dir;
973
974 /* Prevent memory corruption */
975 BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
976
977 if (data->flags & MMC_DATA_READ)
978 dir = DMA_FROM_DEVICE;
979 else
980 dir = DMA_TO_DEVICE;
981
982 /* Make sg buffers DMA ready */
983 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
984 dir);
985
986 if (unlikely(rc != data->sg_len)) {
987 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
988 mmc_hostname(host->mmc), rc);
989 rc = -ENOMEM;
990 goto dma_map_err;
991 }
992
993 pr_debug("%s: %s: %s: sg_len=%d\n",
994 mmc_hostname(host->mmc), __func__,
995 dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
996 data->sg_len);
997
998 goto out;
999
1000dma_map_err:
1001 dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
1002 data->flags);
1003out:
1004 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07001005}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001006#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
1007/**
1008 * Submits data transfer request to SPS driver
1009 *
1010 * This function make sg (scatter gather) data buffers
1011 * DMA ready and then submits them to SPS driver for
1012 * transfer.
1013 *
1014 * @host - Pointer to sdcc host structure
1015 * @data - Pointer to mmc_data structure
1016 *
1017 * @return 0 if success else negative value
1018 */
1019static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
Asutosh Dasaccacd42012-03-08 14:33:17 +05301020 struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -07001021{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001022 int rc = 0;
1023 u32 flags;
1024 int i;
1025 u32 addr, len, data_cnt;
1026 struct scatterlist *sg = data->sg;
1027 struct sps_pipe *sps_pipe_handle;
1028
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001029 host->sps.sg = data->sg;
1030 host->sps.num_ents = data->sg_len;
1031 host->sps.xfer_req_cnt = 0;
1032 if (data->flags & MMC_DATA_READ) {
1033 host->sps.dir = DMA_FROM_DEVICE;
1034 sps_pipe_handle = host->sps.prod.pipe_handle;
1035 } else {
1036 host->sps.dir = DMA_TO_DEVICE;
1037 sps_pipe_handle = host->sps.cons.pipe_handle;
1038 }
1039
Asutosh Dasaccacd42012-03-08 14:33:17 +05301040 if (!data->host_cookie) {
1041 rc = msmsdcc_prep_xfer(host, data);
1042 if (unlikely(rc < 0)) {
1043 host->dma.sg = NULL;
1044 host->dma.num_ents = 0;
1045 goto out;
1046 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001047 }
1048
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001049 for (i = 0; i < data->sg_len; i++) {
1050 /*
1051 * Check if this is the last buffer to transfer?
1052 * If yes then set the INT and EOT flags.
1053 */
1054 len = sg_dma_len(sg);
1055 addr = sg_dma_address(sg);
1056 flags = 0;
1057 while (len > 0) {
1058 if (len > SPS_MAX_DESC_SIZE) {
1059 data_cnt = SPS_MAX_DESC_SIZE;
1060 } else {
1061 data_cnt = len;
1062 if (i == data->sg_len - 1)
1063 flags = SPS_IOVEC_FLAG_INT |
1064 SPS_IOVEC_FLAG_EOT;
1065 }
1066 rc = sps_transfer_one(sps_pipe_handle, addr,
1067 data_cnt, host, flags);
1068 if (rc) {
1069 pr_err("%s: sps_transfer_one() error! rc=%d,"
1070 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
1071 mmc_hostname(host->mmc), rc,
1072 (u32)sps_pipe_handle, (u32)sg, i);
1073 goto dma_map_err;
1074 }
1075 addr += data_cnt;
1076 len -= data_cnt;
1077 host->sps.xfer_req_cnt++;
1078 }
1079 sg++;
1080 }
1081 goto out;
1082
1083dma_map_err:
1084 /* unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +05301085 if (!data->host_cookie)
1086 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
1087 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001088out:
1089 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07001090}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001091#else
1092static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
1093 struct mmc_data *data) { return 0; }
1094#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -07001095
1096static void
San Mehat56a8b5b2009-11-21 12:29:46 -08001097msmsdcc_start_command_deferred(struct msmsdcc_host *host,
1098 struct mmc_command *cmd, u32 *c)
1099{
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301100 DBG(host, "op %02x arg %08x flags %08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001101 cmd->opcode, cmd->arg, cmd->flags);
1102
San Mehat56a8b5b2009-11-21 12:29:46 -08001103 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
1104
1105 if (cmd->flags & MMC_RSP_PRESENT) {
1106 if (cmd->flags & MMC_RSP_136)
1107 *c |= MCI_CPSM_LONGRSP;
1108 *c |= MCI_CPSM_RESPONSE;
1109 }
1110
1111 if (/*interrupt*/0)
1112 *c |= MCI_CPSM_INTERRUPT;
1113
Asutosh Das05049132012-05-09 12:38:15 +05301114 /* DAT_CMD bit should be set for all ADTC */
1115 if (mmc_cmd_type(cmd) == MMC_CMD_ADTC)
San Mehat56a8b5b2009-11-21 12:29:46 -08001116 *c |= MCI_CSPM_DATCMD;
1117
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001118 /* Check if AUTO CMD19 is required or not? */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301119 if (host->tuning_needed &&
1120 !(host->mmc->ios.timing == MMC_TIMING_MMC_HS200)) {
1121
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301122 /*
1123 * For open ended block read operation (without CMD23),
1124 * AUTO_CMD19 bit should be set while sending the READ command.
1125 * For close ended block read operation (with CMD23),
1126 * AUTO_CMD19 bit should be set while sending CMD23.
1127 */
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301128 if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
1129 host->curr.mrq->cmd->opcode ==
1130 MMC_READ_MULTIPLE_BLOCK) ||
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301131 (!host->curr.mrq->sbc &&
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301132 (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
1133 cmd->opcode == MMC_READ_MULTIPLE_BLOCK))) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301134 msmsdcc_enable_cdr_cm_sdc4_dll(host);
1135 *c |= MCI_CSPM_AUTO_CMD19;
1136 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001137 }
1138
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05301139 /* Clear CDR_EN bit for write operations */
1140 if (host->tuning_needed && cmd->mrq->data &&
1141 (cmd->mrq->data->flags & MMC_DATA_WRITE))
1142 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) &
1143 ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
1144
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301145 if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301146 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001147 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301148 }
1149
San Mehat56a8b5b2009-11-21 12:29:46 -08001150 if (cmd == cmd->mrq->stop)
1151 *c |= MCI_CSPM_MCIABORT;
1152
San Mehat56a8b5b2009-11-21 12:29:46 -08001153 if (host->curr.cmd != NULL) {
Girish K Sa3c76eb2011-10-11 11:44:09 +05301154 pr_err("%s: Overlapping command requests\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001155 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -08001156 }
1157 host->curr.cmd = cmd;
1158}
1159
1160static void
1161msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1162 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001163{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301164 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001165 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001166 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001167 unsigned int pio_irqmask = 0;
1168
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301169 BUG_ON(!data->sg);
1170 BUG_ON(!data->sg_len);
1171
San Mehat9d2bd732009-09-22 16:44:22 -07001172 host->curr.data = data;
1173 host->curr.xfer_size = data->blksz * data->blocks;
1174 host->curr.xfer_remain = host->curr.xfer_size;
1175 host->curr.data_xfered = 0;
1176 host->curr.got_dataend = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301177 host->curr.got_auto_prog_done = false;
San Mehat9d2bd732009-09-22 16:44:22 -07001178
San Mehat9d2bd732009-09-22 16:44:22 -07001179 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1180
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301181 if (host->curr.wait_for_auto_prog_done)
1182 datactrl |= MCI_AUTO_PROG_DONE;
San Mehat9d2bd732009-09-22 16:44:22 -07001183
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05301184 if (msmsdcc_is_dma_possible(host, data)) {
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301185 if (is_dma_mode(host) && !msmsdcc_config_dma(host, data)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001186 datactrl |= MCI_DPSM_DMAENABLE;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301187 } else if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001188 if (!msmsdcc_is_dml_busy(host)) {
1189 if (!msmsdcc_sps_start_xfer(host, data)) {
1190 /* Now kick start DML transfer */
1191 mb();
1192 msmsdcc_dml_start_xfer(host, data);
1193 datactrl |= MCI_DPSM_DMAENABLE;
1194 host->sps.busy = 1;
1195 }
1196 } else {
1197 /*
1198 * Can't proceed with new transfer as
1199 * previous trasnfer is already in progress.
1200 * There is no point of going into PIO mode
1201 * as well. Is this a time to do kernel panic?
1202 */
1203 pr_err("%s: %s: DML HW is busy!!!"
1204 " Can't perform new SPS transfers"
1205 " now\n", mmc_hostname(host->mmc),
1206 __func__);
1207 }
1208 }
1209 }
1210
1211 /* Is data transfer in PIO mode required? */
1212 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001213 if (data->flags & MMC_DATA_READ) {
1214 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1215 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1216 pio_irqmask |= MCI_RXDATAAVLBLMASK;
1217 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001218 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1219 MCI_TXFIFOEMPTYMASK;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001220
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001221 msmsdcc_sg_start(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001222 }
1223
1224 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301225 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
Subhash Jadavanif5277752011-10-12 16:47:52 +05301226 else if (host->curr.use_wr_data_pend)
1227 datactrl |= MCI_DATA_PEND;
San Mehat9d2bd732009-09-22 16:44:22 -07001228
San Mehat56a8b5b2009-11-21 12:29:46 -08001229 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001230 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001231 timeout = data->timeout_clks + (unsigned int)clks*2 ;
Subhash Jadavani63540362012-06-12 14:56:04 +05301232 WARN(!timeout,
1233 "%s: data timeout is zero. timeout_ns=0x%x, timeout_clks=0x%x\n",
1234 mmc_hostname(host->mmc), data->timeout_ns, data->timeout_clks);
San Mehat9d2bd732009-09-22 16:44:22 -07001235
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301236 if (is_dma_mode(host) && (datactrl & MCI_DPSM_DMAENABLE)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001237 /* Use ADM (Application Data Mover) HW for Data transfer */
1238 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001239 host->cmd_timeout = timeout;
1240 host->cmd_pio_irqmask = pio_irqmask;
1241 host->cmd_datactrl = datactrl;
1242 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001243
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001244 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1245 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001246 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001247
1248 if (cmd) {
1249 msmsdcc_start_command_deferred(host, cmd, &c);
1250 host->cmd_c = c;
1251 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001252 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1253 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1254 host->base + MMCIMASK0);
1255 mb();
1256 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001257 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001258 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001259 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001260
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001261 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001262
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001263 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1264 (~(MCI_IRQ_PIO))) | pio_irqmask,
1265 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001266 writel_relaxed(datactrl, base + MMCIDATACTRL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001267
1268 if (cmd) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05301269 /* Delay between data/command */
1270 msmsdcc_sync_reg_wr(host);
San Mehat56a8b5b2009-11-21 12:29:46 -08001271 /* Daisy-chain the command if requested */
1272 msmsdcc_start_command(host, cmd, c);
Subhash Jadavanidd432952012-03-28 11:25:56 +05301273 } else {
1274 /*
1275 * We don't need delay after writing to DATA_CTRL
1276 * register if we are not writing to CMD register
1277 * immediately after this. As we already have delay
1278 * before sending the command, we just need mb() here.
1279 */
1280 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001281 }
San Mehat9d2bd732009-09-22 16:44:22 -07001282 }
1283}
1284
1285static void
1286msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1287{
San Mehat56a8b5b2009-11-21 12:29:46 -08001288 msmsdcc_start_command_deferred(host, cmd, &c);
1289 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001290}
1291
1292static void
1293msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1294 unsigned int status)
1295{
1296 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001297 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
Subhash Jadavanib30c9822012-03-27 18:03:16 +05301298 || data->mrq->cmd->opcode == MMC_BUS_TEST_R
1299 || data->mrq->cmd->opcode ==
1300 MMC_SEND_TUNING_BLOCK_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001301 pr_err("%s: Data CRC error\n",
1302 mmc_hostname(host->mmc));
1303 pr_err("%s: opcode 0x%.8x\n", __func__,
1304 data->mrq->cmd->opcode);
1305 pr_err("%s: blksz %d, blocks %d\n", __func__,
1306 data->blksz, data->blocks);
1307 data->error = -EILSEQ;
1308 }
San Mehat9d2bd732009-09-22 16:44:22 -07001309 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001310 /* CRC is optional for the bus test commands, not all
1311 * cards respond back with CRC. However controller
1312 * waits for the CRC and times out. Hence ignore the
1313 * data timeouts during the Bustest.
1314 */
1315 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1316 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301317 pr_err("%s: CMD%d: Data timeout\n",
1318 mmc_hostname(host->mmc),
1319 data->mrq->cmd->opcode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001320 data->error = -ETIMEDOUT;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301321 msmsdcc_dump_sdcc_state(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001322 }
San Mehat9d2bd732009-09-22 16:44:22 -07001323 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001324 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001325 data->error = -EIO;
1326 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001327 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001328 data->error = -EIO;
1329 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001330 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001331 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001332 data->error = -EIO;
1333 }
San Mehat9d2bd732009-09-22 16:44:22 -07001334
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001335 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001336 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001337 host->dummy_52_needed = 0;
1338}
San Mehat9d2bd732009-09-22 16:44:22 -07001339
1340static int
1341msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1342{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001343 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001344 uint32_t *ptr = (uint32_t *) buffer;
1345 int count = 0;
1346
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301347 if (remain % 4)
1348 remain = ((remain >> 2) + 1) << 2;
1349
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001350 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1351
1352 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001353 ptr++;
1354 count += sizeof(uint32_t);
1355
1356 remain -= sizeof(uint32_t);
1357 if (remain == 0)
1358 break;
1359 }
1360 return count;
1361}
1362
1363static int
1364msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001365 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001366{
1367 void __iomem *base = host->base;
1368 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001369 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001370
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001371 while (readl_relaxed(base + MMCISTATUS) &
1372 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1373 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001374
San Mehat9d2bd732009-09-22 16:44:22 -07001375 count = min(remain, maxcnt);
1376
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301377 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1378 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001379 ptr += count;
1380 remain -= count;
1381
1382 if (remain == 0)
1383 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001384 }
1385 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001386
1387 return ptr - buffer;
1388}
1389
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001390/*
1391 * Copy up to a word (4 bytes) between a scatterlist
1392 * and a temporary bounce buffer when the word lies across
1393 * two pages. The temporary buffer can then be read to/
1394 * written from the FIFO once.
1395 */
1396static void _msmsdcc_sg_consume_word(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -07001397{
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001398 struct msmsdcc_pio_data *pio = &host->pio;
1399 unsigned int bytes_avail;
1400
1401 if (host->curr.data->flags & MMC_DATA_READ)
1402 memcpy(pio->sg_miter.addr, pio->bounce_buf,
1403 pio->bounce_buf_len);
1404 else
1405 memcpy(pio->bounce_buf, pio->sg_miter.addr,
1406 pio->bounce_buf_len);
1407
1408 while (pio->bounce_buf_len != 4) {
1409 if (!sg_miter_next(&pio->sg_miter))
1410 break;
1411 bytes_avail = min_t(unsigned int, pio->sg_miter.length,
1412 4 - pio->bounce_buf_len);
1413 if (host->curr.data->flags & MMC_DATA_READ)
1414 memcpy(pio->sg_miter.addr,
1415 &pio->bounce_buf[pio->bounce_buf_len],
1416 bytes_avail);
1417 else
1418 memcpy(&pio->bounce_buf[pio->bounce_buf_len],
1419 pio->sg_miter.addr, bytes_avail);
1420
1421 pio->sg_miter.consumed = bytes_avail;
1422 pio->bounce_buf_len += bytes_avail;
San Mehat9d2bd732009-09-22 16:44:22 -07001423 }
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001424}
1425
1426/*
1427 * Use sg_miter_next to return as many 4-byte aligned
1428 * chunks as possible, using a temporary 4 byte buffer
1429 * for alignment if necessary
1430 */
1431static int msmsdcc_sg_next(struct msmsdcc_host *host, char **buf, int *len)
1432{
1433 struct msmsdcc_pio_data *pio = &host->pio;
1434 unsigned int length, rlength;
1435 char *buffer;
1436
1437 if (!sg_miter_next(&pio->sg_miter))
1438 return 0;
1439
1440 buffer = pio->sg_miter.addr;
1441 length = pio->sg_miter.length;
1442
1443 if (length < host->curr.xfer_remain) {
1444 rlength = round_down(length, 4);
1445 if (rlength) {
1446 /*
1447 * We have a 4-byte aligned chunk.
1448 * The rounding will be reflected by
1449 * a call to msmsdcc_sg_consumed
1450 */
1451 length = rlength;
1452 goto sg_next_end;
1453 }
1454 /*
1455 * We have a length less than 4 bytes. Check to
1456 * see if more buffer is available, and combine
1457 * to make 4 bytes if possible.
1458 */
1459 pio->bounce_buf_len = length;
1460 memset(pio->bounce_buf, 0, 4);
1461
1462 /*
1463 * On a read, get 4 bytes from FIFO, and distribute
1464 * (4-bouce_buf_len) bytes into consecutive
1465 * sgl buffers when msmsdcc_sg_consumed is called
1466 */
1467 if (host->curr.data->flags & MMC_DATA_READ) {
1468 buffer = pio->bounce_buf;
1469 length = 4;
1470 goto sg_next_end;
1471 } else {
1472 _msmsdcc_sg_consume_word(host);
1473 buffer = pio->bounce_buf;
1474 length = pio->bounce_buf_len;
1475 }
1476 }
1477
1478sg_next_end:
1479 *buf = buffer;
1480 *len = length;
1481 return 1;
1482}
1483
1484/*
1485 * Update sg_miter.consumed based on how many bytes were
1486 * consumed. If the bounce buffer was used to read from FIFO,
1487 * redistribute into sgls.
1488 */
1489static void msmsdcc_sg_consumed(struct msmsdcc_host *host,
1490 unsigned int length)
1491{
1492 struct msmsdcc_pio_data *pio = &host->pio;
1493
1494 if (host->curr.data->flags & MMC_DATA_READ) {
1495 if (length > pio->sg_miter.consumed)
1496 /*
1497 * consumed 4 bytes, but sgl
1498 * describes < 4 bytes
1499 */
1500 _msmsdcc_sg_consume_word(host);
1501 else
1502 pio->sg_miter.consumed = length;
1503 } else
1504 if (length < pio->sg_miter.consumed)
1505 pio->sg_miter.consumed = length;
1506}
1507
1508static void msmsdcc_sg_start(struct msmsdcc_host *host)
1509{
1510 unsigned int sg_miter_flags = SG_MITER_ATOMIC;
1511
1512 host->pio.bounce_buf_len = 0;
1513
1514 if (host->curr.data->flags & MMC_DATA_READ)
1515 sg_miter_flags |= SG_MITER_TO_SG;
1516 else
1517 sg_miter_flags |= SG_MITER_FROM_SG;
1518
1519 sg_miter_start(&host->pio.sg_miter, host->curr.data->sg,
1520 host->curr.data->sg_len, sg_miter_flags);
1521}
1522
1523static void msmsdcc_sg_stop(struct msmsdcc_host *host)
1524{
1525 sg_miter_stop(&host->pio.sg_miter);
San Mehat9d2bd732009-09-22 16:44:22 -07001526}
1527
San Mehat1cd22962010-02-03 12:59:29 -08001528static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001529msmsdcc_pio_irq(int irq, void *dev_id)
1530{
1531 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001532 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001533 uint32_t status;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001534 unsigned long flags;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001535 unsigned int remain;
1536 char *buffer;
San Mehat9d2bd732009-09-22 16:44:22 -07001537
Murali Palnati36448a42011-09-02 15:06:18 +05301538 spin_lock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301539
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001540 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001541
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001542 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301543 (MCI_IRQ_PIO)) == 0) {
1544 spin_unlock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301545 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301546 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001547#if IRQ_DEBUG
1548 msmsdcc_print_status(host, "irq1-r", status);
1549#endif
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001550 local_irq_save(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001551
1552 do {
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001553 unsigned int len;
San Mehat9d2bd732009-09-22 16:44:22 -07001554
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001555 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1556 | MCI_RXDATAAVLBL)))
1557 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001558
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001559 if (!msmsdcc_sg_next(host, &buffer, &remain))
1560 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001561
San Mehat9d2bd732009-09-22 16:44:22 -07001562 len = 0;
1563 if (status & MCI_RXACTIVE)
1564 len = msmsdcc_pio_read(host, buffer, remain);
1565 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001566 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001567
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301568 /* len might have aligned to 32bits above */
1569 if (len > remain)
1570 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001571
San Mehat9d2bd732009-09-22 16:44:22 -07001572 host->curr.xfer_remain -= len;
1573 host->curr.data_xfered += len;
1574 remain -= len;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001575 msmsdcc_sg_consumed(host, len);
San Mehat9d2bd732009-09-22 16:44:22 -07001576
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001577 if (remain) /* Done with this page? */
1578 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001579
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001580 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001581 } while (1);
1582
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001583 msmsdcc_sg_stop(host);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001584 local_irq_restore(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001585
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001586 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1587 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1588 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1589 host->base + MMCIMASK0);
1590 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301591 /*
1592 * back to back write to MASK0 register don't need
1593 * synchronization delay.
1594 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001595 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1596 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1597 }
1598 mb();
1599 } else if (!host->curr.xfer_remain) {
1600 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1601 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1602 mb();
1603 }
San Mehat9d2bd732009-09-22 16:44:22 -07001604
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001605 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001606
1607 return IRQ_HANDLED;
1608}
1609
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001610static void
1611msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1612
1613static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1614 struct mmc_data *data)
1615{
1616 u32 loop_cnt = 0;
1617
1618 /*
1619 * For read commands with data less than fifo size, it is possible to
1620 * get DATAEND first and RXDATA_AVAIL might be set later because of
1621 * synchronization delay through the asynchronous RX FIFO. Thus, for
1622 * such cases, even after DATAEND interrupt is received software
1623 * should poll for RXDATA_AVAIL until the requested data is read out
1624 * of FIFO. This change is needed to get around this abnormal but
1625 * sometimes expected behavior of SDCC3 controller.
1626 *
1627 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1628 * after the data is loaded into RX FIFO. This would amount to less
1629 * than a microsecond and thus looping for 1000 times is good enough
1630 * for that delay.
1631 */
1632 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1633 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1634 spin_unlock(&host->lock);
1635 msmsdcc_pio_irq(1, host);
1636 spin_lock(&host->lock);
1637 }
1638 }
1639 if (loop_cnt == 1000) {
1640 pr_info("%s: Timed out while polling for Rx Data\n",
1641 mmc_hostname(host->mmc));
1642 data->error = -ETIMEDOUT;
1643 msmsdcc_reset_and_restore(host);
1644 }
1645}
1646
San Mehat9d2bd732009-09-22 16:44:22 -07001647static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1648{
1649 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001650
1651 host->curr.cmd = NULL;
subhashj8046ae12012-05-02 12:14:52 +05301652 if (mmc_resp_type(cmd))
1653 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1654 /*
1655 * Read rest of the response registers only if
1656 * long response is expected for this command
1657 */
1658 if (mmc_resp_type(cmd) & MMC_RSP_136) {
1659 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1660 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1661 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
1662 }
San Mehat9d2bd732009-09-22 16:44:22 -07001663
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001664 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301665 pr_debug("%s: CMD%d: Command timeout\n",
1666 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001667 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001668 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301669 !host->tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301670 pr_err("%s: CMD%d: Command CRC error\n",
1671 mmc_hostname(host->mmc), cmd->opcode);
1672 msmsdcc_dump_sdcc_state(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001673 cmd->error = -EILSEQ;
1674 }
1675
Subhash Jadavani8706ced2012-05-25 16:09:21 +05301676 if (!cmd->error) {
1677 if (cmd->cmd_timeout_ms > host->curr.req_tout_ms) {
1678 host->curr.req_tout_ms = cmd->cmd_timeout_ms;
1679 mod_timer(&host->req_tout_timer, (jiffies +
1680 msecs_to_jiffies(host->curr.req_tout_ms)));
1681 }
1682 }
1683
San Mehat9d2bd732009-09-22 16:44:22 -07001684 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001685 if (host->curr.data && host->dma.sg &&
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301686 is_dma_mode(host))
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001687 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001688 else if (host->curr.data && host->sps.sg &&
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301689 is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001690 /* Stop current SPS transfer */
1691 msmsdcc_sps_exit_curr_xfer(host);
1692 }
San Mehat9d2bd732009-09-22 16:44:22 -07001693 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301694 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001695 msmsdcc_stop_data(host);
1696 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301697 } else { /* host->data == NULL */
1698 if (!cmd->error && host->prog_enable) {
1699 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001700 host->prog_enable = 0;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301701 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001702 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301703 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301704 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301705 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301706 host->curr.wait_for_auto_prog_done = false;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001707 if (host->dummy_52_needed)
1708 host->dummy_52_needed = 0;
1709 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001710 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301711 msmsdcc_request_end(host, cmd->mrq);
1712 }
1713 }
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301714 } else if (cmd->data) {
Subhash Jadavanif5277752011-10-12 16:47:52 +05301715 if (cmd == host->curr.mrq->sbc)
1716 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1717 else if ((cmd->data->flags & MMC_DATA_WRITE) &&
1718 !host->curr.use_wr_data_pend)
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301719 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001720 }
1721}
1722
San Mehat9d2bd732009-09-22 16:44:22 -07001723static irqreturn_t
1724msmsdcc_irq(int irq, void *dev_id)
1725{
1726 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001727 u32 status;
1728 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001729 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001730
1731 spin_lock(&host->lock);
1732
1733 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001734 struct mmc_command *cmd;
1735 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001736
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001737 if (timer) {
1738 timer = 0;
1739 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001740 }
San Mehat9d2bd732009-09-22 16:44:22 -07001741
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05301742 if (!atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001743 pr_debug("%s: %s: SDIO async irq received\n",
1744 mmc_hostname(host->mmc), __func__);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301745
1746 /*
1747 * Only async interrupt can come when clocks are off,
1748 * disable further interrupts and enable them when
1749 * clocks are on.
1750 */
1751 if (!host->sdcc_irq_disabled) {
1752 disable_irq_nosync(irq);
1753 host->sdcc_irq_disabled = 1;
1754 }
1755
1756 /*
1757 * If mmc_card_wake_sdio_irq() is set, mmc core layer
1758 * will take care of signaling sdio irq during
1759 * mmc_sdio_resume().
1760 */
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301761 if (host->sdcc_suspended) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301762 /*
1763 * This is a wakeup interrupt so hold wakelock
1764 * until SDCC resume is handled.
1765 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001766 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301767 } else {
1768 spin_unlock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301769 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301770 spin_lock(&host->lock);
1771 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301772 ret = 1;
1773 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001774 }
1775
1776 status = readl_relaxed(host->base + MMCISTATUS);
1777
1778 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1779 (~(MCI_IRQ_PIO))) == 0)
San Mehat9d2bd732009-09-22 16:44:22 -07001780 break;
1781
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001782#if IRQ_DEBUG
1783 msmsdcc_print_status(host, "irq0-r", status);
1784#endif
1785 status &= readl_relaxed(host->base + MMCIMASK0);
1786 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301787 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301788 if (host->clk_rate <=
1789 msmsdcc_get_min_sup_clk_rate(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +05301790 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001791#if IRQ_DEBUG
1792 msmsdcc_print_status(host, "irq0-p", status);
1793#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001794
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001795 if (status & MCI_SDIOINTROPE) {
1796 if (host->sdcc_suspending)
1797 wake_lock(&host->sdio_suspend_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301798 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001799 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301800 spin_lock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001801 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001802 data = host->curr.data;
1803
1804 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001805 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1806 MCI_CMDTIMEOUT)) {
1807 if (status & MCI_CMDTIMEOUT)
1808 pr_debug("%s: dummy CMD52 timeout\n",
1809 mmc_hostname(host->mmc));
1810 if (status & MCI_CMDCRCFAIL)
1811 pr_debug("%s: dummy CMD52 CRC failed\n",
1812 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001813 host->dummy_52_sent = 0;
1814 host->dummy_52_needed = 0;
1815 if (data) {
1816 msmsdcc_stop_data(host);
1817 msmsdcc_request_end(host, data->mrq);
1818 }
1819 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001820 spin_unlock(&host->lock);
1821 return IRQ_HANDLED;
1822 }
1823 break;
1824 }
1825
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001826 /*
1827 * Check for proper command response
1828 */
1829 cmd = host->curr.cmd;
1830 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1831 MCI_CMDTIMEOUT | MCI_PROGDONE |
1832 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1833 msmsdcc_do_cmdirq(host, status);
1834 }
1835
Sathish Ambley081d7842011-11-29 11:19:41 -08001836 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001837 /* Check for data errors */
1838 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1839 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1840 msmsdcc_data_err(host, data, status);
1841 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301842 if (host->dma.sg && is_dma_mode(host))
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001843 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301844 else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001845 /* Stop current SPS transfer */
1846 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301847 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001848 msmsdcc_reset_and_restore(host);
1849 if (host->curr.data)
1850 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301851 if (!data->stop || (host->curr.mrq->sbc
1852 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001853 timer |=
1854 msmsdcc_request_end(host,
1855 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301856 else if ((host->curr.mrq->sbc
1857 && data->error) ||
1858 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001859 msmsdcc_start_command(host,
1860 data->stop,
1861 0);
1862 timer = 1;
1863 }
1864 }
1865 }
1866
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301867 /* Check for prog done */
1868 if (host->curr.wait_for_auto_prog_done &&
1869 (status & MCI_PROGDONE))
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301870 host->curr.got_auto_prog_done = true;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301871
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001872 /* Check for data done */
1873 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1874 host->curr.got_dataend = 1;
1875
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301876 if (host->curr.got_dataend &&
1877 (!host->curr.wait_for_auto_prog_done ||
1878 (host->curr.wait_for_auto_prog_done &&
1879 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001880 /*
1881 * If DMA is still in progress, we complete
1882 * via the completion handler
1883 */
1884 if (!host->dma.busy && !host->sps.busy) {
1885 /*
1886 * There appears to be an issue in the
1887 * controller where if you request a
1888 * small block transfer (< fifo size),
1889 * you may get your DATAEND/DATABLKEND
1890 * irq without the PIO data irq.
1891 *
1892 * Check to see if theres still data
1893 * to be read, and simulate a PIO irq.
1894 */
1895 if (data->flags & MMC_DATA_READ)
1896 msmsdcc_wait_for_rxdata(host,
1897 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001898 if (!data->error) {
1899 host->curr.data_xfered =
1900 host->curr.xfer_size;
1901 host->curr.xfer_remain -=
1902 host->curr.xfer_size;
1903 }
1904
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001905 if (!host->dummy_52_needed) {
1906 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301907 if (!data->stop ||
1908 (host->curr.mrq->sbc
1909 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001910 msmsdcc_request_end(
1911 host,
1912 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301913 else if ((host->curr.mrq->sbc
1914 && data->error) ||
1915 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001916 msmsdcc_start_command(
1917 host,
1918 data->stop, 0);
1919 timer = 1;
1920 }
1921 } else {
1922 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001923 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001924 &dummy52cmd,
1925 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001926 }
1927 }
1928 }
1929 }
1930
San Mehat9d2bd732009-09-22 16:44:22 -07001931 ret = 1;
1932 } while (status);
1933
1934 spin_unlock(&host->lock);
1935
San Mehat9d2bd732009-09-22 16:44:22 -07001936 return IRQ_RETVAL(ret);
1937}
1938
1939static void
Asutosh Dasaccacd42012-03-08 14:33:17 +05301940msmsdcc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
1941 bool is_first_request)
1942{
1943 struct msmsdcc_host *host = mmc_priv(mmc);
1944 struct mmc_data *data = mrq->data;
1945 int rc = 0;
1946
1947 if (unlikely(!data)) {
1948 pr_err("%s: %s cannot prepare null data\n", mmc_hostname(mmc),
1949 __func__);
1950 return;
1951 }
1952 if (unlikely(data->host_cookie)) {
1953 /* Very wrong */
1954 data->host_cookie = 0;
1955 pr_err("%s: %s Request reposted for prepare\n",
1956 mmc_hostname(mmc), __func__);
1957 return;
1958 }
1959
1960 if (!msmsdcc_is_dma_possible(host, data))
1961 return;
1962
1963 rc = msmsdcc_prep_xfer(host, data);
1964 if (unlikely(rc < 0)) {
1965 data->host_cookie = 0;
1966 return;
1967 }
1968
1969 data->host_cookie = 1;
1970}
1971
1972static void
1973msmsdcc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, int err)
1974{
1975 struct msmsdcc_host *host = mmc_priv(mmc);
1976 unsigned int dir;
1977 struct mmc_data *data = mrq->data;
1978
1979 if (unlikely(!data)) {
1980 pr_err("%s: %s cannot cleanup null data\n", mmc_hostname(mmc),
1981 __func__);
1982 return;
1983 }
1984 if (data->flags & MMC_DATA_READ)
1985 dir = DMA_FROM_DEVICE;
1986 else
1987 dir = DMA_TO_DEVICE;
1988
1989 if (data->host_cookie)
1990 dma_unmap_sg(mmc_dev(host->mmc), data->sg,
1991 data->sg_len, dir);
1992
1993 data->host_cookie = 0;
1994}
1995
1996static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001997msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1998{
Subhash Jadavanif5277752011-10-12 16:47:52 +05301999 if (mrq->data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002000 /* Queue/read data, daisy-chain command when data starts */
Subhash Jadavanif5277752011-10-12 16:47:52 +05302001 if ((mrq->data->flags & MMC_DATA_READ) ||
2002 host->curr.use_wr_data_pend)
2003 msmsdcc_start_data(host, mrq->data,
2004 mrq->sbc ? mrq->sbc : mrq->cmd,
2005 0);
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302006 else
Subhash Jadavanif5277752011-10-12 16:47:52 +05302007 msmsdcc_start_command(host,
2008 mrq->sbc ? mrq->sbc : mrq->cmd,
2009 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002010 } else {
2011 msmsdcc_start_command(host, mrq->cmd, 0);
2012 }
2013}
2014
2015static void
San Mehat9d2bd732009-09-22 16:44:22 -07002016msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
2017{
2018 struct msmsdcc_host *host = mmc_priv(mmc);
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302019 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07002020
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002021 /*
2022 * Get the SDIO AL client out of LPM.
2023 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002024 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002025 if (host->plat->is_sdio_al_client)
2026 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002027
Subhash Jadavanib5b07742011-08-29 17:48:07 +05302028 /* check if sps pipe reset is pending? */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05302029 if (is_sps_mode(host) && host->sps.pipe_reset_pending) {
Subhash Jadavanib5b07742011-08-29 17:48:07 +05302030 msmsdcc_sps_pipes_reset_and_restore(host);
2031 host->sps.pipe_reset_pending = false;
2032 }
San Mehat9d2bd732009-09-22 16:44:22 -07002033
2034 spin_lock_irqsave(&host->lock, flags);
2035
San Mehat9d2bd732009-09-22 16:44:22 -07002036 if (host->eject) {
2037 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
2038 mrq->cmd->error = 0;
2039 mrq->data->bytes_xfered = mrq->data->blksz *
2040 mrq->data->blocks;
2041 } else
2042 mrq->cmd->error = -ENOMEDIUM;
2043
2044 spin_unlock_irqrestore(&host->lock, flags);
2045 mmc_request_done(mmc, mrq);
2046 return;
2047 }
2048
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302049 /*
subhashjf181c292012-05-02 13:07:40 +05302050 * Don't start the request if SDCC is not in proper state to handle it
2051 */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302052 if (!host->pwr || !atomic_read(&host->clks_on)
2053 || host->sdcc_irq_disabled) {
subhashjf181c292012-05-02 13:07:40 +05302054 WARN(1, "%s: %s: SDCC is in bad state. don't process"
2055 " new request (CMD%d)\n", mmc_hostname(host->mmc),
2056 __func__, mrq->cmd->opcode);
2057 msmsdcc_dump_sdcc_state(host);
2058 mrq->cmd->error = -EIO;
2059 if (mrq->data) {
2060 mrq->data->error = -EIO;
2061 mrq->data->bytes_xfered = 0;
2062 }
2063 spin_unlock_irqrestore(&host->lock, flags);
2064 mmc_request_done(mmc, mrq);
2065 return;
2066 }
2067
2068 WARN(host->curr.mrq, "%s: %s: New request (CMD%d) received while"
2069 " other request (CMD%d) is in progress\n",
2070 mmc_hostname(host->mmc), __func__,
2071 mrq->cmd->opcode, host->curr.mrq->cmd->opcode);
2072
2073 /*
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302074 * Set timeout value to 10 secs (or more in case of buggy cards)
2075 */
2076 if ((mmc->card) && (mmc->card->quirks & MMC_QUIRK_INAND_DATA_TIMEOUT))
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302077 host->curr.req_tout_ms = 20000;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302078 else
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302079 host->curr.req_tout_ms = MSM_MMC_REQ_TIMEOUT;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302080 /*
2081 * Kick the software request timeout timer here with the timeout
2082 * value identified above
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302083 */
2084 mod_timer(&host->req_tout_timer,
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302085 (jiffies +
2086 msecs_to_jiffies(host->curr.req_tout_ms)));
San Mehat9d2bd732009-09-22 16:44:22 -07002087
San Mehat9d2bd732009-09-22 16:44:22 -07002088 host->curr.mrq = mrq;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302089 if (mrq->sbc) {
2090 mrq->sbc->mrq = mrq;
2091 mrq->sbc->data = mrq->data;
2092 }
2093
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302094 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05302095 if (is_auto_prog_done(host)) {
Sujit Reddy Thummab8e83692012-07-17 15:08:13 +05302096 /*
2097 * Auto-prog done will be enabled for following cases:
2098 * mrq->sbc | mrq->stop
2099 * _____________|________________
2100 * True | Don't care
2101 * False | False (CMD24, ACMD25 use case)
2102 */
2103 if (mrq->sbc || !mrq->stop)
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302104 host->curr.wait_for_auto_prog_done = true;
2105 } else {
2106 if ((mrq->cmd->opcode == SD_IO_RW_EXTENDED) ||
2107 (mrq->cmd->opcode == 54))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002108 host->dummy_52_needed = 1;
2109 }
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302110
Subhash Jadavanif5277752011-10-12 16:47:52 +05302111 if ((mrq->cmd->opcode == MMC_WRITE_BLOCK) ||
2112 (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK))
2113 host->curr.use_wr_data_pend = true;
San Mehat9d2bd732009-09-22 16:44:22 -07002114 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302115
Subhash Jadavanif5277752011-10-12 16:47:52 +05302116 msmsdcc_request_start(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302117
San Mehat9d2bd732009-09-22 16:44:22 -07002118 spin_unlock_irqrestore(&host->lock, flags);
2119}
2120
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002121static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
2122 int min_uV, int max_uV)
2123{
2124 int rc = 0;
2125
2126 if (vreg->set_voltage_sup) {
2127 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
2128 if (rc) {
2129 pr_err("%s: regulator_set_voltage(%s) failed."
2130 " min_uV=%d, max_uV=%d, rc=%d\n",
2131 __func__, vreg->name, min_uV, max_uV, rc);
2132 }
2133 }
2134
2135 return rc;
2136}
2137
2138static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
2139 int uA_load)
2140{
2141 int rc = 0;
2142
Krishna Kondafea60182011-11-01 16:01:34 -07002143 /* regulators that do not support regulator_set_voltage also
2144 do not support regulator_set_optimum_mode */
2145 if (vreg->set_voltage_sup) {
2146 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
2147 if (rc < 0)
2148 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
2149 "uA_load=%d) failed. rc=%d\n", __func__,
2150 vreg->name, uA_load, rc);
2151 else
2152 /* regulator_set_optimum_mode() can return non zero
2153 * value even for success case.
2154 */
2155 rc = 0;
2156 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002157
2158 return rc;
2159}
2160
2161static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
2162 struct device *dev)
2163{
2164 int rc = 0;
2165
2166 /* check if regulator is already initialized? */
2167 if (vreg->reg)
2168 goto out;
2169
2170 /* Get the regulator handle */
2171 vreg->reg = regulator_get(dev, vreg->name);
2172 if (IS_ERR(vreg->reg)) {
2173 rc = PTR_ERR(vreg->reg);
2174 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
2175 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002176 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002177 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002178
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05302179 if (regulator_count_voltages(vreg->reg) > 0) {
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002180 vreg->set_voltage_sup = 1;
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05302181 /* sanity check */
2182 if (!vreg->high_vol_level || !vreg->hpm_uA) {
2183 pr_err("%s: %s invalid constraints specified\n",
2184 __func__, vreg->name);
2185 rc = -EINVAL;
2186 }
2187 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002188
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002189out:
2190 return rc;
2191}
2192
2193static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
2194{
2195 if (vreg->reg)
2196 regulator_put(vreg->reg);
2197}
2198
2199/* This init function should be called only once for each SDCC slot */
2200static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
2201{
2202 int rc = 0;
2203 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302204 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vdd_io_reg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002205 struct device *dev = mmc_dev(host->mmc);
2206
2207 curr_slot = host->plat->vreg_data;
2208 if (!curr_slot)
2209 goto out;
2210
2211 curr_vdd_reg = curr_slot->vdd_data;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302212 curr_vdd_io_reg = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002213
2214 if (is_init) {
2215 /*
2216 * Get the regulator handle from voltage regulator framework
2217 * and then try to set the voltage level for the regulator
2218 */
2219 if (curr_vdd_reg) {
2220 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
2221 if (rc)
2222 goto out;
2223 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302224 if (curr_vdd_io_reg) {
2225 rc = msmsdcc_vreg_init_reg(curr_vdd_io_reg, dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002226 if (rc)
2227 goto vdd_reg_deinit;
2228 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002229 rc = msmsdcc_vreg_reset(host);
2230 if (rc)
2231 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
2232 host->pdev_id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002233 goto out;
2234 } else {
2235 /* Deregister all regulators from regulator framework */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302236 goto vdd_io_reg_deinit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002237 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302238vdd_io_reg_deinit:
2239 if (curr_vdd_io_reg)
2240 msmsdcc_vreg_deinit_reg(curr_vdd_io_reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002241vdd_reg_deinit:
2242 if (curr_vdd_reg)
2243 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2244out:
2245 return rc;
2246}
2247
2248static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2249{
2250 int rc = 0;
2251
Subhash Jadavanicc922692011-08-01 23:05:01 +05302252 /* Put regulator in HPM (high power mode) */
2253 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2254 if (rc < 0)
2255 goto out;
2256
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002257 if (!vreg->is_enabled) {
2258 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302259 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2260 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002261 if (rc)
2262 goto out;
2263
2264 rc = regulator_enable(vreg->reg);
2265 if (rc) {
2266 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2267 __func__, vreg->name, rc);
2268 goto out;
2269 }
2270 vreg->is_enabled = true;
2271 }
2272
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002273out:
2274 return rc;
2275}
2276
Krishna Konda3c4142d2012-06-27 11:01:56 -07002277static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg, bool is_init)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002278{
2279 int rc = 0;
2280
2281 /* Never disable regulator marked as always_on */
2282 if (vreg->is_enabled && !vreg->always_on) {
2283 rc = regulator_disable(vreg->reg);
2284 if (rc) {
2285 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2286 __func__, vreg->name, rc);
2287 goto out;
2288 }
2289 vreg->is_enabled = false;
2290
2291 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2292 if (rc < 0)
2293 goto out;
2294
2295 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302296 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002297 if (rc)
2298 goto out;
Krishna Konda3c4142d2012-06-27 11:01:56 -07002299 } else if (vreg->is_enabled && vreg->always_on) {
2300 if (!is_init && vreg->lpm_sup) {
2301 /* Put always_on regulator in LPM (low power mode) */
2302 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2303 if (rc < 0)
2304 goto out;
2305 } else if (is_init && vreg->reset_at_init) {
2306 /**
2307 * The regulator might not actually be disabled if it
2308 * is shared and in use by other drivers.
2309 */
2310 rc = regulator_disable(vreg->reg);
2311 if (rc) {
2312 pr_err("%s: regulator_disable(%s) failed at " \
2313 "bootup. rc=%d\n", __func__,
2314 vreg->name, rc);
2315 goto out;
2316 }
2317 vreg->is_enabled = false;
2318 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002319 }
2320out:
2321 return rc;
2322}
2323
Krishna Konda3c4142d2012-06-27 11:01:56 -07002324static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable,
2325 bool is_init)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002326{
2327 int rc = 0, i;
2328 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302329 struct msm_mmc_reg_data *vreg_table[2];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002330
2331 curr_slot = host->plat->vreg_data;
2332 if (!curr_slot)
2333 goto out;
2334
Subhash Jadavani937c7502012-06-01 15:34:46 +05302335 vreg_table[0] = curr_slot->vdd_data;
2336 vreg_table[1] = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002337
2338 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2339 if (vreg_table[i]) {
2340 if (enable)
2341 rc = msmsdcc_vreg_enable(vreg_table[i]);
2342 else
Krishna Konda3c4142d2012-06-27 11:01:56 -07002343 rc = msmsdcc_vreg_disable(vreg_table[i],
2344 is_init);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002345 if (rc)
2346 goto out;
2347 }
2348 }
2349out:
2350 return rc;
2351}
2352
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002353/*
2354 * Reset vreg by ensuring it is off during probe. A call
2355 * to enable vreg is needed to balance disable vreg
2356 */
2357static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2358{
2359 int rc;
2360
Krishna Konda3c4142d2012-06-27 11:01:56 -07002361 rc = msmsdcc_setup_vreg(host, 1, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002362 if (rc)
2363 return rc;
Krishna Konda3c4142d2012-06-27 11:01:56 -07002364 rc = msmsdcc_setup_vreg(host, 0, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002365 return rc;
2366}
2367
Subhash Jadavani937c7502012-06-01 15:34:46 +05302368enum vdd_io_level {
2369 /* set vdd_io_data->low_vol_level */
2370 VDD_IO_LOW,
2371 /* set vdd_io_data->high_vol_level */
2372 VDD_IO_HIGH,
2373 /*
2374 * set whatever there in voltage_level (third argument) of
2375 * msmsdcc_set_vdd_io_vol() function.
2376 */
2377 VDD_IO_SET_LEVEL,
2378};
2379
2380static int msmsdcc_set_vdd_io_vol(struct msmsdcc_host *host,
2381 enum vdd_io_level level,
2382 unsigned int voltage_level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002383{
2384 int rc = 0;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302385 int set_level;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002386
2387 if (host->plat->vreg_data) {
Subhash Jadavani937c7502012-06-01 15:34:46 +05302388 struct msm_mmc_reg_data *vdd_io_reg =
2389 host->plat->vreg_data->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002390
Subhash Jadavani937c7502012-06-01 15:34:46 +05302391 if (vdd_io_reg && vdd_io_reg->is_enabled) {
2392 switch (level) {
2393 case VDD_IO_LOW:
2394 set_level = vdd_io_reg->low_vol_level;
2395 break;
2396 case VDD_IO_HIGH:
2397 set_level = vdd_io_reg->high_vol_level;
2398 break;
2399 case VDD_IO_SET_LEVEL:
2400 set_level = voltage_level;
2401 break;
2402 default:
2403 pr_err("%s: %s: invalid argument level = %d",
2404 mmc_hostname(host->mmc), __func__,
2405 level);
2406 rc = -EINVAL;
2407 goto out;
2408 }
2409 rc = msmsdcc_vreg_set_voltage(vdd_io_reg,
2410 set_level, set_level);
2411 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002412 }
2413
Subhash Jadavani937c7502012-06-01 15:34:46 +05302414out:
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302415 return rc;
2416}
2417
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002418static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2419{
2420 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2421 return 1;
2422 return 0;
2423}
2424
Asutosh Dasf5298c32012-04-03 14:51:47 +05302425/*
2426 * Any function calling msmsdcc_setup_clocks must
2427 * acquire clk_mutex. May sleep.
2428 */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302429static int msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002430{
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302431 int rc = 0;
2432
2433 if (enable && !atomic_read(&host->clks_on)) {
2434 if (!IS_ERR_OR_NULL(host->bus_clk)) {
2435 rc = clk_prepare_enable(host->bus_clk);
2436 if (rc) {
2437 pr_err("%s: %s: failed to enable the bus-clock with error %d\n",
2438 mmc_hostname(host->mmc), __func__, rc);
2439 goto out;
2440 }
2441 }
2442 if (!IS_ERR(host->pclk)) {
2443 rc = clk_prepare_enable(host->pclk);
2444 if (rc) {
2445 pr_err("%s: %s: failed to enable the pclk with error %d\n",
2446 mmc_hostname(host->mmc), __func__, rc);
2447 goto disable_bus;
2448 }
2449 }
2450 rc = clk_prepare_enable(host->clk);
2451 if (rc) {
2452 pr_err("%s: %s: failed to enable the host-clk with error %d\n",
2453 mmc_hostname(host->mmc), __func__, rc);
2454 goto disable_pclk;
2455 }
Subhash Jadavanidd432952012-03-28 11:25:56 +05302456 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302457 msmsdcc_delay(host);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302458 atomic_set(&host->clks_on, 1);
2459 } else if (!enable && atomic_read(&host->clks_on)) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05302460 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302461 msmsdcc_delay(host);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302462 clk_disable_unprepare(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002463 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302464 clk_disable_unprepare(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05302465 if (!IS_ERR_OR_NULL(host->bus_clk))
2466 clk_disable_unprepare(host->bus_clk);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302467 atomic_set(&host->clks_on, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002468 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302469 goto out;
2470
2471disable_pclk:
2472 if (!IS_ERR_OR_NULL(host->pclk))
2473 clk_disable_unprepare(host->pclk);
2474disable_bus:
2475 if (!IS_ERR_OR_NULL(host->bus_clk))
2476 clk_disable_unprepare(host->bus_clk);
2477out:
2478 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002479}
2480
2481static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2482 unsigned int req_clk)
2483{
2484 unsigned int sel_clk = -1;
2485
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302486 if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
2487 sel_clk = msmsdcc_get_min_sup_clk_rate(host);
2488 goto out;
2489 }
2490
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002491 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2492 unsigned char cnt;
2493
2494 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2495 if (host->plat->sup_clk_table[cnt] > req_clk)
2496 break;
2497 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2498 sel_clk = host->plat->sup_clk_table[cnt];
2499 break;
2500 } else
2501 sel_clk = host->plat->sup_clk_table[cnt];
2502 }
2503 } else {
2504 if ((req_clk < host->plat->msmsdcc_fmax) &&
2505 (req_clk > host->plat->msmsdcc_fmid))
2506 sel_clk = host->plat->msmsdcc_fmid;
2507 else
2508 sel_clk = req_clk;
2509 }
2510
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302511out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002512 return sel_clk;
2513}
2514
2515static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2516 struct msmsdcc_host *host)
2517{
2518 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2519 return host->plat->sup_clk_table[0];
2520 else
2521 return host->plat->msmsdcc_fmin;
2522}
2523
2524static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2525 struct msmsdcc_host *host)
2526{
2527 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2528 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2529 else
2530 return host->plat->msmsdcc_fmax;
2531}
2532
2533static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302534{
2535 struct msm_mmc_gpio_data *curr;
2536 int i, rc = 0;
2537
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002538 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302539 for (i = 0; i < curr->size; i++) {
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05302540 if (!gpio_is_valid(curr->gpio[i].no)) {
2541 rc = -EINVAL;
2542 pr_err("%s: Invalid gpio = %d\n",
2543 mmc_hostname(host->mmc), curr->gpio[i].no);
2544 goto free_gpios;
2545 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302546 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002547 if (curr->gpio[i].is_always_on &&
2548 curr->gpio[i].is_enabled)
2549 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302550 rc = gpio_request(curr->gpio[i].no,
2551 curr->gpio[i].name);
2552 if (rc) {
2553 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2554 mmc_hostname(host->mmc),
2555 curr->gpio[i].no,
2556 curr->gpio[i].name, rc);
2557 goto free_gpios;
2558 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002559 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302560 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002561 if (curr->gpio[i].is_always_on)
2562 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302563 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002564 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302565 }
2566 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002567 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302568
2569free_gpios:
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05302570 for (i--; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302571 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002572 curr->gpio[i].is_enabled = false;
2573 }
2574out:
2575 return rc;
2576}
2577
2578static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2579{
2580 struct msm_mmc_pad_data *curr;
2581 int i;
2582
2583 curr = host->plat->pin_data->pad_data;
2584 for (i = 0; i < curr->drv->size; i++) {
2585 if (enable)
2586 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2587 curr->drv->on[i].val);
2588 else
2589 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2590 curr->drv->off[i].val);
2591 }
2592
2593 for (i = 0; i < curr->pull->size; i++) {
2594 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002595 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002596 curr->pull->on[i].val);
2597 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002598 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002599 curr->pull->off[i].val);
2600 }
2601
2602 return 0;
2603}
2604
2605static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2606{
2607 int rc = 0;
2608
2609 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2610 return 0;
2611
2612 if (host->plat->pin_data->is_gpio)
2613 rc = msmsdcc_setup_gpio(host, enable);
2614 else
2615 rc = msmsdcc_setup_pad(host, enable);
2616
2617 if (!rc)
2618 host->plat->pin_data->cfg_sts = enable;
2619
2620 return rc;
2621}
2622
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302623static int msmsdcc_cfg_mpm_sdiowakeup(struct msmsdcc_host *host,
2624 unsigned mode)
2625{
2626 int ret = 0;
2627 unsigned int pin = host->plat->mpm_sdiowakeup_int;
2628
2629 if (!pin)
2630 return 0;
2631
2632 switch (mode) {
2633 case SDC_DAT1_DISABLE:
2634 ret = msm_mpm_enable_pin(pin, 0);
2635 break;
2636 case SDC_DAT1_ENABLE:
2637 ret = msm_mpm_set_pin_type(pin, IRQ_TYPE_LEVEL_LOW);
2638 ret = msm_mpm_enable_pin(pin, 1);
2639 break;
2640 case SDC_DAT1_ENWAKE:
2641 ret = msm_mpm_set_pin_wake(pin, 1);
2642 break;
2643 case SDC_DAT1_DISWAKE:
2644 ret = msm_mpm_set_pin_wake(pin, 0);
2645 break;
2646 default:
2647 ret = -EINVAL;
2648 break;
2649 }
2650
2651 return ret;
2652}
2653
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302654static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2655{
2656 u32 pwr = 0;
2657 int ret = 0;
2658 struct mmc_host *mmc = host->mmc;
2659
2660 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2661 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2662 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
Krishna Konda3c4142d2012-06-27 11:01:56 -07002663 ret = msmsdcc_setup_vreg(host, !!ios->vdd, false);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302664
2665 if (ret) {
2666 pr_err("%s: Failed to setup voltage regulators\n",
2667 mmc_hostname(host->mmc));
2668 goto out;
2669 }
2670
2671 switch (ios->power_mode) {
2672 case MMC_POWER_OFF:
2673 pwr = MCI_PWR_OFF;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302674 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302675 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05302676 * If VDD IO rail is always on, set low voltage for VDD
2677 * IO rail when slot is not in use (like when card is not
2678 * present or during system suspend).
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302679 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302680 msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302681 msmsdcc_setup_pins(host, false);
2682 break;
2683 case MMC_POWER_UP:
2684 /* writing PWR_UP bit is redundant */
2685 pwr = MCI_PWR_UP;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302686 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302687
Subhash Jadavani937c7502012-06-01 15:34:46 +05302688 msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302689 msmsdcc_setup_pins(host, true);
2690 break;
2691 case MMC_POWER_ON:
2692 pwr = MCI_PWR_ON;
2693 break;
2694 }
2695
2696out:
2697 return pwr;
2698}
2699
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002700static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2701{
2702 unsigned int wakeup_irq;
2703
2704 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2705 host->plat->sdiowakeup_irq :
2706 host->core_irqres->start;
2707
2708 if (!host->irq_wake_enabled) {
2709 enable_irq_wake(wakeup_irq);
2710 host->irq_wake_enabled = true;
2711 }
2712}
2713
2714static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2715{
2716 unsigned int wakeup_irq;
2717
2718 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2719 host->plat->sdiowakeup_irq :
2720 host->core_irqres->start;
2721
2722 if (host->irq_wake_enabled) {
2723 disable_irq_wake(wakeup_irq);
2724 host->irq_wake_enabled = false;
2725 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302726}
2727
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05302728/* Returns required bandwidth in Bytes per Sec */
2729static unsigned int msmsdcc_get_bw_required(struct msmsdcc_host *host,
2730 struct mmc_ios *ios)
2731{
2732 unsigned int bw;
2733
2734 bw = host->clk_rate;
2735 /*
2736 * For DDR mode, SDCC controller clock will be at
2737 * the double rate than the actual clock that goes to card.
2738 */
2739 if (ios->bus_width == MMC_BUS_WIDTH_4)
2740 bw /= 2;
2741 else if (ios->bus_width == MMC_BUS_WIDTH_1)
2742 bw /= 8;
2743
2744 return bw;
2745}
2746
2747static int msmsdcc_msm_bus_get_vote_for_bw(struct msmsdcc_host *host,
2748 unsigned int bw)
2749{
2750 unsigned int *table = host->plat->msm_bus_voting_data->bw_vecs;
2751 unsigned int size = host->plat->msm_bus_voting_data->bw_vecs_size;
2752 int i;
2753
2754 if (host->msm_bus_vote.is_max_bw_needed && bw)
2755 return host->msm_bus_vote.max_bw_vote;
2756
2757 for (i = 0; i < size; i++) {
2758 if (bw <= table[i])
2759 break;
2760 }
2761
2762 if (i && (i == size))
2763 i--;
2764
2765 return i;
2766}
2767
2768static int msmsdcc_msm_bus_register(struct msmsdcc_host *host)
2769{
2770 int rc = 0;
2771 struct msm_bus_scale_pdata *use_cases;
2772
2773 if (host->plat->msm_bus_voting_data &&
2774 host->plat->msm_bus_voting_data->use_cases &&
2775 host->plat->msm_bus_voting_data->bw_vecs &&
2776 host->plat->msm_bus_voting_data->bw_vecs_size) {
2777 use_cases = host->plat->msm_bus_voting_data->use_cases;
2778 host->msm_bus_vote.client_handle =
2779 msm_bus_scale_register_client(use_cases);
2780 } else {
2781 return 0;
2782 }
2783
2784 if (!host->msm_bus_vote.client_handle) {
2785 pr_err("%s: msm_bus_scale_register_client() failed\n",
2786 mmc_hostname(host->mmc));
2787 rc = -EFAULT;
2788 } else {
2789 /* cache the vote index for minimum and maximum bandwidth */
2790 host->msm_bus_vote.min_bw_vote =
2791 msmsdcc_msm_bus_get_vote_for_bw(host, 0);
2792 host->msm_bus_vote.max_bw_vote =
2793 msmsdcc_msm_bus_get_vote_for_bw(host, UINT_MAX);
2794 }
2795
2796 return rc;
2797}
2798
2799static void msmsdcc_msm_bus_unregister(struct msmsdcc_host *host)
2800{
2801 if (host->msm_bus_vote.client_handle)
2802 msm_bus_scale_unregister_client(
2803 host->msm_bus_vote.client_handle);
2804}
2805
2806/*
2807 * This function must be called with host lock acquired.
2808 * Caller of this function should also ensure that msm bus client
2809 * handle is not null.
2810 */
2811static inline int msmsdcc_msm_bus_set_vote(struct msmsdcc_host *host,
2812 int vote,
2813 unsigned long flags)
2814{
2815 int rc = 0;
2816
2817 if (vote != host->msm_bus_vote.curr_vote) {
2818 spin_unlock_irqrestore(&host->lock, flags);
2819 rc = msm_bus_scale_client_update_request(
2820 host->msm_bus_vote.client_handle, vote);
2821 if (rc)
2822 pr_err("%s: msm_bus_scale_client_update_request() failed."
2823 " bus_client_handle=0x%x, vote=%d, err=%d\n",
2824 mmc_hostname(host->mmc),
2825 host->msm_bus_vote.client_handle, vote, rc);
2826 spin_lock_irqsave(&host->lock, flags);
2827 if (!rc)
2828 host->msm_bus_vote.curr_vote = vote;
2829 }
2830
2831 return rc;
2832}
2833
2834/*
2835 * Internal work. Work to set 0 bandwidth for msm bus.
2836 */
2837static void msmsdcc_msm_bus_work(struct work_struct *work)
2838{
2839 struct msmsdcc_host *host = container_of(work,
2840 struct msmsdcc_host,
2841 msm_bus_vote.vote_work.work);
2842 unsigned long flags;
2843
2844 if (!host->msm_bus_vote.client_handle)
2845 return;
2846
2847 spin_lock_irqsave(&host->lock, flags);
2848 /* don't vote for 0 bandwidth if any request is in progress */
2849 if (!host->curr.mrq)
2850 msmsdcc_msm_bus_set_vote(host,
2851 host->msm_bus_vote.min_bw_vote, flags);
2852 else
2853 pr_warning("%s: %s: SDCC transfer in progress. skipping"
2854 " bus voting to 0 bandwidth\n",
2855 mmc_hostname(host->mmc), __func__);
2856 spin_unlock_irqrestore(&host->lock, flags);
2857}
2858
2859/*
2860 * This function cancels any scheduled delayed work
2861 * and sets the bus vote based on ios argument.
2862 * If "ios" argument is NULL, bandwidth required is 0 else
2863 * calculate the bandwidth based on ios parameters.
2864 */
2865static void msmsdcc_msm_bus_cancel_work_and_set_vote(
2866 struct msmsdcc_host *host,
2867 struct mmc_ios *ios)
2868{
2869 unsigned long flags;
2870 unsigned int bw;
2871 int vote;
2872
2873 if (!host->msm_bus_vote.client_handle)
2874 return;
2875
2876 bw = ios ? msmsdcc_get_bw_required(host, ios) : 0;
2877
2878 cancel_delayed_work_sync(&host->msm_bus_vote.vote_work);
2879 spin_lock_irqsave(&host->lock, flags);
2880 vote = msmsdcc_msm_bus_get_vote_for_bw(host, bw);
2881 msmsdcc_msm_bus_set_vote(host, vote, flags);
2882 spin_unlock_irqrestore(&host->lock, flags);
2883}
2884
2885/* This function queues a work which will set the bandwidth requiement to 0 */
2886static void msmsdcc_msm_bus_queue_work(struct msmsdcc_host *host)
2887{
2888 unsigned long flags;
2889
2890 if (!host->msm_bus_vote.client_handle)
2891 return;
2892
2893 spin_lock_irqsave(&host->lock, flags);
2894 if (host->msm_bus_vote.min_bw_vote != host->msm_bus_vote.curr_vote)
2895 queue_delayed_work(system_nrt_wq,
2896 &host->msm_bus_vote.vote_work,
2897 msecs_to_jiffies(MSM_MMC_BUS_VOTING_DELAY));
2898 spin_unlock_irqrestore(&host->lock, flags);
2899}
2900
San Mehat9d2bd732009-09-22 16:44:22 -07002901static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302902msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
2903{
2904 struct mmc_host *mmc = host->mmc;
2905
2906 /*
2907 * SDIO_AL clients has different mechanism of handling LPM through
2908 * sdio_al driver itself. The sdio wakeup interrupt is configured as
2909 * part of that. Here, we are interested only in clients like WLAN.
2910 */
2911 if (!(mmc->card && mmc_card_sdio(mmc->card))
2912 || host->plat->is_sdio_al_client)
2913 goto out;
2914
2915 if (!host->sdcc_suspended) {
2916 /*
2917 * When MSM is not in power collapse and we
2918 * are disabling clocks, enable bit 22 in MASK0
2919 * to handle asynchronous SDIO interrupts.
2920 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302921 if (enable_wakeup_irq) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302922 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302923 mb();
2924 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302925 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302926 msmsdcc_sync_reg_wr(host);
2927 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302928 goto out;
2929 } else if (!mmc_card_wake_sdio_irq(mmc)) {
2930 /*
2931 * Wakeup MSM only if SDIO function drivers set
2932 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
2933 */
2934 goto out;
2935 }
2936
2937 if (enable_wakeup_irq) {
2938 if (!host->plat->sdiowakeup_irq) {
2939 /*
2940 * When there is no gpio line that can be configured
2941 * as wakeup interrupt handle it by configuring
2942 * asynchronous sdio interrupts and DAT1 line.
2943 */
2944 writel_relaxed(MCI_SDIOINTMASK,
2945 host->base + MMCIMASK0);
2946 mb();
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302947 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302948 /* configure sdcc core interrupt as wakeup interrupt */
2949 msmsdcc_enable_irq_wake(host);
2950 } else {
2951 /* Let gpio line handle wakeup interrupt */
2952 writel_relaxed(0, host->base + MMCIMASK0);
2953 mb();
2954 if (host->sdio_wakeupirq_disabled) {
2955 host->sdio_wakeupirq_disabled = 0;
2956 /* configure gpio line as wakeup interrupt */
2957 msmsdcc_enable_irq_wake(host);
2958 enable_irq(host->plat->sdiowakeup_irq);
2959 }
2960 }
2961 } else {
2962 if (!host->plat->sdiowakeup_irq) {
2963 /*
2964 * We may not have cleared bit 22 in the interrupt
2965 * handler as the clocks might be off at that time.
2966 */
2967 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302968 msmsdcc_sync_reg_wr(host);
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302969 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302970 msmsdcc_disable_irq_wake(host);
2971 } else if (!host->sdio_wakeupirq_disabled) {
2972 disable_irq_nosync(host->plat->sdiowakeup_irq);
2973 msmsdcc_disable_irq_wake(host);
2974 host->sdio_wakeupirq_disabled = 1;
2975 }
2976 }
2977out:
2978 return;
San Mehat9d2bd732009-09-22 16:44:22 -07002979}
2980
2981static void
2982msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2983{
2984 struct msmsdcc_host *host = mmc_priv(mmc);
2985 u32 clk = 0, pwr = 0;
2986 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002987 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002988 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002989
Sahitya Tummala7a892482011-01-18 11:22:49 +05302990
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302991 /*
2992 * Disable SDCC core interrupt until set_ios is completed.
2993 * This avoids any race conditions with interrupt raised
2994 * when turning on/off the clocks. One possible
2995 * scenario is SDIO operational interrupt while the clock
2996 * is turned off.
Asutosh Dasf5298c32012-04-03 14:51:47 +05302997 * host->lock is being released intermittently below.
2998 * Thus, prevent concurrent access to host.
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302999 */
3000
Asutosh Dasf5298c32012-04-03 14:51:47 +05303001 mutex_lock(&host->clk_mutex);
3002 DBG(host, "ios->clock = %u\n", ios->clock);
San Mehat9d2bd732009-09-22 16:44:22 -07003003 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303004 if (!host->sdcc_irq_disabled) {
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05303005 disable_irq_nosync(host->core_irqres->start);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303006 host->sdcc_irq_disabled = 1;
3007 }
San Mehatd0719e52009-12-03 10:58:54 -08003008 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07003009
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05303010 /* Make sure sdcc core irq is synchronized */
3011 synchronize_irq(host->core_irqres->start);
3012
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303013 pwr = msmsdcc_setup_pwr(host, ios);
3014
3015 spin_lock_irqsave(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07003016 if (ios->clock) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303017 spin_unlock_irqrestore(&host->lock, flags);
3018 rc = msmsdcc_setup_clocks(host, true);
3019 if (rc)
3020 goto out;
3021 spin_lock_irqsave(&host->lock, flags);
3022 writel_relaxed(host->mci_irqenable, host->base + MMCIMASK0);
3023 mb();
3024 msmsdcc_cfg_sdio_wakeup(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003025 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303026
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003027 /*
3028 * For DDR50 mode, controller needs clock rate to be
3029 * double than what is required on the SD card CLK pin.
3030 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05303031 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003032 /*
3033 * Make sure that we don't double the clock if
3034 * doubled clock rate is already set
3035 */
3036 if (!host->ddr_doubled_clk_rate ||
3037 (host->ddr_doubled_clk_rate &&
3038 (host->ddr_doubled_clk_rate != ios->clock))) {
3039 host->ddr_doubled_clk_rate =
3040 msmsdcc_get_sup_clk_rate(
3041 host, (ios->clock * 2));
3042 clock = host->ddr_doubled_clk_rate;
3043 }
3044 } else {
3045 host->ddr_doubled_clk_rate = 0;
3046 }
3047
3048 if (clock != host->clk_rate) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05303049 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003050 rc = clk_set_rate(host->clk, clock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303051 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003052 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303053 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003054 mmc_hostname(mmc), clock);
3055 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303056 host->reg_write_delay =
3057 (1 + ((3 * USEC_PER_SEC) /
3058 (host->clk_rate ? host->clk_rate :
3059 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003060 }
3061 /*
3062 * give atleast 2 MCLK cycles delay for clocks
3063 * and SDCC core to stabilize
3064 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05303065 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003066 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003067 clk |= MCI_CLK_ENABLE;
3068 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003069 if (ios->bus_width == MMC_BUS_WIDTH_8)
3070 clk |= MCI_CLK_WIDEBUS_8;
3071 else if (ios->bus_width == MMC_BUS_WIDTH_4)
3072 clk |= MCI_CLK_WIDEBUS_4;
3073 else
3074 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07003075
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003076 if (msmsdcc_is_pwrsave(host))
3077 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07003078
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003079 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07003080
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003081 host->tuning_needed = 0;
3082 /*
3083 * Select the controller timing mode according
3084 * to current bus speed mode
3085 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303086 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
3087 (ios->timing == MMC_TIMING_MMC_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003088 clk |= (4 << 14);
3089 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05303090 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003091 clk |= (3 << 14);
3092 } else {
3093 clk |= (2 << 14); /* feedback clock */
San Mehat9d2bd732009-09-22 16:44:22 -07003094 }
3095
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003096 /* Select free running MCLK as input clock of cm_dll_sdc4 */
3097 clk |= (2 << 23);
San Mehat9d2bd732009-09-22 16:44:22 -07003098
Subhash Jadavani00083572012-02-15 16:18:01 +05303099 /* Clear IO_PAD_PWR_SWITCH while powering off the card */
3100 if (!ios->vdd)
3101 host->io_pad_pwr_switch = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07003102
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003103 if (host->io_pad_pwr_switch)
3104 clk |= IO_PAD_PWR_SWITCH;
3105
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303106 /* Don't write into registers if clocks are disabled */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303107 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303108 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
3109 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303110 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003111 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303112 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
3113 host->pwr = pwr;
3114 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303115 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003116 }
San Mehat9d2bd732009-09-22 16:44:22 -07003117 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003118
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303119 if (!(clk & MCI_CLK_ENABLE) && atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303120 msmsdcc_cfg_sdio_wakeup(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303121 spin_unlock_irqrestore(&host->lock, flags);
3122 /*
3123 * May get a wake-up interrupt the instant we disable the
3124 * clocks. This would disable the wake-up interrupt.
3125 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003126 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303127 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003128 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303129
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303130 if (host->tuning_in_progress)
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303131 WARN(!atomic_read(&host->clks_on),
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303132 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303133
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303134 /* Let interrupts be disabled if the host is powered off */
3135 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
3136 enable_irq(host->core_irqres->start);
3137 host->sdcc_irq_disabled = 0;
3138 }
San Mehat4adbbcc2009-11-08 13:00:37 -08003139 spin_unlock_irqrestore(&host->lock, flags);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303140out:
Asutosh Dasf5298c32012-04-03 14:51:47 +05303141 mutex_unlock(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07003142}
3143
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003144int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
3145{
3146 struct msmsdcc_host *host = mmc_priv(mmc);
3147 u32 clk;
3148
3149 clk = readl_relaxed(host->base + MMCICLOCK);
3150 pr_debug("Changing to pwr_save=%d", pwrsave);
3151 if (pwrsave && msmsdcc_is_pwrsave(host))
3152 clk |= MCI_CLK_PWRSAVE;
3153 else
3154 clk &= ~MCI_CLK_PWRSAVE;
3155 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303156 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003157
3158 return 0;
3159}
3160
3161static int msmsdcc_get_ro(struct mmc_host *mmc)
3162{
3163 int status = -ENOSYS;
3164 struct msmsdcc_host *host = mmc_priv(mmc);
3165
3166 if (host->plat->wpswitch) {
3167 status = host->plat->wpswitch(mmc_dev(mmc));
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05303168 } else if (gpio_is_valid(host->plat->wpswitch_gpio)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003169 status = gpio_request(host->plat->wpswitch_gpio,
3170 "SD_WP_Switch");
3171 if (status) {
3172 pr_err("%s: %s: Failed to request GPIO %d\n",
3173 mmc_hostname(mmc), __func__,
3174 host->plat->wpswitch_gpio);
3175 } else {
3176 status = gpio_direction_input(
3177 host->plat->wpswitch_gpio);
3178 if (!status) {
3179 /*
3180 * Wait for atleast 300ms as debounce
3181 * time for GPIO input to stabilize.
3182 */
3183 msleep(300);
3184 status = gpio_get_value_cansleep(
3185 host->plat->wpswitch_gpio);
Sujit Reddy Thumma8f912ea2012-06-22 16:18:43 +05303186 status ^= !host->plat->is_wpswitch_active_low;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003187 }
3188 gpio_free(host->plat->wpswitch_gpio);
3189 }
3190 }
3191
3192 if (status < 0)
3193 status = -ENOSYS;
3194 pr_debug("%s: Card read-only status %d\n", __func__, status);
3195
3196 return status;
San Mehat9d2bd732009-09-22 16:44:22 -07003197}
3198
3199static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
3200{
3201 struct msmsdcc_host *host = mmc_priv(mmc);
3202 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003203
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303204 /*
3205 * We may come here with clocks turned off in that case don't
3206 * attempt to write into MASK0 register. While turning on the
3207 * clocks mci_irqenable will be written to MASK0 register.
3208 */
San Mehat9d2bd732009-09-22 16:44:22 -07003209
3210 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003211 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003212 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303213 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303214 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003215 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303216 mb();
3217 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003218 } else {
3219 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303220 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303221 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003222 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303223 mb();
3224 }
San Mehat9d2bd732009-09-22 16:44:22 -07003225 }
3226 spin_unlock_irqrestore(&host->lock, flags);
3227}
3228
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003229#ifdef CONFIG_PM_RUNTIME
subhashj245831e2012-04-30 18:46:17 +05303230static void msmsdcc_print_rpm_info(struct msmsdcc_host *host)
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003231{
subhashj245831e2012-04-30 18:46:17 +05303232 struct device *dev = mmc_dev(host->mmc);
3233
3234 pr_info("%s: RPM: runtime_status=%d, usage_count=%d,"
3235 " is_suspended=%d, disable_depth=%d, runtime_error=%d,"
3236 " request_pending=%d, request=%d\n",
3237 mmc_hostname(host->mmc), dev->power.runtime_status,
3238 atomic_read(&dev->power.usage_count),
3239 dev->power.is_suspended, dev->power.disable_depth,
3240 dev->power.runtime_error, dev->power.request_pending,
3241 dev->power.request);
3242}
3243
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003244static int msmsdcc_enable(struct mmc_host *mmc)
3245{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003246 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003247 struct device *dev = mmc->parent;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003248 struct msmsdcc_host *host = mmc_priv(mmc);
3249
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303250 msmsdcc_pm_qos_update_latency(host, 1);
3251
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003252 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303253 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003254
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003255 if (host->sdcc_suspended && host->pending_resume &&
3256 !pm_runtime_suspended(dev)) {
3257 host->pending_resume = false;
3258 pm_runtime_get_noresume(dev);
3259 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303260 goto skip_get_sync;
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003261 }
3262
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303263 if (dev->power.runtime_status == RPM_SUSPENDING) {
3264 if (mmc->suspend_task == current) {
3265 pm_runtime_get_noresume(dev);
3266 goto out;
3267 }
Sujit Reddy Thumma112bd752012-06-20 12:29:45 +05303268 } else if (dev->power.runtime_status == RPM_RESUMING) {
3269 pm_runtime_get_noresume(dev);
3270 goto out;
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303271 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003272
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303273 rc = pm_runtime_get_sync(dev);
3274
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303275skip_get_sync:
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303276 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003277 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3278 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303279 msmsdcc_print_rpm_info(host);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303280 return rc;
3281 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303282out:
3283 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303284 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003285}
3286
Steve Mucklef132c6c2012-06-06 18:30:57 -07003287static int msmsdcc_disable(struct mmc_host *mmc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003288{
3289 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303290 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003291
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303292 msmsdcc_pm_qos_update_latency(host, 0);
3293
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303294 if (mmc->card && mmc_card_sdio(mmc->card)) {
3295 rc = 0;
3296 goto out;
3297 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303298
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303299 if (host->plat->disable_runtime_pm)
3300 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003301
3302 rc = pm_runtime_put_sync(mmc->parent);
3303
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003304 /*
3305 * Ignore -EAGAIN as that is not fatal, it means that
3306 * either runtime usage count is non-zero or the runtime
3307 * pm itself is disabled or not in proper state to process
3308 * idle notification.
3309 */
3310 if (rc < 0 && (rc != -EAGAIN)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003311 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3312 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303313 msmsdcc_print_rpm_info(host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003314 return rc;
3315 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303316
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303317out:
3318 msmsdcc_msm_bus_queue_work(host);
3319 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003320}
3321#else
subhashj245831e2012-04-30 18:46:17 +05303322static void msmsdcc_print_rpm_info(struct msmsdcc_host *host) {}
3323
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303324static int msmsdcc_enable(struct mmc_host *mmc)
3325{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003326 struct device *dev = mmc->parent;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303327 struct msmsdcc_host *host = mmc_priv(mmc);
3328 unsigned long flags;
Sujit Reddy Thumma7f5051c2012-05-04 10:14:07 +05303329 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303330
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303331 msmsdcc_pm_qos_update_latency(host, 1);
3332
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303333 if (mmc->card && mmc_card_sdio(mmc->card)) {
3334 rc = 0;
3335 goto out;
3336 }
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003337
3338 if (host->sdcc_suspended && host->pending_resume) {
3339 host->pending_resume = false;
3340 rc = msmsdcc_runtime_resume(dev);
3341 goto out;
3342 }
3343
Asutosh Dasf5298c32012-04-03 14:51:47 +05303344 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303345 rc = msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303346 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303347
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003348out:
3349 if (rc < 0) {
3350 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3351 __func__, rc);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303352 msmsdcc_pm_qos_update_latency(host, 0);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003353 return rc;
3354 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303355 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303356 return 0;
3357}
3358
Steve Mucklef132c6c2012-06-06 18:30:57 -07003359static int msmsdcc_disable(struct mmc_host *mmc)
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303360{
3361 struct msmsdcc_host *host = mmc_priv(mmc);
3362 unsigned long flags;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303363 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303364
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303365 msmsdcc_pm_qos_update_latency(host, 0);
3366
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303367 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303368 goto out;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303369
Asutosh Dasf5298c32012-04-03 14:51:47 +05303370 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303371 rc = msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303372 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303373
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303374 if (rc) {
3375 msmsdcc_pm_qos_update_latency(host, 1);
3376 return rc;
3377 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303378out:
3379 msmsdcc_msm_bus_queue_work(host);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303380 return rc;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303381}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003382#endif
3383
Subhash Jadavani937c7502012-06-01 15:34:46 +05303384static int msmsdcc_switch_io_voltage(struct mmc_host *mmc,
3385 struct mmc_ios *ios)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003386{
3387 struct msmsdcc_host *host = mmc_priv(mmc);
3388 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303389 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003390
Subhash Jadavani00083572012-02-15 16:18:01 +05303391 spin_lock_irqsave(&host->lock, flags);
3392 host->io_pad_pwr_switch = 0;
3393 spin_unlock_irqrestore(&host->lock, flags);
3394
Subhash Jadavani937c7502012-06-01 15:34:46 +05303395 switch (ios->signal_voltage) {
3396 case MMC_SIGNAL_VOLTAGE_330:
3397 /* Set VDD IO to high voltage range (2.7v - 3.6v) */
3398 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303399 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303400 case MMC_SIGNAL_VOLTAGE_180:
3401 break;
3402 case MMC_SIGNAL_VOLTAGE_120:
3403 /*
3404 * For eMMC cards, VDD_IO voltage range must be changed
3405 * only if it operates in HS200 SDR 1.2V mode or in
3406 * DDR 1.2V mode.
3407 */
3408 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_SET_LEVEL, 1200000);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003409 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303410 default:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003411 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303412 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003413 goto out;
3414 }
San Mehat9d2bd732009-09-22 16:44:22 -07003415
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003416 /*
3417 * If we are here means voltage switch from high voltage to
3418 * low voltage is required
3419 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303420 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003421
3422 /*
3423 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
3424 * register until they become all zeros.
3425 */
3426 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303427 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003428 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
3429 mmc_hostname(mmc), __func__);
3430 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07003431 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003432
3433 /* Stop SD CLK output. */
3434 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3435 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303436 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003437 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003438
3439 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05303440 * Switch VDD Io from high voltage range (2.7v - 3.6v) to
3441 * low voltage range (1.7v - 1.95v).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003442 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303443 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303444 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003445 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003446
3447 spin_lock_irqsave(&host->lock, flags);
3448 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3449 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303450 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003451 host->io_pad_pwr_switch = 1;
3452 spin_unlock_irqrestore(&host->lock, flags);
3453
3454 /* Wait 5 ms for the voltage regulater in the card to become stable. */
3455 usleep_range(5000, 5500);
3456
3457 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303458 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003459 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3460 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303461 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003462 spin_unlock_irqrestore(&host->lock, flags);
3463
3464 /*
3465 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
3466 * don't become all ones within 1 ms then a Voltage Switch
3467 * sequence has failed and a power cycle to the card is required.
3468 * Otherwise Voltage Switch sequence is completed successfully.
3469 */
3470 usleep_range(1000, 1500);
3471
3472 spin_lock_irqsave(&host->lock, flags);
3473 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
3474 != (0xF << 1)) {
3475 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
3476 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303477 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003478 goto out_unlock;
3479 }
3480
3481out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303482 /* Enable PWRSAVE */
3483 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3484 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303485 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003486 spin_unlock_irqrestore(&host->lock, flags);
3487out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303488 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003489}
3490
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303491static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003492{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003493 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003494
3495 /* Program the MCLK value to MCLK_FREQ bit field */
3496 if (host->clk_rate <= 112000000)
3497 mclk_freq = 0;
3498 else if (host->clk_rate <= 125000000)
3499 mclk_freq = 1;
3500 else if (host->clk_rate <= 137000000)
3501 mclk_freq = 2;
3502 else if (host->clk_rate <= 150000000)
3503 mclk_freq = 3;
3504 else if (host->clk_rate <= 162000000)
3505 mclk_freq = 4;
3506 else if (host->clk_rate <= 175000000)
3507 mclk_freq = 5;
3508 else if (host->clk_rate <= 187000000)
3509 mclk_freq = 6;
3510 else if (host->clk_rate <= 200000000)
3511 mclk_freq = 7;
3512
3513 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3514 & ~(7 << 24)) | (mclk_freq << 24)),
3515 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003516}
3517
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303518/* Initialize the DLL (Programmable Delay Line ) */
3519static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003520{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003521 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303522 unsigned long flags;
3523 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003524
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303525 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003526 /*
3527 * Make sure that clock is always enabled when DLL
3528 * tuning is in progress. Keeping PWRSAVE ON may
3529 * turn off the clock. So let's disable the PWRSAVE
3530 * here and re-enable it once tuning is completed.
3531 */
3532 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3533 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303534 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303535
3536 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3537 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3538 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3539
3540 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3541 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3542 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3543
3544 msmsdcc_cm_sdc4_dll_set_freq(host);
3545
3546 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3547 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3548 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3549
3550 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3551 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3552 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3553
3554 /* Set DLL_EN bit to 1. */
3555 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3556 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3557
3558 /* Set CK_OUT_EN bit to 1. */
3559 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3560 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3561
3562 wait_cnt = 50;
3563 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3564 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3565 /* max. wait for 50us sec for LOCK bit to be set */
3566 if (--wait_cnt == 0) {
3567 pr_err("%s: %s: DLL failed to LOCK\n",
3568 mmc_hostname(host->mmc), __func__);
3569 rc = -ETIMEDOUT;
3570 goto out;
3571 }
3572 /* wait for 1us before polling again */
3573 udelay(1);
3574 }
3575
3576out:
3577 /* re-enable PWRSAVE */
3578 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3579 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303580 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303581 spin_unlock_irqrestore(&host->lock, flags);
3582
3583 return rc;
3584}
3585
3586static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3587 u8 poll)
3588{
3589 int rc = 0;
3590 u32 wait_cnt = 50;
3591 u8 ck_out_en = 0;
3592
3593 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3594 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3595 MCI_CK_OUT_EN);
3596
3597 while (ck_out_en != poll) {
3598 if (--wait_cnt == 0) {
3599 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3600 mmc_hostname(host->mmc), __func__, poll);
3601 rc = -ETIMEDOUT;
3602 goto out;
3603 }
3604 udelay(1);
3605
3606 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3607 MCI_CK_OUT_EN);
3608 }
3609out:
3610 return rc;
3611}
3612
3613/*
3614 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3615 * calibration sequence. This function should be called before
3616 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3617 * commands (CMD17/CMD18).
3618 *
3619 * This function gets called when host spinlock acquired.
3620 */
3621static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3622{
3623 int rc = 0;
3624 u32 config;
3625
3626 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3627 config |= MCI_CDR_EN;
3628 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3629 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3630
3631 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3632 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3633 if (rc)
3634 goto err_out;
3635
3636 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3637 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3638 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3639
3640 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3641 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3642 if (rc)
3643 goto err_out;
3644
3645 goto out;
3646
3647err_out:
3648 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3649out:
3650 return rc;
3651}
3652
3653static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3654 u8 phase)
3655{
3656 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303657 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3658 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3659 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303660 unsigned long flags;
3661 u32 config;
3662
3663 spin_lock_irqsave(&host->lock, flags);
3664
3665 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3666 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3667 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3668 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3669
3670 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3671 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3672 if (rc)
3673 goto err_out;
3674
3675 /*
3676 * Write the selected DLL clock output phase (0 ... 15)
3677 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
3678 */
3679 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3680 & ~(0xF << 20))
3681 | (grey_coded_phase_table[phase] << 20)),
3682 host->base + MCI_DLL_CONFIG);
3683
3684 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3685 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3686 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3687
3688 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3689 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3690 if (rc)
3691 goto err_out;
3692
3693 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3694 config |= MCI_CDR_EN;
3695 config &= ~MCI_CDR_EXT_EN;
3696 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3697 goto out;
3698
3699err_out:
3700 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3701 mmc_hostname(host->mmc), __func__, phase);
3702out:
3703 spin_unlock_irqrestore(&host->lock, flags);
3704 return rc;
3705}
3706
3707/*
3708 * Find out the greatest range of consecuitive selected
3709 * DLL clock output phases that can be used as sampling
3710 * setting for SD3.0 UHS-I card read operation (in SDR104
3711 * timing mode) or for eMMC4.5 card read operation (in HS200
3712 * timing mode).
3713 * Select the 3/4 of the range and configure the DLL with the
3714 * selected DLL clock output phase.
3715*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303716static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303717 u8 *phase_table, u8 total_phases)
3718{
Subhash Jadavani6159c622012-03-15 19:05:55 +05303719 #define MAX_PHASES 16
Subhash Jadavani34187042012-03-02 10:59:49 +05303720 int ret;
Subhash Jadavani6159c622012-03-15 19:05:55 +05303721 u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
3722 u8 phases_per_row[MAX_PHASES] = {0};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303723 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303724 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3725 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303726
Subhash Jadavani6159c622012-03-15 19:05:55 +05303727 if (!total_phases || (total_phases > MAX_PHASES)) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303728 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3729 mmc_hostname(host->mmc), __func__, total_phases);
3730 return -EINVAL;
3731 }
3732
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303733 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303734 ranges[row_index][col_index] = phase_table[cnt];
3735 phases_per_row[row_index] += 1;
3736 col_index++;
3737
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303738 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303739 continue;
3740 /* check if next phase in phase_table is consecutive or not */
3741 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3742 row_index++;
3743 col_index = 0;
3744 }
3745 }
3746
Subhash Jadavani6159c622012-03-15 19:05:55 +05303747 if (row_index >= MAX_PHASES)
3748 return -EINVAL;
3749
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303750 /* Check if phase-0 is present in first valid window? */
3751 if (!ranges[0][0]) {
3752 phase_0_found = true;
3753 phase_0_raw_index = 0;
3754 /* Check if cycle exist between 2 valid windows */
3755 for (cnt = 1; cnt <= row_index; cnt++) {
3756 if (phases_per_row[cnt]) {
Subhash Jadavani6159c622012-03-15 19:05:55 +05303757 for (i = 0; i < phases_per_row[cnt]; i++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303758 if (ranges[cnt][i] == 15) {
3759 phase_15_found = true;
3760 phase_15_raw_index = cnt;
3761 break;
3762 }
3763 }
3764 }
3765 }
3766 }
3767
3768 /* If 2 valid windows form cycle then merge them as single window */
3769 if (phase_0_found && phase_15_found) {
3770 /* number of phases in raw where phase 0 is present */
3771 u8 phases_0 = phases_per_row[phase_0_raw_index];
3772 /* number of phases in raw where phase 15 is present */
3773 u8 phases_15 = phases_per_row[phase_15_raw_index];
3774
Subhash Jadavani6159c622012-03-15 19:05:55 +05303775 if (phases_0 + phases_15 >= MAX_PHASES)
3776 /*
3777 * If there are more than 1 phase windows then total
3778 * number of phases in both the windows should not be
3779 * more than or equal to MAX_PHASES.
3780 */
3781 return -EINVAL;
3782
3783 /* Merge 2 cyclic windows */
3784 i = phases_15;
3785 for (cnt = 0; cnt < phases_0; cnt++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303786 ranges[phase_15_raw_index][i] =
3787 ranges[phase_0_raw_index][cnt];
Subhash Jadavani6159c622012-03-15 19:05:55 +05303788 if (++i >= MAX_PHASES)
3789 break;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303790 }
Subhash Jadavani6159c622012-03-15 19:05:55 +05303791
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303792 phases_per_row[phase_0_raw_index] = 0;
3793 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
3794 }
3795
3796 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303797 if (phases_per_row[cnt] > curr_max) {
3798 curr_max = phases_per_row[cnt];
3799 selected_row_index = cnt;
3800 }
3801 }
3802
Subhash Jadavani6159c622012-03-15 19:05:55 +05303803 i = ((curr_max * 3) / 4);
3804 if (i)
3805 i--;
3806
Subhash Jadavani34187042012-03-02 10:59:49 +05303807 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303808
Subhash Jadavani6159c622012-03-15 19:05:55 +05303809 if (ret >= MAX_PHASES) {
3810 ret = -EINVAL;
3811 pr_err("%s: %s: invalid phase selected=%d\n",
3812 mmc_hostname(host->mmc), __func__, ret);
3813 }
3814
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303815 return ret;
3816}
3817
Girish K Sa3f41692012-02-29 12:00:09 +05303818static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303819{
3820 int rc = 0;
3821 struct msmsdcc_host *host = mmc_priv(mmc);
3822 unsigned long flags;
3823 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303824 const u32 *tuning_block_pattern = tuning_block_64;
3825 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303826
3827 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
3828
3829 /* Tuning is only required for SDR104 modes */
3830 if (!host->tuning_needed) {
3831 rc = 0;
3832 goto exit;
3833 }
3834
3835 spin_lock_irqsave(&host->lock, flags);
3836 WARN(!host->pwr, "SDCC power is turned off\n");
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303837 WARN(!atomic_read(&host->clks_on), "SDCC clocks are turned off\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303838 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
3839
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303840 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303841 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
3842 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
3843 tuning_block_pattern = tuning_block_128;
3844 size = sizeof(tuning_block_128);
3845 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303846 spin_unlock_irqrestore(&host->lock, flags);
3847
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003848 /* first of all reset the tuning block */
3849 rc = msmsdcc_init_cm_sdc4_dll(host);
3850 if (rc)
3851 goto out;
3852
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303853 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003854 if (!data_buf) {
3855 rc = -ENOMEM;
3856 goto out;
3857 }
3858
3859 phase = 0;
3860 do {
3861 struct mmc_command cmd = {0};
3862 struct mmc_data data = {0};
3863 struct mmc_request mrq = {
3864 .cmd = &cmd,
3865 .data = &data
3866 };
3867 struct scatterlist sg;
3868
3869 /* set the phase in delay line hw block */
3870 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3871 if (rc)
3872 goto kfree;
3873
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303874 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003875 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
3876
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303877 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003878 data.blocks = 1;
3879 data.flags = MMC_DATA_READ;
3880 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
3881
3882 data.sg = &sg;
3883 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303884 sg_init_one(&sg, data_buf, size);
3885 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003886 mmc_wait_for_req(mmc, &mrq);
3887
3888 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303889 !memcmp(data_buf, tuning_block_pattern, size)) {
3890 /* tuning is successful at this tuning point */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003891 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303892 pr_debug("%s: %s: found good phase = %d\n",
3893 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003894 }
3895 } while (++phase < 16);
3896
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003897 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303898 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303899 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05303900 if (rc < 0)
3901 goto kfree;
3902 else
3903 phase = (u8)rc;
3904
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003905 /*
3906 * Finally set the selected phase in delay
3907 * line hw block.
3908 */
3909 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3910 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303911 goto kfree;
3912 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
3913 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003914 } else {
3915 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303916 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003917 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303918 msmsdcc_dump_sdcc_state(host);
3919 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003920 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003921
3922kfree:
3923 kfree(data_buf);
3924out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303925 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303926 host->tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303927 spin_unlock_irqrestore(&host->lock, flags);
3928exit:
3929 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003930 return rc;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003931}
3932
San Mehat9d2bd732009-09-22 16:44:22 -07003933static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003934 .enable = msmsdcc_enable,
3935 .disable = msmsdcc_disable,
Asutosh Dasaccacd42012-03-08 14:33:17 +05303936 .pre_req = msmsdcc_pre_req,
3937 .post_req = msmsdcc_post_req,
San Mehat9d2bd732009-09-22 16:44:22 -07003938 .request = msmsdcc_request,
3939 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003940 .get_ro = msmsdcc_get_ro,
San Mehat9d2bd732009-09-22 16:44:22 -07003941 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Subhash Jadavani937c7502012-06-01 15:34:46 +05303942 .start_signal_voltage_switch = msmsdcc_switch_io_voltage,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003943 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07003944};
3945
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003946static unsigned int
3947msmsdcc_slot_status(struct msmsdcc_host *host)
3948{
3949 int status;
3950 unsigned int gpio_no = host->plat->status_gpio;
3951
3952 status = gpio_request(gpio_no, "SD_HW_Detect");
3953 if (status) {
3954 pr_err("%s: %s: Failed to request GPIO %d\n",
3955 mmc_hostname(host->mmc), __func__, gpio_no);
3956 } else {
3957 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003958 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08003959 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003960 if (host->plat->is_status_gpio_active_low)
3961 status = !status;
3962 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003963 gpio_free(gpio_no);
3964 }
3965 return status;
3966}
3967
San Mehat9d2bd732009-09-22 16:44:22 -07003968static void
3969msmsdcc_check_status(unsigned long data)
3970{
3971 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3972 unsigned int status;
3973
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05303974 if (host->plat->status || gpio_is_valid(host->plat->status_gpio)) {
Krishna Konda941604a2012-01-10 17:46:34 -08003975 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003976 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003977 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003978 status = msmsdcc_slot_status(host);
3979
Krishna Konda941604a2012-01-10 17:46:34 -08003980 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08003981
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003982 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08003983 if (host->plat->status)
3984 pr_info("%s: Slot status change detected "
3985 "(%d -> %d)\n",
3986 mmc_hostname(host->mmc),
3987 host->oldstat, status);
3988 else if (host->plat->is_status_gpio_active_low)
3989 pr_info("%s: Slot status change detected "
3990 "(%d -> %d) and the card detect GPIO"
3991 " is ACTIVE_LOW\n",
3992 mmc_hostname(host->mmc),
3993 host->oldstat, status);
3994 else
3995 pr_info("%s: Slot status change detected "
3996 "(%d -> %d) and the card detect GPIO"
3997 " is ACTIVE_HIGH\n",
3998 mmc_hostname(host->mmc),
3999 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07004000 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004001 }
4002 host->oldstat = status;
4003 } else {
4004 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07004005 }
San Mehat9d2bd732009-09-22 16:44:22 -07004006}
4007
4008static irqreturn_t
4009msmsdcc_platform_status_irq(int irq, void *dev_id)
4010{
4011 struct msmsdcc_host *host = dev_id;
4012
Girish K Sa3c76eb2011-10-11 11:44:09 +05304013 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07004014 msmsdcc_check_status((unsigned long) host);
4015 return IRQ_HANDLED;
4016}
4017
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004018static irqreturn_t
4019msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
4020{
4021 struct msmsdcc_host *host = dev_id;
4022
4023 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
4024 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304025 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004026 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304027 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004028 wake_lock(&host->sdio_wlock);
4029 msmsdcc_disable_irq_wake(host);
4030 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304031 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004032 }
4033 if (host->plat->is_sdio_al_client) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004034 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304035 spin_unlock(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304036 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304037 goto out_unlocked;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004038 }
4039 spin_unlock(&host->lock);
4040
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304041out_unlocked:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004042 return IRQ_HANDLED;
4043}
4044
San Mehat9d2bd732009-09-22 16:44:22 -07004045static void
4046msmsdcc_status_notify_cb(int card_present, void *dev_id)
4047{
4048 struct msmsdcc_host *host = dev_id;
4049
Girish K Sa3c76eb2011-10-11 11:44:09 +05304050 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07004051 card_present);
4052 msmsdcc_check_status((unsigned long) host);
4053}
4054
San Mehat9d2bd732009-09-22 16:44:22 -07004055static int
4056msmsdcc_init_dma(struct msmsdcc_host *host)
4057{
4058 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
4059 host->dma.host = host;
4060 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004061 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004062
4063 if (!host->dmares)
4064 return -ENODEV;
4065
4066 host->dma.nc = dma_alloc_coherent(NULL,
4067 sizeof(struct msmsdcc_nc_dmadata),
4068 &host->dma.nc_busaddr,
4069 GFP_KERNEL);
4070 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004071 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07004072 return -ENOMEM;
4073 }
4074 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
4075 host->dma.cmd_busaddr = host->dma.nc_busaddr;
4076 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
4077 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
4078 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07004079 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07004080
4081 return 0;
4082}
4083
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004084#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
4085/**
4086 * Allocate and Connect a SDCC peripheral's SPS endpoint
4087 *
4088 * This function allocates endpoint context and
4089 * connect it with memory endpoint by calling
4090 * appropriate SPS driver APIs.
4091 *
4092 * Also registers a SPS callback function with
4093 * SPS driver
4094 *
4095 * This function should only be called once typically
4096 * during driver probe.
4097 *
4098 * @host - Pointer to sdcc host structure
4099 * @ep - Pointer to sps endpoint data structure
4100 * @is_produce - 1 means Producer endpoint
4101 * 0 means Consumer endpoint
4102 *
4103 * @return - 0 if successful else negative value.
4104 *
4105 */
4106static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
4107 struct msmsdcc_sps_ep_conn_data *ep,
4108 bool is_producer)
4109{
4110 int rc = 0;
4111 struct sps_pipe *sps_pipe_handle;
4112 struct sps_connect *sps_config = &ep->config;
4113 struct sps_register_event *sps_event = &ep->event;
4114
4115 /* Allocate endpoint context */
4116 sps_pipe_handle = sps_alloc_endpoint();
4117 if (!sps_pipe_handle) {
4118 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
4119 mmc_hostname(host->mmc), is_producer);
4120 rc = -ENOMEM;
4121 goto out;
4122 }
4123
4124 /* Get default connection configuration for an endpoint */
4125 rc = sps_get_config(sps_pipe_handle, sps_config);
4126 if (rc) {
4127 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
4128 " rc=%d", mmc_hostname(host->mmc),
4129 (u32)sps_pipe_handle, rc);
4130 goto get_config_err;
4131 }
4132
4133 /* Modify the default connection configuration */
4134 if (is_producer) {
4135 /*
4136 * For SDCC producer transfer, source should be
4137 * SDCC peripheral where as destination should
4138 * be system memory.
4139 */
4140 sps_config->source = host->sps.bam_handle;
4141 sps_config->destination = SPS_DEV_HANDLE_MEM;
4142 /* Producer pipe will handle this connection */
4143 sps_config->mode = SPS_MODE_SRC;
4144 sps_config->options =
4145 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4146 } else {
4147 /*
4148 * For SDCC consumer transfer, source should be
4149 * system memory where as destination should
4150 * SDCC peripheral
4151 */
4152 sps_config->source = SPS_DEV_HANDLE_MEM;
4153 sps_config->destination = host->sps.bam_handle;
4154 sps_config->mode = SPS_MODE_DEST;
4155 sps_config->options =
4156 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4157 }
4158
4159 /* Producer pipe index */
4160 sps_config->src_pipe_index = host->sps.src_pipe_index;
4161 /* Consumer pipe index */
4162 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
4163 /*
4164 * This event thresold value is only significant for BAM-to-BAM
4165 * transfer. It's ignored for BAM-to-System mode transfer.
4166 */
4167 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304168
4169 /* Allocate maximum descriptor fifo size */
4170 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
4171 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004172 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
4173 sps_config->desc.size,
4174 &sps_config->desc.phys_base,
4175 GFP_KERNEL);
4176
Pratibhasagar V00b94332011-10-18 14:57:27 +05304177 if (!sps_config->desc.base) {
4178 rc = -ENOMEM;
4179 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
4180 , mmc_hostname(host->mmc));
4181 goto get_config_err;
4182 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004183 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
4184
4185 /* Establish connection between peripheral and memory endpoint */
4186 rc = sps_connect(sps_pipe_handle, sps_config);
4187 if (rc) {
4188 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4189 " rc=%d", mmc_hostname(host->mmc),
4190 (u32)sps_pipe_handle, rc);
4191 goto sps_connect_err;
4192 }
4193
4194 sps_event->mode = SPS_TRIGGER_CALLBACK;
4195 sps_event->options = SPS_O_EOT;
4196 sps_event->callback = msmsdcc_sps_complete_cb;
4197 sps_event->xfer_done = NULL;
4198 sps_event->user = (void *)host;
4199
4200 /* Register callback event for EOT (End of transfer) event. */
4201 rc = sps_register_event(sps_pipe_handle, sps_event);
4202 if (rc) {
4203 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4204 " rc=%d", mmc_hostname(host->mmc),
4205 (u32)sps_pipe_handle, rc);
4206 goto reg_event_err;
4207 }
4208 /* Now save the sps pipe handle */
4209 ep->pipe_handle = sps_pipe_handle;
4210 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
4211 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
4212 __func__, is_producer ? "READ" : "WRITE",
4213 (u32)sps_pipe_handle, sps_config->desc.phys_base);
4214 goto out;
4215
4216reg_event_err:
4217 sps_disconnect(sps_pipe_handle);
4218sps_connect_err:
4219 dma_free_coherent(mmc_dev(host->mmc),
4220 sps_config->desc.size,
4221 sps_config->desc.base,
4222 sps_config->desc.phys_base);
4223get_config_err:
4224 sps_free_endpoint(sps_pipe_handle);
4225out:
4226 return rc;
4227}
4228
4229/**
4230 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
4231 *
4232 * This function disconnect endpoint and deallocates
4233 * endpoint context.
4234 *
4235 * This function should only be called once typically
4236 * during driver remove.
4237 *
4238 * @host - Pointer to sdcc host structure
4239 * @ep - Pointer to sps endpoint data structure
4240 *
4241 */
4242static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
4243 struct msmsdcc_sps_ep_conn_data *ep)
4244{
4245 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4246 struct sps_connect *sps_config = &ep->config;
4247 struct sps_register_event *sps_event = &ep->event;
4248
4249 sps_event->xfer_done = NULL;
4250 sps_event->callback = NULL;
4251 sps_register_event(sps_pipe_handle, sps_event);
4252 sps_disconnect(sps_pipe_handle);
4253 dma_free_coherent(mmc_dev(host->mmc),
4254 sps_config->desc.size,
4255 sps_config->desc.base,
4256 sps_config->desc.phys_base);
4257 sps_free_endpoint(sps_pipe_handle);
4258}
4259
4260/**
4261 * Reset SDCC peripheral's SPS endpoint
4262 *
4263 * This function disconnects an endpoint.
4264 *
4265 * This function should be called for reseting
4266 * SPS endpoint when data transfer error is
4267 * encountered during data transfer. This
4268 * can be considered as soft reset to endpoint.
4269 *
4270 * This function should only be called if
4271 * msmsdcc_sps_init() is already called.
4272 *
4273 * @host - Pointer to sdcc host structure
4274 * @ep - Pointer to sps endpoint data structure
4275 *
4276 * @return - 0 if successful else negative value.
4277 */
4278static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
4279 struct msmsdcc_sps_ep_conn_data *ep)
4280{
4281 int rc = 0;
4282 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4283
4284 rc = sps_disconnect(sps_pipe_handle);
4285 if (rc) {
4286 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
4287 " rc=%d", mmc_hostname(host->mmc), __func__,
4288 (u32)sps_pipe_handle, rc);
4289 goto out;
4290 }
4291 out:
4292 return rc;
4293}
4294
4295/**
4296 * Restore SDCC peripheral's SPS endpoint
4297 *
4298 * This function connects an endpoint.
4299 *
4300 * This function should be called for restoring
4301 * SPS endpoint after data transfer error is
4302 * encountered during data transfer. This
4303 * can be considered as soft reset to endpoint.
4304 *
4305 * This function should only be called if
4306 * msmsdcc_sps_reset_ep() is called before.
4307 *
4308 * @host - Pointer to sdcc host structure
4309 * @ep - Pointer to sps endpoint data structure
4310 *
4311 * @return - 0 if successful else negative value.
4312 */
4313static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
4314 struct msmsdcc_sps_ep_conn_data *ep)
4315{
4316 int rc = 0;
4317 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4318 struct sps_connect *sps_config = &ep->config;
4319 struct sps_register_event *sps_event = &ep->event;
4320
4321 /* Establish connection between peripheral and memory endpoint */
4322 rc = sps_connect(sps_pipe_handle, sps_config);
4323 if (rc) {
4324 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
4325 " rc=%d", mmc_hostname(host->mmc), __func__,
4326 (u32)sps_pipe_handle, rc);
4327 goto out;
4328 }
4329
4330 /* Register callback event for EOT (End of transfer) event. */
4331 rc = sps_register_event(sps_pipe_handle, sps_event);
4332 if (rc) {
4333 pr_err("%s: %s: sps_register_event() failed!!!"
4334 " pipe_handle=0x%x, rc=%d",
4335 mmc_hostname(host->mmc), __func__,
4336 (u32)sps_pipe_handle, rc);
4337 goto reg_event_err;
4338 }
4339 goto out;
4340
4341reg_event_err:
4342 sps_disconnect(sps_pipe_handle);
4343out:
4344 return rc;
4345}
4346
4347/**
Krishna Konda5af8f972012-05-14 16:15:24 -07004348 * Handle BAM device's global error condition
4349 *
4350 * This is an error handler for the SDCC bam device
4351 *
4352 * This function is registered as a callback with SPS-BAM
4353 * driver and will called in case there are an errors for
4354 * the SDCC BAM deivce. Any error conditions in the BAM
4355 * device are global and will be result in this function
4356 * being called once per device.
4357 *
4358 * This function will be called from the sps driver's
4359 * interrupt context.
4360 *
4361 * @sps_cb_case - indicates what error it is
4362 * @user - Pointer to sdcc host structure
4363 */
4364static void
4365msmsdcc_sps_bam_global_irq_cb(enum sps_callback_case sps_cb_case, void *user)
4366{
4367 struct msmsdcc_host *host = (struct msmsdcc_host *)user;
4368 struct mmc_request *mrq;
4369 unsigned long flags;
4370 int32_t error = 0;
4371
4372 BUG_ON(!host);
4373 BUG_ON(!is_sps_mode(host));
4374
4375 if (sps_cb_case == SPS_CALLBACK_BAM_ERROR_IRQ) {
4376 /**
4377 * Reset the all endpoints along with reseting the sps device.
4378 */
4379 host->sps.pipe_reset_pending = true;
4380 host->sps.reset_device = true;
4381
4382 pr_err("%s: BAM Global ERROR IRQ happened\n",
4383 mmc_hostname(host->mmc));
4384 error = EAGAIN;
4385 } else if (sps_cb_case == SPS_CALLBACK_BAM_HRESP_ERR_IRQ) {
4386 /**
4387 * This means that there was an AHB access error and
4388 * the address we are trying to read/write is something
4389 * we dont have priviliges to do so.
4390 */
4391 pr_err("%s: BAM HRESP_ERR_IRQ happened\n",
4392 mmc_hostname(host->mmc));
4393 error = EACCES;
4394 } else {
4395 /**
4396 * This should not have happened ideally. If this happens
4397 * there is some seriously wrong.
4398 */
4399 pr_err("%s: BAM global IRQ callback received, type:%d\n",
4400 mmc_hostname(host->mmc), (u32) sps_cb_case);
4401 error = EIO;
4402 }
4403
4404 spin_lock_irqsave(&host->lock, flags);
4405
4406 mrq = host->curr.mrq;
4407
4408 if (mrq && mrq->cmd) {
4409 msmsdcc_dump_sdcc_state(host);
4410
4411 if (!mrq->cmd->error)
4412 mrq->cmd->error = -error;
4413 if (host->curr.data) {
4414 if (mrq->data && !mrq->data->error)
4415 mrq->data->error = -error;
4416 host->curr.data_xfered = 0;
4417 if (host->sps.sg && is_sps_mode(host)) {
4418 /* Stop current SPS transfer */
4419 msmsdcc_sps_exit_curr_xfer(host);
4420 } else {
4421 /* this condition should not have happened */
4422 pr_err("%s: something is seriously wrong. "\
4423 "Funtion: %s, line: %d\n",
4424 mmc_hostname(host->mmc),
4425 __func__, __LINE__);
4426 }
4427 } else {
4428 /* this condition should not have happened */
4429 pr_err("%s: something is seriously wrong. Funtion: "\
4430 "%s, line: %d\n", mmc_hostname(host->mmc),
4431 __func__, __LINE__);
4432 }
4433 }
4434 spin_unlock_irqrestore(&host->lock, flags);
4435}
4436
4437/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004438 * Initialize SPS HW connected with SDCC core
4439 *
4440 * This function register BAM HW resources with
4441 * SPS driver and then initialize 2 SPS endpoints
4442 *
4443 * This function should only be called once typically
4444 * during driver probe.
4445 *
4446 * @host - Pointer to sdcc host structure
4447 *
4448 * @return - 0 if successful else negative value.
4449 *
4450 */
4451static int msmsdcc_sps_init(struct msmsdcc_host *host)
4452{
4453 int rc = 0;
4454 struct sps_bam_props bam = {0};
4455
4456 host->bam_base = ioremap(host->bam_memres->start,
4457 resource_size(host->bam_memres));
4458 if (!host->bam_base) {
4459 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
4460 " size=0x%x", mmc_hostname(host->mmc),
4461 host->bam_memres->start,
4462 (host->bam_memres->end -
4463 host->bam_memres->start));
4464 rc = -ENOMEM;
4465 goto out;
4466 }
4467
4468 bam.phys_addr = host->bam_memres->start;
4469 bam.virt_addr = host->bam_base;
4470 /*
4471 * This event thresold value is only significant for BAM-to-BAM
4472 * transfer. It's ignored for BAM-to-System mode transfer.
4473 */
4474 bam.event_threshold = 0x10; /* Pipe event threshold */
4475 /*
4476 * This threshold controls when the BAM publish
4477 * the descriptor size on the sideband interface.
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304478 * SPS HW will be used for data transfer size even
4479 * less than SDCC FIFO size. So let's set BAM summing
4480 * thresold to SPS_MIN_XFER_SIZE bytes.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004481 */
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304482 bam.summing_threshold = SPS_MIN_XFER_SIZE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004483 /* SPS driver wll handle the SDCC BAM IRQ */
4484 bam.irq = (u32)host->bam_irqres->start;
4485 bam.manage = SPS_BAM_MGR_LOCAL;
Krishna Konda5af8f972012-05-14 16:15:24 -07004486 bam.callback = msmsdcc_sps_bam_global_irq_cb;
4487 bam.user = (void *)host;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004488
4489 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
4490 (u32)bam.phys_addr);
4491 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
4492 (u32)bam.virt_addr);
4493
4494 /* Register SDCC Peripheral BAM device to SPS driver */
4495 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
4496 if (rc) {
4497 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
4498 mmc_hostname(host->mmc), rc);
4499 goto reg_bam_err;
4500 }
4501 pr_info("%s: BAM device registered. bam_handle=0x%x",
4502 mmc_hostname(host->mmc), host->sps.bam_handle);
4503
4504 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
4505 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
4506
4507 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
4508 SPS_PROD_PERIPHERAL);
4509 if (rc)
4510 goto sps_reset_err;
4511 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
4512 SPS_CONS_PERIPHERAL);
4513 if (rc)
4514 goto cons_conn_err;
4515
4516 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
4517 mmc_hostname(host->mmc),
4518 (unsigned long long)host->bam_memres->start,
4519 (unsigned int)host->bam_irqres->start);
4520 goto out;
4521
4522cons_conn_err:
4523 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4524sps_reset_err:
4525 sps_deregister_bam_device(host->sps.bam_handle);
4526reg_bam_err:
4527 iounmap(host->bam_base);
4528out:
4529 return rc;
4530}
4531
4532/**
4533 * De-initialize SPS HW connected with SDCC core
4534 *
4535 * This function deinitialize SPS endpoints and then
4536 * deregisters BAM resources from SPS driver.
4537 *
4538 * This function should only be called once typically
4539 * during driver remove.
4540 *
4541 * @host - Pointer to sdcc host structure
4542 *
4543 */
4544static void msmsdcc_sps_exit(struct msmsdcc_host *host)
4545{
4546 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
4547 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4548 sps_deregister_bam_device(host->sps.bam_handle);
4549 iounmap(host->bam_base);
4550}
4551#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
4552
4553static ssize_t
4554show_polling(struct device *dev, struct device_attribute *attr, char *buf)
4555{
4556 struct mmc_host *mmc = dev_get_drvdata(dev);
4557 struct msmsdcc_host *host = mmc_priv(mmc);
4558 int poll;
4559 unsigned long flags;
4560
4561 spin_lock_irqsave(&host->lock, flags);
4562 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
4563 spin_unlock_irqrestore(&host->lock, flags);
4564
4565 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
4566}
4567
4568static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05304569store_polling(struct device *dev, struct device_attribute *attr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004570 const char *buf, size_t count)
4571{
4572 struct mmc_host *mmc = dev_get_drvdata(dev);
4573 struct msmsdcc_host *host = mmc_priv(mmc);
4574 int value;
4575 unsigned long flags;
4576
4577 sscanf(buf, "%d", &value);
4578
4579 spin_lock_irqsave(&host->lock, flags);
4580 if (value) {
4581 mmc->caps |= MMC_CAP_NEEDS_POLL;
4582 mmc_detect_change(host->mmc, 0);
4583 } else {
4584 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4585 }
4586#ifdef CONFIG_HAS_EARLYSUSPEND
4587 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
4588#endif
4589 spin_unlock_irqrestore(&host->lock, flags);
4590 return count;
4591}
4592
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304593static ssize_t
4594show_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
4595 char *buf)
4596{
4597 struct mmc_host *mmc = dev_get_drvdata(dev);
4598 struct msmsdcc_host *host = mmc_priv(mmc);
4599
4600 return snprintf(buf, PAGE_SIZE, "%u\n",
4601 host->msm_bus_vote.is_max_bw_needed);
4602}
4603
4604static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05304605store_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304606 const char *buf, size_t count)
4607{
4608 struct mmc_host *mmc = dev_get_drvdata(dev);
4609 struct msmsdcc_host *host = mmc_priv(mmc);
4610 uint32_t value;
4611 unsigned long flags;
4612
4613 if (!kstrtou32(buf, 0, &value)) {
4614 spin_lock_irqsave(&host->lock, flags);
4615 host->msm_bus_vote.is_max_bw_needed = !!value;
4616 spin_unlock_irqrestore(&host->lock, flags);
4617 }
4618
4619 return count;
4620}
4621
Pratibhasagar V13d1d032012-07-09 20:12:38 +05304622static ssize_t
4623show_idle_timeout(struct device *dev, struct device_attribute *attr,
4624 char *buf)
4625{
4626 struct mmc_host *mmc = dev_get_drvdata(dev);
4627 struct msmsdcc_host *host = mmc_priv(mmc);
4628
4629 return snprintf(buf, PAGE_SIZE, "%u (Min 5 sec)\n",
4630 host->idle_tout_ms / 1000);
4631}
4632
4633static ssize_t
4634store_idle_timeout(struct device *dev, struct device_attribute *attr,
4635 const char *buf, size_t count)
4636{
4637 struct mmc_host *mmc = dev_get_drvdata(dev);
4638 struct msmsdcc_host *host = mmc_priv(mmc);
4639 unsigned int long flags;
4640 int timeout; /* in secs */
4641
4642 if (!kstrtou32(buf, 0, &timeout)
4643 && (timeout > MSM_MMC_DEFAULT_IDLE_TIMEOUT / 1000)) {
4644 spin_lock_irqsave(&host->lock, flags);
4645 host->idle_tout_ms = timeout * 1000;
4646 spin_unlock_irqrestore(&host->lock, flags);
4647 }
4648 return count;
4649}
4650
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004651#ifdef CONFIG_HAS_EARLYSUSPEND
4652static void msmsdcc_early_suspend(struct early_suspend *h)
4653{
4654 struct msmsdcc_host *host =
4655 container_of(h, struct msmsdcc_host, early_suspend);
4656 unsigned long flags;
4657
4658 spin_lock_irqsave(&host->lock, flags);
4659 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
4660 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4661 spin_unlock_irqrestore(&host->lock, flags);
4662};
4663static void msmsdcc_late_resume(struct early_suspend *h)
4664{
4665 struct msmsdcc_host *host =
4666 container_of(h, struct msmsdcc_host, early_suspend);
4667 unsigned long flags;
4668
4669 if (host->polling_enabled) {
4670 spin_lock_irqsave(&host->lock, flags);
4671 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
4672 mmc_detect_change(host->mmc, 0);
4673 spin_unlock_irqrestore(&host->lock, flags);
4674 }
4675};
4676#endif
4677
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304678static void msmsdcc_print_regs(const char *name, void __iomem *base,
4679 u32 phys_base, unsigned int no_of_regs)
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304680{
4681 unsigned int i;
4682
4683 if (!base)
4684 return;
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304685
4686 pr_info("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
4687 " =====\n", name, phys_base, (u32)base);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304688 for (i = 0; i < no_of_regs; i = i + 4) {
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304689 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
4690 (u32)readl_relaxed(base + i*4),
4691 (u32)readl_relaxed(base + ((i+1)*4)),
4692 (u32)readl_relaxed(base + ((i+2)*4)),
4693 (u32)readl_relaxed(base + ((i+3)*4)));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304694 }
4695}
4696
4697static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
4698{
4699 /* Dump current state of SDCC clocks, power and irq */
4700 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304701 (host->pwr ? "ON" : "OFF"));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304702 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304703 mmc_hostname(host->mmc),
4704 (atomic_read(&host->clks_on) ? "ON" : "OFF"),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304705 (u32)clk_get_rate(host->clk));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304706 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
4707 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
4708
4709 /* Now dump SDCC registers. Don't print FIFO registers */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304710 if (atomic_read(&host->clks_on))
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304711 msmsdcc_print_regs("SDCC-CORE", host->base,
4712 host->core_memres->start, 28);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304713
4714 if (host->curr.data) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304715 if (!msmsdcc_is_dma_possible(host, host->curr.data))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304716 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304717 else if (is_dma_mode(host))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304718 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
4719 mmc_hostname(host->mmc), host->dma.busy,
4720 host->dma.channel, host->dma.crci);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304721 else if (is_sps_mode(host)) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304722 if (host->sps.busy && atomic_read(&host->clks_on))
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304723 msmsdcc_print_regs("SDCC-DML", host->dml_base,
4724 host->dml_memres->start,
4725 16);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304726 pr_info("%s: SPS mode: busy=%d\n",
4727 mmc_hostname(host->mmc), host->sps.busy);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304728 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304729
4730 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
4731 mmc_hostname(host->mmc), host->curr.xfer_size,
4732 host->curr.data_xfered, host->curr.xfer_remain);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304733 }
4734
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304735 pr_info("%s: got_dataend=%d, prog_enable=%d,"
Subhash Jadavani8706ced2012-05-25 16:09:21 +05304736 " wait_for_auto_prog_done=%d, got_auto_prog_done=%d,"
4737 " req_tout_ms=%d\n", mmc_hostname(host->mmc),
4738 host->curr.got_dataend, host->prog_enable,
4739 host->curr.wait_for_auto_prog_done,
4740 host->curr.got_auto_prog_done, host->curr.req_tout_ms);
subhashj245831e2012-04-30 18:46:17 +05304741 msmsdcc_print_rpm_info(host);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304742}
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304743
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004744static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
4745{
4746 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4747 struct mmc_request *mrq;
4748 unsigned long flags;
4749
4750 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004751 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004752 pr_info("%s: %s: dummy CMD52 timeout\n",
4753 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004754 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004755 }
4756
4757 mrq = host->curr.mrq;
4758
4759 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304760 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
4761 mrq->cmd->opcode);
4762 msmsdcc_dump_sdcc_state(host);
4763
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004764 if (!mrq->cmd->error)
4765 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304766 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004767 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004768 if (mrq->data && !mrq->data->error)
4769 mrq->data->error = -ETIMEDOUT;
4770 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304771 if (host->dma.sg && is_dma_mode(host)) {
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07004772 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304773 } else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004774 /* Stop current SPS transfer */
4775 msmsdcc_sps_exit_curr_xfer(host);
4776 } else {
4777 msmsdcc_reset_and_restore(host);
4778 msmsdcc_stop_data(host);
4779 if (mrq->data && mrq->data->stop)
4780 msmsdcc_start_command(host,
4781 mrq->data->stop, 0);
4782 else
4783 msmsdcc_request_end(host, mrq);
4784 }
4785 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304786 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05304787 host->curr.wait_for_auto_prog_done = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004788 msmsdcc_reset_and_restore(host);
4789 msmsdcc_request_end(host, mrq);
4790 }
4791 }
4792 spin_unlock_irqrestore(&host->lock, flags);
4793}
4794
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05304795/*
4796 * msmsdcc_dt_get_array - Wrapper fn to read an array of 32 bit integers
4797 *
4798 * @dev: device node from which the property value is to be read.
4799 * @prop_name: name of the property to be searched.
4800 * @out_array: filled array returned to caller
4801 * @len: filled array size returned to caller
4802 * @size: expected size of the array
4803 *
4804 * If expected "size" doesn't match with "len" an error is returned. If
4805 * expected size is zero, the length of actual array is returned provided
4806 * return value is zero.
4807 *
4808 * RETURNS:
4809 * zero on success, negative error if failed.
4810 */
4811static int msmsdcc_dt_get_array(struct device *dev, const char *prop_name,
4812 u32 **out_array, int *len, int size)
4813{
4814 int ret = 0;
4815 u32 *array = NULL;
4816 struct device_node *np = dev->of_node;
4817
4818 if (of_get_property(np, prop_name, len)) {
4819 size_t sz;
4820 sz = *len = *len / sizeof(*array);
4821
4822 if (sz > 0 && !(size > 0 && (sz != size))) {
4823 array = devm_kzalloc(dev, sz * sizeof(*array),
4824 GFP_KERNEL);
4825 if (!array) {
4826 dev_err(dev, "%s: no memory\n", prop_name);
4827 ret = -ENOMEM;
4828 goto out;
4829 }
4830
4831 ret = of_property_read_u32_array(np, prop_name,
4832 array, sz);
4833 if (ret < 0) {
4834 dev_err(dev, "%s: error reading array %d\n",
4835 prop_name, ret);
4836 goto out;
4837 }
4838 } else {
4839 dev_err(dev, "%s invalid size\n", prop_name);
4840 ret = -EINVAL;
4841 goto out;
4842 }
4843 } else {
4844 dev_err(dev, "%s not specified\n", prop_name);
4845 ret = -EINVAL;
4846 goto out;
4847 }
4848 *out_array = array;
4849out:
4850 if (ret)
4851 *len = 0;
4852 return ret;
4853}
4854
4855static int msmsdcc_dt_get_pad_pull_info(struct device *dev, int id,
4856 struct msm_mmc_pad_pull_data **pad_pull_data)
4857{
4858 int ret = 0, base = 0, len, i;
4859 u32 *tmp;
4860 struct msm_mmc_pad_pull_data *pull_data;
4861 struct msm_mmc_pad_pull *pull;
4862
4863 switch (id) {
4864 case 1:
4865 base = TLMM_PULL_SDC1_CLK;
4866 break;
4867 case 2:
4868 base = TLMM_PULL_SDC2_CLK;
4869 break;
4870 case 3:
4871 base = TLMM_PULL_SDC3_CLK;
4872 break;
4873 case 4:
4874 base = TLMM_PULL_SDC4_CLK;
4875 break;
4876 default:
4877 dev_err(dev, "%s: Invalid slot id\n", __func__);
4878 ret = -EINVAL;
4879 goto err;
4880 }
4881
4882 pull_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_pull_data),
4883 GFP_KERNEL);
4884 if (!pull_data) {
4885 dev_err(dev, "No memory msm_mmc_pad_pull_data\n");
4886 ret = -ENOMEM;
4887 goto err;
4888 }
4889 pull_data->size = 3; /* array size for clk, cmd, data */
4890
4891 /* Allocate on, off configs for clk, cmd, data */
4892 pull = devm_kzalloc(dev, 2 * pull_data->size *\
4893 sizeof(struct msm_mmc_pad_pull), GFP_KERNEL);
4894 if (!pull) {
4895 dev_err(dev, "No memory for msm_mmc_pad_pull\n");
4896 ret = -ENOMEM;
4897 goto err;
4898 }
4899 pull_data->on = pull;
4900 pull_data->off = pull + pull_data->size;
4901
4902 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-pull-on",
4903 &tmp, &len, pull_data->size);
4904 if (!ret) {
4905 for (i = 0; i < len; i++) {
4906 pull_data->on[i].no = base + i;
4907 pull_data->on[i].val = tmp[i];
4908 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
4909 i, pull_data->on[i].val);
4910 }
4911 } else {
4912 goto err;
4913 }
4914
4915 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-pull-off",
4916 &tmp, &len, pull_data->size);
4917 if (!ret) {
4918 for (i = 0; i < len; i++) {
4919 pull_data->off[i].no = base + i;
4920 pull_data->off[i].val = tmp[i];
4921 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
4922 i, pull_data->off[i].val);
4923 }
4924 } else {
4925 goto err;
4926 }
4927
4928 *pad_pull_data = pull_data;
4929err:
4930 return ret;
4931}
4932
4933static int msmsdcc_dt_get_pad_drv_info(struct device *dev, int id,
4934 struct msm_mmc_pad_drv_data **pad_drv_data)
4935{
4936 int ret = 0, base = 0, len, i;
4937 u32 *tmp;
4938 struct msm_mmc_pad_drv_data *drv_data;
4939 struct msm_mmc_pad_drv *drv;
4940
4941 switch (id) {
4942 case 1:
4943 base = TLMM_HDRV_SDC1_CLK;
4944 break;
4945 case 2:
4946 base = TLMM_HDRV_SDC2_CLK;
4947 break;
4948 case 3:
4949 base = TLMM_HDRV_SDC3_CLK;
4950 break;
4951 case 4:
4952 base = TLMM_HDRV_SDC4_CLK;
4953 break;
4954 default:
4955 dev_err(dev, "%s: Invalid slot id\n", __func__);
4956 ret = -EINVAL;
4957 goto err;
4958 }
4959
4960 drv_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_drv_data),
4961 GFP_KERNEL);
4962 if (!drv_data) {
4963 dev_err(dev, "No memory for msm_mmc_pad_drv_data\n");
4964 ret = -ENOMEM;
4965 goto err;
4966 }
4967 drv_data->size = 3; /* array size for clk, cmd, data */
4968
4969 /* Allocate on, off configs for clk, cmd, data */
4970 drv = devm_kzalloc(dev, 2 * drv_data->size *\
4971 sizeof(struct msm_mmc_pad_drv), GFP_KERNEL);
4972 if (!drv) {
4973 dev_err(dev, "No memory msm_mmc_pad_drv\n");
4974 ret = -ENOMEM;
4975 goto err;
4976 }
4977 drv_data->on = drv;
4978 drv_data->off = drv + drv_data->size;
4979
4980 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-drv-on",
4981 &tmp, &len, drv_data->size);
4982 if (!ret) {
4983 for (i = 0; i < len; i++) {
4984 drv_data->on[i].no = base + i;
4985 drv_data->on[i].val = tmp[i];
4986 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
4987 i, drv_data->on[i].val);
4988 }
4989 } else {
4990 goto err;
4991 }
4992
4993 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-drv-off",
4994 &tmp, &len, drv_data->size);
4995 if (!ret) {
4996 for (i = 0; i < len; i++) {
4997 drv_data->off[i].no = base + i;
4998 drv_data->off[i].val = tmp[i];
4999 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5000 i, drv_data->off[i].val);
5001 }
5002 } else {
5003 goto err;
5004 }
5005
5006 *pad_drv_data = drv_data;
5007err:
5008 return ret;
5009}
5010
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305011static void msmsdcc_dt_get_cd_wp_gpio(struct device *dev,
5012 struct mmc_platform_data *pdata)
5013{
5014 enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
5015 struct device_node *np = dev->of_node;
5016
5017 pdata->status_gpio = of_get_named_gpio_flags(np,
5018 "cd-gpios", 0, &flags);
5019 if (gpio_is_valid(pdata->status_gpio)) {
5020 pdata->status_irq = gpio_to_irq(pdata->status_gpio);
5021 pdata->is_status_gpio_active_low = flags & OF_GPIO_ACTIVE_LOW;
5022 }
5023
5024 pdata->wpswitch_gpio = of_get_named_gpio_flags(np,
5025 "wp-gpios", 0, &flags);
5026 if (gpio_is_valid(pdata->wpswitch_gpio))
5027 pdata->is_wpswitch_active_low = flags & OF_GPIO_ACTIVE_LOW;
5028}
5029
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305030static int msmsdcc_dt_parse_gpio_info(struct device *dev,
5031 struct mmc_platform_data *pdata)
5032{
5033 int ret = 0, id = 0, cnt, i;
5034 struct msm_mmc_pin_data *pin_data;
5035 struct device_node *np = dev->of_node;
5036
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305037 msmsdcc_dt_get_cd_wp_gpio(dev, pdata);
5038
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305039 pin_data = devm_kzalloc(dev, sizeof(*pin_data), GFP_KERNEL);
5040 if (!pin_data) {
5041 dev_err(dev, "No memory for pin_data\n");
5042 ret = -ENOMEM;
5043 goto err;
5044 }
5045
5046 cnt = of_gpio_count(np);
5047 if (cnt > 0) {
5048 pin_data->is_gpio = true;
5049
5050 pin_data->gpio_data = devm_kzalloc(dev,
5051 sizeof(struct msm_mmc_gpio_data), GFP_KERNEL);
5052 if (!pin_data->gpio_data) {
5053 dev_err(dev, "No memory for gpio_data\n");
5054 ret = -ENOMEM;
5055 goto err;
5056 }
5057 pin_data->gpio_data->size = cnt;
5058 pin_data->gpio_data->gpio = devm_kzalloc(dev,
5059 cnt * sizeof(struct msm_mmc_gpio), GFP_KERNEL);
5060 if (!pin_data->gpio_data->gpio) {
5061 dev_err(dev, "No memory for gpio\n");
5062 ret = -ENOMEM;
5063 goto err;
5064 }
5065
5066 for (i = 0; i < cnt; i++) {
5067 const char *name = NULL;
5068 char result[32];
5069 pin_data->gpio_data->gpio[i].no = of_get_gpio(np, i);
5070 of_property_read_string_index(np,
5071 "qcom,sdcc-gpio-names", i, &name);
5072
5073 snprintf(result, 32, "%s-%s",
5074 dev_name(dev), name ? name : "?");
5075 pin_data->gpio_data->gpio[i].name = result;
5076 dev_dbg(dev, "%s: gpio[%s] = %d\n", __func__,
5077 pin_data->gpio_data->gpio[i].name,
5078 pin_data->gpio_data->gpio[i].no);
5079 }
5080 } else {
5081 pin_data->pad_data = devm_kzalloc(dev,
5082 sizeof(struct msm_mmc_pad_data), GFP_KERNEL);
5083 if (!pin_data->pad_data) {
5084 dev_err(dev, "No memory for pin_data->pad_data\n");
5085 ret = -ENOMEM;
5086 goto err;
5087 }
5088
5089 of_property_read_u32(np, "cell-index", &id);
5090
5091 ret = msmsdcc_dt_get_pad_pull_info(dev, id,
5092 &pin_data->pad_data->pull);
5093 if (ret)
5094 goto err;
5095 ret = msmsdcc_dt_get_pad_drv_info(dev, id,
5096 &pin_data->pad_data->drv);
5097 if (ret)
5098 goto err;
5099 }
5100
5101 pdata->pin_data = pin_data;
5102err:
5103 if (ret)
5104 dev_err(dev, "%s failed with err %d\n", __func__, ret);
5105 return ret;
5106}
5107
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305108#define MAX_PROP_SIZE 32
5109static int msmsdcc_dt_parse_vreg_info(struct device *dev,
5110 struct msm_mmc_reg_data **vreg_data, const char *vreg_name)
5111{
5112 int len, ret = 0;
5113 const __be32 *prop;
5114 char prop_name[MAX_PROP_SIZE];
5115 struct msm_mmc_reg_data *vreg;
5116 struct device_node *np = dev->of_node;
5117
5118 snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", vreg_name);
5119 if (of_parse_phandle(np, prop_name, 0)) {
5120 vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
5121 if (!vreg) {
5122 dev_err(dev, "No memory for vreg: %s\n", vreg_name);
5123 ret = -ENOMEM;
5124 goto err;
5125 }
5126
5127 vreg->name = vreg_name;
5128
5129 snprintf(prop_name, MAX_PROP_SIZE,
5130 "qcom,sdcc-%s-always_on", vreg_name);
5131 if (of_get_property(np, prop_name, NULL))
5132 vreg->always_on = true;
5133
5134 snprintf(prop_name, MAX_PROP_SIZE,
5135 "qcom,sdcc-%s-lpm_sup", vreg_name);
5136 if (of_get_property(np, prop_name, NULL))
5137 vreg->lpm_sup = true;
5138
5139 snprintf(prop_name, MAX_PROP_SIZE,
5140 "qcom,sdcc-%s-voltage_level", vreg_name);
5141 prop = of_get_property(np, prop_name, &len);
5142 if (!prop || (len != (2 * sizeof(__be32)))) {
5143 dev_warn(dev, "%s %s property\n",
5144 prop ? "invalid format" : "no", prop_name);
5145 } else {
5146 vreg->low_vol_level = be32_to_cpup(&prop[0]);
5147 vreg->high_vol_level = be32_to_cpup(&prop[1]);
5148 }
5149
5150 snprintf(prop_name, MAX_PROP_SIZE,
5151 "qcom,sdcc-%s-current_level", vreg_name);
5152 prop = of_get_property(np, prop_name, &len);
5153 if (!prop || (len != (2 * sizeof(__be32)))) {
5154 dev_warn(dev, "%s %s property\n",
5155 prop ? "invalid format" : "no", prop_name);
5156 } else {
5157 vreg->lpm_uA = be32_to_cpup(&prop[0]);
5158 vreg->hpm_uA = be32_to_cpup(&prop[1]);
5159 }
5160
5161 *vreg_data = vreg;
5162 dev_dbg(dev, "%s: %s %s vol=[%d %d]uV, curr=[%d %d]uA\n",
5163 vreg->name, vreg->always_on ? "always_on," : "",
5164 vreg->lpm_sup ? "lpm_sup," : "", vreg->low_vol_level,
5165 vreg->high_vol_level, vreg->lpm_uA, vreg->hpm_uA);
5166 }
5167
5168err:
5169 return ret;
5170}
5171
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305172static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
5173{
5174 int i, ret;
5175 struct mmc_platform_data *pdata;
5176 struct device_node *np = dev->of_node;
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305177 u32 bus_width = 0, current_limit = 0;
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305178 u32 *clk_table, *sup_voltages;
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305179 int clk_table_len, sup_volt_len, len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305180
5181 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
5182 if (!pdata) {
5183 dev_err(dev, "could not allocate memory for platform data\n");
5184 goto err;
5185 }
5186
5187 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
5188 if (bus_width == 8) {
5189 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
5190 } else if (bus_width == 4) {
5191 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
5192 } else {
5193 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
5194 pdata->mmc_bus_width = 0;
5195 }
5196
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305197 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-sup-voltages",
5198 &sup_voltages, &sup_volt_len, 0);
5199 if (!ret) {
5200 for (i = 0; i < sup_volt_len; i += 2) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305201 u32 mask;
5202
5203 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
5204 sup_voltages[i + 1]);
5205 if (!mask)
5206 dev_err(dev, "Invalide voltage range %d\n", i);
5207 pdata->ocr_mask |= mask;
5208 }
5209 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305210 }
5211
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305212 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-clk-rates",
5213 &clk_table, &clk_table_len, 0);
5214 if (!ret) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305215 pdata->sup_clk_table = clk_table;
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305216 pdata->sup_clk_cnt = clk_table_len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305217 }
5218
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305219 pdata->vreg_data = devm_kzalloc(dev,
5220 sizeof(struct msm_mmc_slot_reg_data), GFP_KERNEL);
5221 if (!pdata->vreg_data) {
5222 dev_err(dev, "could not allocate memory for vreg_data\n");
5223 goto err;
5224 }
5225
5226 if (msmsdcc_dt_parse_vreg_info(dev,
5227 &pdata->vreg_data->vdd_data, "vdd"))
5228 goto err;
5229
5230 if (msmsdcc_dt_parse_vreg_info(dev,
5231 &pdata->vreg_data->vdd_io_data, "vdd-io"))
5232 goto err;
5233
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305234 if (msmsdcc_dt_parse_gpio_info(dev, pdata))
5235 goto err;
5236
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305237 len = of_property_count_strings(np, "qcom,sdcc-bus-speed-mode");
5238
5239 for (i = 0; i < len; i++) {
5240 const char *name = NULL;
5241
5242 of_property_read_string_index(np,
5243 "qcom,sdcc-bus-speed-mode", i, &name);
5244 if (!name)
5245 continue;
5246
5247 if (!strncmp(name, "SDR12", sizeof("SDR12")))
5248 pdata->uhs_caps |= MMC_CAP_UHS_SDR12;
5249 else if (!strncmp(name, "SDR25", sizeof("SDR25")))
5250 pdata->uhs_caps |= MMC_CAP_UHS_SDR25;
5251 else if (!strncmp(name, "SDR50", sizeof("SDR50")))
5252 pdata->uhs_caps |= MMC_CAP_UHS_SDR50;
5253 else if (!strncmp(name, "DDR50", sizeof("DDR50")))
5254 pdata->uhs_caps |= MMC_CAP_UHS_DDR50;
5255 else if (!strncmp(name, "SDR104", sizeof("SDR104")))
5256 pdata->uhs_caps |= MMC_CAP_UHS_SDR104;
5257 else if (!strncmp(name, "HS200_1p8v", sizeof("HS200_1p8v")))
5258 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_8V_SDR;
5259 else if (!strncmp(name, "HS200_1p2v", sizeof("HS200_1p2v")))
5260 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_2V_SDR;
5261 else if (!strncmp(name, "DDR_1p8v", sizeof("DDR_1p8v")))
5262 pdata->uhs_caps |= MMC_CAP_1_8V_DDR
5263 | MMC_CAP_UHS_DDR50;
5264 else if (!strncmp(name, "DDR_1p2v", sizeof("DDR_1p2v")))
5265 pdata->uhs_caps |= MMC_CAP_1_2V_DDR
5266 | MMC_CAP_UHS_DDR50;
5267 }
5268
5269 of_property_read_u32(np, "qcom,sdcc-current-limit", &current_limit);
5270 if (current_limit == 800)
5271 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_800;
5272 else if (current_limit == 600)
5273 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_600;
5274 else if (current_limit == 400)
5275 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_400;
5276 else if (current_limit == 200)
5277 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_200;
5278
5279 if (of_get_property(np, "qcom,sdcc-xpc", NULL))
5280 pdata->xpc_cap = true;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305281 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
5282 pdata->nonremovable = true;
5283 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
5284 pdata->disable_cmd23 = true;
5285
5286 return pdata;
5287err:
5288 return NULL;
5289}
5290
San Mehat9d2bd732009-09-22 16:44:22 -07005291static int
5292msmsdcc_probe(struct platform_device *pdev)
5293{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305294 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07005295 struct msmsdcc_host *host;
5296 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005297 unsigned long flags;
5298 struct resource *core_irqres = NULL;
5299 struct resource *bam_irqres = NULL;
5300 struct resource *core_memres = NULL;
5301 struct resource *dml_memres = NULL;
5302 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07005303 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07005304 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05305305 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005306 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07005307
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305308 if (pdev->dev.of_node) {
5309 plat = msmsdcc_populate_pdata(&pdev->dev);
5310 of_property_read_u32((&pdev->dev)->of_node,
5311 "cell-index", &pdev->id);
5312 } else {
5313 plat = pdev->dev.platform_data;
5314 }
San Mehat9d2bd732009-09-22 16:44:22 -07005315
5316 /* must have platform data */
5317 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005318 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005319 ret = -EINVAL;
5320 goto out;
5321 }
5322
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005323 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07005324 return -EINVAL;
5325
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305326 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
5327 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
5328 return -EINVAL;
5329 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005330
San Mehat9d2bd732009-09-22 16:44:22 -07005331 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005332 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005333 return -ENXIO;
5334 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305335 if (pdev->dev.of_node) {
5336 /*
5337 * Device tree iomem resources are only accessible by index.
5338 * index = 0 -> SDCC register interface
5339 * index = 1 -> DML register interface
5340 * index = 2 -> BAM register interface
5341 * IRQ resources:
5342 * index = 0 -> SDCC IRQ
5343 * index = 1 -> BAM IRQ
5344 */
5345 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
5346 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
5347 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
5348 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
5349 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
5350 } else {
5351 for (i = 0; i < pdev->num_resources; i++) {
5352 if (pdev->resource[i].flags & IORESOURCE_MEM) {
5353 if (!strncmp(pdev->resource[i].name,
5354 "sdcc_dml_addr",
5355 sizeof("sdcc_dml_addr")))
5356 dml_memres = &pdev->resource[i];
5357 else if (!strncmp(pdev->resource[i].name,
5358 "sdcc_bam_addr",
5359 sizeof("sdcc_bam_addr")))
5360 bam_memres = &pdev->resource[i];
5361 else
5362 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07005363
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305364 }
5365 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
5366 if (!strncmp(pdev->resource[i].name,
5367 "sdcc_bam_irq",
5368 sizeof("sdcc_bam_irq")))
5369 bam_irqres = &pdev->resource[i];
5370 else
5371 core_irqres = &pdev->resource[i];
5372 }
5373 if (pdev->resource[i].flags & IORESOURCE_DMA) {
5374 if (!strncmp(pdev->resource[i].name,
5375 "sdcc_dma_chnl",
5376 sizeof("sdcc_dma_chnl")))
5377 dmares = &pdev->resource[i];
5378 else if (!strncmp(pdev->resource[i].name,
5379 "sdcc_dma_crci",
5380 sizeof("sdcc_dma_crci")))
5381 dma_crci_res = &pdev->resource[i];
5382 }
Krishna Konda25786ec2011-07-25 16:21:36 -07005383 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005384 }
San Mehat9d2bd732009-09-22 16:44:22 -07005385
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005386 if (!core_irqres || !core_memres) {
5387 pr_err("%s: Invalid sdcc core resource\n", __func__);
5388 return -ENXIO;
5389 }
5390
5391 /*
5392 * Both BAM and DML memory resource should be preset.
5393 * BAM IRQ resource should also be present.
5394 */
5395 if ((bam_memres && !dml_memres) ||
5396 (!bam_memres && dml_memres) ||
5397 ((bam_memres && dml_memres) && !bam_irqres)) {
5398 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005399 return -ENXIO;
5400 }
5401
5402 /*
5403 * Setup our host structure
5404 */
San Mehat9d2bd732009-09-22 16:44:22 -07005405 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
5406 if (!mmc) {
5407 ret = -ENOMEM;
5408 goto out;
5409 }
5410
5411 host = mmc_priv(mmc);
5412 host->pdev_id = pdev->id;
5413 host->plat = plat;
5414 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08005415 host->curr.cmd = NULL;
Sahitya Tummala19207f02011-05-02 18:10:01 +05305416
Sahitya Tummalad9df3272011-08-19 16:50:46 +05305417 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305418 set_hw_caps(host, MSMSDCC_SPS_BAM_SUP);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005419 else if (dmares)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305420 set_hw_caps(host, MSMSDCC_DMA_SUP);
San Mehat9d2bd732009-09-22 16:44:22 -07005421
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005422 host->base = ioremap(core_memres->start,
5423 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07005424 if (!host->base) {
5425 ret = -ENOMEM;
Sahitya Tummaladce7c752011-05-02 18:06:05 +05305426 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005427 }
5428
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005429 host->core_irqres = core_irqres;
5430 host->bam_irqres = bam_irqres;
5431 host->core_memres = core_memres;
5432 host->dml_memres = dml_memres;
5433 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07005434 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07005435 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07005436 spin_lock_init(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305437 mutex_init(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07005438
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005439#ifdef CONFIG_MMC_EMBEDDED_SDIO
5440 if (plat->embedded_sdio)
5441 mmc_set_embedded_sdio_data(mmc,
5442 &plat->embedded_sdio->cis,
5443 &plat->embedded_sdio->cccr,
5444 plat->embedded_sdio->funcs,
5445 plat->embedded_sdio->num_funcs);
5446#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005447
Sahitya Tummala62612cf2010-12-08 15:03:03 +05305448 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
5449 (unsigned long)host);
5450
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005451 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
5452 (unsigned long)host);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305453 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005454 /* Setup DMA */
Subhash Jadavani190657c2011-05-02 18:10:40 +05305455 ret = msmsdcc_init_dma(host);
5456 if (ret)
5457 goto ioremap_free;
5458 } else {
5459 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07005460 host->dma.crci = -1;
Subhash Jadavani190657c2011-05-02 18:10:40 +05305461 }
San Mehat9d2bd732009-09-22 16:44:22 -07005462
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005463 /*
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305464 * Setup SDCC bus voter clock.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005465 */
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305466 host->bus_clk = clk_get(&pdev->dev, "bus_clk");
5467 if (!IS_ERR_OR_NULL(host->bus_clk)) {
5468 /* Vote for max. clk rate for max. performance */
5469 ret = clk_set_rate(host->bus_clk, INT_MAX);
5470 if (ret)
5471 goto bus_clk_put;
5472 ret = clk_prepare_enable(host->bus_clk);
5473 if (ret)
5474 goto bus_clk_put;
San Mehat9d2bd732009-09-22 16:44:22 -07005475 }
5476
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005477 /*
5478 * Setup main peripheral bus clock
5479 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07005480 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005481 if (!IS_ERR(host->pclk)) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305482 ret = clk_prepare_enable(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005483 if (ret)
5484 goto pclk_put;
5485
5486 host->pclk_rate = clk_get_rate(host->pclk);
5487 }
5488
5489 /*
5490 * Setup SDC MMC clock
5491 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07005492 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07005493 if (IS_ERR(host->clk)) {
5494 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005495 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07005496 }
5497
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005498 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
Sahitya Tummala514d9ed2011-05-02 18:07:01 +05305499 if (ret) {
5500 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
5501 goto clk_put;
5502 }
5503
Asutosh Dasf5298c32012-04-03 14:51:47 +05305504 ret = clk_prepare_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07005505 if (ret)
5506 goto clk_put;
5507
San Mehat9d2bd732009-09-22 16:44:22 -07005508 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05305509 if (!host->clk_rate)
5510 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05305511
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305512 set_default_hw_caps(host);
5513
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05305514 /*
5515 * Set the register write delay according to min. clock frequency
5516 * supported and update later when the host->clk_rate changes.
5517 */
5518 host->reg_write_delay =
5519 (1 + ((3 * USEC_PER_SEC) /
5520 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005521
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305522 atomic_set(&host->clks_on, 1);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05305523 /* Apply Hard reset to SDCC to put it in power on default state */
5524 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005525
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005526#define MSM_MMC_DEFAULT_CPUDMA_LATENCY 200 /* usecs */
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305527 /* pm qos request to prevent apps idle power collapse */
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005528 if (host->plat->cpu_dma_latency)
5529 host->cpu_dma_latency = host->plat->cpu_dma_latency;
5530 else
5531 host->cpu_dma_latency = MSM_MMC_DEFAULT_CPUDMA_LATENCY;
5532 pm_qos_add_request(&host->pm_qos_req_dma,
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305533 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
5534
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305535 ret = msmsdcc_msm_bus_register(host);
5536 if (ret)
5537 goto pm_qos_remove;
5538
5539 if (host->msm_bus_vote.client_handle)
5540 INIT_DELAYED_WORK(&host->msm_bus_vote.vote_work,
5541 msmsdcc_msm_bus_work);
5542
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005543 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07005544 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005545 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07005546 goto clk_disable;
5547 }
5548
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005549
5550 /* Clocks has to be running before accessing SPS/DML HW blocks */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305551 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005552 /* Initialize SPS */
5553 ret = msmsdcc_sps_init(host);
5554 if (ret)
5555 goto vreg_deinit;
5556 /* Initialize DML */
5557 ret = msmsdcc_dml_init(host);
5558 if (ret)
5559 goto sps_exit;
5560 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05305561 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07005562
San Mehat9d2bd732009-09-22 16:44:22 -07005563 /*
5564 * Setup MMC host structure
5565 */
5566 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005567 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
5568 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005569 mmc->ocr_avail = plat->ocr_mask;
Sujit Reddy Thumma0e05f022012-06-11 19:44:18 +05305570 mmc->clkgate_delay = MSM_MMC_CLK_GATE_DELAY;
5571
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005572 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
5573 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07005574 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05305575 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
San Mehat9d2bd732009-09-22 16:44:22 -07005576
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05305577 /*
5578 * If we send the CMD23 before multi block write/read command
5579 * then we need not to send CMD12 at the end of the transfer.
5580 * If we don't send the CMD12 then only way to detect the PROG_DONE
5581 * status is to use the AUTO_PROG_DONE status provided by SDCC4
5582 * controller. So let's enable the CMD23 for SDCC4 only.
5583 */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305584 if (!plat->disable_cmd23 && is_auto_prog_done(host))
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05305585 mmc->caps |= MMC_CAP_CMD23;
San Mehat9d2bd732009-09-22 16:44:22 -07005586
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005587 mmc->caps |= plat->uhs_caps;
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305588 mmc->caps2 |= plat->uhs_caps2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005589 /*
5590 * XPC controls the maximum current in the default speed mode of SDXC
5591 * card. XPC=0 means 100mA (max.) but speed class is not supported.
5592 * XPC=1 means 150mA (max.) and speed class is supported.
5593 */
5594 if (plat->xpc_cap)
5595 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
5596 MMC_CAP_SET_XPC_180);
5597
Maya Erez25e22612012-05-20 08:45:01 +03005598 mmc->caps2 |= MMC_CAP2_PACKED_WR;
Maya Erez8afe8d22012-05-20 15:11:52 +03005599 mmc->caps2 |= MMC_CAP2_PACKED_WR_CONTROL;
Subhash Jadavani6bb34a82012-04-18 13:18:40 +05305600 mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
Yaniv Gardi14098552012-06-04 10:56:03 +03005601 mmc->caps2 |= MMC_CAP2_SANITIZE;
5602
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005603 if (plat->nonremovable)
5604 mmc->caps |= MMC_CAP_NONREMOVABLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005605 mmc->caps |= MMC_CAP_SDIO_IRQ;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005606
Konstantin Dorfman9db69fc2012-06-01 14:04:45 +03005607 mmc->caps2 |= MMC_CAP2_INIT_BKOPS | MMC_CAP2_BKOPS;
5608
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005609 if (plat->is_sdio_al_client)
5610 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07005611
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305612 mmc->max_segs = msmsdcc_get_nr_sg(host);
5613 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
5614 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07005615
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305616 mmc->max_req_size = MMC_MAX_REQ_SIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07005617 mmc->max_seg_size = mmc->max_req_size;
5618
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005619 writel_relaxed(0, host->base + MMCIMASK0);
5620 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05305621 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005622
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005623 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
5624 mb();
5625 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07005626
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005627 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
5628 DRIVER_NAME " (cmd)", host);
5629 if (ret)
5630 goto dml_exit;
5631
5632 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
5633 DRIVER_NAME " (pio)", host);
5634 if (ret)
5635 goto irq_free;
5636
5637 /*
5638 * Enable SDCC IRQ only when host is powered on. Otherwise, this
5639 * IRQ is un-necessarily being monitored by MPM (Modem power
5640 * management block) during idle-power collapse. The MPM will be
5641 * configured to monitor the DATA1 GPIO line with level-low trigger
5642 * and thus depending on the GPIO status, it prevents TCXO shutdown
5643 * during idle-power collapse.
5644 */
5645 disable_irq(core_irqres->start);
5646 host->sdcc_irq_disabled = 1;
5647
5648 if (plat->sdiowakeup_irq) {
5649 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5650 mmc_hostname(mmc));
5651 ret = request_irq(plat->sdiowakeup_irq,
5652 msmsdcc_platform_sdiowakeup_irq,
5653 IRQF_SHARED | IRQF_TRIGGER_LOW,
5654 DRIVER_NAME "sdiowakeup", host);
5655 if (ret) {
5656 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
5657 plat->sdiowakeup_irq, ret);
5658 goto pio_irq_free;
5659 } else {
5660 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305661 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005662 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305663 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005664 }
5665 spin_unlock_irqrestore(&host->lock, flags);
5666 }
5667 }
5668
Subhash Jadavanic9b85752012-04-13 11:16:49 +05305669 if (host->plat->mpm_sdiowakeup_int) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005670 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5671 mmc_hostname(mmc));
5672 }
5673
5674 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
5675 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005676 /*
5677 * Setup card detect change
5678 */
5679
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305680 if (!plat->status_gpio)
5681 plat->status_gpio = -ENOENT;
5682 if (!plat->wpswitch_gpio)
5683 plat->wpswitch_gpio = -ENOENT;
5684
5685 if (plat->status || gpio_is_valid(plat->status_gpio)) {
Krishna Konda941604a2012-01-10 17:46:34 -08005686 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005687 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08005688 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005689 host->oldstat = msmsdcc_slot_status(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005690
Krishna Konda941604a2012-01-10 17:46:34 -08005691 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005692 }
San Mehat9d2bd732009-09-22 16:44:22 -07005693
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005694 if (plat->status_irq) {
5695 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07005696 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005697 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07005698 DRIVER_NAME " (slot)",
5699 host);
5700 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005701 pr_err("Unable to get slot IRQ %d (%d)\n",
5702 plat->status_irq, ret);
5703 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005704 }
5705 } else if (plat->register_status_notify) {
5706 plat->register_status_notify(msmsdcc_status_notify_cb, host);
5707 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005708 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07005709 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005710
5711 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005712
5713 ret = pm_runtime_set_active(&(pdev)->dev);
5714 if (ret < 0)
5715 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
5716 __func__, ret);
5717 /*
5718 * There is no notion of suspend/resume for SD/MMC/SDIO
5719 * cards. So host can be suspended/resumed with out
5720 * worrying about its children.
5721 */
5722 pm_suspend_ignore_children(&(pdev)->dev, true);
5723
5724 /*
5725 * MMC/SD/SDIO bus suspend/resume operations are defined
5726 * only for the slots that will be used for non-removable
5727 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
5728 * defined. Otherwise, they simply become card removal and
5729 * insertion events during suspend and resume respectively.
5730 * Hence, enable run-time PM only for slots for which bus
5731 * suspend/resume operations are defined.
5732 */
5733#ifdef CONFIG_MMC_UNSAFE_RESUME
5734 /*
5735 * If this capability is set, MMC core will enable/disable host
5736 * for every claim/release operation on a host. We use this
5737 * notification to increment/decrement runtime pm usage count.
5738 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005739 pm_runtime_enable(&(pdev)->dev);
5740#else
5741 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005742 pm_runtime_enable(&(pdev)->dev);
5743 }
5744#endif
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305745 host->idle_tout_ms = MSM_MMC_DEFAULT_IDLE_TIMEOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005746 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
5747 (unsigned long)host);
5748
San Mehat9d2bd732009-09-22 16:44:22 -07005749 mmc_add_host(mmc);
5750
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005751#ifdef CONFIG_HAS_EARLYSUSPEND
5752 host->early_suspend.suspend = msmsdcc_early_suspend;
5753 host->early_suspend.resume = msmsdcc_late_resume;
5754 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
5755 register_early_suspend(&host->early_suspend);
5756#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005757
Krishna Konda25786ec2011-07-25 16:21:36 -07005758 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
5759 " dmacrcri %d\n", mmc_hostname(mmc),
5760 (unsigned long long)core_memres->start,
5761 (unsigned int) core_irqres->start,
5762 (unsigned int) plat->status_irq, host->dma.channel,
5763 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005764
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305765 pr_info("%s: Controller capabilities: 0x%.8x\n",
5766 mmc_hostname(mmc), host->hw_caps);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005767 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
5768 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
5769 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
5770 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
5771 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
5772 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
5773 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
5774 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
5775 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
5776 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
5777 host->eject);
5778 pr_info("%s: Power save feature enable = %d\n",
5779 mmc_hostname(mmc), msmsdcc_pwrsave);
5780
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305781 if (is_dma_mode(host) && host->dma.channel != -1
Krishna Konda25786ec2011-07-25 16:21:36 -07005782 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005783 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005784 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005785 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005786 mmc_hostname(mmc), host->dma.cmd_busaddr,
5787 host->dma.cmdptr_busaddr);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305788 } else if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005789 pr_info("%s: SPS-BAM data transfer mode available\n",
5790 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005791 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005792 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005793
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005794#if defined(CONFIG_DEBUG_FS)
5795 msmsdcc_dbg_createhost(host);
5796#endif
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305797
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305798 host->max_bus_bw.show = show_sdcc_to_mem_max_bus_bw;
5799 host->max_bus_bw.store = store_sdcc_to_mem_max_bus_bw;
5800 sysfs_attr_init(&host->max_bus_bw.attr);
5801 host->max_bus_bw.attr.name = "max_bus_bw";
5802 host->max_bus_bw.attr.mode = S_IRUGO | S_IWUSR;
5803 ret = device_create_file(&pdev->dev, &host->max_bus_bw);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305804 if (ret)
5805 goto platform_irq_free;
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305806
5807 if (!plat->status_irq) {
5808 host->polling.show = show_polling;
5809 host->polling.store = store_polling;
5810 sysfs_attr_init(&host->polling.attr);
5811 host->polling.attr.name = "polling";
5812 host->polling.attr.mode = S_IRUGO | S_IWUSR;
5813 ret = device_create_file(&pdev->dev, &host->polling);
5814 if (ret)
5815 goto remove_max_bus_bw_file;
5816 }
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305817 host->idle_timeout.show = show_idle_timeout;
5818 host->idle_timeout.store = store_idle_timeout;
5819 sysfs_attr_init(&host->idle_timeout.attr);
5820 host->idle_timeout.attr.name = "idle_timeout";
5821 host->idle_timeout.attr.mode = S_IRUGO | S_IWUSR;
5822 ret = device_create_file(&pdev->dev, &host->idle_timeout);
5823 if (ret)
5824 goto remove_polling_file;
San Mehat9d2bd732009-09-22 16:44:22 -07005825 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005826
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305827 remove_polling_file:
5828 if (!plat->status_irq)
5829 device_remove_file(&pdev->dev, &host->polling);
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305830 remove_max_bus_bw_file:
5831 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005832 platform_irq_free:
5833 del_timer_sync(&host->req_tout_timer);
5834 pm_runtime_disable(&(pdev)->dev);
5835 pm_runtime_set_suspended(&(pdev)->dev);
5836
5837 if (plat->status_irq)
5838 free_irq(plat->status_irq, host);
5839 sdiowakeup_irq_free:
5840 wake_lock_destroy(&host->sdio_suspend_wlock);
5841 if (plat->sdiowakeup_irq)
5842 free_irq(plat->sdiowakeup_irq, host);
5843 pio_irq_free:
5844 if (plat->sdiowakeup_irq)
5845 wake_lock_destroy(&host->sdio_wlock);
5846 free_irq(core_irqres->start, host);
5847 irq_free:
5848 free_irq(core_irqres->start, host);
5849 dml_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305850 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005851 msmsdcc_dml_exit(host);
5852 sps_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305853 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005854 msmsdcc_sps_exit(host);
5855 vreg_deinit:
5856 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07005857 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005858 clk_disable(host->clk);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305859 msmsdcc_msm_bus_unregister(host);
5860 pm_qos_remove:
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005861 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305862 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07005863 clk_put:
5864 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005865 pclk_disable:
5866 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05305867 clk_disable_unprepare(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07005868 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005869 if (!IS_ERR(host->pclk))
5870 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305871 if (!IS_ERR_OR_NULL(host->bus_clk))
5872 clk_disable_unprepare(host->bus_clk);
5873 bus_clk_put:
5874 if (!IS_ERR_OR_NULL(host->bus_clk))
5875 clk_put(host->bus_clk);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305876 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005877 if (host->dmares)
5878 dma_free_coherent(NULL,
5879 sizeof(struct msmsdcc_nc_dmadata),
5880 host->dma.nc, host->dma.nc_busaddr);
5881 }
5882 ioremap_free:
Sahitya Tummaladce7c752011-05-02 18:06:05 +05305883 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07005884 host_free:
5885 mmc_free_host(mmc);
5886 out:
5887 return ret;
5888}
5889
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005890static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07005891{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005892 struct mmc_host *mmc = mmc_get_drvdata(pdev);
5893 struct mmc_platform_data *plat;
5894 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07005895
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005896 if (!mmc)
5897 return -ENXIO;
5898
5899 if (pm_runtime_suspended(&(pdev)->dev))
5900 pm_runtime_resume(&(pdev)->dev);
5901
5902 host = mmc_priv(mmc);
5903
5904 DBG(host, "Removing SDCC device = %d\n", pdev->id);
5905 plat = host->plat;
5906
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305907 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005908 if (!plat->status_irq)
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305909 device_remove_file(&pdev->dev, &host->polling);
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305910 device_remove_file(&pdev->dev, &host->idle_timeout);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005911
5912 del_timer_sync(&host->req_tout_timer);
5913 tasklet_kill(&host->dma_tlet);
5914 tasklet_kill(&host->sps.tlet);
5915 mmc_remove_host(mmc);
5916
5917 if (plat->status_irq)
5918 free_irq(plat->status_irq, host);
5919
5920 wake_lock_destroy(&host->sdio_suspend_wlock);
5921 if (plat->sdiowakeup_irq) {
5922 wake_lock_destroy(&host->sdio_wlock);
5923 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
5924 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07005925 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005926
5927 free_irq(host->core_irqres->start, host);
5928 free_irq(host->core_irqres->start, host);
5929
5930 clk_put(host->clk);
5931 if (!IS_ERR(host->pclk))
5932 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305933 if (!IS_ERR_OR_NULL(host->bus_clk))
5934 clk_put(host->bus_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005935
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005936 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305937 pm_qos_remove_request(&host->pm_qos_req_dma);
5938
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305939 if (host->msm_bus_vote.client_handle) {
5940 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
5941 msmsdcc_msm_bus_unregister(host);
5942 }
5943
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005944 msmsdcc_vreg_init(host, false);
5945
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305946 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005947 if (host->dmares)
5948 dma_free_coherent(NULL,
5949 sizeof(struct msmsdcc_nc_dmadata),
5950 host->dma.nc, host->dma.nc_busaddr);
5951 }
5952
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305953 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005954 msmsdcc_dml_exit(host);
5955 msmsdcc_sps_exit(host);
5956 }
5957
5958 iounmap(host->base);
5959 mmc_free_host(mmc);
5960
5961#ifdef CONFIG_HAS_EARLYSUSPEND
5962 unregister_early_suspend(&host->early_suspend);
5963#endif
5964 pm_runtime_disable(&(pdev)->dev);
5965 pm_runtime_set_suspended(&(pdev)->dev);
5966
5967 return 0;
5968}
5969
5970#ifdef CONFIG_MSM_SDIO_AL
5971int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
5972{
5973 struct msmsdcc_host *host = mmc_priv(mmc);
5974 unsigned long flags;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305975 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005976
Asutosh Dasf5298c32012-04-03 14:51:47 +05305977 mutex_lock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005978 spin_lock_irqsave(&host->lock, flags);
5979 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
5980 enable ? "En" : "Dis");
5981
5982 if (enable) {
5983 if (!host->sdcc_irq_disabled) {
5984 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05305985 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005986 host->sdcc_irq_disabled = 1;
5987 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305988 rc = msmsdcc_setup_clocks(host, false);
5989 if (rc)
5990 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005991
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305992 if (host->plat->sdio_lpm_gpio_setup &&
5993 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005994 spin_unlock_irqrestore(&host->lock, flags);
5995 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
5996 spin_lock_irqsave(&host->lock, flags);
5997 host->sdio_gpio_lpm = 1;
5998 }
5999
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306000 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006001 msmsdcc_enable_irq_wake(host);
6002 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306003 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006004 }
6005 } else {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306006 rc = msmsdcc_setup_clocks(host, true);
6007 if (rc)
6008 goto out;
6009
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306010 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006011 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306012 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006013 msmsdcc_disable_irq_wake(host);
6014 }
6015
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05306016 if (host->plat->sdio_lpm_gpio_setup &&
6017 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006018 spin_unlock_irqrestore(&host->lock, flags);
6019 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
6020 spin_lock_irqsave(&host->lock, flags);
6021 host->sdio_gpio_lpm = 0;
6022 }
6023
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306024 if (host->sdcc_irq_disabled && atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006025 writel_relaxed(host->mci_irqenable,
6026 host->base + MMCIMASK0);
6027 mb();
6028 enable_irq(host->core_irqres->start);
6029 host->sdcc_irq_disabled = 0;
6030 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006031 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306032out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006033 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05306034 mutex_unlock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306035 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006036}
6037#else
6038int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
6039{
6040 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07006041}
6042#endif
6043
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006044#ifdef CONFIG_PM
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306045#ifdef CONFIG_MMC_CLKGATE
6046static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6047{
6048 struct mmc_host *mmc = host->mmc;
6049 unsigned long flags;
6050
6051 mmc_host_clk_hold(mmc);
6052 spin_lock_irqsave(&mmc->clk_lock, flags);
6053 mmc->clk_old = mmc->ios.clock;
6054 mmc->ios.clock = 0;
6055 mmc->clk_gated = true;
6056 spin_unlock_irqrestore(&mmc->clk_lock, flags);
6057 mmc_set_ios(mmc);
6058 mmc_host_clk_release(mmc);
6059}
6060
6061static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6062{
6063 struct mmc_host *mmc = host->mmc;
6064
6065 mmc_host_clk_hold(mmc);
6066 mmc->ios.clock = host->clk_rate;
6067 mmc_set_ios(mmc);
6068 mmc_host_clk_release(mmc);
6069}
6070#else
6071static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6072{
6073 struct mmc_host *mmc = host->mmc;
6074
6075 mmc->ios.clock = 0;
6076 mmc_set_ios(mmc);
6077}
6078
6079static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6080{
6081 struct mmc_host *mmc = host->mmc;
6082
6083 mmc->ios.clock = host->clk_rate;
6084 mmc_set_ios(mmc);
6085}
6086#endif
6087
San Mehat9d2bd732009-09-22 16:44:22 -07006088static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006089msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006090{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006091 struct mmc_host *mmc = dev_get_drvdata(dev);
6092 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006093 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306094 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07006095
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306096 if (host->plat->is_sdio_al_client) {
6097 rc = 0;
6098 goto out;
San Mehat9d2bd732009-09-22 16:44:22 -07006099 }
San Mehat9d2bd732009-09-22 16:44:22 -07006100
Sahitya Tummala7661a452011-07-18 13:28:35 +05306101 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006102 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006103 host->sdcc_suspending = 1;
6104 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07006105
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006106 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006107 * MMC core thinks that host is disabled by now since
6108 * runtime suspend is scheduled after msmsdcc_disable()
6109 * is called. Thus, MMC core will try to enable the host
6110 * while suspending it. This results in a synchronous
6111 * runtime resume request while in runtime suspending
6112 * context and hence inorder to complete this resume
6113 * requet, it will wait for suspend to be complete,
6114 * but runtime suspend also can not proceed further
6115 * until the host is resumed. Thus, it leads to a hang.
6116 * Hence, increase the pm usage count before suspending
6117 * the host so that any resume requests after this will
6118 * simple become pm usage counter increment operations.
6119 */
6120 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306121 /* If there is pending detect work abort runtime suspend */
6122 if (unlikely(work_busy(&mmc->detect.work)))
6123 rc = -EAGAIN;
6124 else
6125 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006126 pm_runtime_put_noidle(dev);
6127
6128 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306129 spin_lock_irqsave(&host->lock, flags);
6130 host->sdcc_suspended = true;
6131 spin_unlock_irqrestore(&host->lock, flags);
6132 if (mmc->card && mmc_card_sdio(mmc->card) &&
6133 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006134 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306135 * If SDIO function driver doesn't want
6136 * to power off the card, atleast turn off
6137 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006138 */
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306139 msmsdcc_gate_clock(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006140 }
6141 }
6142 host->sdcc_suspending = 0;
6143 mmc->suspend_task = NULL;
6144 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
6145 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006146 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306147 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306148out:
6149 /* set bus bandwidth to 0 immediately */
6150 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
San Mehat9d2bd732009-09-22 16:44:22 -07006151 return rc;
6152}
6153
6154static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006155msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006156{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006157 struct mmc_host *mmc = dev_get_drvdata(dev);
6158 struct msmsdcc_host *host = mmc_priv(mmc);
6159 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07006160
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006161 if (host->plat->is_sdio_al_client)
6162 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07006163
Sahitya Tummala7661a452011-07-18 13:28:35 +05306164 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006165 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306166 if (mmc->card && mmc_card_sdio(mmc->card) &&
6167 mmc_card_keep_power(mmc)) {
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306168 msmsdcc_ungate_clock(host);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05306169 }
San Mehat9d2bd732009-09-22 16:44:22 -07006170
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006171 mmc_resume_host(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006172
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006173 /*
6174 * FIXME: Clearing of flags must be handled in clients
6175 * resume handler.
6176 */
6177 spin_lock_irqsave(&host->lock, flags);
6178 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306179 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006180 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07006181
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006182 /*
6183 * After resuming the host wait for sometime so that
6184 * the SDIO work will be processed.
6185 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306186 if (mmc->card && mmc_card_sdio(mmc->card)) {
Subhash Jadavanic9b85752012-04-13 11:16:49 +05306187 if ((host->plat->mpm_sdiowakeup_int ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006188 host->plat->sdiowakeup_irq) &&
6189 wake_lock_active(&host->sdio_wlock))
6190 wake_lock_timeout(&host->sdio_wlock, 1);
6191 }
6192
6193 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006194 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05306195 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006196 return 0;
6197}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006198
6199static int msmsdcc_runtime_idle(struct device *dev)
6200{
6201 struct mmc_host *mmc = dev_get_drvdata(dev);
6202 struct msmsdcc_host *host = mmc_priv(mmc);
6203
6204 if (host->plat->is_sdio_al_client)
6205 return 0;
6206
6207 /* Idle timeout is not configurable for now */
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306208 pm_schedule_suspend(dev, host->idle_tout_ms);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006209
6210 return -EAGAIN;
6211}
6212
6213static int msmsdcc_pm_suspend(struct device *dev)
6214{
6215 struct mmc_host *mmc = dev_get_drvdata(dev);
6216 struct msmsdcc_host *host = mmc_priv(mmc);
6217 int rc = 0;
6218
6219 if (host->plat->is_sdio_al_client)
6220 return 0;
6221
6222
6223 if (host->plat->status_irq)
6224 disable_irq(host->plat->status_irq);
6225
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006226 if (!pm_runtime_suspended(dev))
6227 rc = msmsdcc_runtime_suspend(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006228
6229 return rc;
6230}
6231
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306232static int msmsdcc_suspend_noirq(struct device *dev)
6233{
6234 struct mmc_host *mmc = dev_get_drvdata(dev);
6235 struct msmsdcc_host *host = mmc_priv(mmc);
6236 int rc = 0;
6237
6238 /*
6239 * After platform suspend there may be active request
6240 * which might have enabled clocks. For example, in SDIO
6241 * case, ksdioirq thread might have scheduled after sdcc
6242 * suspend but before system freeze. In that case abort
6243 * suspend and retry instead of keeping the clocks on
6244 * during suspend and not allowing TCXO.
6245 */
6246
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306247 if (atomic_read(&host->clks_on) && !host->plat->is_sdio_al_client) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306248 pr_warn("%s: clocks are on after suspend, aborting system "
6249 "suspend\n", mmc_hostname(mmc));
6250 rc = -EAGAIN;
6251 }
6252
6253 return rc;
6254}
6255
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006256static int msmsdcc_pm_resume(struct device *dev)
6257{
6258 struct mmc_host *mmc = dev_get_drvdata(dev);
6259 struct msmsdcc_host *host = mmc_priv(mmc);
6260 int rc = 0;
6261
6262 if (host->plat->is_sdio_al_client)
6263 return 0;
6264
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006265 if (mmc->card && mmc_card_sdio(mmc->card))
Sahitya Tummalafb486372011-09-02 19:01:49 +05306266 rc = msmsdcc_runtime_resume(dev);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006267 else
6268 host->pending_resume = true;
6269
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006270 if (host->plat->status_irq) {
6271 msmsdcc_check_status((unsigned long)host);
6272 enable_irq(host->plat->status_irq);
6273 }
6274
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006275 return rc;
6276}
6277
Daniel Walker08ecfde2010-06-23 12:32:20 -07006278#else
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006279static int msmsdcc_runtime_suspend(struct device *dev)
6280{
6281 return 0;
6282}
6283static int msmsdcc_runtime_idle(struct device *dev)
6284{
6285 return 0;
6286}
6287static int msmsdcc_pm_suspend(struct device *dev)
6288{
6289 return 0;
6290}
6291static int msmsdcc_pm_resume(struct device *dev)
6292{
6293 return 0;
6294}
6295static int msmsdcc_suspend_noirq(struct device *dev)
6296{
6297 return 0;
6298}
6299static int msmsdcc_runtime_resume(struct device *dev)
6300{
6301 return 0;
6302}
Daniel Walker08ecfde2010-06-23 12:32:20 -07006303#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006304
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006305static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
6306 .runtime_suspend = msmsdcc_runtime_suspend,
6307 .runtime_resume = msmsdcc_runtime_resume,
6308 .runtime_idle = msmsdcc_runtime_idle,
6309 .suspend = msmsdcc_pm_suspend,
6310 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306311 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006312};
6313
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306314static const struct of_device_id msmsdcc_dt_match[] = {
6315 {.compatible = "qcom,msm-sdcc"},
6316
6317};
6318MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
6319
San Mehat9d2bd732009-09-22 16:44:22 -07006320static struct platform_driver msmsdcc_driver = {
6321 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006322 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07006323 .driver = {
6324 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006325 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306326 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07006327 },
6328};
6329
6330static int __init msmsdcc_init(void)
6331{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006332#if defined(CONFIG_DEBUG_FS)
6333 int ret = 0;
6334 ret = msmsdcc_dbg_init();
6335 if (ret) {
6336 pr_err("Failed to create debug fs dir \n");
6337 return ret;
6338 }
6339#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006340 return platform_driver_register(&msmsdcc_driver);
6341}
San Mehat9d2bd732009-09-22 16:44:22 -07006342
San Mehat9d2bd732009-09-22 16:44:22 -07006343static void __exit msmsdcc_exit(void)
6344{
6345 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006346
6347#if defined(CONFIG_DEBUG_FS)
6348 debugfs_remove(debugfs_file);
6349 debugfs_remove(debugfs_dir);
6350#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006351}
6352
6353module_init(msmsdcc_init);
6354module_exit(msmsdcc_exit);
6355
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006356MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07006357MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006358
6359#if defined(CONFIG_DEBUG_FS)
6360
6361static int
6362msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
6363{
6364 file->private_data = inode->i_private;
6365 return 0;
6366}
6367
6368static ssize_t
6369msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
6370 size_t count, loff_t *ppos)
6371{
6372 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08006373 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006374 int max, i;
6375
6376 i = 0;
6377 max = sizeof(buf) - 1;
6378
6379 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
6380 host->curr.cmd, host->curr.data);
6381 if (host->curr.cmd) {
6382 struct mmc_command *cmd = host->curr.cmd;
6383
6384 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
6385 cmd->opcode, cmd->arg, cmd->flags);
6386 }
6387 if (host->curr.data) {
6388 struct mmc_data *data = host->curr.data;
6389 i += scnprintf(buf + i, max - i,
6390 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
6391 data->timeout_ns, data->timeout_clks,
6392 data->blksz, data->blocks, data->error,
6393 data->flags);
6394 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
6395 host->curr.xfer_size, host->curr.xfer_remain,
6396 host->curr.data_xfered, host->dma.sg);
6397 }
6398
6399 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
6400}
6401
6402static const struct file_operations msmsdcc_dbg_state_ops = {
6403 .read = msmsdcc_dbg_state_read,
6404 .open = msmsdcc_dbg_state_open,
6405};
6406
6407static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
6408{
6409 if (debugfs_dir) {
6410 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
6411 0644, debugfs_dir, host,
6412 &msmsdcc_dbg_state_ops);
6413 }
6414}
6415
6416static int __init msmsdcc_dbg_init(void)
6417{
6418 int err;
6419
6420 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
6421 if (IS_ERR(debugfs_dir)) {
6422 err = PTR_ERR(debugfs_dir);
6423 debugfs_dir = NULL;
6424 return err;
6425 }
6426
6427 return 0;
6428}
6429#endif