blob: 3a02d3a21ed14e65e9317aa083ed74855c1667d7 [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 Jadavanif97d2992012-07-13 14:47:47 +05301139 if (cmd->mrq->data && (cmd->mrq->data->flags & MMC_DATA_READ))
1140 writel_relaxed((readl_relaxed(host->base +
1141 MCI_DLL_CONFIG) | MCI_CDR_EN),
1142 host->base + MCI_DLL_CONFIG);
1143 else
1144 /* Clear CDR_EN bit for non read operations */
1145 writel_relaxed((readl_relaxed(host->base +
1146 MCI_DLL_CONFIG) & ~MCI_CDR_EN),
1147 host->base + MCI_DLL_CONFIG);
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05301148
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301149 if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301150 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001151 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301152 }
1153
San Mehat56a8b5b2009-11-21 12:29:46 -08001154 if (cmd == cmd->mrq->stop)
1155 *c |= MCI_CSPM_MCIABORT;
1156
San Mehat56a8b5b2009-11-21 12:29:46 -08001157 if (host->curr.cmd != NULL) {
Girish K Sa3c76eb2011-10-11 11:44:09 +05301158 pr_err("%s: Overlapping command requests\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001159 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -08001160 }
1161 host->curr.cmd = cmd;
1162}
1163
1164static void
1165msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1166 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001167{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301168 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001169 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001170 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001171 unsigned int pio_irqmask = 0;
1172
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301173 BUG_ON(!data->sg);
1174 BUG_ON(!data->sg_len);
1175
San Mehat9d2bd732009-09-22 16:44:22 -07001176 host->curr.data = data;
1177 host->curr.xfer_size = data->blksz * data->blocks;
1178 host->curr.xfer_remain = host->curr.xfer_size;
1179 host->curr.data_xfered = 0;
1180 host->curr.got_dataend = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301181 host->curr.got_auto_prog_done = false;
San Mehat9d2bd732009-09-22 16:44:22 -07001182
San Mehat9d2bd732009-09-22 16:44:22 -07001183 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1184
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301185 if (host->curr.wait_for_auto_prog_done)
1186 datactrl |= MCI_AUTO_PROG_DONE;
San Mehat9d2bd732009-09-22 16:44:22 -07001187
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05301188 if (msmsdcc_is_dma_possible(host, data)) {
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301189 if (is_dma_mode(host) && !msmsdcc_config_dma(host, data)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001190 datactrl |= MCI_DPSM_DMAENABLE;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301191 } else if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001192 if (!msmsdcc_is_dml_busy(host)) {
1193 if (!msmsdcc_sps_start_xfer(host, data)) {
1194 /* Now kick start DML transfer */
1195 mb();
1196 msmsdcc_dml_start_xfer(host, data);
1197 datactrl |= MCI_DPSM_DMAENABLE;
1198 host->sps.busy = 1;
1199 }
1200 } else {
1201 /*
1202 * Can't proceed with new transfer as
1203 * previous trasnfer is already in progress.
1204 * There is no point of going into PIO mode
1205 * as well. Is this a time to do kernel panic?
1206 */
1207 pr_err("%s: %s: DML HW is busy!!!"
1208 " Can't perform new SPS transfers"
1209 " now\n", mmc_hostname(host->mmc),
1210 __func__);
1211 }
1212 }
1213 }
1214
1215 /* Is data transfer in PIO mode required? */
1216 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001217 if (data->flags & MMC_DATA_READ) {
1218 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1219 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1220 pio_irqmask |= MCI_RXDATAAVLBLMASK;
1221 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001222 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1223 MCI_TXFIFOEMPTYMASK;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001224
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001225 msmsdcc_sg_start(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001226 }
1227
1228 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301229 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
Subhash Jadavanif5277752011-10-12 16:47:52 +05301230 else if (host->curr.use_wr_data_pend)
1231 datactrl |= MCI_DATA_PEND;
San Mehat9d2bd732009-09-22 16:44:22 -07001232
San Mehat56a8b5b2009-11-21 12:29:46 -08001233 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001234 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001235 timeout = data->timeout_clks + (unsigned int)clks*2 ;
Subhash Jadavani63540362012-06-12 14:56:04 +05301236 WARN(!timeout,
1237 "%s: data timeout is zero. timeout_ns=0x%x, timeout_clks=0x%x\n",
1238 mmc_hostname(host->mmc), data->timeout_ns, data->timeout_clks);
San Mehat9d2bd732009-09-22 16:44:22 -07001239
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301240 if (is_dma_mode(host) && (datactrl & MCI_DPSM_DMAENABLE)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001241 /* Use ADM (Application Data Mover) HW for Data transfer */
1242 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001243 host->cmd_timeout = timeout;
1244 host->cmd_pio_irqmask = pio_irqmask;
1245 host->cmd_datactrl = datactrl;
1246 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001247
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001248 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1249 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001250 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001251
1252 if (cmd) {
1253 msmsdcc_start_command_deferred(host, cmd, &c);
1254 host->cmd_c = c;
1255 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001256 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1257 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1258 host->base + MMCIMASK0);
1259 mb();
1260 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001261 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001262 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001263 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001264
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001265 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001266
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001267 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1268 (~(MCI_IRQ_PIO))) | pio_irqmask,
1269 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001270 writel_relaxed(datactrl, base + MMCIDATACTRL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001271
1272 if (cmd) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05301273 /* Delay between data/command */
1274 msmsdcc_sync_reg_wr(host);
San Mehat56a8b5b2009-11-21 12:29:46 -08001275 /* Daisy-chain the command if requested */
1276 msmsdcc_start_command(host, cmd, c);
Subhash Jadavanidd432952012-03-28 11:25:56 +05301277 } else {
1278 /*
1279 * We don't need delay after writing to DATA_CTRL
1280 * register if we are not writing to CMD register
1281 * immediately after this. As we already have delay
1282 * before sending the command, we just need mb() here.
1283 */
1284 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001285 }
San Mehat9d2bd732009-09-22 16:44:22 -07001286 }
1287}
1288
1289static void
1290msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1291{
San Mehat56a8b5b2009-11-21 12:29:46 -08001292 msmsdcc_start_command_deferred(host, cmd, &c);
1293 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001294}
1295
1296static void
1297msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1298 unsigned int status)
1299{
1300 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001301 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
Subhash Jadavanib30c9822012-03-27 18:03:16 +05301302 || data->mrq->cmd->opcode == MMC_BUS_TEST_R
1303 || data->mrq->cmd->opcode ==
1304 MMC_SEND_TUNING_BLOCK_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001305 pr_err("%s: Data CRC error\n",
1306 mmc_hostname(host->mmc));
1307 pr_err("%s: opcode 0x%.8x\n", __func__,
1308 data->mrq->cmd->opcode);
1309 pr_err("%s: blksz %d, blocks %d\n", __func__,
1310 data->blksz, data->blocks);
1311 data->error = -EILSEQ;
1312 }
San Mehat9d2bd732009-09-22 16:44:22 -07001313 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001314 /* CRC is optional for the bus test commands, not all
1315 * cards respond back with CRC. However controller
1316 * waits for the CRC and times out. Hence ignore the
1317 * data timeouts during the Bustest.
1318 */
1319 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1320 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301321 pr_err("%s: CMD%d: Data timeout\n",
1322 mmc_hostname(host->mmc),
1323 data->mrq->cmd->opcode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001324 data->error = -ETIMEDOUT;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301325 msmsdcc_dump_sdcc_state(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001326 }
San Mehat9d2bd732009-09-22 16:44:22 -07001327 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001328 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001329 data->error = -EIO;
1330 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001331 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001332 data->error = -EIO;
1333 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001334 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001335 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001336 data->error = -EIO;
1337 }
San Mehat9d2bd732009-09-22 16:44:22 -07001338
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001339 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001340 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001341 host->dummy_52_needed = 0;
1342}
San Mehat9d2bd732009-09-22 16:44:22 -07001343
1344static int
1345msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1346{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001347 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001348 uint32_t *ptr = (uint32_t *) buffer;
1349 int count = 0;
1350
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301351 if (remain % 4)
1352 remain = ((remain >> 2) + 1) << 2;
1353
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001354 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1355
1356 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001357 ptr++;
1358 count += sizeof(uint32_t);
1359
1360 remain -= sizeof(uint32_t);
1361 if (remain == 0)
1362 break;
1363 }
1364 return count;
1365}
1366
1367static int
1368msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001369 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001370{
1371 void __iomem *base = host->base;
1372 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001373 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001374
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001375 while (readl_relaxed(base + MMCISTATUS) &
1376 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1377 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001378
San Mehat9d2bd732009-09-22 16:44:22 -07001379 count = min(remain, maxcnt);
1380
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301381 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1382 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001383 ptr += count;
1384 remain -= count;
1385
1386 if (remain == 0)
1387 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001388 }
1389 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001390
1391 return ptr - buffer;
1392}
1393
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001394/*
1395 * Copy up to a word (4 bytes) between a scatterlist
1396 * and a temporary bounce buffer when the word lies across
1397 * two pages. The temporary buffer can then be read to/
1398 * written from the FIFO once.
1399 */
1400static void _msmsdcc_sg_consume_word(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -07001401{
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001402 struct msmsdcc_pio_data *pio = &host->pio;
1403 unsigned int bytes_avail;
1404
1405 if (host->curr.data->flags & MMC_DATA_READ)
1406 memcpy(pio->sg_miter.addr, pio->bounce_buf,
1407 pio->bounce_buf_len);
1408 else
1409 memcpy(pio->bounce_buf, pio->sg_miter.addr,
1410 pio->bounce_buf_len);
1411
1412 while (pio->bounce_buf_len != 4) {
1413 if (!sg_miter_next(&pio->sg_miter))
1414 break;
1415 bytes_avail = min_t(unsigned int, pio->sg_miter.length,
1416 4 - pio->bounce_buf_len);
1417 if (host->curr.data->flags & MMC_DATA_READ)
1418 memcpy(pio->sg_miter.addr,
1419 &pio->bounce_buf[pio->bounce_buf_len],
1420 bytes_avail);
1421 else
1422 memcpy(&pio->bounce_buf[pio->bounce_buf_len],
1423 pio->sg_miter.addr, bytes_avail);
1424
1425 pio->sg_miter.consumed = bytes_avail;
1426 pio->bounce_buf_len += bytes_avail;
San Mehat9d2bd732009-09-22 16:44:22 -07001427 }
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001428}
1429
1430/*
1431 * Use sg_miter_next to return as many 4-byte aligned
1432 * chunks as possible, using a temporary 4 byte buffer
1433 * for alignment if necessary
1434 */
1435static int msmsdcc_sg_next(struct msmsdcc_host *host, char **buf, int *len)
1436{
1437 struct msmsdcc_pio_data *pio = &host->pio;
1438 unsigned int length, rlength;
1439 char *buffer;
1440
1441 if (!sg_miter_next(&pio->sg_miter))
1442 return 0;
1443
1444 buffer = pio->sg_miter.addr;
1445 length = pio->sg_miter.length;
1446
1447 if (length < host->curr.xfer_remain) {
1448 rlength = round_down(length, 4);
1449 if (rlength) {
1450 /*
1451 * We have a 4-byte aligned chunk.
1452 * The rounding will be reflected by
1453 * a call to msmsdcc_sg_consumed
1454 */
1455 length = rlength;
1456 goto sg_next_end;
1457 }
1458 /*
1459 * We have a length less than 4 bytes. Check to
1460 * see if more buffer is available, and combine
1461 * to make 4 bytes if possible.
1462 */
1463 pio->bounce_buf_len = length;
1464 memset(pio->bounce_buf, 0, 4);
1465
1466 /*
1467 * On a read, get 4 bytes from FIFO, and distribute
1468 * (4-bouce_buf_len) bytes into consecutive
1469 * sgl buffers when msmsdcc_sg_consumed is called
1470 */
1471 if (host->curr.data->flags & MMC_DATA_READ) {
1472 buffer = pio->bounce_buf;
1473 length = 4;
1474 goto sg_next_end;
1475 } else {
1476 _msmsdcc_sg_consume_word(host);
1477 buffer = pio->bounce_buf;
1478 length = pio->bounce_buf_len;
1479 }
1480 }
1481
1482sg_next_end:
1483 *buf = buffer;
1484 *len = length;
1485 return 1;
1486}
1487
1488/*
1489 * Update sg_miter.consumed based on how many bytes were
1490 * consumed. If the bounce buffer was used to read from FIFO,
1491 * redistribute into sgls.
1492 */
1493static void msmsdcc_sg_consumed(struct msmsdcc_host *host,
1494 unsigned int length)
1495{
1496 struct msmsdcc_pio_data *pio = &host->pio;
1497
1498 if (host->curr.data->flags & MMC_DATA_READ) {
1499 if (length > pio->sg_miter.consumed)
1500 /*
1501 * consumed 4 bytes, but sgl
1502 * describes < 4 bytes
1503 */
1504 _msmsdcc_sg_consume_word(host);
1505 else
1506 pio->sg_miter.consumed = length;
1507 } else
1508 if (length < pio->sg_miter.consumed)
1509 pio->sg_miter.consumed = length;
1510}
1511
1512static void msmsdcc_sg_start(struct msmsdcc_host *host)
1513{
1514 unsigned int sg_miter_flags = SG_MITER_ATOMIC;
1515
1516 host->pio.bounce_buf_len = 0;
1517
1518 if (host->curr.data->flags & MMC_DATA_READ)
1519 sg_miter_flags |= SG_MITER_TO_SG;
1520 else
1521 sg_miter_flags |= SG_MITER_FROM_SG;
1522
1523 sg_miter_start(&host->pio.sg_miter, host->curr.data->sg,
1524 host->curr.data->sg_len, sg_miter_flags);
1525}
1526
1527static void msmsdcc_sg_stop(struct msmsdcc_host *host)
1528{
1529 sg_miter_stop(&host->pio.sg_miter);
San Mehat9d2bd732009-09-22 16:44:22 -07001530}
1531
San Mehat1cd22962010-02-03 12:59:29 -08001532static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001533msmsdcc_pio_irq(int irq, void *dev_id)
1534{
1535 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001536 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001537 uint32_t status;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001538 unsigned long flags;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001539 unsigned int remain;
1540 char *buffer;
San Mehat9d2bd732009-09-22 16:44:22 -07001541
Murali Palnati36448a42011-09-02 15:06:18 +05301542 spin_lock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301543
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001544 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001545
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001546 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301547 (MCI_IRQ_PIO)) == 0) {
1548 spin_unlock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301549 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301550 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001551#if IRQ_DEBUG
1552 msmsdcc_print_status(host, "irq1-r", status);
1553#endif
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001554 local_irq_save(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001555
1556 do {
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001557 unsigned int len;
San Mehat9d2bd732009-09-22 16:44:22 -07001558
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001559 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1560 | MCI_RXDATAAVLBL)))
1561 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001562
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001563 if (!msmsdcc_sg_next(host, &buffer, &remain))
1564 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001565
San Mehat9d2bd732009-09-22 16:44:22 -07001566 len = 0;
1567 if (status & MCI_RXACTIVE)
1568 len = msmsdcc_pio_read(host, buffer, remain);
1569 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001570 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001571
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301572 /* len might have aligned to 32bits above */
1573 if (len > remain)
1574 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001575
San Mehat9d2bd732009-09-22 16:44:22 -07001576 host->curr.xfer_remain -= len;
1577 host->curr.data_xfered += len;
1578 remain -= len;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001579 msmsdcc_sg_consumed(host, len);
San Mehat9d2bd732009-09-22 16:44:22 -07001580
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001581 if (remain) /* Done with this page? */
1582 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001583
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001584 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001585 } while (1);
1586
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001587 msmsdcc_sg_stop(host);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001588 local_irq_restore(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001589
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001590 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1591 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1592 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1593 host->base + MMCIMASK0);
1594 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301595 /*
1596 * back to back write to MASK0 register don't need
1597 * synchronization delay.
1598 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001599 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1600 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1601 }
1602 mb();
1603 } else if (!host->curr.xfer_remain) {
1604 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1605 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1606 mb();
1607 }
San Mehat9d2bd732009-09-22 16:44:22 -07001608
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001609 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001610
1611 return IRQ_HANDLED;
1612}
1613
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001614static void
1615msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1616
1617static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1618 struct mmc_data *data)
1619{
1620 u32 loop_cnt = 0;
1621
1622 /*
1623 * For read commands with data less than fifo size, it is possible to
1624 * get DATAEND first and RXDATA_AVAIL might be set later because of
1625 * synchronization delay through the asynchronous RX FIFO. Thus, for
1626 * such cases, even after DATAEND interrupt is received software
1627 * should poll for RXDATA_AVAIL until the requested data is read out
1628 * of FIFO. This change is needed to get around this abnormal but
1629 * sometimes expected behavior of SDCC3 controller.
1630 *
1631 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1632 * after the data is loaded into RX FIFO. This would amount to less
1633 * than a microsecond and thus looping for 1000 times is good enough
1634 * for that delay.
1635 */
1636 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1637 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1638 spin_unlock(&host->lock);
1639 msmsdcc_pio_irq(1, host);
1640 spin_lock(&host->lock);
1641 }
1642 }
1643 if (loop_cnt == 1000) {
1644 pr_info("%s: Timed out while polling for Rx Data\n",
1645 mmc_hostname(host->mmc));
1646 data->error = -ETIMEDOUT;
1647 msmsdcc_reset_and_restore(host);
1648 }
1649}
1650
San Mehat9d2bd732009-09-22 16:44:22 -07001651static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1652{
1653 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001654
1655 host->curr.cmd = NULL;
subhashj8046ae12012-05-02 12:14:52 +05301656 if (mmc_resp_type(cmd))
1657 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1658 /*
1659 * Read rest of the response registers only if
1660 * long response is expected for this command
1661 */
1662 if (mmc_resp_type(cmd) & MMC_RSP_136) {
1663 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1664 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1665 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
1666 }
San Mehat9d2bd732009-09-22 16:44:22 -07001667
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001668 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301669 pr_debug("%s: CMD%d: Command timeout\n",
1670 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001671 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001672 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301673 !host->tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301674 pr_err("%s: CMD%d: Command CRC error\n",
1675 mmc_hostname(host->mmc), cmd->opcode);
1676 msmsdcc_dump_sdcc_state(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001677 cmd->error = -EILSEQ;
1678 }
1679
Subhash Jadavani8706ced2012-05-25 16:09:21 +05301680 if (!cmd->error) {
1681 if (cmd->cmd_timeout_ms > host->curr.req_tout_ms) {
1682 host->curr.req_tout_ms = cmd->cmd_timeout_ms;
1683 mod_timer(&host->req_tout_timer, (jiffies +
1684 msecs_to_jiffies(host->curr.req_tout_ms)));
1685 }
1686 }
1687
San Mehat9d2bd732009-09-22 16:44:22 -07001688 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001689 if (host->curr.data && host->dma.sg &&
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301690 is_dma_mode(host))
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001691 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001692 else if (host->curr.data && host->sps.sg &&
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301693 is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001694 /* Stop current SPS transfer */
1695 msmsdcc_sps_exit_curr_xfer(host);
1696 }
San Mehat9d2bd732009-09-22 16:44:22 -07001697 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301698 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001699 msmsdcc_stop_data(host);
1700 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301701 } else { /* host->data == NULL */
1702 if (!cmd->error && host->prog_enable) {
1703 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001704 host->prog_enable = 0;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301705 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001706 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301707 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301708 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301709 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301710 host->curr.wait_for_auto_prog_done = false;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001711 if (host->dummy_52_needed)
1712 host->dummy_52_needed = 0;
1713 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001714 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301715 msmsdcc_request_end(host, cmd->mrq);
1716 }
1717 }
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301718 } else if (cmd->data) {
Subhash Jadavanif5277752011-10-12 16:47:52 +05301719 if (cmd == host->curr.mrq->sbc)
1720 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1721 else if ((cmd->data->flags & MMC_DATA_WRITE) &&
1722 !host->curr.use_wr_data_pend)
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301723 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001724 }
1725}
1726
San Mehat9d2bd732009-09-22 16:44:22 -07001727static irqreturn_t
1728msmsdcc_irq(int irq, void *dev_id)
1729{
1730 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001731 u32 status;
1732 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001733 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001734
1735 spin_lock(&host->lock);
1736
1737 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001738 struct mmc_command *cmd;
1739 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001740
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001741 if (timer) {
1742 timer = 0;
1743 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001744 }
San Mehat9d2bd732009-09-22 16:44:22 -07001745
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05301746 if (!atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001747 pr_debug("%s: %s: SDIO async irq received\n",
1748 mmc_hostname(host->mmc), __func__);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301749
1750 /*
1751 * Only async interrupt can come when clocks are off,
1752 * disable further interrupts and enable them when
1753 * clocks are on.
1754 */
1755 if (!host->sdcc_irq_disabled) {
1756 disable_irq_nosync(irq);
1757 host->sdcc_irq_disabled = 1;
1758 }
1759
1760 /*
1761 * If mmc_card_wake_sdio_irq() is set, mmc core layer
1762 * will take care of signaling sdio irq during
1763 * mmc_sdio_resume().
1764 */
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301765 if (host->sdcc_suspended) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301766 /*
1767 * This is a wakeup interrupt so hold wakelock
1768 * until SDCC resume is handled.
1769 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001770 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301771 } else {
1772 spin_unlock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301773 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301774 spin_lock(&host->lock);
1775 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301776 ret = 1;
1777 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001778 }
1779
1780 status = readl_relaxed(host->base + MMCISTATUS);
1781
1782 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1783 (~(MCI_IRQ_PIO))) == 0)
San Mehat9d2bd732009-09-22 16:44:22 -07001784 break;
1785
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001786#if IRQ_DEBUG
1787 msmsdcc_print_status(host, "irq0-r", status);
1788#endif
1789 status &= readl_relaxed(host->base + MMCIMASK0);
1790 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301791 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301792 if (host->clk_rate <=
1793 msmsdcc_get_min_sup_clk_rate(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +05301794 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001795#if IRQ_DEBUG
1796 msmsdcc_print_status(host, "irq0-p", status);
1797#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001798
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001799 if (status & MCI_SDIOINTROPE) {
1800 if (host->sdcc_suspending)
1801 wake_lock(&host->sdio_suspend_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301802 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001803 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301804 spin_lock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001805 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001806 data = host->curr.data;
1807
1808 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001809 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1810 MCI_CMDTIMEOUT)) {
1811 if (status & MCI_CMDTIMEOUT)
1812 pr_debug("%s: dummy CMD52 timeout\n",
1813 mmc_hostname(host->mmc));
1814 if (status & MCI_CMDCRCFAIL)
1815 pr_debug("%s: dummy CMD52 CRC failed\n",
1816 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001817 host->dummy_52_sent = 0;
1818 host->dummy_52_needed = 0;
1819 if (data) {
1820 msmsdcc_stop_data(host);
1821 msmsdcc_request_end(host, data->mrq);
1822 }
1823 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001824 spin_unlock(&host->lock);
1825 return IRQ_HANDLED;
1826 }
1827 break;
1828 }
1829
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001830 /*
1831 * Check for proper command response
1832 */
1833 cmd = host->curr.cmd;
1834 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1835 MCI_CMDTIMEOUT | MCI_PROGDONE |
1836 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1837 msmsdcc_do_cmdirq(host, status);
1838 }
1839
Sathish Ambley081d7842011-11-29 11:19:41 -08001840 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001841 /* Check for data errors */
1842 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1843 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1844 msmsdcc_data_err(host, data, status);
1845 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301846 if (host->dma.sg && is_dma_mode(host))
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001847 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301848 else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001849 /* Stop current SPS transfer */
1850 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301851 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001852 msmsdcc_reset_and_restore(host);
1853 if (host->curr.data)
1854 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301855 if (!data->stop || (host->curr.mrq->sbc
1856 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001857 timer |=
1858 msmsdcc_request_end(host,
1859 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301860 else if ((host->curr.mrq->sbc
1861 && data->error) ||
1862 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001863 msmsdcc_start_command(host,
1864 data->stop,
1865 0);
1866 timer = 1;
1867 }
1868 }
1869 }
1870
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301871 /* Check for prog done */
1872 if (host->curr.wait_for_auto_prog_done &&
1873 (status & MCI_PROGDONE))
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301874 host->curr.got_auto_prog_done = true;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301875
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001876 /* Check for data done */
1877 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1878 host->curr.got_dataend = 1;
1879
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301880 if (host->curr.got_dataend &&
1881 (!host->curr.wait_for_auto_prog_done ||
1882 (host->curr.wait_for_auto_prog_done &&
1883 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001884 /*
1885 * If DMA is still in progress, we complete
1886 * via the completion handler
1887 */
1888 if (!host->dma.busy && !host->sps.busy) {
1889 /*
1890 * There appears to be an issue in the
1891 * controller where if you request a
1892 * small block transfer (< fifo size),
1893 * you may get your DATAEND/DATABLKEND
1894 * irq without the PIO data irq.
1895 *
1896 * Check to see if theres still data
1897 * to be read, and simulate a PIO irq.
1898 */
1899 if (data->flags & MMC_DATA_READ)
1900 msmsdcc_wait_for_rxdata(host,
1901 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001902 if (!data->error) {
1903 host->curr.data_xfered =
1904 host->curr.xfer_size;
1905 host->curr.xfer_remain -=
1906 host->curr.xfer_size;
1907 }
1908
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001909 if (!host->dummy_52_needed) {
1910 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301911 if (!data->stop ||
1912 (host->curr.mrq->sbc
1913 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001914 msmsdcc_request_end(
1915 host,
1916 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301917 else if ((host->curr.mrq->sbc
1918 && data->error) ||
1919 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001920 msmsdcc_start_command(
1921 host,
1922 data->stop, 0);
1923 timer = 1;
1924 }
1925 } else {
1926 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001927 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001928 &dummy52cmd,
1929 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001930 }
1931 }
1932 }
1933 }
1934
San Mehat9d2bd732009-09-22 16:44:22 -07001935 ret = 1;
1936 } while (status);
1937
1938 spin_unlock(&host->lock);
1939
San Mehat9d2bd732009-09-22 16:44:22 -07001940 return IRQ_RETVAL(ret);
1941}
1942
1943static void
Asutosh Dasaccacd42012-03-08 14:33:17 +05301944msmsdcc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
1945 bool is_first_request)
1946{
1947 struct msmsdcc_host *host = mmc_priv(mmc);
1948 struct mmc_data *data = mrq->data;
1949 int rc = 0;
1950
1951 if (unlikely(!data)) {
1952 pr_err("%s: %s cannot prepare null data\n", mmc_hostname(mmc),
1953 __func__);
1954 return;
1955 }
1956 if (unlikely(data->host_cookie)) {
1957 /* Very wrong */
1958 data->host_cookie = 0;
1959 pr_err("%s: %s Request reposted for prepare\n",
1960 mmc_hostname(mmc), __func__);
1961 return;
1962 }
1963
1964 if (!msmsdcc_is_dma_possible(host, data))
1965 return;
1966
1967 rc = msmsdcc_prep_xfer(host, data);
1968 if (unlikely(rc < 0)) {
1969 data->host_cookie = 0;
1970 return;
1971 }
1972
1973 data->host_cookie = 1;
1974}
1975
1976static void
1977msmsdcc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, int err)
1978{
1979 struct msmsdcc_host *host = mmc_priv(mmc);
1980 unsigned int dir;
1981 struct mmc_data *data = mrq->data;
1982
1983 if (unlikely(!data)) {
1984 pr_err("%s: %s cannot cleanup null data\n", mmc_hostname(mmc),
1985 __func__);
1986 return;
1987 }
1988 if (data->flags & MMC_DATA_READ)
1989 dir = DMA_FROM_DEVICE;
1990 else
1991 dir = DMA_TO_DEVICE;
1992
1993 if (data->host_cookie)
1994 dma_unmap_sg(mmc_dev(host->mmc), data->sg,
1995 data->sg_len, dir);
1996
1997 data->host_cookie = 0;
1998}
1999
2000static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002001msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
2002{
Subhash Jadavanif5277752011-10-12 16:47:52 +05302003 if (mrq->data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002004 /* Queue/read data, daisy-chain command when data starts */
Subhash Jadavanif5277752011-10-12 16:47:52 +05302005 if ((mrq->data->flags & MMC_DATA_READ) ||
2006 host->curr.use_wr_data_pend)
2007 msmsdcc_start_data(host, mrq->data,
2008 mrq->sbc ? mrq->sbc : mrq->cmd,
2009 0);
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302010 else
Subhash Jadavanif5277752011-10-12 16:47:52 +05302011 msmsdcc_start_command(host,
2012 mrq->sbc ? mrq->sbc : mrq->cmd,
2013 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002014 } else {
2015 msmsdcc_start_command(host, mrq->cmd, 0);
2016 }
2017}
2018
2019static void
San Mehat9d2bd732009-09-22 16:44:22 -07002020msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
2021{
2022 struct msmsdcc_host *host = mmc_priv(mmc);
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302023 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07002024
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002025 /*
2026 * Get the SDIO AL client out of LPM.
2027 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002028 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002029 if (host->plat->is_sdio_al_client)
2030 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002031
Subhash Jadavanib5b07742011-08-29 17:48:07 +05302032 /* check if sps pipe reset is pending? */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05302033 if (is_sps_mode(host) && host->sps.pipe_reset_pending) {
Subhash Jadavanib5b07742011-08-29 17:48:07 +05302034 msmsdcc_sps_pipes_reset_and_restore(host);
2035 host->sps.pipe_reset_pending = false;
2036 }
San Mehat9d2bd732009-09-22 16:44:22 -07002037
2038 spin_lock_irqsave(&host->lock, flags);
2039
San Mehat9d2bd732009-09-22 16:44:22 -07002040 if (host->eject) {
2041 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
2042 mrq->cmd->error = 0;
2043 mrq->data->bytes_xfered = mrq->data->blksz *
2044 mrq->data->blocks;
2045 } else
2046 mrq->cmd->error = -ENOMEDIUM;
2047
2048 spin_unlock_irqrestore(&host->lock, flags);
2049 mmc_request_done(mmc, mrq);
2050 return;
2051 }
2052
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302053 /*
subhashjf181c292012-05-02 13:07:40 +05302054 * Don't start the request if SDCC is not in proper state to handle it
2055 */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302056 if (!host->pwr || !atomic_read(&host->clks_on)
2057 || host->sdcc_irq_disabled) {
subhashjf181c292012-05-02 13:07:40 +05302058 WARN(1, "%s: %s: SDCC is in bad state. don't process"
2059 " new request (CMD%d)\n", mmc_hostname(host->mmc),
2060 __func__, mrq->cmd->opcode);
2061 msmsdcc_dump_sdcc_state(host);
2062 mrq->cmd->error = -EIO;
2063 if (mrq->data) {
2064 mrq->data->error = -EIO;
2065 mrq->data->bytes_xfered = 0;
2066 }
2067 spin_unlock_irqrestore(&host->lock, flags);
2068 mmc_request_done(mmc, mrq);
2069 return;
2070 }
2071
2072 WARN(host->curr.mrq, "%s: %s: New request (CMD%d) received while"
2073 " other request (CMD%d) is in progress\n",
2074 mmc_hostname(host->mmc), __func__,
2075 mrq->cmd->opcode, host->curr.mrq->cmd->opcode);
2076
2077 /*
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302078 * Set timeout value to 10 secs (or more in case of buggy cards)
2079 */
2080 if ((mmc->card) && (mmc->card->quirks & MMC_QUIRK_INAND_DATA_TIMEOUT))
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302081 host->curr.req_tout_ms = 20000;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302082 else
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302083 host->curr.req_tout_ms = MSM_MMC_REQ_TIMEOUT;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302084 /*
2085 * Kick the software request timeout timer here with the timeout
2086 * value identified above
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302087 */
2088 mod_timer(&host->req_tout_timer,
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302089 (jiffies +
2090 msecs_to_jiffies(host->curr.req_tout_ms)));
San Mehat9d2bd732009-09-22 16:44:22 -07002091
San Mehat9d2bd732009-09-22 16:44:22 -07002092 host->curr.mrq = mrq;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302093 if (mrq->sbc) {
2094 mrq->sbc->mrq = mrq;
2095 mrq->sbc->data = mrq->data;
2096 }
2097
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302098 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05302099 if (is_auto_prog_done(host)) {
Sujit Reddy Thummab8e83692012-07-17 15:08:13 +05302100 /*
2101 * Auto-prog done will be enabled for following cases:
2102 * mrq->sbc | mrq->stop
2103 * _____________|________________
2104 * True | Don't care
2105 * False | False (CMD24, ACMD25 use case)
2106 */
2107 if (mrq->sbc || !mrq->stop)
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302108 host->curr.wait_for_auto_prog_done = true;
2109 } else {
2110 if ((mrq->cmd->opcode == SD_IO_RW_EXTENDED) ||
2111 (mrq->cmd->opcode == 54))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002112 host->dummy_52_needed = 1;
2113 }
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302114
Subhash Jadavanif5277752011-10-12 16:47:52 +05302115 if ((mrq->cmd->opcode == MMC_WRITE_BLOCK) ||
2116 (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK))
2117 host->curr.use_wr_data_pend = true;
San Mehat9d2bd732009-09-22 16:44:22 -07002118 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302119
Subhash Jadavanif5277752011-10-12 16:47:52 +05302120 msmsdcc_request_start(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302121
San Mehat9d2bd732009-09-22 16:44:22 -07002122 spin_unlock_irqrestore(&host->lock, flags);
2123}
2124
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002125static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
2126 int min_uV, int max_uV)
2127{
2128 int rc = 0;
2129
2130 if (vreg->set_voltage_sup) {
2131 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
2132 if (rc) {
2133 pr_err("%s: regulator_set_voltage(%s) failed."
2134 " min_uV=%d, max_uV=%d, rc=%d\n",
2135 __func__, vreg->name, min_uV, max_uV, rc);
2136 }
2137 }
2138
2139 return rc;
2140}
2141
2142static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
2143 int uA_load)
2144{
2145 int rc = 0;
2146
Krishna Kondafea60182011-11-01 16:01:34 -07002147 /* regulators that do not support regulator_set_voltage also
2148 do not support regulator_set_optimum_mode */
2149 if (vreg->set_voltage_sup) {
2150 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
2151 if (rc < 0)
2152 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
2153 "uA_load=%d) failed. rc=%d\n", __func__,
2154 vreg->name, uA_load, rc);
2155 else
2156 /* regulator_set_optimum_mode() can return non zero
2157 * value even for success case.
2158 */
2159 rc = 0;
2160 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002161
2162 return rc;
2163}
2164
2165static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
2166 struct device *dev)
2167{
2168 int rc = 0;
2169
2170 /* check if regulator is already initialized? */
2171 if (vreg->reg)
2172 goto out;
2173
2174 /* Get the regulator handle */
2175 vreg->reg = regulator_get(dev, vreg->name);
2176 if (IS_ERR(vreg->reg)) {
2177 rc = PTR_ERR(vreg->reg);
2178 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
2179 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002180 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002181 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002182
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05302183 if (regulator_count_voltages(vreg->reg) > 0) {
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002184 vreg->set_voltage_sup = 1;
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05302185 /* sanity check */
2186 if (!vreg->high_vol_level || !vreg->hpm_uA) {
2187 pr_err("%s: %s invalid constraints specified\n",
2188 __func__, vreg->name);
2189 rc = -EINVAL;
2190 }
2191 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002192
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002193out:
2194 return rc;
2195}
2196
2197static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
2198{
2199 if (vreg->reg)
2200 regulator_put(vreg->reg);
2201}
2202
2203/* This init function should be called only once for each SDCC slot */
2204static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
2205{
2206 int rc = 0;
2207 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302208 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vdd_io_reg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002209 struct device *dev = mmc_dev(host->mmc);
2210
2211 curr_slot = host->plat->vreg_data;
2212 if (!curr_slot)
2213 goto out;
2214
2215 curr_vdd_reg = curr_slot->vdd_data;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302216 curr_vdd_io_reg = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002217
2218 if (is_init) {
2219 /*
2220 * Get the regulator handle from voltage regulator framework
2221 * and then try to set the voltage level for the regulator
2222 */
2223 if (curr_vdd_reg) {
2224 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
2225 if (rc)
2226 goto out;
2227 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302228 if (curr_vdd_io_reg) {
2229 rc = msmsdcc_vreg_init_reg(curr_vdd_io_reg, dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002230 if (rc)
2231 goto vdd_reg_deinit;
2232 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002233 rc = msmsdcc_vreg_reset(host);
2234 if (rc)
2235 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
2236 host->pdev_id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002237 goto out;
2238 } else {
2239 /* Deregister all regulators from regulator framework */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302240 goto vdd_io_reg_deinit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002241 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302242vdd_io_reg_deinit:
2243 if (curr_vdd_io_reg)
2244 msmsdcc_vreg_deinit_reg(curr_vdd_io_reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002245vdd_reg_deinit:
2246 if (curr_vdd_reg)
2247 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2248out:
2249 return rc;
2250}
2251
2252static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2253{
2254 int rc = 0;
2255
Subhash Jadavanicc922692011-08-01 23:05:01 +05302256 /* Put regulator in HPM (high power mode) */
2257 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2258 if (rc < 0)
2259 goto out;
2260
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002261 if (!vreg->is_enabled) {
2262 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302263 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2264 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002265 if (rc)
2266 goto out;
2267
2268 rc = regulator_enable(vreg->reg);
2269 if (rc) {
2270 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2271 __func__, vreg->name, rc);
2272 goto out;
2273 }
2274 vreg->is_enabled = true;
2275 }
2276
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002277out:
2278 return rc;
2279}
2280
Krishna Konda3c4142d2012-06-27 11:01:56 -07002281static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg, bool is_init)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002282{
2283 int rc = 0;
2284
2285 /* Never disable regulator marked as always_on */
2286 if (vreg->is_enabled && !vreg->always_on) {
2287 rc = regulator_disable(vreg->reg);
2288 if (rc) {
2289 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2290 __func__, vreg->name, rc);
2291 goto out;
2292 }
2293 vreg->is_enabled = false;
2294
2295 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2296 if (rc < 0)
2297 goto out;
2298
2299 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302300 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002301 if (rc)
2302 goto out;
Krishna Konda3c4142d2012-06-27 11:01:56 -07002303 } else if (vreg->is_enabled && vreg->always_on) {
2304 if (!is_init && vreg->lpm_sup) {
2305 /* Put always_on regulator in LPM (low power mode) */
2306 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2307 if (rc < 0)
2308 goto out;
2309 } else if (is_init && vreg->reset_at_init) {
2310 /**
2311 * The regulator might not actually be disabled if it
2312 * is shared and in use by other drivers.
2313 */
2314 rc = regulator_disable(vreg->reg);
2315 if (rc) {
2316 pr_err("%s: regulator_disable(%s) failed at " \
2317 "bootup. rc=%d\n", __func__,
2318 vreg->name, rc);
2319 goto out;
2320 }
2321 vreg->is_enabled = false;
2322 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002323 }
2324out:
2325 return rc;
2326}
2327
Krishna Konda3c4142d2012-06-27 11:01:56 -07002328static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable,
2329 bool is_init)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002330{
2331 int rc = 0, i;
2332 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302333 struct msm_mmc_reg_data *vreg_table[2];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002334
2335 curr_slot = host->plat->vreg_data;
2336 if (!curr_slot)
2337 goto out;
2338
Subhash Jadavani937c7502012-06-01 15:34:46 +05302339 vreg_table[0] = curr_slot->vdd_data;
2340 vreg_table[1] = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002341
2342 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2343 if (vreg_table[i]) {
2344 if (enable)
2345 rc = msmsdcc_vreg_enable(vreg_table[i]);
2346 else
Krishna Konda3c4142d2012-06-27 11:01:56 -07002347 rc = msmsdcc_vreg_disable(vreg_table[i],
2348 is_init);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002349 if (rc)
2350 goto out;
2351 }
2352 }
2353out:
2354 return rc;
2355}
2356
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002357/*
2358 * Reset vreg by ensuring it is off during probe. A call
2359 * to enable vreg is needed to balance disable vreg
2360 */
2361static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2362{
2363 int rc;
2364
Krishna Konda3c4142d2012-06-27 11:01:56 -07002365 rc = msmsdcc_setup_vreg(host, 1, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002366 if (rc)
2367 return rc;
Krishna Konda3c4142d2012-06-27 11:01:56 -07002368 rc = msmsdcc_setup_vreg(host, 0, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002369 return rc;
2370}
2371
Subhash Jadavani937c7502012-06-01 15:34:46 +05302372enum vdd_io_level {
2373 /* set vdd_io_data->low_vol_level */
2374 VDD_IO_LOW,
2375 /* set vdd_io_data->high_vol_level */
2376 VDD_IO_HIGH,
2377 /*
2378 * set whatever there in voltage_level (third argument) of
2379 * msmsdcc_set_vdd_io_vol() function.
2380 */
2381 VDD_IO_SET_LEVEL,
2382};
2383
2384static int msmsdcc_set_vdd_io_vol(struct msmsdcc_host *host,
2385 enum vdd_io_level level,
2386 unsigned int voltage_level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002387{
2388 int rc = 0;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302389 int set_level;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002390
2391 if (host->plat->vreg_data) {
Subhash Jadavani937c7502012-06-01 15:34:46 +05302392 struct msm_mmc_reg_data *vdd_io_reg =
2393 host->plat->vreg_data->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002394
Subhash Jadavani937c7502012-06-01 15:34:46 +05302395 if (vdd_io_reg && vdd_io_reg->is_enabled) {
2396 switch (level) {
2397 case VDD_IO_LOW:
2398 set_level = vdd_io_reg->low_vol_level;
2399 break;
2400 case VDD_IO_HIGH:
2401 set_level = vdd_io_reg->high_vol_level;
2402 break;
2403 case VDD_IO_SET_LEVEL:
2404 set_level = voltage_level;
2405 break;
2406 default:
2407 pr_err("%s: %s: invalid argument level = %d",
2408 mmc_hostname(host->mmc), __func__,
2409 level);
2410 rc = -EINVAL;
2411 goto out;
2412 }
2413 rc = msmsdcc_vreg_set_voltage(vdd_io_reg,
2414 set_level, set_level);
2415 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002416 }
2417
Subhash Jadavani937c7502012-06-01 15:34:46 +05302418out:
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302419 return rc;
2420}
2421
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002422static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2423{
2424 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2425 return 1;
2426 return 0;
2427}
2428
Asutosh Dasf5298c32012-04-03 14:51:47 +05302429/*
2430 * Any function calling msmsdcc_setup_clocks must
2431 * acquire clk_mutex. May sleep.
2432 */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302433static int msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002434{
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302435 int rc = 0;
2436
2437 if (enable && !atomic_read(&host->clks_on)) {
2438 if (!IS_ERR_OR_NULL(host->bus_clk)) {
2439 rc = clk_prepare_enable(host->bus_clk);
2440 if (rc) {
2441 pr_err("%s: %s: failed to enable the bus-clock with error %d\n",
2442 mmc_hostname(host->mmc), __func__, rc);
2443 goto out;
2444 }
2445 }
2446 if (!IS_ERR(host->pclk)) {
2447 rc = clk_prepare_enable(host->pclk);
2448 if (rc) {
2449 pr_err("%s: %s: failed to enable the pclk with error %d\n",
2450 mmc_hostname(host->mmc), __func__, rc);
2451 goto disable_bus;
2452 }
2453 }
2454 rc = clk_prepare_enable(host->clk);
2455 if (rc) {
2456 pr_err("%s: %s: failed to enable the host-clk with error %d\n",
2457 mmc_hostname(host->mmc), __func__, rc);
2458 goto disable_pclk;
2459 }
Subhash Jadavanidd432952012-03-28 11:25:56 +05302460 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302461 msmsdcc_delay(host);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302462 atomic_set(&host->clks_on, 1);
2463 } else if (!enable && atomic_read(&host->clks_on)) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05302464 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302465 msmsdcc_delay(host);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302466 clk_disable_unprepare(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002467 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302468 clk_disable_unprepare(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05302469 if (!IS_ERR_OR_NULL(host->bus_clk))
2470 clk_disable_unprepare(host->bus_clk);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302471 atomic_set(&host->clks_on, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002472 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302473 goto out;
2474
2475disable_pclk:
2476 if (!IS_ERR_OR_NULL(host->pclk))
2477 clk_disable_unprepare(host->pclk);
2478disable_bus:
2479 if (!IS_ERR_OR_NULL(host->bus_clk))
2480 clk_disable_unprepare(host->bus_clk);
2481out:
2482 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002483}
2484
2485static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2486 unsigned int req_clk)
2487{
2488 unsigned int sel_clk = -1;
2489
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302490 if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
2491 sel_clk = msmsdcc_get_min_sup_clk_rate(host);
2492 goto out;
2493 }
2494
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002495 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2496 unsigned char cnt;
2497
2498 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2499 if (host->plat->sup_clk_table[cnt] > req_clk)
2500 break;
2501 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2502 sel_clk = host->plat->sup_clk_table[cnt];
2503 break;
2504 } else
2505 sel_clk = host->plat->sup_clk_table[cnt];
2506 }
2507 } else {
2508 if ((req_clk < host->plat->msmsdcc_fmax) &&
2509 (req_clk > host->plat->msmsdcc_fmid))
2510 sel_clk = host->plat->msmsdcc_fmid;
2511 else
2512 sel_clk = req_clk;
2513 }
2514
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302515out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002516 return sel_clk;
2517}
2518
2519static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2520 struct msmsdcc_host *host)
2521{
2522 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2523 return host->plat->sup_clk_table[0];
2524 else
2525 return host->plat->msmsdcc_fmin;
2526}
2527
2528static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2529 struct msmsdcc_host *host)
2530{
2531 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2532 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2533 else
2534 return host->plat->msmsdcc_fmax;
2535}
2536
2537static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302538{
2539 struct msm_mmc_gpio_data *curr;
2540 int i, rc = 0;
2541
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002542 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302543 for (i = 0; i < curr->size; i++) {
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05302544 if (!gpio_is_valid(curr->gpio[i].no)) {
2545 rc = -EINVAL;
2546 pr_err("%s: Invalid gpio = %d\n",
2547 mmc_hostname(host->mmc), curr->gpio[i].no);
2548 goto free_gpios;
2549 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302550 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002551 if (curr->gpio[i].is_always_on &&
2552 curr->gpio[i].is_enabled)
2553 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302554 rc = gpio_request(curr->gpio[i].no,
2555 curr->gpio[i].name);
2556 if (rc) {
2557 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2558 mmc_hostname(host->mmc),
2559 curr->gpio[i].no,
2560 curr->gpio[i].name, rc);
2561 goto free_gpios;
2562 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002563 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302564 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002565 if (curr->gpio[i].is_always_on)
2566 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302567 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002568 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302569 }
2570 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002571 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302572
2573free_gpios:
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05302574 for (i--; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302575 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002576 curr->gpio[i].is_enabled = false;
2577 }
2578out:
2579 return rc;
2580}
2581
2582static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2583{
2584 struct msm_mmc_pad_data *curr;
2585 int i;
2586
2587 curr = host->plat->pin_data->pad_data;
2588 for (i = 0; i < curr->drv->size; i++) {
2589 if (enable)
2590 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2591 curr->drv->on[i].val);
2592 else
2593 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2594 curr->drv->off[i].val);
2595 }
2596
2597 for (i = 0; i < curr->pull->size; i++) {
2598 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002599 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002600 curr->pull->on[i].val);
2601 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002602 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002603 curr->pull->off[i].val);
2604 }
2605
2606 return 0;
2607}
2608
2609static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2610{
2611 int rc = 0;
2612
2613 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2614 return 0;
2615
2616 if (host->plat->pin_data->is_gpio)
2617 rc = msmsdcc_setup_gpio(host, enable);
2618 else
2619 rc = msmsdcc_setup_pad(host, enable);
2620
2621 if (!rc)
2622 host->plat->pin_data->cfg_sts = enable;
2623
2624 return rc;
2625}
2626
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302627static int msmsdcc_cfg_mpm_sdiowakeup(struct msmsdcc_host *host,
2628 unsigned mode)
2629{
2630 int ret = 0;
2631 unsigned int pin = host->plat->mpm_sdiowakeup_int;
2632
2633 if (!pin)
2634 return 0;
2635
2636 switch (mode) {
2637 case SDC_DAT1_DISABLE:
2638 ret = msm_mpm_enable_pin(pin, 0);
2639 break;
2640 case SDC_DAT1_ENABLE:
2641 ret = msm_mpm_set_pin_type(pin, IRQ_TYPE_LEVEL_LOW);
2642 ret = msm_mpm_enable_pin(pin, 1);
2643 break;
2644 case SDC_DAT1_ENWAKE:
2645 ret = msm_mpm_set_pin_wake(pin, 1);
2646 break;
2647 case SDC_DAT1_DISWAKE:
2648 ret = msm_mpm_set_pin_wake(pin, 0);
2649 break;
2650 default:
2651 ret = -EINVAL;
2652 break;
2653 }
2654
2655 return ret;
2656}
2657
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302658static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2659{
2660 u32 pwr = 0;
2661 int ret = 0;
2662 struct mmc_host *mmc = host->mmc;
2663
2664 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2665 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2666 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
Krishna Konda3c4142d2012-06-27 11:01:56 -07002667 ret = msmsdcc_setup_vreg(host, !!ios->vdd, false);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302668
2669 if (ret) {
2670 pr_err("%s: Failed to setup voltage regulators\n",
2671 mmc_hostname(host->mmc));
2672 goto out;
2673 }
2674
2675 switch (ios->power_mode) {
2676 case MMC_POWER_OFF:
2677 pwr = MCI_PWR_OFF;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302678 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302679 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05302680 * If VDD IO rail is always on, set low voltage for VDD
2681 * IO rail when slot is not in use (like when card is not
2682 * present or during system suspend).
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302683 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302684 msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302685 msmsdcc_setup_pins(host, false);
2686 break;
2687 case MMC_POWER_UP:
2688 /* writing PWR_UP bit is redundant */
2689 pwr = MCI_PWR_UP;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302690 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302691
Subhash Jadavani937c7502012-06-01 15:34:46 +05302692 msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302693 msmsdcc_setup_pins(host, true);
2694 break;
2695 case MMC_POWER_ON:
2696 pwr = MCI_PWR_ON;
2697 break;
2698 }
2699
2700out:
2701 return pwr;
2702}
2703
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002704static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2705{
2706 unsigned int wakeup_irq;
2707
2708 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2709 host->plat->sdiowakeup_irq :
2710 host->core_irqres->start;
2711
2712 if (!host->irq_wake_enabled) {
2713 enable_irq_wake(wakeup_irq);
2714 host->irq_wake_enabled = true;
2715 }
2716}
2717
2718static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2719{
2720 unsigned int wakeup_irq;
2721
2722 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2723 host->plat->sdiowakeup_irq :
2724 host->core_irqres->start;
2725
2726 if (host->irq_wake_enabled) {
2727 disable_irq_wake(wakeup_irq);
2728 host->irq_wake_enabled = false;
2729 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302730}
2731
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05302732/* Returns required bandwidth in Bytes per Sec */
2733static unsigned int msmsdcc_get_bw_required(struct msmsdcc_host *host,
2734 struct mmc_ios *ios)
2735{
2736 unsigned int bw;
2737
2738 bw = host->clk_rate;
2739 /*
2740 * For DDR mode, SDCC controller clock will be at
2741 * the double rate than the actual clock that goes to card.
2742 */
2743 if (ios->bus_width == MMC_BUS_WIDTH_4)
2744 bw /= 2;
2745 else if (ios->bus_width == MMC_BUS_WIDTH_1)
2746 bw /= 8;
2747
2748 return bw;
2749}
2750
2751static int msmsdcc_msm_bus_get_vote_for_bw(struct msmsdcc_host *host,
2752 unsigned int bw)
2753{
2754 unsigned int *table = host->plat->msm_bus_voting_data->bw_vecs;
2755 unsigned int size = host->plat->msm_bus_voting_data->bw_vecs_size;
2756 int i;
2757
2758 if (host->msm_bus_vote.is_max_bw_needed && bw)
2759 return host->msm_bus_vote.max_bw_vote;
2760
2761 for (i = 0; i < size; i++) {
2762 if (bw <= table[i])
2763 break;
2764 }
2765
2766 if (i && (i == size))
2767 i--;
2768
2769 return i;
2770}
2771
2772static int msmsdcc_msm_bus_register(struct msmsdcc_host *host)
2773{
2774 int rc = 0;
2775 struct msm_bus_scale_pdata *use_cases;
2776
2777 if (host->plat->msm_bus_voting_data &&
2778 host->plat->msm_bus_voting_data->use_cases &&
2779 host->plat->msm_bus_voting_data->bw_vecs &&
2780 host->plat->msm_bus_voting_data->bw_vecs_size) {
2781 use_cases = host->plat->msm_bus_voting_data->use_cases;
2782 host->msm_bus_vote.client_handle =
2783 msm_bus_scale_register_client(use_cases);
2784 } else {
2785 return 0;
2786 }
2787
2788 if (!host->msm_bus_vote.client_handle) {
2789 pr_err("%s: msm_bus_scale_register_client() failed\n",
2790 mmc_hostname(host->mmc));
2791 rc = -EFAULT;
2792 } else {
2793 /* cache the vote index for minimum and maximum bandwidth */
2794 host->msm_bus_vote.min_bw_vote =
2795 msmsdcc_msm_bus_get_vote_for_bw(host, 0);
2796 host->msm_bus_vote.max_bw_vote =
2797 msmsdcc_msm_bus_get_vote_for_bw(host, UINT_MAX);
2798 }
2799
2800 return rc;
2801}
2802
2803static void msmsdcc_msm_bus_unregister(struct msmsdcc_host *host)
2804{
2805 if (host->msm_bus_vote.client_handle)
2806 msm_bus_scale_unregister_client(
2807 host->msm_bus_vote.client_handle);
2808}
2809
2810/*
2811 * This function must be called with host lock acquired.
2812 * Caller of this function should also ensure that msm bus client
2813 * handle is not null.
2814 */
2815static inline int msmsdcc_msm_bus_set_vote(struct msmsdcc_host *host,
2816 int vote,
2817 unsigned long flags)
2818{
2819 int rc = 0;
2820
2821 if (vote != host->msm_bus_vote.curr_vote) {
2822 spin_unlock_irqrestore(&host->lock, flags);
2823 rc = msm_bus_scale_client_update_request(
2824 host->msm_bus_vote.client_handle, vote);
2825 if (rc)
2826 pr_err("%s: msm_bus_scale_client_update_request() failed."
2827 " bus_client_handle=0x%x, vote=%d, err=%d\n",
2828 mmc_hostname(host->mmc),
2829 host->msm_bus_vote.client_handle, vote, rc);
2830 spin_lock_irqsave(&host->lock, flags);
2831 if (!rc)
2832 host->msm_bus_vote.curr_vote = vote;
2833 }
2834
2835 return rc;
2836}
2837
2838/*
2839 * Internal work. Work to set 0 bandwidth for msm bus.
2840 */
2841static void msmsdcc_msm_bus_work(struct work_struct *work)
2842{
2843 struct msmsdcc_host *host = container_of(work,
2844 struct msmsdcc_host,
2845 msm_bus_vote.vote_work.work);
2846 unsigned long flags;
2847
2848 if (!host->msm_bus_vote.client_handle)
2849 return;
2850
2851 spin_lock_irqsave(&host->lock, flags);
2852 /* don't vote for 0 bandwidth if any request is in progress */
2853 if (!host->curr.mrq)
2854 msmsdcc_msm_bus_set_vote(host,
2855 host->msm_bus_vote.min_bw_vote, flags);
2856 else
2857 pr_warning("%s: %s: SDCC transfer in progress. skipping"
2858 " bus voting to 0 bandwidth\n",
2859 mmc_hostname(host->mmc), __func__);
2860 spin_unlock_irqrestore(&host->lock, flags);
2861}
2862
2863/*
2864 * This function cancels any scheduled delayed work
2865 * and sets the bus vote based on ios argument.
2866 * If "ios" argument is NULL, bandwidth required is 0 else
2867 * calculate the bandwidth based on ios parameters.
2868 */
2869static void msmsdcc_msm_bus_cancel_work_and_set_vote(
2870 struct msmsdcc_host *host,
2871 struct mmc_ios *ios)
2872{
2873 unsigned long flags;
2874 unsigned int bw;
2875 int vote;
2876
2877 if (!host->msm_bus_vote.client_handle)
2878 return;
2879
2880 bw = ios ? msmsdcc_get_bw_required(host, ios) : 0;
2881
2882 cancel_delayed_work_sync(&host->msm_bus_vote.vote_work);
2883 spin_lock_irqsave(&host->lock, flags);
2884 vote = msmsdcc_msm_bus_get_vote_for_bw(host, bw);
2885 msmsdcc_msm_bus_set_vote(host, vote, flags);
2886 spin_unlock_irqrestore(&host->lock, flags);
2887}
2888
2889/* This function queues a work which will set the bandwidth requiement to 0 */
2890static void msmsdcc_msm_bus_queue_work(struct msmsdcc_host *host)
2891{
2892 unsigned long flags;
2893
2894 if (!host->msm_bus_vote.client_handle)
2895 return;
2896
2897 spin_lock_irqsave(&host->lock, flags);
2898 if (host->msm_bus_vote.min_bw_vote != host->msm_bus_vote.curr_vote)
2899 queue_delayed_work(system_nrt_wq,
2900 &host->msm_bus_vote.vote_work,
2901 msecs_to_jiffies(MSM_MMC_BUS_VOTING_DELAY));
2902 spin_unlock_irqrestore(&host->lock, flags);
2903}
2904
San Mehat9d2bd732009-09-22 16:44:22 -07002905static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302906msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
2907{
2908 struct mmc_host *mmc = host->mmc;
2909
2910 /*
2911 * SDIO_AL clients has different mechanism of handling LPM through
2912 * sdio_al driver itself. The sdio wakeup interrupt is configured as
2913 * part of that. Here, we are interested only in clients like WLAN.
2914 */
2915 if (!(mmc->card && mmc_card_sdio(mmc->card))
2916 || host->plat->is_sdio_al_client)
2917 goto out;
2918
2919 if (!host->sdcc_suspended) {
2920 /*
2921 * When MSM is not in power collapse and we
2922 * are disabling clocks, enable bit 22 in MASK0
2923 * to handle asynchronous SDIO interrupts.
2924 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302925 if (enable_wakeup_irq) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302926 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302927 mb();
2928 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302929 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302930 msmsdcc_sync_reg_wr(host);
2931 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302932 goto out;
2933 } else if (!mmc_card_wake_sdio_irq(mmc)) {
2934 /*
2935 * Wakeup MSM only if SDIO function drivers set
2936 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
2937 */
2938 goto out;
2939 }
2940
2941 if (enable_wakeup_irq) {
2942 if (!host->plat->sdiowakeup_irq) {
2943 /*
2944 * When there is no gpio line that can be configured
2945 * as wakeup interrupt handle it by configuring
2946 * asynchronous sdio interrupts and DAT1 line.
2947 */
2948 writel_relaxed(MCI_SDIOINTMASK,
2949 host->base + MMCIMASK0);
2950 mb();
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302951 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302952 /* configure sdcc core interrupt as wakeup interrupt */
2953 msmsdcc_enable_irq_wake(host);
2954 } else {
2955 /* Let gpio line handle wakeup interrupt */
2956 writel_relaxed(0, host->base + MMCIMASK0);
2957 mb();
2958 if (host->sdio_wakeupirq_disabled) {
2959 host->sdio_wakeupirq_disabled = 0;
2960 /* configure gpio line as wakeup interrupt */
2961 msmsdcc_enable_irq_wake(host);
2962 enable_irq(host->plat->sdiowakeup_irq);
2963 }
2964 }
2965 } else {
2966 if (!host->plat->sdiowakeup_irq) {
2967 /*
2968 * We may not have cleared bit 22 in the interrupt
2969 * handler as the clocks might be off at that time.
2970 */
2971 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302972 msmsdcc_sync_reg_wr(host);
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302973 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302974 msmsdcc_disable_irq_wake(host);
2975 } else if (!host->sdio_wakeupirq_disabled) {
2976 disable_irq_nosync(host->plat->sdiowakeup_irq);
2977 msmsdcc_disable_irq_wake(host);
2978 host->sdio_wakeupirq_disabled = 1;
2979 }
2980 }
2981out:
2982 return;
San Mehat9d2bd732009-09-22 16:44:22 -07002983}
2984
2985static void
2986msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2987{
2988 struct msmsdcc_host *host = mmc_priv(mmc);
2989 u32 clk = 0, pwr = 0;
2990 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002991 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002992 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002993
Sahitya Tummala7a892482011-01-18 11:22:49 +05302994
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302995 /*
2996 * Disable SDCC core interrupt until set_ios is completed.
2997 * This avoids any race conditions with interrupt raised
2998 * when turning on/off the clocks. One possible
2999 * scenario is SDIO operational interrupt while the clock
3000 * is turned off.
Asutosh Dasf5298c32012-04-03 14:51:47 +05303001 * host->lock is being released intermittently below.
3002 * Thus, prevent concurrent access to host.
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303003 */
3004
Asutosh Dasf5298c32012-04-03 14:51:47 +05303005 mutex_lock(&host->clk_mutex);
3006 DBG(host, "ios->clock = %u\n", ios->clock);
San Mehat9d2bd732009-09-22 16:44:22 -07003007 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303008 if (!host->sdcc_irq_disabled) {
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05303009 disable_irq_nosync(host->core_irqres->start);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303010 host->sdcc_irq_disabled = 1;
3011 }
San Mehatd0719e52009-12-03 10:58:54 -08003012 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07003013
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05303014 /* Make sure sdcc core irq is synchronized */
3015 synchronize_irq(host->core_irqres->start);
3016
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303017 pwr = msmsdcc_setup_pwr(host, ios);
3018
3019 spin_lock_irqsave(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07003020 if (ios->clock) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303021 spin_unlock_irqrestore(&host->lock, flags);
3022 rc = msmsdcc_setup_clocks(host, true);
3023 if (rc)
3024 goto out;
3025 spin_lock_irqsave(&host->lock, flags);
3026 writel_relaxed(host->mci_irqenable, host->base + MMCIMASK0);
3027 mb();
3028 msmsdcc_cfg_sdio_wakeup(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003029 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303030
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003031 /*
3032 * For DDR50 mode, controller needs clock rate to be
3033 * double than what is required on the SD card CLK pin.
3034 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05303035 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003036 /*
3037 * Make sure that we don't double the clock if
3038 * doubled clock rate is already set
3039 */
3040 if (!host->ddr_doubled_clk_rate ||
3041 (host->ddr_doubled_clk_rate &&
3042 (host->ddr_doubled_clk_rate != ios->clock))) {
3043 host->ddr_doubled_clk_rate =
3044 msmsdcc_get_sup_clk_rate(
3045 host, (ios->clock * 2));
3046 clock = host->ddr_doubled_clk_rate;
3047 }
3048 } else {
3049 host->ddr_doubled_clk_rate = 0;
3050 }
3051
3052 if (clock != host->clk_rate) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05303053 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003054 rc = clk_set_rate(host->clk, clock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303055 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003056 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303057 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003058 mmc_hostname(mmc), clock);
3059 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303060 host->reg_write_delay =
3061 (1 + ((3 * USEC_PER_SEC) /
3062 (host->clk_rate ? host->clk_rate :
3063 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003064 }
3065 /*
3066 * give atleast 2 MCLK cycles delay for clocks
3067 * and SDCC core to stabilize
3068 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05303069 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003070 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003071 clk |= MCI_CLK_ENABLE;
3072 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003073 if (ios->bus_width == MMC_BUS_WIDTH_8)
3074 clk |= MCI_CLK_WIDEBUS_8;
3075 else if (ios->bus_width == MMC_BUS_WIDTH_4)
3076 clk |= MCI_CLK_WIDEBUS_4;
3077 else
3078 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07003079
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003080 if (msmsdcc_is_pwrsave(host))
3081 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07003082
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003083 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07003084
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003085 host->tuning_needed = 0;
3086 /*
3087 * Select the controller timing mode according
3088 * to current bus speed mode
3089 */
Subhash Jadavanif97d2992012-07-13 14:47:47 +05303090 if (host->clk_rate > (100 * 1000 * 1000) &&
3091 (ios->timing == MMC_TIMING_UHS_SDR104 ||
3092 ios->timing == MMC_TIMING_MMC_HS200)) {
3093 /* Card clock frequency must be > 100MHz to enable tuning */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003094 clk |= (4 << 14);
3095 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05303096 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003097 clk |= (3 << 14);
3098 } else {
3099 clk |= (2 << 14); /* feedback clock */
San Mehat9d2bd732009-09-22 16:44:22 -07003100 }
3101
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003102 /* Select free running MCLK as input clock of cm_dll_sdc4 */
3103 clk |= (2 << 23);
San Mehat9d2bd732009-09-22 16:44:22 -07003104
Subhash Jadavani00083572012-02-15 16:18:01 +05303105 /* Clear IO_PAD_PWR_SWITCH while powering off the card */
3106 if (!ios->vdd)
3107 host->io_pad_pwr_switch = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07003108
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003109 if (host->io_pad_pwr_switch)
3110 clk |= IO_PAD_PWR_SWITCH;
3111
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303112 /* Don't write into registers if clocks are disabled */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303113 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303114 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
3115 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303116 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003117 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303118 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
3119 host->pwr = pwr;
3120 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303121 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003122 }
San Mehat9d2bd732009-09-22 16:44:22 -07003123 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003124
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303125 if (!(clk & MCI_CLK_ENABLE) && atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303126 msmsdcc_cfg_sdio_wakeup(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303127 spin_unlock_irqrestore(&host->lock, flags);
3128 /*
3129 * May get a wake-up interrupt the instant we disable the
3130 * clocks. This would disable the wake-up interrupt.
3131 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003132 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303133 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003134 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303135
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303136 if (host->tuning_in_progress)
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303137 WARN(!atomic_read(&host->clks_on),
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303138 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303139
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303140 /* Let interrupts be disabled if the host is powered off */
3141 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
3142 enable_irq(host->core_irqres->start);
3143 host->sdcc_irq_disabled = 0;
3144 }
San Mehat4adbbcc2009-11-08 13:00:37 -08003145 spin_unlock_irqrestore(&host->lock, flags);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303146out:
Asutosh Dasf5298c32012-04-03 14:51:47 +05303147 mutex_unlock(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07003148}
3149
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003150int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
3151{
3152 struct msmsdcc_host *host = mmc_priv(mmc);
3153 u32 clk;
3154
3155 clk = readl_relaxed(host->base + MMCICLOCK);
3156 pr_debug("Changing to pwr_save=%d", pwrsave);
3157 if (pwrsave && msmsdcc_is_pwrsave(host))
3158 clk |= MCI_CLK_PWRSAVE;
3159 else
3160 clk &= ~MCI_CLK_PWRSAVE;
3161 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303162 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003163
3164 return 0;
3165}
3166
3167static int msmsdcc_get_ro(struct mmc_host *mmc)
3168{
3169 int status = -ENOSYS;
3170 struct msmsdcc_host *host = mmc_priv(mmc);
3171
3172 if (host->plat->wpswitch) {
3173 status = host->plat->wpswitch(mmc_dev(mmc));
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05303174 } else if (gpio_is_valid(host->plat->wpswitch_gpio)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003175 status = gpio_request(host->plat->wpswitch_gpio,
3176 "SD_WP_Switch");
3177 if (status) {
3178 pr_err("%s: %s: Failed to request GPIO %d\n",
3179 mmc_hostname(mmc), __func__,
3180 host->plat->wpswitch_gpio);
3181 } else {
3182 status = gpio_direction_input(
3183 host->plat->wpswitch_gpio);
3184 if (!status) {
3185 /*
3186 * Wait for atleast 300ms as debounce
3187 * time for GPIO input to stabilize.
3188 */
3189 msleep(300);
3190 status = gpio_get_value_cansleep(
3191 host->plat->wpswitch_gpio);
Sujit Reddy Thumma8f912ea2012-06-22 16:18:43 +05303192 status ^= !host->plat->is_wpswitch_active_low;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003193 }
3194 gpio_free(host->plat->wpswitch_gpio);
3195 }
3196 }
3197
3198 if (status < 0)
3199 status = -ENOSYS;
3200 pr_debug("%s: Card read-only status %d\n", __func__, status);
3201
3202 return status;
San Mehat9d2bd732009-09-22 16:44:22 -07003203}
3204
3205static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
3206{
3207 struct msmsdcc_host *host = mmc_priv(mmc);
3208 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003209
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303210 /*
3211 * We may come here with clocks turned off in that case don't
3212 * attempt to write into MASK0 register. While turning on the
3213 * clocks mci_irqenable will be written to MASK0 register.
3214 */
San Mehat9d2bd732009-09-22 16:44:22 -07003215
3216 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003217 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003218 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303219 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303220 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003221 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303222 mb();
3223 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003224 } else {
3225 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303226 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303227 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003228 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303229 mb();
3230 }
San Mehat9d2bd732009-09-22 16:44:22 -07003231 }
3232 spin_unlock_irqrestore(&host->lock, flags);
3233}
3234
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003235#ifdef CONFIG_PM_RUNTIME
subhashj245831e2012-04-30 18:46:17 +05303236static void msmsdcc_print_rpm_info(struct msmsdcc_host *host)
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003237{
subhashj245831e2012-04-30 18:46:17 +05303238 struct device *dev = mmc_dev(host->mmc);
3239
3240 pr_info("%s: RPM: runtime_status=%d, usage_count=%d,"
3241 " is_suspended=%d, disable_depth=%d, runtime_error=%d,"
3242 " request_pending=%d, request=%d\n",
3243 mmc_hostname(host->mmc), dev->power.runtime_status,
3244 atomic_read(&dev->power.usage_count),
3245 dev->power.is_suspended, dev->power.disable_depth,
3246 dev->power.runtime_error, dev->power.request_pending,
3247 dev->power.request);
3248}
3249
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003250static int msmsdcc_enable(struct mmc_host *mmc)
3251{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003252 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003253 struct device *dev = mmc->parent;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003254 struct msmsdcc_host *host = mmc_priv(mmc);
3255
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303256 msmsdcc_pm_qos_update_latency(host, 1);
3257
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003258 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303259 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003260
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003261 if (host->sdcc_suspended && host->pending_resume &&
3262 !pm_runtime_suspended(dev)) {
3263 host->pending_resume = false;
3264 pm_runtime_get_noresume(dev);
3265 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303266 goto skip_get_sync;
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003267 }
3268
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303269 if (dev->power.runtime_status == RPM_SUSPENDING) {
3270 if (mmc->suspend_task == current) {
3271 pm_runtime_get_noresume(dev);
3272 goto out;
3273 }
Sujit Reddy Thumma112bd752012-06-20 12:29:45 +05303274 } else if (dev->power.runtime_status == RPM_RESUMING) {
3275 pm_runtime_get_noresume(dev);
3276 goto out;
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303277 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003278
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303279 rc = pm_runtime_get_sync(dev);
3280
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303281skip_get_sync:
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303282 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003283 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3284 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303285 msmsdcc_print_rpm_info(host);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303286 return rc;
3287 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303288out:
3289 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303290 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003291}
3292
Steve Mucklef132c6c2012-06-06 18:30:57 -07003293static int msmsdcc_disable(struct mmc_host *mmc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003294{
3295 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303296 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003297
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303298 msmsdcc_pm_qos_update_latency(host, 0);
3299
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303300 if (mmc->card && mmc_card_sdio(mmc->card)) {
3301 rc = 0;
3302 goto out;
3303 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303304
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303305 if (host->plat->disable_runtime_pm)
3306 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003307
3308 rc = pm_runtime_put_sync(mmc->parent);
3309
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003310 /*
3311 * Ignore -EAGAIN as that is not fatal, it means that
3312 * either runtime usage count is non-zero or the runtime
3313 * pm itself is disabled or not in proper state to process
3314 * idle notification.
3315 */
3316 if (rc < 0 && (rc != -EAGAIN)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003317 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3318 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303319 msmsdcc_print_rpm_info(host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003320 return rc;
3321 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303322
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303323out:
3324 msmsdcc_msm_bus_queue_work(host);
3325 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003326}
3327#else
subhashj245831e2012-04-30 18:46:17 +05303328static void msmsdcc_print_rpm_info(struct msmsdcc_host *host) {}
3329
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303330static int msmsdcc_enable(struct mmc_host *mmc)
3331{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003332 struct device *dev = mmc->parent;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303333 struct msmsdcc_host *host = mmc_priv(mmc);
3334 unsigned long flags;
Sujit Reddy Thumma7f5051c2012-05-04 10:14:07 +05303335 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303336
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303337 msmsdcc_pm_qos_update_latency(host, 1);
3338
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303339 if (mmc->card && mmc_card_sdio(mmc->card)) {
3340 rc = 0;
3341 goto out;
3342 }
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003343
3344 if (host->sdcc_suspended && host->pending_resume) {
3345 host->pending_resume = false;
3346 rc = msmsdcc_runtime_resume(dev);
3347 goto out;
3348 }
3349
Asutosh Dasf5298c32012-04-03 14:51:47 +05303350 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303351 rc = msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303352 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303353
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003354out:
3355 if (rc < 0) {
3356 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3357 __func__, rc);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303358 msmsdcc_pm_qos_update_latency(host, 0);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003359 return rc;
3360 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303361 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303362 return 0;
3363}
3364
Steve Mucklef132c6c2012-06-06 18:30:57 -07003365static int msmsdcc_disable(struct mmc_host *mmc)
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303366{
3367 struct msmsdcc_host *host = mmc_priv(mmc);
3368 unsigned long flags;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303369 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303370
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303371 msmsdcc_pm_qos_update_latency(host, 0);
3372
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303373 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303374 goto out;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303375
Asutosh Dasf5298c32012-04-03 14:51:47 +05303376 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303377 rc = msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303378 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303379
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303380 if (rc) {
3381 msmsdcc_pm_qos_update_latency(host, 1);
3382 return rc;
3383 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303384out:
3385 msmsdcc_msm_bus_queue_work(host);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303386 return rc;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303387}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003388#endif
3389
Subhash Jadavani937c7502012-06-01 15:34:46 +05303390static int msmsdcc_switch_io_voltage(struct mmc_host *mmc,
3391 struct mmc_ios *ios)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003392{
3393 struct msmsdcc_host *host = mmc_priv(mmc);
3394 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303395 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003396
Subhash Jadavani00083572012-02-15 16:18:01 +05303397 spin_lock_irqsave(&host->lock, flags);
3398 host->io_pad_pwr_switch = 0;
3399 spin_unlock_irqrestore(&host->lock, flags);
3400
Subhash Jadavani937c7502012-06-01 15:34:46 +05303401 switch (ios->signal_voltage) {
3402 case MMC_SIGNAL_VOLTAGE_330:
3403 /* Set VDD IO to high voltage range (2.7v - 3.6v) */
3404 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303405 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303406 case MMC_SIGNAL_VOLTAGE_180:
3407 break;
3408 case MMC_SIGNAL_VOLTAGE_120:
3409 /*
3410 * For eMMC cards, VDD_IO voltage range must be changed
3411 * only if it operates in HS200 SDR 1.2V mode or in
3412 * DDR 1.2V mode.
3413 */
3414 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_SET_LEVEL, 1200000);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003415 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303416 default:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003417 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303418 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003419 goto out;
3420 }
San Mehat9d2bd732009-09-22 16:44:22 -07003421
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003422 /*
3423 * If we are here means voltage switch from high voltage to
3424 * low voltage is required
3425 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303426 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003427
3428 /*
3429 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
3430 * register until they become all zeros.
3431 */
3432 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303433 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003434 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
3435 mmc_hostname(mmc), __func__);
3436 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07003437 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003438
3439 /* Stop SD CLK output. */
3440 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3441 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303442 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003443 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003444
3445 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05303446 * Switch VDD Io from high voltage range (2.7v - 3.6v) to
3447 * low voltage range (1.7v - 1.95v).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003448 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303449 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303450 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003451 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003452
3453 spin_lock_irqsave(&host->lock, flags);
3454 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3455 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303456 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003457 host->io_pad_pwr_switch = 1;
3458 spin_unlock_irqrestore(&host->lock, flags);
3459
3460 /* Wait 5 ms for the voltage regulater in the card to become stable. */
3461 usleep_range(5000, 5500);
3462
3463 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303464 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003465 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3466 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303467 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003468 spin_unlock_irqrestore(&host->lock, flags);
3469
3470 /*
3471 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
3472 * don't become all ones within 1 ms then a Voltage Switch
3473 * sequence has failed and a power cycle to the card is required.
3474 * Otherwise Voltage Switch sequence is completed successfully.
3475 */
3476 usleep_range(1000, 1500);
3477
3478 spin_lock_irqsave(&host->lock, flags);
3479 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
3480 != (0xF << 1)) {
3481 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
3482 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303483 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003484 goto out_unlock;
3485 }
3486
3487out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303488 /* Enable PWRSAVE */
3489 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3490 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303491 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003492 spin_unlock_irqrestore(&host->lock, flags);
3493out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303494 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003495}
3496
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303497static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003498{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003499 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003500
3501 /* Program the MCLK value to MCLK_FREQ bit field */
3502 if (host->clk_rate <= 112000000)
3503 mclk_freq = 0;
3504 else if (host->clk_rate <= 125000000)
3505 mclk_freq = 1;
3506 else if (host->clk_rate <= 137000000)
3507 mclk_freq = 2;
3508 else if (host->clk_rate <= 150000000)
3509 mclk_freq = 3;
3510 else if (host->clk_rate <= 162000000)
3511 mclk_freq = 4;
3512 else if (host->clk_rate <= 175000000)
3513 mclk_freq = 5;
3514 else if (host->clk_rate <= 187000000)
3515 mclk_freq = 6;
3516 else if (host->clk_rate <= 200000000)
3517 mclk_freq = 7;
3518
3519 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3520 & ~(7 << 24)) | (mclk_freq << 24)),
3521 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003522}
3523
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303524/* Initialize the DLL (Programmable Delay Line ) */
3525static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003526{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003527 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303528 unsigned long flags;
3529 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003530
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303531 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003532 /*
3533 * Make sure that clock is always enabled when DLL
3534 * tuning is in progress. Keeping PWRSAVE ON may
3535 * turn off the clock. So let's disable the PWRSAVE
3536 * here and re-enable it once tuning is completed.
3537 */
3538 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3539 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303540 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303541
3542 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3543 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3544 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3545
3546 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3547 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3548 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3549
3550 msmsdcc_cm_sdc4_dll_set_freq(host);
3551
3552 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3553 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3554 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3555
3556 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3557 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3558 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3559
3560 /* Set DLL_EN bit to 1. */
3561 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3562 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3563
3564 /* Set CK_OUT_EN bit to 1. */
3565 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3566 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3567
3568 wait_cnt = 50;
3569 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3570 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3571 /* max. wait for 50us sec for LOCK bit to be set */
3572 if (--wait_cnt == 0) {
3573 pr_err("%s: %s: DLL failed to LOCK\n",
3574 mmc_hostname(host->mmc), __func__);
3575 rc = -ETIMEDOUT;
3576 goto out;
3577 }
3578 /* wait for 1us before polling again */
3579 udelay(1);
3580 }
3581
3582out:
3583 /* re-enable PWRSAVE */
3584 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3585 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303586 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303587 spin_unlock_irqrestore(&host->lock, flags);
3588
3589 return rc;
3590}
3591
3592static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3593 u8 poll)
3594{
3595 int rc = 0;
3596 u32 wait_cnt = 50;
3597 u8 ck_out_en = 0;
3598
3599 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3600 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3601 MCI_CK_OUT_EN);
3602
3603 while (ck_out_en != poll) {
3604 if (--wait_cnt == 0) {
3605 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3606 mmc_hostname(host->mmc), __func__, poll);
3607 rc = -ETIMEDOUT;
3608 goto out;
3609 }
3610 udelay(1);
3611
3612 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3613 MCI_CK_OUT_EN);
3614 }
3615out:
3616 return rc;
3617}
3618
3619/*
3620 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3621 * calibration sequence. This function should be called before
3622 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3623 * commands (CMD17/CMD18).
3624 *
3625 * This function gets called when host spinlock acquired.
3626 */
3627static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3628{
3629 int rc = 0;
3630 u32 config;
3631
3632 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3633 config |= MCI_CDR_EN;
3634 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3635 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3636
3637 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3638 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3639 if (rc)
3640 goto err_out;
3641
3642 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3643 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3644 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3645
3646 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3647 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3648 if (rc)
3649 goto err_out;
3650
3651 goto out;
3652
3653err_out:
3654 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3655out:
3656 return rc;
3657}
3658
3659static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3660 u8 phase)
3661{
3662 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303663 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3664 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3665 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303666 unsigned long flags;
3667 u32 config;
3668
3669 spin_lock_irqsave(&host->lock, flags);
3670
3671 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3672 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3673 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3674 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3675
3676 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3677 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3678 if (rc)
3679 goto err_out;
3680
3681 /*
3682 * Write the selected DLL clock output phase (0 ... 15)
3683 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
3684 */
3685 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3686 & ~(0xF << 20))
3687 | (grey_coded_phase_table[phase] << 20)),
3688 host->base + MCI_DLL_CONFIG);
3689
3690 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3691 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3692 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3693
3694 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3695 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3696 if (rc)
3697 goto err_out;
3698
3699 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3700 config |= MCI_CDR_EN;
3701 config &= ~MCI_CDR_EXT_EN;
3702 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3703 goto out;
3704
3705err_out:
3706 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3707 mmc_hostname(host->mmc), __func__, phase);
3708out:
3709 spin_unlock_irqrestore(&host->lock, flags);
3710 return rc;
3711}
3712
3713/*
3714 * Find out the greatest range of consecuitive selected
3715 * DLL clock output phases that can be used as sampling
3716 * setting for SD3.0 UHS-I card read operation (in SDR104
3717 * timing mode) or for eMMC4.5 card read operation (in HS200
3718 * timing mode).
3719 * Select the 3/4 of the range and configure the DLL with the
3720 * selected DLL clock output phase.
3721*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303722static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303723 u8 *phase_table, u8 total_phases)
3724{
Subhash Jadavani6159c622012-03-15 19:05:55 +05303725 #define MAX_PHASES 16
Subhash Jadavani34187042012-03-02 10:59:49 +05303726 int ret;
Subhash Jadavani6159c622012-03-15 19:05:55 +05303727 u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
3728 u8 phases_per_row[MAX_PHASES] = {0};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303729 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303730 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3731 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303732
Subhash Jadavani6159c622012-03-15 19:05:55 +05303733 if (!total_phases || (total_phases > MAX_PHASES)) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303734 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3735 mmc_hostname(host->mmc), __func__, total_phases);
3736 return -EINVAL;
3737 }
3738
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303739 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303740 ranges[row_index][col_index] = phase_table[cnt];
3741 phases_per_row[row_index] += 1;
3742 col_index++;
3743
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303744 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303745 continue;
3746 /* check if next phase in phase_table is consecutive or not */
3747 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3748 row_index++;
3749 col_index = 0;
3750 }
3751 }
3752
Subhash Jadavani6159c622012-03-15 19:05:55 +05303753 if (row_index >= MAX_PHASES)
3754 return -EINVAL;
3755
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303756 /* Check if phase-0 is present in first valid window? */
3757 if (!ranges[0][0]) {
3758 phase_0_found = true;
3759 phase_0_raw_index = 0;
3760 /* Check if cycle exist between 2 valid windows */
3761 for (cnt = 1; cnt <= row_index; cnt++) {
3762 if (phases_per_row[cnt]) {
Subhash Jadavani6159c622012-03-15 19:05:55 +05303763 for (i = 0; i < phases_per_row[cnt]; i++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303764 if (ranges[cnt][i] == 15) {
3765 phase_15_found = true;
3766 phase_15_raw_index = cnt;
3767 break;
3768 }
3769 }
3770 }
3771 }
3772 }
3773
3774 /* If 2 valid windows form cycle then merge them as single window */
3775 if (phase_0_found && phase_15_found) {
3776 /* number of phases in raw where phase 0 is present */
3777 u8 phases_0 = phases_per_row[phase_0_raw_index];
3778 /* number of phases in raw where phase 15 is present */
3779 u8 phases_15 = phases_per_row[phase_15_raw_index];
3780
Subhash Jadavani6159c622012-03-15 19:05:55 +05303781 if (phases_0 + phases_15 >= MAX_PHASES)
3782 /*
3783 * If there are more than 1 phase windows then total
3784 * number of phases in both the windows should not be
3785 * more than or equal to MAX_PHASES.
3786 */
3787 return -EINVAL;
3788
3789 /* Merge 2 cyclic windows */
3790 i = phases_15;
3791 for (cnt = 0; cnt < phases_0; cnt++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303792 ranges[phase_15_raw_index][i] =
3793 ranges[phase_0_raw_index][cnt];
Subhash Jadavani6159c622012-03-15 19:05:55 +05303794 if (++i >= MAX_PHASES)
3795 break;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303796 }
Subhash Jadavani6159c622012-03-15 19:05:55 +05303797
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303798 phases_per_row[phase_0_raw_index] = 0;
3799 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
3800 }
3801
3802 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303803 if (phases_per_row[cnt] > curr_max) {
3804 curr_max = phases_per_row[cnt];
3805 selected_row_index = cnt;
3806 }
3807 }
3808
Subhash Jadavani6159c622012-03-15 19:05:55 +05303809 i = ((curr_max * 3) / 4);
3810 if (i)
3811 i--;
3812
Subhash Jadavani34187042012-03-02 10:59:49 +05303813 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303814
Subhash Jadavani6159c622012-03-15 19:05:55 +05303815 if (ret >= MAX_PHASES) {
3816 ret = -EINVAL;
3817 pr_err("%s: %s: invalid phase selected=%d\n",
3818 mmc_hostname(host->mmc), __func__, ret);
3819 }
3820
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303821 return ret;
3822}
3823
Girish K Sa3f41692012-02-29 12:00:09 +05303824static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303825{
3826 int rc = 0;
3827 struct msmsdcc_host *host = mmc_priv(mmc);
3828 unsigned long flags;
3829 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303830 const u32 *tuning_block_pattern = tuning_block_64;
3831 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303832
3833 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
3834
3835 /* Tuning is only required for SDR104 modes */
3836 if (!host->tuning_needed) {
3837 rc = 0;
3838 goto exit;
3839 }
3840
3841 spin_lock_irqsave(&host->lock, flags);
3842 WARN(!host->pwr, "SDCC power is turned off\n");
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303843 WARN(!atomic_read(&host->clks_on), "SDCC clocks are turned off\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303844 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
3845
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303846 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303847 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
3848 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
3849 tuning_block_pattern = tuning_block_128;
3850 size = sizeof(tuning_block_128);
3851 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303852 spin_unlock_irqrestore(&host->lock, flags);
3853
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003854 /* first of all reset the tuning block */
3855 rc = msmsdcc_init_cm_sdc4_dll(host);
3856 if (rc)
3857 goto out;
3858
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303859 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003860 if (!data_buf) {
3861 rc = -ENOMEM;
3862 goto out;
3863 }
3864
3865 phase = 0;
3866 do {
3867 struct mmc_command cmd = {0};
3868 struct mmc_data data = {0};
3869 struct mmc_request mrq = {
3870 .cmd = &cmd,
3871 .data = &data
3872 };
3873 struct scatterlist sg;
3874
3875 /* set the phase in delay line hw block */
3876 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3877 if (rc)
3878 goto kfree;
3879
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303880 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003881 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
3882
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303883 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003884 data.blocks = 1;
3885 data.flags = MMC_DATA_READ;
3886 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
3887
3888 data.sg = &sg;
3889 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303890 sg_init_one(&sg, data_buf, size);
3891 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003892 mmc_wait_for_req(mmc, &mrq);
3893
3894 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303895 !memcmp(data_buf, tuning_block_pattern, size)) {
3896 /* tuning is successful at this tuning point */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003897 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303898 pr_debug("%s: %s: found good phase = %d\n",
3899 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003900 }
3901 } while (++phase < 16);
3902
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003903 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303904 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303905 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05303906 if (rc < 0)
3907 goto kfree;
3908 else
3909 phase = (u8)rc;
3910
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003911 /*
3912 * Finally set the selected phase in delay
3913 * line hw block.
3914 */
3915 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3916 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303917 goto kfree;
3918 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
3919 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003920 } else {
3921 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303922 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003923 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303924 msmsdcc_dump_sdcc_state(host);
3925 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003926 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003927
3928kfree:
3929 kfree(data_buf);
3930out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303931 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303932 host->tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303933 spin_unlock_irqrestore(&host->lock, flags);
3934exit:
3935 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003936 return rc;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003937}
3938
San Mehat9d2bd732009-09-22 16:44:22 -07003939static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003940 .enable = msmsdcc_enable,
3941 .disable = msmsdcc_disable,
Asutosh Dasaccacd42012-03-08 14:33:17 +05303942 .pre_req = msmsdcc_pre_req,
3943 .post_req = msmsdcc_post_req,
San Mehat9d2bd732009-09-22 16:44:22 -07003944 .request = msmsdcc_request,
3945 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003946 .get_ro = msmsdcc_get_ro,
San Mehat9d2bd732009-09-22 16:44:22 -07003947 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Subhash Jadavani937c7502012-06-01 15:34:46 +05303948 .start_signal_voltage_switch = msmsdcc_switch_io_voltage,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003949 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07003950};
3951
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003952static unsigned int
3953msmsdcc_slot_status(struct msmsdcc_host *host)
3954{
3955 int status;
3956 unsigned int gpio_no = host->plat->status_gpio;
3957
3958 status = gpio_request(gpio_no, "SD_HW_Detect");
3959 if (status) {
3960 pr_err("%s: %s: Failed to request GPIO %d\n",
3961 mmc_hostname(host->mmc), __func__, gpio_no);
3962 } else {
3963 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003964 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08003965 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003966 if (host->plat->is_status_gpio_active_low)
3967 status = !status;
3968 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003969 gpio_free(gpio_no);
3970 }
3971 return status;
3972}
3973
San Mehat9d2bd732009-09-22 16:44:22 -07003974static void
3975msmsdcc_check_status(unsigned long data)
3976{
3977 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3978 unsigned int status;
3979
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05303980 if (host->plat->status || gpio_is_valid(host->plat->status_gpio)) {
Krishna Konda941604a2012-01-10 17:46:34 -08003981 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003982 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003983 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003984 status = msmsdcc_slot_status(host);
3985
Krishna Konda941604a2012-01-10 17:46:34 -08003986 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08003987
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003988 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08003989 if (host->plat->status)
3990 pr_info("%s: Slot status change detected "
3991 "(%d -> %d)\n",
3992 mmc_hostname(host->mmc),
3993 host->oldstat, status);
3994 else if (host->plat->is_status_gpio_active_low)
3995 pr_info("%s: Slot status change detected "
3996 "(%d -> %d) and the card detect GPIO"
3997 " is ACTIVE_LOW\n",
3998 mmc_hostname(host->mmc),
3999 host->oldstat, status);
4000 else
4001 pr_info("%s: Slot status change detected "
4002 "(%d -> %d) and the card detect GPIO"
4003 " is ACTIVE_HIGH\n",
4004 mmc_hostname(host->mmc),
4005 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07004006 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004007 }
4008 host->oldstat = status;
4009 } else {
4010 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07004011 }
San Mehat9d2bd732009-09-22 16:44:22 -07004012}
4013
4014static irqreturn_t
4015msmsdcc_platform_status_irq(int irq, void *dev_id)
4016{
4017 struct msmsdcc_host *host = dev_id;
4018
Girish K Sa3c76eb2011-10-11 11:44:09 +05304019 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07004020 msmsdcc_check_status((unsigned long) host);
4021 return IRQ_HANDLED;
4022}
4023
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004024static irqreturn_t
4025msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
4026{
4027 struct msmsdcc_host *host = dev_id;
4028
4029 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
4030 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304031 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004032 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304033 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004034 wake_lock(&host->sdio_wlock);
4035 msmsdcc_disable_irq_wake(host);
4036 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304037 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004038 }
4039 if (host->plat->is_sdio_al_client) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004040 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304041 spin_unlock(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304042 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304043 goto out_unlocked;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004044 }
4045 spin_unlock(&host->lock);
4046
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304047out_unlocked:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004048 return IRQ_HANDLED;
4049}
4050
San Mehat9d2bd732009-09-22 16:44:22 -07004051static void
4052msmsdcc_status_notify_cb(int card_present, void *dev_id)
4053{
4054 struct msmsdcc_host *host = dev_id;
4055
Girish K Sa3c76eb2011-10-11 11:44:09 +05304056 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07004057 card_present);
4058 msmsdcc_check_status((unsigned long) host);
4059}
4060
San Mehat9d2bd732009-09-22 16:44:22 -07004061static int
4062msmsdcc_init_dma(struct msmsdcc_host *host)
4063{
4064 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
4065 host->dma.host = host;
4066 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004067 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004068
4069 if (!host->dmares)
4070 return -ENODEV;
4071
4072 host->dma.nc = dma_alloc_coherent(NULL,
4073 sizeof(struct msmsdcc_nc_dmadata),
4074 &host->dma.nc_busaddr,
4075 GFP_KERNEL);
4076 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004077 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07004078 return -ENOMEM;
4079 }
4080 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
4081 host->dma.cmd_busaddr = host->dma.nc_busaddr;
4082 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
4083 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
4084 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07004085 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07004086
4087 return 0;
4088}
4089
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004090#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
4091/**
4092 * Allocate and Connect a SDCC peripheral's SPS endpoint
4093 *
4094 * This function allocates endpoint context and
4095 * connect it with memory endpoint by calling
4096 * appropriate SPS driver APIs.
4097 *
4098 * Also registers a SPS callback function with
4099 * SPS driver
4100 *
4101 * This function should only be called once typically
4102 * during driver probe.
4103 *
4104 * @host - Pointer to sdcc host structure
4105 * @ep - Pointer to sps endpoint data structure
4106 * @is_produce - 1 means Producer endpoint
4107 * 0 means Consumer endpoint
4108 *
4109 * @return - 0 if successful else negative value.
4110 *
4111 */
4112static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
4113 struct msmsdcc_sps_ep_conn_data *ep,
4114 bool is_producer)
4115{
4116 int rc = 0;
4117 struct sps_pipe *sps_pipe_handle;
4118 struct sps_connect *sps_config = &ep->config;
4119 struct sps_register_event *sps_event = &ep->event;
4120
4121 /* Allocate endpoint context */
4122 sps_pipe_handle = sps_alloc_endpoint();
4123 if (!sps_pipe_handle) {
4124 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
4125 mmc_hostname(host->mmc), is_producer);
4126 rc = -ENOMEM;
4127 goto out;
4128 }
4129
4130 /* Get default connection configuration for an endpoint */
4131 rc = sps_get_config(sps_pipe_handle, sps_config);
4132 if (rc) {
4133 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
4134 " rc=%d", mmc_hostname(host->mmc),
4135 (u32)sps_pipe_handle, rc);
4136 goto get_config_err;
4137 }
4138
4139 /* Modify the default connection configuration */
4140 if (is_producer) {
4141 /*
4142 * For SDCC producer transfer, source should be
4143 * SDCC peripheral where as destination should
4144 * be system memory.
4145 */
4146 sps_config->source = host->sps.bam_handle;
4147 sps_config->destination = SPS_DEV_HANDLE_MEM;
4148 /* Producer pipe will handle this connection */
4149 sps_config->mode = SPS_MODE_SRC;
4150 sps_config->options =
4151 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4152 } else {
4153 /*
4154 * For SDCC consumer transfer, source should be
4155 * system memory where as destination should
4156 * SDCC peripheral
4157 */
4158 sps_config->source = SPS_DEV_HANDLE_MEM;
4159 sps_config->destination = host->sps.bam_handle;
4160 sps_config->mode = SPS_MODE_DEST;
4161 sps_config->options =
4162 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4163 }
4164
4165 /* Producer pipe index */
4166 sps_config->src_pipe_index = host->sps.src_pipe_index;
4167 /* Consumer pipe index */
4168 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
4169 /*
4170 * This event thresold value is only significant for BAM-to-BAM
4171 * transfer. It's ignored for BAM-to-System mode transfer.
4172 */
4173 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304174
4175 /* Allocate maximum descriptor fifo size */
4176 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
4177 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004178 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
4179 sps_config->desc.size,
4180 &sps_config->desc.phys_base,
4181 GFP_KERNEL);
4182
Pratibhasagar V00b94332011-10-18 14:57:27 +05304183 if (!sps_config->desc.base) {
4184 rc = -ENOMEM;
4185 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
4186 , mmc_hostname(host->mmc));
4187 goto get_config_err;
4188 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004189 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
4190
4191 /* Establish connection between peripheral and memory endpoint */
4192 rc = sps_connect(sps_pipe_handle, sps_config);
4193 if (rc) {
4194 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4195 " rc=%d", mmc_hostname(host->mmc),
4196 (u32)sps_pipe_handle, rc);
4197 goto sps_connect_err;
4198 }
4199
4200 sps_event->mode = SPS_TRIGGER_CALLBACK;
4201 sps_event->options = SPS_O_EOT;
4202 sps_event->callback = msmsdcc_sps_complete_cb;
4203 sps_event->xfer_done = NULL;
4204 sps_event->user = (void *)host;
4205
4206 /* Register callback event for EOT (End of transfer) event. */
4207 rc = sps_register_event(sps_pipe_handle, sps_event);
4208 if (rc) {
4209 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4210 " rc=%d", mmc_hostname(host->mmc),
4211 (u32)sps_pipe_handle, rc);
4212 goto reg_event_err;
4213 }
4214 /* Now save the sps pipe handle */
4215 ep->pipe_handle = sps_pipe_handle;
4216 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
4217 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
4218 __func__, is_producer ? "READ" : "WRITE",
4219 (u32)sps_pipe_handle, sps_config->desc.phys_base);
4220 goto out;
4221
4222reg_event_err:
4223 sps_disconnect(sps_pipe_handle);
4224sps_connect_err:
4225 dma_free_coherent(mmc_dev(host->mmc),
4226 sps_config->desc.size,
4227 sps_config->desc.base,
4228 sps_config->desc.phys_base);
4229get_config_err:
4230 sps_free_endpoint(sps_pipe_handle);
4231out:
4232 return rc;
4233}
4234
4235/**
4236 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
4237 *
4238 * This function disconnect endpoint and deallocates
4239 * endpoint context.
4240 *
4241 * This function should only be called once typically
4242 * during driver remove.
4243 *
4244 * @host - Pointer to sdcc host structure
4245 * @ep - Pointer to sps endpoint data structure
4246 *
4247 */
4248static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
4249 struct msmsdcc_sps_ep_conn_data *ep)
4250{
4251 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4252 struct sps_connect *sps_config = &ep->config;
4253 struct sps_register_event *sps_event = &ep->event;
4254
4255 sps_event->xfer_done = NULL;
4256 sps_event->callback = NULL;
4257 sps_register_event(sps_pipe_handle, sps_event);
4258 sps_disconnect(sps_pipe_handle);
4259 dma_free_coherent(mmc_dev(host->mmc),
4260 sps_config->desc.size,
4261 sps_config->desc.base,
4262 sps_config->desc.phys_base);
4263 sps_free_endpoint(sps_pipe_handle);
4264}
4265
4266/**
4267 * Reset SDCC peripheral's SPS endpoint
4268 *
4269 * This function disconnects an endpoint.
4270 *
4271 * This function should be called for reseting
4272 * SPS endpoint when data transfer error is
4273 * encountered during data transfer. This
4274 * can be considered as soft reset to endpoint.
4275 *
4276 * This function should only be called if
4277 * msmsdcc_sps_init() is already called.
4278 *
4279 * @host - Pointer to sdcc host structure
4280 * @ep - Pointer to sps endpoint data structure
4281 *
4282 * @return - 0 if successful else negative value.
4283 */
4284static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
4285 struct msmsdcc_sps_ep_conn_data *ep)
4286{
4287 int rc = 0;
4288 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4289
4290 rc = sps_disconnect(sps_pipe_handle);
4291 if (rc) {
4292 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
4293 " rc=%d", mmc_hostname(host->mmc), __func__,
4294 (u32)sps_pipe_handle, rc);
4295 goto out;
4296 }
4297 out:
4298 return rc;
4299}
4300
4301/**
4302 * Restore SDCC peripheral's SPS endpoint
4303 *
4304 * This function connects an endpoint.
4305 *
4306 * This function should be called for restoring
4307 * SPS endpoint after data transfer error is
4308 * encountered during data transfer. This
4309 * can be considered as soft reset to endpoint.
4310 *
4311 * This function should only be called if
4312 * msmsdcc_sps_reset_ep() is called before.
4313 *
4314 * @host - Pointer to sdcc host structure
4315 * @ep - Pointer to sps endpoint data structure
4316 *
4317 * @return - 0 if successful else negative value.
4318 */
4319static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
4320 struct msmsdcc_sps_ep_conn_data *ep)
4321{
4322 int rc = 0;
4323 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4324 struct sps_connect *sps_config = &ep->config;
4325 struct sps_register_event *sps_event = &ep->event;
4326
4327 /* Establish connection between peripheral and memory endpoint */
4328 rc = sps_connect(sps_pipe_handle, sps_config);
4329 if (rc) {
4330 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
4331 " rc=%d", mmc_hostname(host->mmc), __func__,
4332 (u32)sps_pipe_handle, rc);
4333 goto out;
4334 }
4335
4336 /* Register callback event for EOT (End of transfer) event. */
4337 rc = sps_register_event(sps_pipe_handle, sps_event);
4338 if (rc) {
4339 pr_err("%s: %s: sps_register_event() failed!!!"
4340 " pipe_handle=0x%x, rc=%d",
4341 mmc_hostname(host->mmc), __func__,
4342 (u32)sps_pipe_handle, rc);
4343 goto reg_event_err;
4344 }
4345 goto out;
4346
4347reg_event_err:
4348 sps_disconnect(sps_pipe_handle);
4349out:
4350 return rc;
4351}
4352
4353/**
Krishna Konda5af8f972012-05-14 16:15:24 -07004354 * Handle BAM device's global error condition
4355 *
4356 * This is an error handler for the SDCC bam device
4357 *
4358 * This function is registered as a callback with SPS-BAM
4359 * driver and will called in case there are an errors for
4360 * the SDCC BAM deivce. Any error conditions in the BAM
4361 * device are global and will be result in this function
4362 * being called once per device.
4363 *
4364 * This function will be called from the sps driver's
4365 * interrupt context.
4366 *
4367 * @sps_cb_case - indicates what error it is
4368 * @user - Pointer to sdcc host structure
4369 */
4370static void
4371msmsdcc_sps_bam_global_irq_cb(enum sps_callback_case sps_cb_case, void *user)
4372{
4373 struct msmsdcc_host *host = (struct msmsdcc_host *)user;
4374 struct mmc_request *mrq;
4375 unsigned long flags;
4376 int32_t error = 0;
4377
4378 BUG_ON(!host);
4379 BUG_ON(!is_sps_mode(host));
4380
4381 if (sps_cb_case == SPS_CALLBACK_BAM_ERROR_IRQ) {
4382 /**
4383 * Reset the all endpoints along with reseting the sps device.
4384 */
4385 host->sps.pipe_reset_pending = true;
4386 host->sps.reset_device = true;
4387
4388 pr_err("%s: BAM Global ERROR IRQ happened\n",
4389 mmc_hostname(host->mmc));
4390 error = EAGAIN;
4391 } else if (sps_cb_case == SPS_CALLBACK_BAM_HRESP_ERR_IRQ) {
4392 /**
4393 * This means that there was an AHB access error and
4394 * the address we are trying to read/write is something
4395 * we dont have priviliges to do so.
4396 */
4397 pr_err("%s: BAM HRESP_ERR_IRQ happened\n",
4398 mmc_hostname(host->mmc));
4399 error = EACCES;
4400 } else {
4401 /**
4402 * This should not have happened ideally. If this happens
4403 * there is some seriously wrong.
4404 */
4405 pr_err("%s: BAM global IRQ callback received, type:%d\n",
4406 mmc_hostname(host->mmc), (u32) sps_cb_case);
4407 error = EIO;
4408 }
4409
4410 spin_lock_irqsave(&host->lock, flags);
4411
4412 mrq = host->curr.mrq;
4413
4414 if (mrq && mrq->cmd) {
4415 msmsdcc_dump_sdcc_state(host);
4416
4417 if (!mrq->cmd->error)
4418 mrq->cmd->error = -error;
4419 if (host->curr.data) {
4420 if (mrq->data && !mrq->data->error)
4421 mrq->data->error = -error;
4422 host->curr.data_xfered = 0;
4423 if (host->sps.sg && is_sps_mode(host)) {
4424 /* Stop current SPS transfer */
4425 msmsdcc_sps_exit_curr_xfer(host);
4426 } else {
4427 /* this condition should not have happened */
4428 pr_err("%s: something is seriously wrong. "\
4429 "Funtion: %s, line: %d\n",
4430 mmc_hostname(host->mmc),
4431 __func__, __LINE__);
4432 }
4433 } else {
4434 /* this condition should not have happened */
4435 pr_err("%s: something is seriously wrong. Funtion: "\
4436 "%s, line: %d\n", mmc_hostname(host->mmc),
4437 __func__, __LINE__);
4438 }
4439 }
4440 spin_unlock_irqrestore(&host->lock, flags);
4441}
4442
4443/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004444 * Initialize SPS HW connected with SDCC core
4445 *
4446 * This function register BAM HW resources with
4447 * SPS driver and then initialize 2 SPS endpoints
4448 *
4449 * This function should only be called once typically
4450 * during driver probe.
4451 *
4452 * @host - Pointer to sdcc host structure
4453 *
4454 * @return - 0 if successful else negative value.
4455 *
4456 */
4457static int msmsdcc_sps_init(struct msmsdcc_host *host)
4458{
4459 int rc = 0;
4460 struct sps_bam_props bam = {0};
4461
4462 host->bam_base = ioremap(host->bam_memres->start,
4463 resource_size(host->bam_memres));
4464 if (!host->bam_base) {
4465 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
4466 " size=0x%x", mmc_hostname(host->mmc),
4467 host->bam_memres->start,
4468 (host->bam_memres->end -
4469 host->bam_memres->start));
4470 rc = -ENOMEM;
4471 goto out;
4472 }
4473
4474 bam.phys_addr = host->bam_memres->start;
4475 bam.virt_addr = host->bam_base;
4476 /*
4477 * This event thresold value is only significant for BAM-to-BAM
4478 * transfer. It's ignored for BAM-to-System mode transfer.
4479 */
4480 bam.event_threshold = 0x10; /* Pipe event threshold */
4481 /*
4482 * This threshold controls when the BAM publish
4483 * the descriptor size on the sideband interface.
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304484 * SPS HW will be used for data transfer size even
4485 * less than SDCC FIFO size. So let's set BAM summing
4486 * thresold to SPS_MIN_XFER_SIZE bytes.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004487 */
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304488 bam.summing_threshold = SPS_MIN_XFER_SIZE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004489 /* SPS driver wll handle the SDCC BAM IRQ */
4490 bam.irq = (u32)host->bam_irqres->start;
4491 bam.manage = SPS_BAM_MGR_LOCAL;
Krishna Konda5af8f972012-05-14 16:15:24 -07004492 bam.callback = msmsdcc_sps_bam_global_irq_cb;
4493 bam.user = (void *)host;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004494
4495 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
4496 (u32)bam.phys_addr);
4497 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
4498 (u32)bam.virt_addr);
4499
4500 /* Register SDCC Peripheral BAM device to SPS driver */
4501 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
4502 if (rc) {
4503 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
4504 mmc_hostname(host->mmc), rc);
4505 goto reg_bam_err;
4506 }
4507 pr_info("%s: BAM device registered. bam_handle=0x%x",
4508 mmc_hostname(host->mmc), host->sps.bam_handle);
4509
4510 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
4511 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
4512
4513 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
4514 SPS_PROD_PERIPHERAL);
4515 if (rc)
4516 goto sps_reset_err;
4517 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
4518 SPS_CONS_PERIPHERAL);
4519 if (rc)
4520 goto cons_conn_err;
4521
4522 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
4523 mmc_hostname(host->mmc),
4524 (unsigned long long)host->bam_memres->start,
4525 (unsigned int)host->bam_irqres->start);
4526 goto out;
4527
4528cons_conn_err:
4529 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4530sps_reset_err:
4531 sps_deregister_bam_device(host->sps.bam_handle);
4532reg_bam_err:
4533 iounmap(host->bam_base);
4534out:
4535 return rc;
4536}
4537
4538/**
4539 * De-initialize SPS HW connected with SDCC core
4540 *
4541 * This function deinitialize SPS endpoints and then
4542 * deregisters BAM resources from SPS driver.
4543 *
4544 * This function should only be called once typically
4545 * during driver remove.
4546 *
4547 * @host - Pointer to sdcc host structure
4548 *
4549 */
4550static void msmsdcc_sps_exit(struct msmsdcc_host *host)
4551{
4552 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
4553 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4554 sps_deregister_bam_device(host->sps.bam_handle);
4555 iounmap(host->bam_base);
4556}
4557#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
4558
4559static ssize_t
4560show_polling(struct device *dev, struct device_attribute *attr, char *buf)
4561{
4562 struct mmc_host *mmc = dev_get_drvdata(dev);
4563 struct msmsdcc_host *host = mmc_priv(mmc);
4564 int poll;
4565 unsigned long flags;
4566
4567 spin_lock_irqsave(&host->lock, flags);
4568 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
4569 spin_unlock_irqrestore(&host->lock, flags);
4570
4571 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
4572}
4573
4574static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05304575store_polling(struct device *dev, struct device_attribute *attr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004576 const char *buf, size_t count)
4577{
4578 struct mmc_host *mmc = dev_get_drvdata(dev);
4579 struct msmsdcc_host *host = mmc_priv(mmc);
4580 int value;
4581 unsigned long flags;
4582
4583 sscanf(buf, "%d", &value);
4584
4585 spin_lock_irqsave(&host->lock, flags);
4586 if (value) {
4587 mmc->caps |= MMC_CAP_NEEDS_POLL;
4588 mmc_detect_change(host->mmc, 0);
4589 } else {
4590 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4591 }
4592#ifdef CONFIG_HAS_EARLYSUSPEND
4593 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
4594#endif
4595 spin_unlock_irqrestore(&host->lock, flags);
4596 return count;
4597}
4598
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304599static ssize_t
4600show_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
4601 char *buf)
4602{
4603 struct mmc_host *mmc = dev_get_drvdata(dev);
4604 struct msmsdcc_host *host = mmc_priv(mmc);
4605
4606 return snprintf(buf, PAGE_SIZE, "%u\n",
4607 host->msm_bus_vote.is_max_bw_needed);
4608}
4609
4610static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05304611store_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304612 const char *buf, size_t count)
4613{
4614 struct mmc_host *mmc = dev_get_drvdata(dev);
4615 struct msmsdcc_host *host = mmc_priv(mmc);
4616 uint32_t value;
4617 unsigned long flags;
4618
4619 if (!kstrtou32(buf, 0, &value)) {
4620 spin_lock_irqsave(&host->lock, flags);
4621 host->msm_bus_vote.is_max_bw_needed = !!value;
4622 spin_unlock_irqrestore(&host->lock, flags);
4623 }
4624
4625 return count;
4626}
4627
Pratibhasagar V13d1d032012-07-09 20:12:38 +05304628static ssize_t
4629show_idle_timeout(struct device *dev, struct device_attribute *attr,
4630 char *buf)
4631{
4632 struct mmc_host *mmc = dev_get_drvdata(dev);
4633 struct msmsdcc_host *host = mmc_priv(mmc);
4634
4635 return snprintf(buf, PAGE_SIZE, "%u (Min 5 sec)\n",
4636 host->idle_tout_ms / 1000);
4637}
4638
4639static ssize_t
4640store_idle_timeout(struct device *dev, struct device_attribute *attr,
4641 const char *buf, size_t count)
4642{
4643 struct mmc_host *mmc = dev_get_drvdata(dev);
4644 struct msmsdcc_host *host = mmc_priv(mmc);
4645 unsigned int long flags;
4646 int timeout; /* in secs */
4647
4648 if (!kstrtou32(buf, 0, &timeout)
4649 && (timeout > MSM_MMC_DEFAULT_IDLE_TIMEOUT / 1000)) {
4650 spin_lock_irqsave(&host->lock, flags);
4651 host->idle_tout_ms = timeout * 1000;
4652 spin_unlock_irqrestore(&host->lock, flags);
4653 }
4654 return count;
4655}
4656
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004657#ifdef CONFIG_HAS_EARLYSUSPEND
4658static void msmsdcc_early_suspend(struct early_suspend *h)
4659{
4660 struct msmsdcc_host *host =
4661 container_of(h, struct msmsdcc_host, early_suspend);
4662 unsigned long flags;
4663
4664 spin_lock_irqsave(&host->lock, flags);
4665 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
4666 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4667 spin_unlock_irqrestore(&host->lock, flags);
4668};
4669static void msmsdcc_late_resume(struct early_suspend *h)
4670{
4671 struct msmsdcc_host *host =
4672 container_of(h, struct msmsdcc_host, early_suspend);
4673 unsigned long flags;
4674
4675 if (host->polling_enabled) {
4676 spin_lock_irqsave(&host->lock, flags);
4677 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
4678 mmc_detect_change(host->mmc, 0);
4679 spin_unlock_irqrestore(&host->lock, flags);
4680 }
4681};
4682#endif
4683
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304684static void msmsdcc_print_regs(const char *name, void __iomem *base,
4685 u32 phys_base, unsigned int no_of_regs)
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304686{
4687 unsigned int i;
4688
4689 if (!base)
4690 return;
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304691
4692 pr_info("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
4693 " =====\n", name, phys_base, (u32)base);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304694 for (i = 0; i < no_of_regs; i = i + 4) {
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304695 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
4696 (u32)readl_relaxed(base + i*4),
4697 (u32)readl_relaxed(base + ((i+1)*4)),
4698 (u32)readl_relaxed(base + ((i+2)*4)),
4699 (u32)readl_relaxed(base + ((i+3)*4)));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304700 }
4701}
4702
4703static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
4704{
4705 /* Dump current state of SDCC clocks, power and irq */
4706 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304707 (host->pwr ? "ON" : "OFF"));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304708 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304709 mmc_hostname(host->mmc),
4710 (atomic_read(&host->clks_on) ? "ON" : "OFF"),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304711 (u32)clk_get_rate(host->clk));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304712 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
4713 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
4714
4715 /* Now dump SDCC registers. Don't print FIFO registers */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304716 if (atomic_read(&host->clks_on))
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304717 msmsdcc_print_regs("SDCC-CORE", host->base,
4718 host->core_memres->start, 28);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304719
4720 if (host->curr.data) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304721 if (!msmsdcc_is_dma_possible(host, host->curr.data))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304722 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304723 else if (is_dma_mode(host))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304724 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
4725 mmc_hostname(host->mmc), host->dma.busy,
4726 host->dma.channel, host->dma.crci);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304727 else if (is_sps_mode(host)) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304728 if (host->sps.busy && atomic_read(&host->clks_on))
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304729 msmsdcc_print_regs("SDCC-DML", host->dml_base,
4730 host->dml_memres->start,
4731 16);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304732 pr_info("%s: SPS mode: busy=%d\n",
4733 mmc_hostname(host->mmc), host->sps.busy);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304734 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304735
4736 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
4737 mmc_hostname(host->mmc), host->curr.xfer_size,
4738 host->curr.data_xfered, host->curr.xfer_remain);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304739 }
4740
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304741 pr_info("%s: got_dataend=%d, prog_enable=%d,"
Subhash Jadavani8706ced2012-05-25 16:09:21 +05304742 " wait_for_auto_prog_done=%d, got_auto_prog_done=%d,"
4743 " req_tout_ms=%d\n", mmc_hostname(host->mmc),
4744 host->curr.got_dataend, host->prog_enable,
4745 host->curr.wait_for_auto_prog_done,
4746 host->curr.got_auto_prog_done, host->curr.req_tout_ms);
subhashj245831e2012-04-30 18:46:17 +05304747 msmsdcc_print_rpm_info(host);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304748}
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304749
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004750static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
4751{
4752 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4753 struct mmc_request *mrq;
4754 unsigned long flags;
4755
4756 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004757 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004758 pr_info("%s: %s: dummy CMD52 timeout\n",
4759 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004760 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004761 }
4762
4763 mrq = host->curr.mrq;
4764
4765 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304766 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
4767 mrq->cmd->opcode);
4768 msmsdcc_dump_sdcc_state(host);
4769
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004770 if (!mrq->cmd->error)
4771 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304772 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004773 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004774 if (mrq->data && !mrq->data->error)
4775 mrq->data->error = -ETIMEDOUT;
4776 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304777 if (host->dma.sg && is_dma_mode(host)) {
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07004778 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304779 } else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004780 /* Stop current SPS transfer */
4781 msmsdcc_sps_exit_curr_xfer(host);
4782 } else {
4783 msmsdcc_reset_and_restore(host);
4784 msmsdcc_stop_data(host);
4785 if (mrq->data && mrq->data->stop)
4786 msmsdcc_start_command(host,
4787 mrq->data->stop, 0);
4788 else
4789 msmsdcc_request_end(host, mrq);
4790 }
4791 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304792 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05304793 host->curr.wait_for_auto_prog_done = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004794 msmsdcc_reset_and_restore(host);
4795 msmsdcc_request_end(host, mrq);
4796 }
4797 }
4798 spin_unlock_irqrestore(&host->lock, flags);
4799}
4800
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05304801/*
4802 * msmsdcc_dt_get_array - Wrapper fn to read an array of 32 bit integers
4803 *
4804 * @dev: device node from which the property value is to be read.
4805 * @prop_name: name of the property to be searched.
4806 * @out_array: filled array returned to caller
4807 * @len: filled array size returned to caller
4808 * @size: expected size of the array
4809 *
4810 * If expected "size" doesn't match with "len" an error is returned. If
4811 * expected size is zero, the length of actual array is returned provided
4812 * return value is zero.
4813 *
4814 * RETURNS:
4815 * zero on success, negative error if failed.
4816 */
4817static int msmsdcc_dt_get_array(struct device *dev, const char *prop_name,
4818 u32 **out_array, int *len, int size)
4819{
4820 int ret = 0;
4821 u32 *array = NULL;
4822 struct device_node *np = dev->of_node;
4823
4824 if (of_get_property(np, prop_name, len)) {
4825 size_t sz;
4826 sz = *len = *len / sizeof(*array);
4827
4828 if (sz > 0 && !(size > 0 && (sz != size))) {
4829 array = devm_kzalloc(dev, sz * sizeof(*array),
4830 GFP_KERNEL);
4831 if (!array) {
4832 dev_err(dev, "%s: no memory\n", prop_name);
4833 ret = -ENOMEM;
4834 goto out;
4835 }
4836
4837 ret = of_property_read_u32_array(np, prop_name,
4838 array, sz);
4839 if (ret < 0) {
4840 dev_err(dev, "%s: error reading array %d\n",
4841 prop_name, ret);
4842 goto out;
4843 }
4844 } else {
4845 dev_err(dev, "%s invalid size\n", prop_name);
4846 ret = -EINVAL;
4847 goto out;
4848 }
4849 } else {
4850 dev_err(dev, "%s not specified\n", prop_name);
4851 ret = -EINVAL;
4852 goto out;
4853 }
4854 *out_array = array;
4855out:
4856 if (ret)
4857 *len = 0;
4858 return ret;
4859}
4860
4861static int msmsdcc_dt_get_pad_pull_info(struct device *dev, int id,
4862 struct msm_mmc_pad_pull_data **pad_pull_data)
4863{
4864 int ret = 0, base = 0, len, i;
4865 u32 *tmp;
4866 struct msm_mmc_pad_pull_data *pull_data;
4867 struct msm_mmc_pad_pull *pull;
4868
4869 switch (id) {
4870 case 1:
4871 base = TLMM_PULL_SDC1_CLK;
4872 break;
4873 case 2:
4874 base = TLMM_PULL_SDC2_CLK;
4875 break;
4876 case 3:
4877 base = TLMM_PULL_SDC3_CLK;
4878 break;
4879 case 4:
4880 base = TLMM_PULL_SDC4_CLK;
4881 break;
4882 default:
4883 dev_err(dev, "%s: Invalid slot id\n", __func__);
4884 ret = -EINVAL;
4885 goto err;
4886 }
4887
4888 pull_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_pull_data),
4889 GFP_KERNEL);
4890 if (!pull_data) {
4891 dev_err(dev, "No memory msm_mmc_pad_pull_data\n");
4892 ret = -ENOMEM;
4893 goto err;
4894 }
4895 pull_data->size = 3; /* array size for clk, cmd, data */
4896
4897 /* Allocate on, off configs for clk, cmd, data */
4898 pull = devm_kzalloc(dev, 2 * pull_data->size *\
4899 sizeof(struct msm_mmc_pad_pull), GFP_KERNEL);
4900 if (!pull) {
4901 dev_err(dev, "No memory for msm_mmc_pad_pull\n");
4902 ret = -ENOMEM;
4903 goto err;
4904 }
4905 pull_data->on = pull;
4906 pull_data->off = pull + pull_data->size;
4907
4908 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-pull-on",
4909 &tmp, &len, pull_data->size);
4910 if (!ret) {
4911 for (i = 0; i < len; i++) {
4912 pull_data->on[i].no = base + i;
4913 pull_data->on[i].val = tmp[i];
4914 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
4915 i, pull_data->on[i].val);
4916 }
4917 } else {
4918 goto err;
4919 }
4920
4921 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-pull-off",
4922 &tmp, &len, pull_data->size);
4923 if (!ret) {
4924 for (i = 0; i < len; i++) {
4925 pull_data->off[i].no = base + i;
4926 pull_data->off[i].val = tmp[i];
4927 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
4928 i, pull_data->off[i].val);
4929 }
4930 } else {
4931 goto err;
4932 }
4933
4934 *pad_pull_data = pull_data;
4935err:
4936 return ret;
4937}
4938
4939static int msmsdcc_dt_get_pad_drv_info(struct device *dev, int id,
4940 struct msm_mmc_pad_drv_data **pad_drv_data)
4941{
4942 int ret = 0, base = 0, len, i;
4943 u32 *tmp;
4944 struct msm_mmc_pad_drv_data *drv_data;
4945 struct msm_mmc_pad_drv *drv;
4946
4947 switch (id) {
4948 case 1:
4949 base = TLMM_HDRV_SDC1_CLK;
4950 break;
4951 case 2:
4952 base = TLMM_HDRV_SDC2_CLK;
4953 break;
4954 case 3:
4955 base = TLMM_HDRV_SDC3_CLK;
4956 break;
4957 case 4:
4958 base = TLMM_HDRV_SDC4_CLK;
4959 break;
4960 default:
4961 dev_err(dev, "%s: Invalid slot id\n", __func__);
4962 ret = -EINVAL;
4963 goto err;
4964 }
4965
4966 drv_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_drv_data),
4967 GFP_KERNEL);
4968 if (!drv_data) {
4969 dev_err(dev, "No memory for msm_mmc_pad_drv_data\n");
4970 ret = -ENOMEM;
4971 goto err;
4972 }
4973 drv_data->size = 3; /* array size for clk, cmd, data */
4974
4975 /* Allocate on, off configs for clk, cmd, data */
4976 drv = devm_kzalloc(dev, 2 * drv_data->size *\
4977 sizeof(struct msm_mmc_pad_drv), GFP_KERNEL);
4978 if (!drv) {
4979 dev_err(dev, "No memory msm_mmc_pad_drv\n");
4980 ret = -ENOMEM;
4981 goto err;
4982 }
4983 drv_data->on = drv;
4984 drv_data->off = drv + drv_data->size;
4985
4986 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-drv-on",
4987 &tmp, &len, drv_data->size);
4988 if (!ret) {
4989 for (i = 0; i < len; i++) {
4990 drv_data->on[i].no = base + i;
4991 drv_data->on[i].val = tmp[i];
4992 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
4993 i, drv_data->on[i].val);
4994 }
4995 } else {
4996 goto err;
4997 }
4998
4999 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-drv-off",
5000 &tmp, &len, drv_data->size);
5001 if (!ret) {
5002 for (i = 0; i < len; i++) {
5003 drv_data->off[i].no = base + i;
5004 drv_data->off[i].val = tmp[i];
5005 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5006 i, drv_data->off[i].val);
5007 }
5008 } else {
5009 goto err;
5010 }
5011
5012 *pad_drv_data = drv_data;
5013err:
5014 return ret;
5015}
5016
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305017static void msmsdcc_dt_get_cd_wp_gpio(struct device *dev,
5018 struct mmc_platform_data *pdata)
5019{
5020 enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
5021 struct device_node *np = dev->of_node;
5022
5023 pdata->status_gpio = of_get_named_gpio_flags(np,
5024 "cd-gpios", 0, &flags);
5025 if (gpio_is_valid(pdata->status_gpio)) {
5026 pdata->status_irq = gpio_to_irq(pdata->status_gpio);
5027 pdata->is_status_gpio_active_low = flags & OF_GPIO_ACTIVE_LOW;
5028 }
5029
5030 pdata->wpswitch_gpio = of_get_named_gpio_flags(np,
5031 "wp-gpios", 0, &flags);
5032 if (gpio_is_valid(pdata->wpswitch_gpio))
5033 pdata->is_wpswitch_active_low = flags & OF_GPIO_ACTIVE_LOW;
5034}
5035
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305036static int msmsdcc_dt_parse_gpio_info(struct device *dev,
5037 struct mmc_platform_data *pdata)
5038{
5039 int ret = 0, id = 0, cnt, i;
5040 struct msm_mmc_pin_data *pin_data;
5041 struct device_node *np = dev->of_node;
5042
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305043 msmsdcc_dt_get_cd_wp_gpio(dev, pdata);
5044
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305045 pin_data = devm_kzalloc(dev, sizeof(*pin_data), GFP_KERNEL);
5046 if (!pin_data) {
5047 dev_err(dev, "No memory for pin_data\n");
5048 ret = -ENOMEM;
5049 goto err;
5050 }
5051
5052 cnt = of_gpio_count(np);
5053 if (cnt > 0) {
5054 pin_data->is_gpio = true;
5055
5056 pin_data->gpio_data = devm_kzalloc(dev,
5057 sizeof(struct msm_mmc_gpio_data), GFP_KERNEL);
5058 if (!pin_data->gpio_data) {
5059 dev_err(dev, "No memory for gpio_data\n");
5060 ret = -ENOMEM;
5061 goto err;
5062 }
5063 pin_data->gpio_data->size = cnt;
5064 pin_data->gpio_data->gpio = devm_kzalloc(dev,
5065 cnt * sizeof(struct msm_mmc_gpio), GFP_KERNEL);
5066 if (!pin_data->gpio_data->gpio) {
5067 dev_err(dev, "No memory for gpio\n");
5068 ret = -ENOMEM;
5069 goto err;
5070 }
5071
5072 for (i = 0; i < cnt; i++) {
5073 const char *name = NULL;
5074 char result[32];
5075 pin_data->gpio_data->gpio[i].no = of_get_gpio(np, i);
5076 of_property_read_string_index(np,
5077 "qcom,sdcc-gpio-names", i, &name);
5078
5079 snprintf(result, 32, "%s-%s",
5080 dev_name(dev), name ? name : "?");
5081 pin_data->gpio_data->gpio[i].name = result;
5082 dev_dbg(dev, "%s: gpio[%s] = %d\n", __func__,
5083 pin_data->gpio_data->gpio[i].name,
5084 pin_data->gpio_data->gpio[i].no);
5085 }
5086 } else {
5087 pin_data->pad_data = devm_kzalloc(dev,
5088 sizeof(struct msm_mmc_pad_data), GFP_KERNEL);
5089 if (!pin_data->pad_data) {
5090 dev_err(dev, "No memory for pin_data->pad_data\n");
5091 ret = -ENOMEM;
5092 goto err;
5093 }
5094
5095 of_property_read_u32(np, "cell-index", &id);
5096
5097 ret = msmsdcc_dt_get_pad_pull_info(dev, id,
5098 &pin_data->pad_data->pull);
5099 if (ret)
5100 goto err;
5101 ret = msmsdcc_dt_get_pad_drv_info(dev, id,
5102 &pin_data->pad_data->drv);
5103 if (ret)
5104 goto err;
5105 }
5106
5107 pdata->pin_data = pin_data;
5108err:
5109 if (ret)
5110 dev_err(dev, "%s failed with err %d\n", __func__, ret);
5111 return ret;
5112}
5113
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305114#define MAX_PROP_SIZE 32
5115static int msmsdcc_dt_parse_vreg_info(struct device *dev,
5116 struct msm_mmc_reg_data **vreg_data, const char *vreg_name)
5117{
5118 int len, ret = 0;
5119 const __be32 *prop;
5120 char prop_name[MAX_PROP_SIZE];
5121 struct msm_mmc_reg_data *vreg;
5122 struct device_node *np = dev->of_node;
5123
5124 snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", vreg_name);
5125 if (of_parse_phandle(np, prop_name, 0)) {
5126 vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
5127 if (!vreg) {
5128 dev_err(dev, "No memory for vreg: %s\n", vreg_name);
5129 ret = -ENOMEM;
5130 goto err;
5131 }
5132
5133 vreg->name = vreg_name;
5134
5135 snprintf(prop_name, MAX_PROP_SIZE,
5136 "qcom,sdcc-%s-always_on", vreg_name);
5137 if (of_get_property(np, prop_name, NULL))
5138 vreg->always_on = true;
5139
5140 snprintf(prop_name, MAX_PROP_SIZE,
5141 "qcom,sdcc-%s-lpm_sup", vreg_name);
5142 if (of_get_property(np, prop_name, NULL))
5143 vreg->lpm_sup = true;
5144
5145 snprintf(prop_name, MAX_PROP_SIZE,
5146 "qcom,sdcc-%s-voltage_level", vreg_name);
5147 prop = of_get_property(np, prop_name, &len);
5148 if (!prop || (len != (2 * sizeof(__be32)))) {
5149 dev_warn(dev, "%s %s property\n",
5150 prop ? "invalid format" : "no", prop_name);
5151 } else {
5152 vreg->low_vol_level = be32_to_cpup(&prop[0]);
5153 vreg->high_vol_level = be32_to_cpup(&prop[1]);
5154 }
5155
5156 snprintf(prop_name, MAX_PROP_SIZE,
5157 "qcom,sdcc-%s-current_level", vreg_name);
5158 prop = of_get_property(np, prop_name, &len);
5159 if (!prop || (len != (2 * sizeof(__be32)))) {
5160 dev_warn(dev, "%s %s property\n",
5161 prop ? "invalid format" : "no", prop_name);
5162 } else {
5163 vreg->lpm_uA = be32_to_cpup(&prop[0]);
5164 vreg->hpm_uA = be32_to_cpup(&prop[1]);
5165 }
5166
5167 *vreg_data = vreg;
5168 dev_dbg(dev, "%s: %s %s vol=[%d %d]uV, curr=[%d %d]uA\n",
5169 vreg->name, vreg->always_on ? "always_on," : "",
5170 vreg->lpm_sup ? "lpm_sup," : "", vreg->low_vol_level,
5171 vreg->high_vol_level, vreg->lpm_uA, vreg->hpm_uA);
5172 }
5173
5174err:
5175 return ret;
5176}
5177
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305178static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
5179{
5180 int i, ret;
5181 struct mmc_platform_data *pdata;
5182 struct device_node *np = dev->of_node;
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305183 u32 bus_width = 0, current_limit = 0;
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305184 u32 *clk_table, *sup_voltages;
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305185 int clk_table_len, sup_volt_len, len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305186
5187 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
5188 if (!pdata) {
5189 dev_err(dev, "could not allocate memory for platform data\n");
5190 goto err;
5191 }
5192
5193 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
5194 if (bus_width == 8) {
5195 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
5196 } else if (bus_width == 4) {
5197 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
5198 } else {
5199 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
5200 pdata->mmc_bus_width = 0;
5201 }
5202
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305203 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-sup-voltages",
5204 &sup_voltages, &sup_volt_len, 0);
5205 if (!ret) {
5206 for (i = 0; i < sup_volt_len; i += 2) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305207 u32 mask;
5208
5209 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
5210 sup_voltages[i + 1]);
5211 if (!mask)
5212 dev_err(dev, "Invalide voltage range %d\n", i);
5213 pdata->ocr_mask |= mask;
5214 }
5215 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305216 }
5217
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305218 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-clk-rates",
5219 &clk_table, &clk_table_len, 0);
5220 if (!ret) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305221 pdata->sup_clk_table = clk_table;
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305222 pdata->sup_clk_cnt = clk_table_len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305223 }
5224
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305225 pdata->vreg_data = devm_kzalloc(dev,
5226 sizeof(struct msm_mmc_slot_reg_data), GFP_KERNEL);
5227 if (!pdata->vreg_data) {
5228 dev_err(dev, "could not allocate memory for vreg_data\n");
5229 goto err;
5230 }
5231
5232 if (msmsdcc_dt_parse_vreg_info(dev,
5233 &pdata->vreg_data->vdd_data, "vdd"))
5234 goto err;
5235
5236 if (msmsdcc_dt_parse_vreg_info(dev,
5237 &pdata->vreg_data->vdd_io_data, "vdd-io"))
5238 goto err;
5239
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305240 if (msmsdcc_dt_parse_gpio_info(dev, pdata))
5241 goto err;
5242
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305243 len = of_property_count_strings(np, "qcom,sdcc-bus-speed-mode");
5244
5245 for (i = 0; i < len; i++) {
5246 const char *name = NULL;
5247
5248 of_property_read_string_index(np,
5249 "qcom,sdcc-bus-speed-mode", i, &name);
5250 if (!name)
5251 continue;
5252
5253 if (!strncmp(name, "SDR12", sizeof("SDR12")))
5254 pdata->uhs_caps |= MMC_CAP_UHS_SDR12;
5255 else if (!strncmp(name, "SDR25", sizeof("SDR25")))
5256 pdata->uhs_caps |= MMC_CAP_UHS_SDR25;
5257 else if (!strncmp(name, "SDR50", sizeof("SDR50")))
5258 pdata->uhs_caps |= MMC_CAP_UHS_SDR50;
5259 else if (!strncmp(name, "DDR50", sizeof("DDR50")))
5260 pdata->uhs_caps |= MMC_CAP_UHS_DDR50;
5261 else if (!strncmp(name, "SDR104", sizeof("SDR104")))
5262 pdata->uhs_caps |= MMC_CAP_UHS_SDR104;
5263 else if (!strncmp(name, "HS200_1p8v", sizeof("HS200_1p8v")))
5264 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_8V_SDR;
5265 else if (!strncmp(name, "HS200_1p2v", sizeof("HS200_1p2v")))
5266 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_2V_SDR;
5267 else if (!strncmp(name, "DDR_1p8v", sizeof("DDR_1p8v")))
5268 pdata->uhs_caps |= MMC_CAP_1_8V_DDR
5269 | MMC_CAP_UHS_DDR50;
5270 else if (!strncmp(name, "DDR_1p2v", sizeof("DDR_1p2v")))
5271 pdata->uhs_caps |= MMC_CAP_1_2V_DDR
5272 | MMC_CAP_UHS_DDR50;
5273 }
5274
5275 of_property_read_u32(np, "qcom,sdcc-current-limit", &current_limit);
5276 if (current_limit == 800)
5277 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_800;
5278 else if (current_limit == 600)
5279 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_600;
5280 else if (current_limit == 400)
5281 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_400;
5282 else if (current_limit == 200)
5283 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_200;
5284
5285 if (of_get_property(np, "qcom,sdcc-xpc", NULL))
5286 pdata->xpc_cap = true;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305287 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
5288 pdata->nonremovable = true;
5289 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
5290 pdata->disable_cmd23 = true;
5291
5292 return pdata;
5293err:
5294 return NULL;
5295}
5296
San Mehat9d2bd732009-09-22 16:44:22 -07005297static int
5298msmsdcc_probe(struct platform_device *pdev)
5299{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305300 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07005301 struct msmsdcc_host *host;
5302 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005303 unsigned long flags;
5304 struct resource *core_irqres = NULL;
5305 struct resource *bam_irqres = NULL;
5306 struct resource *core_memres = NULL;
5307 struct resource *dml_memres = NULL;
5308 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07005309 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07005310 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05305311 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005312 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07005313
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305314 if (pdev->dev.of_node) {
5315 plat = msmsdcc_populate_pdata(&pdev->dev);
5316 of_property_read_u32((&pdev->dev)->of_node,
5317 "cell-index", &pdev->id);
5318 } else {
5319 plat = pdev->dev.platform_data;
5320 }
San Mehat9d2bd732009-09-22 16:44:22 -07005321
5322 /* must have platform data */
5323 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005324 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005325 ret = -EINVAL;
5326 goto out;
5327 }
5328
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005329 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07005330 return -EINVAL;
5331
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305332 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
5333 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
5334 return -EINVAL;
5335 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005336
San Mehat9d2bd732009-09-22 16:44:22 -07005337 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005338 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005339 return -ENXIO;
5340 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305341 if (pdev->dev.of_node) {
5342 /*
5343 * Device tree iomem resources are only accessible by index.
5344 * index = 0 -> SDCC register interface
5345 * index = 1 -> DML register interface
5346 * index = 2 -> BAM register interface
5347 * IRQ resources:
5348 * index = 0 -> SDCC IRQ
5349 * index = 1 -> BAM IRQ
5350 */
5351 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
5352 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
5353 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
5354 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
5355 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
5356 } else {
5357 for (i = 0; i < pdev->num_resources; i++) {
5358 if (pdev->resource[i].flags & IORESOURCE_MEM) {
5359 if (!strncmp(pdev->resource[i].name,
5360 "sdcc_dml_addr",
5361 sizeof("sdcc_dml_addr")))
5362 dml_memres = &pdev->resource[i];
5363 else if (!strncmp(pdev->resource[i].name,
5364 "sdcc_bam_addr",
5365 sizeof("sdcc_bam_addr")))
5366 bam_memres = &pdev->resource[i];
5367 else
5368 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07005369
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305370 }
5371 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
5372 if (!strncmp(pdev->resource[i].name,
5373 "sdcc_bam_irq",
5374 sizeof("sdcc_bam_irq")))
5375 bam_irqres = &pdev->resource[i];
5376 else
5377 core_irqres = &pdev->resource[i];
5378 }
5379 if (pdev->resource[i].flags & IORESOURCE_DMA) {
5380 if (!strncmp(pdev->resource[i].name,
5381 "sdcc_dma_chnl",
5382 sizeof("sdcc_dma_chnl")))
5383 dmares = &pdev->resource[i];
5384 else if (!strncmp(pdev->resource[i].name,
5385 "sdcc_dma_crci",
5386 sizeof("sdcc_dma_crci")))
5387 dma_crci_res = &pdev->resource[i];
5388 }
Krishna Konda25786ec2011-07-25 16:21:36 -07005389 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005390 }
San Mehat9d2bd732009-09-22 16:44:22 -07005391
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005392 if (!core_irqres || !core_memres) {
5393 pr_err("%s: Invalid sdcc core resource\n", __func__);
5394 return -ENXIO;
5395 }
5396
5397 /*
5398 * Both BAM and DML memory resource should be preset.
5399 * BAM IRQ resource should also be present.
5400 */
5401 if ((bam_memres && !dml_memres) ||
5402 (!bam_memres && dml_memres) ||
5403 ((bam_memres && dml_memres) && !bam_irqres)) {
5404 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005405 return -ENXIO;
5406 }
5407
5408 /*
5409 * Setup our host structure
5410 */
San Mehat9d2bd732009-09-22 16:44:22 -07005411 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
5412 if (!mmc) {
5413 ret = -ENOMEM;
5414 goto out;
5415 }
5416
5417 host = mmc_priv(mmc);
5418 host->pdev_id = pdev->id;
5419 host->plat = plat;
5420 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08005421 host->curr.cmd = NULL;
Sahitya Tummala19207f02011-05-02 18:10:01 +05305422
Sahitya Tummalad9df3272011-08-19 16:50:46 +05305423 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305424 set_hw_caps(host, MSMSDCC_SPS_BAM_SUP);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005425 else if (dmares)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305426 set_hw_caps(host, MSMSDCC_DMA_SUP);
San Mehat9d2bd732009-09-22 16:44:22 -07005427
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005428 host->base = ioremap(core_memres->start,
5429 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07005430 if (!host->base) {
5431 ret = -ENOMEM;
Sahitya Tummaladce7c752011-05-02 18:06:05 +05305432 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005433 }
5434
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005435 host->core_irqres = core_irqres;
5436 host->bam_irqres = bam_irqres;
5437 host->core_memres = core_memres;
5438 host->dml_memres = dml_memres;
5439 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07005440 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07005441 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07005442 spin_lock_init(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305443 mutex_init(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07005444
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005445#ifdef CONFIG_MMC_EMBEDDED_SDIO
5446 if (plat->embedded_sdio)
5447 mmc_set_embedded_sdio_data(mmc,
5448 &plat->embedded_sdio->cis,
5449 &plat->embedded_sdio->cccr,
5450 plat->embedded_sdio->funcs,
5451 plat->embedded_sdio->num_funcs);
5452#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005453
Sahitya Tummala62612cf2010-12-08 15:03:03 +05305454 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
5455 (unsigned long)host);
5456
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005457 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
5458 (unsigned long)host);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305459 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005460 /* Setup DMA */
Subhash Jadavani190657c2011-05-02 18:10:40 +05305461 ret = msmsdcc_init_dma(host);
5462 if (ret)
5463 goto ioremap_free;
5464 } else {
5465 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07005466 host->dma.crci = -1;
Subhash Jadavani190657c2011-05-02 18:10:40 +05305467 }
San Mehat9d2bd732009-09-22 16:44:22 -07005468
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005469 /*
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305470 * Setup SDCC bus voter clock.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005471 */
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305472 host->bus_clk = clk_get(&pdev->dev, "bus_clk");
5473 if (!IS_ERR_OR_NULL(host->bus_clk)) {
5474 /* Vote for max. clk rate for max. performance */
5475 ret = clk_set_rate(host->bus_clk, INT_MAX);
5476 if (ret)
5477 goto bus_clk_put;
5478 ret = clk_prepare_enable(host->bus_clk);
5479 if (ret)
5480 goto bus_clk_put;
San Mehat9d2bd732009-09-22 16:44:22 -07005481 }
5482
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005483 /*
5484 * Setup main peripheral bus clock
5485 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07005486 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005487 if (!IS_ERR(host->pclk)) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305488 ret = clk_prepare_enable(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005489 if (ret)
5490 goto pclk_put;
5491
5492 host->pclk_rate = clk_get_rate(host->pclk);
5493 }
5494
5495 /*
5496 * Setup SDC MMC clock
5497 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07005498 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07005499 if (IS_ERR(host->clk)) {
5500 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005501 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07005502 }
5503
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005504 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
Sahitya Tummala514d9ed2011-05-02 18:07:01 +05305505 if (ret) {
5506 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
5507 goto clk_put;
5508 }
5509
Asutosh Dasf5298c32012-04-03 14:51:47 +05305510 ret = clk_prepare_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07005511 if (ret)
5512 goto clk_put;
5513
San Mehat9d2bd732009-09-22 16:44:22 -07005514 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05305515 if (!host->clk_rate)
5516 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05305517
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305518 set_default_hw_caps(host);
5519
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05305520 /*
5521 * Set the register write delay according to min. clock frequency
5522 * supported and update later when the host->clk_rate changes.
5523 */
5524 host->reg_write_delay =
5525 (1 + ((3 * USEC_PER_SEC) /
5526 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005527
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305528 atomic_set(&host->clks_on, 1);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05305529 /* Apply Hard reset to SDCC to put it in power on default state */
5530 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005531
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005532#define MSM_MMC_DEFAULT_CPUDMA_LATENCY 200 /* usecs */
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305533 /* pm qos request to prevent apps idle power collapse */
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005534 if (host->plat->cpu_dma_latency)
5535 host->cpu_dma_latency = host->plat->cpu_dma_latency;
5536 else
5537 host->cpu_dma_latency = MSM_MMC_DEFAULT_CPUDMA_LATENCY;
5538 pm_qos_add_request(&host->pm_qos_req_dma,
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305539 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
5540
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305541 ret = msmsdcc_msm_bus_register(host);
5542 if (ret)
5543 goto pm_qos_remove;
5544
5545 if (host->msm_bus_vote.client_handle)
5546 INIT_DELAYED_WORK(&host->msm_bus_vote.vote_work,
5547 msmsdcc_msm_bus_work);
5548
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005549 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07005550 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005551 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07005552 goto clk_disable;
5553 }
5554
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005555
5556 /* Clocks has to be running before accessing SPS/DML HW blocks */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305557 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005558 /* Initialize SPS */
5559 ret = msmsdcc_sps_init(host);
5560 if (ret)
5561 goto vreg_deinit;
5562 /* Initialize DML */
5563 ret = msmsdcc_dml_init(host);
5564 if (ret)
5565 goto sps_exit;
5566 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05305567 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07005568
San Mehat9d2bd732009-09-22 16:44:22 -07005569 /*
5570 * Setup MMC host structure
5571 */
5572 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005573 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
5574 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005575 mmc->ocr_avail = plat->ocr_mask;
Sujit Reddy Thumma0e05f022012-06-11 19:44:18 +05305576 mmc->clkgate_delay = MSM_MMC_CLK_GATE_DELAY;
5577
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005578 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
5579 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07005580 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05305581 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
San Mehat9d2bd732009-09-22 16:44:22 -07005582
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05305583 /*
5584 * If we send the CMD23 before multi block write/read command
5585 * then we need not to send CMD12 at the end of the transfer.
5586 * If we don't send the CMD12 then only way to detect the PROG_DONE
5587 * status is to use the AUTO_PROG_DONE status provided by SDCC4
5588 * controller. So let's enable the CMD23 for SDCC4 only.
5589 */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305590 if (!plat->disable_cmd23 && is_auto_prog_done(host))
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05305591 mmc->caps |= MMC_CAP_CMD23;
San Mehat9d2bd732009-09-22 16:44:22 -07005592
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005593 mmc->caps |= plat->uhs_caps;
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305594 mmc->caps2 |= plat->uhs_caps2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005595 /*
5596 * XPC controls the maximum current in the default speed mode of SDXC
5597 * card. XPC=0 means 100mA (max.) but speed class is not supported.
5598 * XPC=1 means 150mA (max.) and speed class is supported.
5599 */
5600 if (plat->xpc_cap)
5601 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
5602 MMC_CAP_SET_XPC_180);
5603
Maya Erez25e22612012-05-20 08:45:01 +03005604 mmc->caps2 |= MMC_CAP2_PACKED_WR;
Maya Erez8afe8d22012-05-20 15:11:52 +03005605 mmc->caps2 |= MMC_CAP2_PACKED_WR_CONTROL;
Subhash Jadavani6bb34a82012-04-18 13:18:40 +05305606 mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
Yaniv Gardi14098552012-06-04 10:56:03 +03005607 mmc->caps2 |= MMC_CAP2_SANITIZE;
5608
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005609 if (plat->nonremovable)
5610 mmc->caps |= MMC_CAP_NONREMOVABLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005611 mmc->caps |= MMC_CAP_SDIO_IRQ;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005612
Konstantin Dorfman9db69fc2012-06-01 14:04:45 +03005613 mmc->caps2 |= MMC_CAP2_INIT_BKOPS | MMC_CAP2_BKOPS;
5614
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005615 if (plat->is_sdio_al_client)
5616 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07005617
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305618 mmc->max_segs = msmsdcc_get_nr_sg(host);
5619 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
5620 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07005621
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305622 mmc->max_req_size = MMC_MAX_REQ_SIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07005623 mmc->max_seg_size = mmc->max_req_size;
5624
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005625 writel_relaxed(0, host->base + MMCIMASK0);
5626 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05305627 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005628
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005629 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
5630 mb();
5631 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07005632
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005633 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
5634 DRIVER_NAME " (cmd)", host);
5635 if (ret)
5636 goto dml_exit;
5637
5638 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
5639 DRIVER_NAME " (pio)", host);
5640 if (ret)
5641 goto irq_free;
5642
5643 /*
5644 * Enable SDCC IRQ only when host is powered on. Otherwise, this
5645 * IRQ is un-necessarily being monitored by MPM (Modem power
5646 * management block) during idle-power collapse. The MPM will be
5647 * configured to monitor the DATA1 GPIO line with level-low trigger
5648 * and thus depending on the GPIO status, it prevents TCXO shutdown
5649 * during idle-power collapse.
5650 */
5651 disable_irq(core_irqres->start);
5652 host->sdcc_irq_disabled = 1;
5653
5654 if (plat->sdiowakeup_irq) {
5655 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5656 mmc_hostname(mmc));
5657 ret = request_irq(plat->sdiowakeup_irq,
5658 msmsdcc_platform_sdiowakeup_irq,
5659 IRQF_SHARED | IRQF_TRIGGER_LOW,
5660 DRIVER_NAME "sdiowakeup", host);
5661 if (ret) {
5662 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
5663 plat->sdiowakeup_irq, ret);
5664 goto pio_irq_free;
5665 } else {
5666 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305667 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005668 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305669 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005670 }
5671 spin_unlock_irqrestore(&host->lock, flags);
5672 }
5673 }
5674
Subhash Jadavanic9b85752012-04-13 11:16:49 +05305675 if (host->plat->mpm_sdiowakeup_int) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005676 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5677 mmc_hostname(mmc));
5678 }
5679
5680 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
5681 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005682 /*
5683 * Setup card detect change
5684 */
5685
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305686 if (!plat->status_gpio)
5687 plat->status_gpio = -ENOENT;
5688 if (!plat->wpswitch_gpio)
5689 plat->wpswitch_gpio = -ENOENT;
5690
5691 if (plat->status || gpio_is_valid(plat->status_gpio)) {
Krishna Konda941604a2012-01-10 17:46:34 -08005692 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005693 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08005694 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005695 host->oldstat = msmsdcc_slot_status(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005696
Krishna Konda941604a2012-01-10 17:46:34 -08005697 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005698 }
San Mehat9d2bd732009-09-22 16:44:22 -07005699
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005700 if (plat->status_irq) {
5701 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07005702 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005703 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07005704 DRIVER_NAME " (slot)",
5705 host);
5706 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005707 pr_err("Unable to get slot IRQ %d (%d)\n",
5708 plat->status_irq, ret);
5709 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005710 }
5711 } else if (plat->register_status_notify) {
5712 plat->register_status_notify(msmsdcc_status_notify_cb, host);
5713 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005714 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07005715 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005716
5717 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005718
5719 ret = pm_runtime_set_active(&(pdev)->dev);
5720 if (ret < 0)
5721 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
5722 __func__, ret);
5723 /*
5724 * There is no notion of suspend/resume for SD/MMC/SDIO
5725 * cards. So host can be suspended/resumed with out
5726 * worrying about its children.
5727 */
5728 pm_suspend_ignore_children(&(pdev)->dev, true);
5729
5730 /*
5731 * MMC/SD/SDIO bus suspend/resume operations are defined
5732 * only for the slots that will be used for non-removable
5733 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
5734 * defined. Otherwise, they simply become card removal and
5735 * insertion events during suspend and resume respectively.
5736 * Hence, enable run-time PM only for slots for which bus
5737 * suspend/resume operations are defined.
5738 */
5739#ifdef CONFIG_MMC_UNSAFE_RESUME
5740 /*
5741 * If this capability is set, MMC core will enable/disable host
5742 * for every claim/release operation on a host. We use this
5743 * notification to increment/decrement runtime pm usage count.
5744 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005745 pm_runtime_enable(&(pdev)->dev);
5746#else
5747 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005748 pm_runtime_enable(&(pdev)->dev);
5749 }
5750#endif
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305751 host->idle_tout_ms = MSM_MMC_DEFAULT_IDLE_TIMEOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005752 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
5753 (unsigned long)host);
5754
San Mehat9d2bd732009-09-22 16:44:22 -07005755 mmc_add_host(mmc);
5756
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005757#ifdef CONFIG_HAS_EARLYSUSPEND
5758 host->early_suspend.suspend = msmsdcc_early_suspend;
5759 host->early_suspend.resume = msmsdcc_late_resume;
5760 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
5761 register_early_suspend(&host->early_suspend);
5762#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005763
Krishna Konda25786ec2011-07-25 16:21:36 -07005764 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
5765 " dmacrcri %d\n", mmc_hostname(mmc),
5766 (unsigned long long)core_memres->start,
5767 (unsigned int) core_irqres->start,
5768 (unsigned int) plat->status_irq, host->dma.channel,
5769 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005770
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305771 pr_info("%s: Controller capabilities: 0x%.8x\n",
5772 mmc_hostname(mmc), host->hw_caps);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005773 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
5774 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
5775 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
5776 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
5777 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
5778 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
5779 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
5780 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
5781 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
5782 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
5783 host->eject);
5784 pr_info("%s: Power save feature enable = %d\n",
5785 mmc_hostname(mmc), msmsdcc_pwrsave);
5786
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305787 if (is_dma_mode(host) && host->dma.channel != -1
Krishna Konda25786ec2011-07-25 16:21:36 -07005788 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005789 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005790 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005791 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005792 mmc_hostname(mmc), host->dma.cmd_busaddr,
5793 host->dma.cmdptr_busaddr);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305794 } else if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005795 pr_info("%s: SPS-BAM data transfer mode available\n",
5796 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005797 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005798 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005799
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005800#if defined(CONFIG_DEBUG_FS)
5801 msmsdcc_dbg_createhost(host);
5802#endif
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305803
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305804 host->max_bus_bw.show = show_sdcc_to_mem_max_bus_bw;
5805 host->max_bus_bw.store = store_sdcc_to_mem_max_bus_bw;
5806 sysfs_attr_init(&host->max_bus_bw.attr);
5807 host->max_bus_bw.attr.name = "max_bus_bw";
5808 host->max_bus_bw.attr.mode = S_IRUGO | S_IWUSR;
5809 ret = device_create_file(&pdev->dev, &host->max_bus_bw);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305810 if (ret)
5811 goto platform_irq_free;
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305812
5813 if (!plat->status_irq) {
5814 host->polling.show = show_polling;
5815 host->polling.store = store_polling;
5816 sysfs_attr_init(&host->polling.attr);
5817 host->polling.attr.name = "polling";
5818 host->polling.attr.mode = S_IRUGO | S_IWUSR;
5819 ret = device_create_file(&pdev->dev, &host->polling);
5820 if (ret)
5821 goto remove_max_bus_bw_file;
5822 }
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305823 host->idle_timeout.show = show_idle_timeout;
5824 host->idle_timeout.store = store_idle_timeout;
5825 sysfs_attr_init(&host->idle_timeout.attr);
5826 host->idle_timeout.attr.name = "idle_timeout";
5827 host->idle_timeout.attr.mode = S_IRUGO | S_IWUSR;
5828 ret = device_create_file(&pdev->dev, &host->idle_timeout);
5829 if (ret)
5830 goto remove_polling_file;
San Mehat9d2bd732009-09-22 16:44:22 -07005831 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005832
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305833 remove_polling_file:
5834 if (!plat->status_irq)
5835 device_remove_file(&pdev->dev, &host->polling);
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305836 remove_max_bus_bw_file:
5837 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005838 platform_irq_free:
5839 del_timer_sync(&host->req_tout_timer);
5840 pm_runtime_disable(&(pdev)->dev);
5841 pm_runtime_set_suspended(&(pdev)->dev);
5842
5843 if (plat->status_irq)
5844 free_irq(plat->status_irq, host);
5845 sdiowakeup_irq_free:
5846 wake_lock_destroy(&host->sdio_suspend_wlock);
5847 if (plat->sdiowakeup_irq)
5848 free_irq(plat->sdiowakeup_irq, host);
5849 pio_irq_free:
5850 if (plat->sdiowakeup_irq)
5851 wake_lock_destroy(&host->sdio_wlock);
5852 free_irq(core_irqres->start, host);
5853 irq_free:
5854 free_irq(core_irqres->start, host);
5855 dml_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305856 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005857 msmsdcc_dml_exit(host);
5858 sps_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305859 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005860 msmsdcc_sps_exit(host);
5861 vreg_deinit:
5862 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07005863 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005864 clk_disable(host->clk);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305865 msmsdcc_msm_bus_unregister(host);
5866 pm_qos_remove:
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005867 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305868 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07005869 clk_put:
5870 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005871 pclk_disable:
5872 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05305873 clk_disable_unprepare(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07005874 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005875 if (!IS_ERR(host->pclk))
5876 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305877 if (!IS_ERR_OR_NULL(host->bus_clk))
5878 clk_disable_unprepare(host->bus_clk);
5879 bus_clk_put:
5880 if (!IS_ERR_OR_NULL(host->bus_clk))
5881 clk_put(host->bus_clk);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305882 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005883 if (host->dmares)
5884 dma_free_coherent(NULL,
5885 sizeof(struct msmsdcc_nc_dmadata),
5886 host->dma.nc, host->dma.nc_busaddr);
5887 }
5888 ioremap_free:
Sahitya Tummaladce7c752011-05-02 18:06:05 +05305889 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07005890 host_free:
5891 mmc_free_host(mmc);
5892 out:
5893 return ret;
5894}
5895
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005896static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07005897{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005898 struct mmc_host *mmc = mmc_get_drvdata(pdev);
5899 struct mmc_platform_data *plat;
5900 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07005901
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005902 if (!mmc)
5903 return -ENXIO;
5904
5905 if (pm_runtime_suspended(&(pdev)->dev))
5906 pm_runtime_resume(&(pdev)->dev);
5907
5908 host = mmc_priv(mmc);
5909
5910 DBG(host, "Removing SDCC device = %d\n", pdev->id);
5911 plat = host->plat;
5912
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305913 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005914 if (!plat->status_irq)
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305915 device_remove_file(&pdev->dev, &host->polling);
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305916 device_remove_file(&pdev->dev, &host->idle_timeout);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005917
5918 del_timer_sync(&host->req_tout_timer);
5919 tasklet_kill(&host->dma_tlet);
5920 tasklet_kill(&host->sps.tlet);
5921 mmc_remove_host(mmc);
5922
5923 if (plat->status_irq)
5924 free_irq(plat->status_irq, host);
5925
5926 wake_lock_destroy(&host->sdio_suspend_wlock);
5927 if (plat->sdiowakeup_irq) {
5928 wake_lock_destroy(&host->sdio_wlock);
5929 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
5930 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07005931 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005932
5933 free_irq(host->core_irqres->start, host);
5934 free_irq(host->core_irqres->start, host);
5935
5936 clk_put(host->clk);
5937 if (!IS_ERR(host->pclk))
5938 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305939 if (!IS_ERR_OR_NULL(host->bus_clk))
5940 clk_put(host->bus_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005941
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005942 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305943 pm_qos_remove_request(&host->pm_qos_req_dma);
5944
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305945 if (host->msm_bus_vote.client_handle) {
5946 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
5947 msmsdcc_msm_bus_unregister(host);
5948 }
5949
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005950 msmsdcc_vreg_init(host, false);
5951
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305952 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005953 if (host->dmares)
5954 dma_free_coherent(NULL,
5955 sizeof(struct msmsdcc_nc_dmadata),
5956 host->dma.nc, host->dma.nc_busaddr);
5957 }
5958
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305959 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005960 msmsdcc_dml_exit(host);
5961 msmsdcc_sps_exit(host);
5962 }
5963
5964 iounmap(host->base);
5965 mmc_free_host(mmc);
5966
5967#ifdef CONFIG_HAS_EARLYSUSPEND
5968 unregister_early_suspend(&host->early_suspend);
5969#endif
5970 pm_runtime_disable(&(pdev)->dev);
5971 pm_runtime_set_suspended(&(pdev)->dev);
5972
5973 return 0;
5974}
5975
5976#ifdef CONFIG_MSM_SDIO_AL
5977int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
5978{
5979 struct msmsdcc_host *host = mmc_priv(mmc);
5980 unsigned long flags;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305981 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005982
Asutosh Dasf5298c32012-04-03 14:51:47 +05305983 mutex_lock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005984 spin_lock_irqsave(&host->lock, flags);
5985 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
5986 enable ? "En" : "Dis");
5987
5988 if (enable) {
5989 if (!host->sdcc_irq_disabled) {
5990 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05305991 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005992 host->sdcc_irq_disabled = 1;
5993 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305994 rc = msmsdcc_setup_clocks(host, false);
5995 if (rc)
5996 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005997
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305998 if (host->plat->sdio_lpm_gpio_setup &&
5999 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006000 spin_unlock_irqrestore(&host->lock, flags);
6001 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
6002 spin_lock_irqsave(&host->lock, flags);
6003 host->sdio_gpio_lpm = 1;
6004 }
6005
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306006 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006007 msmsdcc_enable_irq_wake(host);
6008 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306009 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006010 }
6011 } else {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306012 rc = msmsdcc_setup_clocks(host, true);
6013 if (rc)
6014 goto out;
6015
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306016 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006017 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306018 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006019 msmsdcc_disable_irq_wake(host);
6020 }
6021
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05306022 if (host->plat->sdio_lpm_gpio_setup &&
6023 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006024 spin_unlock_irqrestore(&host->lock, flags);
6025 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
6026 spin_lock_irqsave(&host->lock, flags);
6027 host->sdio_gpio_lpm = 0;
6028 }
6029
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306030 if (host->sdcc_irq_disabled && atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006031 writel_relaxed(host->mci_irqenable,
6032 host->base + MMCIMASK0);
6033 mb();
6034 enable_irq(host->core_irqres->start);
6035 host->sdcc_irq_disabled = 0;
6036 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006037 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306038out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006039 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05306040 mutex_unlock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306041 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006042}
6043#else
6044int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
6045{
6046 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07006047}
6048#endif
6049
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006050#ifdef CONFIG_PM
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306051#ifdef CONFIG_MMC_CLKGATE
6052static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6053{
6054 struct mmc_host *mmc = host->mmc;
6055 unsigned long flags;
6056
6057 mmc_host_clk_hold(mmc);
6058 spin_lock_irqsave(&mmc->clk_lock, flags);
6059 mmc->clk_old = mmc->ios.clock;
6060 mmc->ios.clock = 0;
6061 mmc->clk_gated = true;
6062 spin_unlock_irqrestore(&mmc->clk_lock, flags);
6063 mmc_set_ios(mmc);
6064 mmc_host_clk_release(mmc);
6065}
6066
6067static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6068{
6069 struct mmc_host *mmc = host->mmc;
6070
6071 mmc_host_clk_hold(mmc);
6072 mmc->ios.clock = host->clk_rate;
6073 mmc_set_ios(mmc);
6074 mmc_host_clk_release(mmc);
6075}
6076#else
6077static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6078{
6079 struct mmc_host *mmc = host->mmc;
6080
6081 mmc->ios.clock = 0;
6082 mmc_set_ios(mmc);
6083}
6084
6085static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6086{
6087 struct mmc_host *mmc = host->mmc;
6088
6089 mmc->ios.clock = host->clk_rate;
6090 mmc_set_ios(mmc);
6091}
6092#endif
6093
San Mehat9d2bd732009-09-22 16:44:22 -07006094static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006095msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006096{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006097 struct mmc_host *mmc = dev_get_drvdata(dev);
6098 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006099 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306100 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07006101
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306102 if (host->plat->is_sdio_al_client) {
6103 rc = 0;
6104 goto out;
San Mehat9d2bd732009-09-22 16:44:22 -07006105 }
San Mehat9d2bd732009-09-22 16:44:22 -07006106
Sahitya Tummala7661a452011-07-18 13:28:35 +05306107 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006108 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006109 host->sdcc_suspending = 1;
6110 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07006111
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006112 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006113 * MMC core thinks that host is disabled by now since
6114 * runtime suspend is scheduled after msmsdcc_disable()
6115 * is called. Thus, MMC core will try to enable the host
6116 * while suspending it. This results in a synchronous
6117 * runtime resume request while in runtime suspending
6118 * context and hence inorder to complete this resume
6119 * requet, it will wait for suspend to be complete,
6120 * but runtime suspend also can not proceed further
6121 * until the host is resumed. Thus, it leads to a hang.
6122 * Hence, increase the pm usage count before suspending
6123 * the host so that any resume requests after this will
6124 * simple become pm usage counter increment operations.
6125 */
6126 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306127 /* If there is pending detect work abort runtime suspend */
6128 if (unlikely(work_busy(&mmc->detect.work)))
6129 rc = -EAGAIN;
6130 else
6131 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006132 pm_runtime_put_noidle(dev);
6133
6134 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306135 spin_lock_irqsave(&host->lock, flags);
6136 host->sdcc_suspended = true;
6137 spin_unlock_irqrestore(&host->lock, flags);
6138 if (mmc->card && mmc_card_sdio(mmc->card) &&
6139 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006140 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306141 * If SDIO function driver doesn't want
6142 * to power off the card, atleast turn off
6143 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006144 */
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306145 msmsdcc_gate_clock(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006146 }
6147 }
6148 host->sdcc_suspending = 0;
6149 mmc->suspend_task = NULL;
6150 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
6151 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006152 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306153 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306154out:
6155 /* set bus bandwidth to 0 immediately */
6156 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
San Mehat9d2bd732009-09-22 16:44:22 -07006157 return rc;
6158}
6159
6160static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006161msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006162{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006163 struct mmc_host *mmc = dev_get_drvdata(dev);
6164 struct msmsdcc_host *host = mmc_priv(mmc);
6165 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07006166
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006167 if (host->plat->is_sdio_al_client)
6168 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07006169
Sahitya Tummala7661a452011-07-18 13:28:35 +05306170 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006171 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306172 if (mmc->card && mmc_card_sdio(mmc->card) &&
6173 mmc_card_keep_power(mmc)) {
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306174 msmsdcc_ungate_clock(host);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05306175 }
San Mehat9d2bd732009-09-22 16:44:22 -07006176
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006177 mmc_resume_host(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006178
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006179 /*
6180 * FIXME: Clearing of flags must be handled in clients
6181 * resume handler.
6182 */
6183 spin_lock_irqsave(&host->lock, flags);
6184 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306185 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006186 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07006187
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006188 /*
6189 * After resuming the host wait for sometime so that
6190 * the SDIO work will be processed.
6191 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306192 if (mmc->card && mmc_card_sdio(mmc->card)) {
Subhash Jadavanic9b85752012-04-13 11:16:49 +05306193 if ((host->plat->mpm_sdiowakeup_int ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006194 host->plat->sdiowakeup_irq) &&
6195 wake_lock_active(&host->sdio_wlock))
6196 wake_lock_timeout(&host->sdio_wlock, 1);
6197 }
6198
6199 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006200 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05306201 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006202 return 0;
6203}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006204
6205static int msmsdcc_runtime_idle(struct device *dev)
6206{
6207 struct mmc_host *mmc = dev_get_drvdata(dev);
6208 struct msmsdcc_host *host = mmc_priv(mmc);
6209
6210 if (host->plat->is_sdio_al_client)
6211 return 0;
6212
6213 /* Idle timeout is not configurable for now */
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306214 pm_schedule_suspend(dev, host->idle_tout_ms);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006215
6216 return -EAGAIN;
6217}
6218
6219static int msmsdcc_pm_suspend(struct device *dev)
6220{
6221 struct mmc_host *mmc = dev_get_drvdata(dev);
6222 struct msmsdcc_host *host = mmc_priv(mmc);
6223 int rc = 0;
6224
6225 if (host->plat->is_sdio_al_client)
6226 return 0;
6227
6228
6229 if (host->plat->status_irq)
6230 disable_irq(host->plat->status_irq);
6231
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006232 if (!pm_runtime_suspended(dev))
6233 rc = msmsdcc_runtime_suspend(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006234
6235 return rc;
6236}
6237
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306238static int msmsdcc_suspend_noirq(struct device *dev)
6239{
6240 struct mmc_host *mmc = dev_get_drvdata(dev);
6241 struct msmsdcc_host *host = mmc_priv(mmc);
6242 int rc = 0;
6243
6244 /*
6245 * After platform suspend there may be active request
6246 * which might have enabled clocks. For example, in SDIO
6247 * case, ksdioirq thread might have scheduled after sdcc
6248 * suspend but before system freeze. In that case abort
6249 * suspend and retry instead of keeping the clocks on
6250 * during suspend and not allowing TCXO.
6251 */
6252
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306253 if (atomic_read(&host->clks_on) && !host->plat->is_sdio_al_client) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306254 pr_warn("%s: clocks are on after suspend, aborting system "
6255 "suspend\n", mmc_hostname(mmc));
6256 rc = -EAGAIN;
6257 }
6258
6259 return rc;
6260}
6261
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006262static int msmsdcc_pm_resume(struct device *dev)
6263{
6264 struct mmc_host *mmc = dev_get_drvdata(dev);
6265 struct msmsdcc_host *host = mmc_priv(mmc);
6266 int rc = 0;
6267
6268 if (host->plat->is_sdio_al_client)
6269 return 0;
6270
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006271 if (mmc->card && mmc_card_sdio(mmc->card))
Sahitya Tummalafb486372011-09-02 19:01:49 +05306272 rc = msmsdcc_runtime_resume(dev);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006273 else
6274 host->pending_resume = true;
6275
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006276 if (host->plat->status_irq) {
6277 msmsdcc_check_status((unsigned long)host);
6278 enable_irq(host->plat->status_irq);
6279 }
6280
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006281 return rc;
6282}
6283
Daniel Walker08ecfde2010-06-23 12:32:20 -07006284#else
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006285static int msmsdcc_runtime_suspend(struct device *dev)
6286{
6287 return 0;
6288}
6289static int msmsdcc_runtime_idle(struct device *dev)
6290{
6291 return 0;
6292}
6293static int msmsdcc_pm_suspend(struct device *dev)
6294{
6295 return 0;
6296}
6297static int msmsdcc_pm_resume(struct device *dev)
6298{
6299 return 0;
6300}
6301static int msmsdcc_suspend_noirq(struct device *dev)
6302{
6303 return 0;
6304}
6305static int msmsdcc_runtime_resume(struct device *dev)
6306{
6307 return 0;
6308}
Daniel Walker08ecfde2010-06-23 12:32:20 -07006309#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006310
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006311static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
6312 .runtime_suspend = msmsdcc_runtime_suspend,
6313 .runtime_resume = msmsdcc_runtime_resume,
6314 .runtime_idle = msmsdcc_runtime_idle,
6315 .suspend = msmsdcc_pm_suspend,
6316 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306317 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006318};
6319
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306320static const struct of_device_id msmsdcc_dt_match[] = {
6321 {.compatible = "qcom,msm-sdcc"},
6322
6323};
6324MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
6325
San Mehat9d2bd732009-09-22 16:44:22 -07006326static struct platform_driver msmsdcc_driver = {
6327 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006328 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07006329 .driver = {
6330 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006331 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306332 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07006333 },
6334};
6335
6336static int __init msmsdcc_init(void)
6337{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006338#if defined(CONFIG_DEBUG_FS)
6339 int ret = 0;
6340 ret = msmsdcc_dbg_init();
6341 if (ret) {
6342 pr_err("Failed to create debug fs dir \n");
6343 return ret;
6344 }
6345#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006346 return platform_driver_register(&msmsdcc_driver);
6347}
San Mehat9d2bd732009-09-22 16:44:22 -07006348
San Mehat9d2bd732009-09-22 16:44:22 -07006349static void __exit msmsdcc_exit(void)
6350{
6351 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006352
6353#if defined(CONFIG_DEBUG_FS)
6354 debugfs_remove(debugfs_file);
6355 debugfs_remove(debugfs_dir);
6356#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006357}
6358
6359module_init(msmsdcc_init);
6360module_exit(msmsdcc_exit);
6361
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006362MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07006363MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006364
6365#if defined(CONFIG_DEBUG_FS)
6366
6367static int
6368msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
6369{
6370 file->private_data = inode->i_private;
6371 return 0;
6372}
6373
6374static ssize_t
6375msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
6376 size_t count, loff_t *ppos)
6377{
6378 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08006379 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006380 int max, i;
6381
6382 i = 0;
6383 max = sizeof(buf) - 1;
6384
6385 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
6386 host->curr.cmd, host->curr.data);
6387 if (host->curr.cmd) {
6388 struct mmc_command *cmd = host->curr.cmd;
6389
6390 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
6391 cmd->opcode, cmd->arg, cmd->flags);
6392 }
6393 if (host->curr.data) {
6394 struct mmc_data *data = host->curr.data;
6395 i += scnprintf(buf + i, max - i,
6396 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
6397 data->timeout_ns, data->timeout_clks,
6398 data->blksz, data->blocks, data->error,
6399 data->flags);
6400 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
6401 host->curr.xfer_size, host->curr.xfer_remain,
6402 host->curr.data_xfered, host->dma.sg);
6403 }
6404
6405 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
6406}
6407
6408static const struct file_operations msmsdcc_dbg_state_ops = {
6409 .read = msmsdcc_dbg_state_read,
6410 .open = msmsdcc_dbg_state_open,
6411};
6412
6413static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
6414{
6415 if (debugfs_dir) {
6416 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
6417 0644, debugfs_dir, host,
6418 &msmsdcc_dbg_state_ops);
6419 }
6420}
6421
6422static int __init msmsdcc_dbg_init(void)
6423{
6424 int err;
6425
6426 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
6427 if (IS_ERR(debugfs_dir)) {
6428 err = PTR_ERR(debugfs_dir);
6429 debugfs_dir = NULL;
6430 return err;
6431 }
6432
6433 return 0;
6434}
6435#endif