blob: 353b4391c19cc7e0103be20a64519c0f32d0c7e1 [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
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530403static void msmsdcc_reset_dpsm(struct msmsdcc_host *host)
404{
405 struct mmc_request *mrq = host->curr.mrq;
406
407 if (!mrq || !mrq->cmd || (!mrq->data && !host->pending_dpsm_reset))
408 goto out;
409
410 /*
411 * For CMD24, if auto prog done is not supported defer
412 * dpsm reset until prog done is received. Otherwise,
413 * we poll here unnecessarily as TXACTIVE will not be
414 * deasserted until DAT0 goes high.
415 */
416 if ((mrq->cmd->opcode == MMC_WRITE_BLOCK) && !is_auto_prog_done(host)) {
417 host->pending_dpsm_reset = true;
418 goto out;
419 }
420
421 /* Make sure h/w (TX/RX) is inactive before resetting DPSM */
422 if (is_wait_for_tx_rx_active(host)) {
423 ktime_t start = ktime_get();
424
425 while (readl_relaxed(host->base + MMCISTATUS) &
426 (MCI_TXACTIVE | MCI_RXACTIVE)) {
427 /*
428 * TX/RX active bits may be asserted for 4HCLK + 4MCLK
429 * cycles (~11us) after data transfer due to clock mux
430 * switching delays. Let's poll for 1ms and panic if
431 * still active.
432 */
433 if (ktime_to_us(ktime_sub(ktime_get(), start)) > 1000) {
434 pr_err("%s: %s still active\n",
435 mmc_hostname(host->mmc),
436 readl_relaxed(host->base + MMCISTATUS)
437 & MCI_TXACTIVE ? "TX" : "RX");
438 msmsdcc_dump_sdcc_state(host);
439 BUG();
440 }
441 }
442 }
443
444 writel_relaxed(0, host->base + MMCIDATACTRL);
445 msmsdcc_sync_reg_wr(host); /* Allow the DPSM to be reset */
446 host->pending_dpsm_reset = false;
447out:
448 return;
449}
450
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700451static int
San Mehat9d2bd732009-09-22 16:44:22 -0700452msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
453{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700454 int retval = 0;
455
San Mehat9d2bd732009-09-22 16:44:22 -0700456 BUG_ON(host->curr.data);
457
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700458 del_timer(&host->req_tout_timer);
San Mehat9d2bd732009-09-22 16:44:22 -0700459
460 if (mrq->data)
461 mrq->data->bytes_xfered = host->curr.data_xfered;
462 if (mrq->cmd->error == -ETIMEDOUT)
463 mdelay(5);
464
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530465 msmsdcc_reset_dpsm(host);
466
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530467 /* Clear current request information as current request has ended */
468 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
469
San Mehat9d2bd732009-09-22 16:44:22 -0700470 /*
471 * Need to drop the host lock here; mmc_request_done may call
472 * back into the driver...
473 */
474 spin_unlock(&host->lock);
475 mmc_request_done(host->mmc, mrq);
476 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700477
478 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700479}
480
481static void
482msmsdcc_stop_data(struct msmsdcc_host *host)
483{
San Mehat9d2bd732009-09-22 16:44:22 -0700484 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530485 host->curr.got_dataend = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +0530486 host->curr.wait_for_auto_prog_done = false;
487 host->curr.got_auto_prog_done = false;
San Mehat9d2bd732009-09-22 16:44:22 -0700488}
489
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700490static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700491{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700492 return host->core_memres->start + MMCIFIFO;
493}
494
495static inline unsigned int msmsdcc_get_min_sup_clk_rate(
496 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530497
Subhash Jadavanidd432952012-03-28 11:25:56 +0530498static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700499{
500 mb();
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530501 if (!is_wait_for_reg_write(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +0530502 udelay(host->reg_write_delay);
503 else if (readl_relaxed(host->base + MCI_STATUS2) &
504 MCI_MCLK_REG_WR_ACTIVE) {
505 ktime_t start, diff;
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530506
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530507 start = ktime_get();
508 while (readl_relaxed(host->base + MCI_STATUS2) &
509 MCI_MCLK_REG_WR_ACTIVE) {
510 diff = ktime_sub(ktime_get(), start);
511 /* poll for max. 1 ms */
512 if (ktime_to_us(diff) > 1000) {
513 pr_warning("%s: previous reg. write is"
514 " still active\n",
515 mmc_hostname(host->mmc));
516 break;
517 }
518 }
519 }
San Mehat9d2bd732009-09-22 16:44:22 -0700520}
521
Subhash Jadavanidd432952012-03-28 11:25:56 +0530522static inline void msmsdcc_delay(struct msmsdcc_host *host)
523{
524 udelay(host->reg_write_delay);
525
San Mehat9d2bd732009-09-22 16:44:22 -0700526}
527
San Mehat56a8b5b2009-11-21 12:29:46 -0800528static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700529msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
530{
531 writel_relaxed(arg, host->base + MMCIARGUMENT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700532 writel_relaxed(c, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530533 /*
534 * As after sending the command, we don't write any of the
535 * controller registers and just wait for the
536 * CMD_RESPOND_END/CMD_SENT/Command failure notication
537 * from Controller.
538 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700539 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800540}
541
542static void
543msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
544{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700545 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800546
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700547 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
548 writel_relaxed((unsigned int)host->curr.xfer_size,
549 host->base + MMCIDATALENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700550 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530551 msmsdcc_sync_reg_wr(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800552
San Mehat6ac9ea62009-12-02 17:24:58 -0800553 if (host->cmd_cmd) {
554 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700555 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800556 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800557}
558
San Mehat9d2bd732009-09-22 16:44:22 -0700559static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530560msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700561{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530562 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700563 unsigned long flags;
564 struct mmc_request *mrq;
565
566 spin_lock_irqsave(&host->lock, flags);
567 mrq = host->curr.mrq;
568 BUG_ON(!mrq);
569
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530570 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700571 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700572 goto out;
573 }
574
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530575 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700576 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700577 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700578 } else {
579 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530580 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700581 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530582 mmc_hostname(host->mmc), host->dma.result);
583 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700584 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530585 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530586 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700587 host->dma.err.flush[0], host->dma.err.flush[1],
588 host->dma.err.flush[2], host->dma.err.flush[3],
589 host->dma.err.flush[4],
590 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530591 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700592 if (!mrq->data->error)
593 mrq->data->error = -EIO;
594 }
Asutosh Dasaccacd42012-03-08 14:33:17 +0530595 if (!mrq->data->host_cookie)
596 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
597 host->dma.num_ents, host->dma.dir);
San Mehat9d2bd732009-09-22 16:44:22 -0700598
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700599 if (host->curr.user_pages) {
600 struct scatterlist *sg = host->dma.sg;
601 int i;
602
603 for (i = 0; i < host->dma.num_ents; i++, sg++)
604 flush_dcache_page(sg_page(sg));
605 }
San Mehat9d2bd732009-09-22 16:44:22 -0700606
San Mehat9d2bd732009-09-22 16:44:22 -0700607 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800608 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700609
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530610 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
611 (host->curr.wait_for_auto_prog_done &&
612 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700613 /*
614 * If we've already gotten our DATAEND / DATABLKEND
615 * for this request, then complete it through here.
616 */
San Mehat9d2bd732009-09-22 16:44:22 -0700617
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700618 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700619 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700620 host->curr.xfer_remain -= host->curr.xfer_size;
621 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700622 if (host->dummy_52_needed) {
San Mehat9d2bd732009-09-22 16:44:22 -0700623 mrq->data->bytes_xfered = host->curr.data_xfered;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700624 host->dummy_52_sent = 1;
625 msmsdcc_start_command(host, &dummy52cmd,
626 MCI_CPSM_PROGENA);
627 goto out;
628 }
629 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530630 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530631 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700632 mrq->data->bytes_xfered = host->curr.data_xfered;
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530633 msmsdcc_reset_dpsm(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700634 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530635 /*
636 * Clear current request information as current
637 * request has ended
638 */
639 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
San Mehat9d2bd732009-09-22 16:44:22 -0700640 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700641
San Mehat9d2bd732009-09-22 16:44:22 -0700642 mmc_request_done(host->mmc, mrq);
643 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530644 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
645 || !mrq->sbc)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700646 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530647 }
San Mehat9d2bd732009-09-22 16:44:22 -0700648 }
649
650out:
651 spin_unlock_irqrestore(&host->lock, flags);
652 return;
653}
654
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700655#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
656/**
657 * Callback notification from SPS driver
658 *
659 * This callback function gets triggered called from
660 * SPS driver when requested SPS data transfer is
661 * completed.
662 *
663 * SPS driver invokes this callback in BAM irq context so
664 * SDCC driver schedule a tasklet for further processing
665 * this callback notification at later point of time in
666 * tasklet context and immediately returns control back
667 * to SPS driver.
668 *
669 * @nofity - Pointer to sps event notify sturcture
670 *
671 */
672static void
673msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
674{
675 struct msmsdcc_host *host =
676 (struct msmsdcc_host *)
677 ((struct sps_event_notify *)notify)->user;
678
679 host->sps.notify = *notify;
680 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
681 mmc_hostname(host->mmc), __func__, notify->event_id,
682 notify->data.transfer.iovec.addr,
683 notify->data.transfer.iovec.size,
684 notify->data.transfer.iovec.flags);
685 /* Schedule a tasklet for completing data transfer */
686 tasklet_schedule(&host->sps.tlet);
687}
688
689/**
690 * Tasklet handler for processing SPS callback event
691 *
692 * This function processing SPS event notification and
693 * checks if the SPS transfer is completed or not and
694 * then accordingly notifies status to MMC core layer.
695 *
696 * This function is called in tasklet context.
697 *
698 * @data - Pointer to sdcc driver data
699 *
700 */
701static void msmsdcc_sps_complete_tlet(unsigned long data)
702{
703 unsigned long flags;
704 int i, rc;
705 u32 data_xfered = 0;
706 struct mmc_request *mrq;
707 struct sps_iovec iovec;
708 struct sps_pipe *sps_pipe_handle;
709 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
710 struct sps_event_notify *notify = &host->sps.notify;
711
712 spin_lock_irqsave(&host->lock, flags);
713 if (host->sps.dir == DMA_FROM_DEVICE)
714 sps_pipe_handle = host->sps.prod.pipe_handle;
715 else
716 sps_pipe_handle = host->sps.cons.pipe_handle;
717 mrq = host->curr.mrq;
718
719 if (!mrq) {
720 spin_unlock_irqrestore(&host->lock, flags);
721 return;
722 }
723
724 pr_debug("%s: %s: sps event_id=%d\n",
725 mmc_hostname(host->mmc), __func__,
726 notify->event_id);
727
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700728 /*
729 * Got End of transfer event!!! Check if all of the data
730 * has been transferred?
731 */
732 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
733 rc = sps_get_iovec(sps_pipe_handle, &iovec);
734 if (rc) {
735 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
736 mmc_hostname(host->mmc), __func__, rc, i);
737 break;
738 }
739 data_xfered += iovec.size;
740 }
741
742 if (data_xfered == host->curr.xfer_size) {
743 host->curr.data_xfered = host->curr.xfer_size;
744 host->curr.xfer_remain -= host->curr.xfer_size;
745 pr_debug("%s: Data xfer success. data_xfered=0x%x",
746 mmc_hostname(host->mmc),
747 host->curr.xfer_size);
748 } else {
749 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
750 " xfer_size=%d", mmc_hostname(host->mmc),
751 data_xfered, host->curr.xfer_size);
752 msmsdcc_reset_and_restore(host);
753 if (!mrq->data->error)
754 mrq->data->error = -EIO;
755 }
756
757 /* Unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +0530758 if (!mrq->data->host_cookie)
759 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
760 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700761 host->sps.sg = NULL;
762 host->sps.busy = 0;
763
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530764 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
765 (host->curr.wait_for_auto_prog_done &&
766 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700767 /*
768 * If we've already gotten our DATAEND / DATABLKEND
769 * for this request, then complete it through here.
770 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700771
772 if (!mrq->data->error) {
773 host->curr.data_xfered = host->curr.xfer_size;
774 host->curr.xfer_remain -= host->curr.xfer_size;
775 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700776 if (host->dummy_52_needed) {
777 mrq->data->bytes_xfered = host->curr.data_xfered;
778 host->dummy_52_sent = 1;
779 msmsdcc_start_command(host, &dummy52cmd,
780 MCI_CPSM_PROGENA);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700781 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700782 return;
783 }
784 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530785 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530786 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700787 mrq->data->bytes_xfered = host->curr.data_xfered;
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530788 msmsdcc_reset_dpsm(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700789 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530790 /*
791 * Clear current request information as current
792 * request has ended
793 */
794 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700795 spin_unlock_irqrestore(&host->lock, flags);
796
797 mmc_request_done(host->mmc, mrq);
798 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530799 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
800 || !mrq->sbc)) {
801 msmsdcc_start_command(host, mrq->data->stop, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700802 }
803 }
804 spin_unlock_irqrestore(&host->lock, flags);
805}
806
807/**
808 * Exit from current SPS data transfer
809 *
810 * This function exits from current SPS data transfer.
811 *
812 * This function should be called when error condition
813 * is encountered during data transfer.
814 *
815 * @host - Pointer to sdcc host structure
816 *
817 */
818static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
819{
820 struct mmc_request *mrq;
821
822 mrq = host->curr.mrq;
823 BUG_ON(!mrq);
824
825 msmsdcc_reset_and_restore(host);
826 if (!mrq->data->error)
827 mrq->data->error = -EIO;
828
829 /* Unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +0530830 if (!mrq->data->host_cookie)
831 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
832 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700833
834 host->sps.sg = NULL;
835 host->sps.busy = 0;
836 if (host->curr.data)
837 msmsdcc_stop_data(host);
838
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530839 if (!mrq->data->stop || mrq->cmd->error ||
840 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700841 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530842 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
843 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700844 msmsdcc_start_command(host, mrq->data->stop, 0);
845
846}
847#else
848static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
849static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
850static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
851#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
852
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530853static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700854
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530855static void
856msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
857 unsigned int result,
858 struct msm_dmov_errdata *err)
859{
860 struct msmsdcc_dma_data *dma_data =
861 container_of(cmd, struct msmsdcc_dma_data, hdr);
862 struct msmsdcc_host *host = dma_data->host;
863
864 dma_data->result = result;
865 if (err)
866 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
867
868 tasklet_schedule(&host->dma_tlet);
869}
870
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530871static bool msmsdcc_is_dma_possible(struct msmsdcc_host *host,
872 struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700873{
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530874 bool ret = true;
875 u32 xfer_size = data->blksz * data->blocks;
San Mehat9d2bd732009-09-22 16:44:22 -0700876
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530877 if (is_sps_mode(host)) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530878 /*
879 * BAM Mode: Fall back on PIO if size is less
880 * than or equal to SPS_MIN_XFER_SIZE bytes.
881 */
882 if (xfer_size <= SPS_MIN_XFER_SIZE)
883 ret = false;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530884 } else if (is_dma_mode(host)) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530885 /*
886 * ADM Mode: Fall back on PIO if size is less than FIFO size
887 * or not integer multiple of FIFO size
888 */
889 if (xfer_size % MCI_FIFOSIZE)
890 ret = false;
891 } else {
892 /* PIO Mode */
893 ret = false;
894 }
895
896 return ret;
San Mehat9d2bd732009-09-22 16:44:22 -0700897}
898
899static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
900{
901 struct msmsdcc_nc_dmadata *nc;
902 dmov_box *box;
903 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700904 unsigned int n;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530905 int i, err = 0, box_cmd_cnt = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700906 struct scatterlist *sg = data->sg;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530907 unsigned int len, offset;
San Mehat9d2bd732009-09-22 16:44:22 -0700908
Krishna Konda25786ec2011-07-25 16:21:36 -0700909 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700910 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700911
Krishna Konda25786ec2011-07-25 16:21:36 -0700912 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
San Mehat9d2bd732009-09-22 16:44:22 -0700913
914 host->dma.sg = data->sg;
915 host->dma.num_ents = data->sg_len;
916
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530917 /* Prevent memory corruption */
918 BUG_ON(host->dma.num_ents > msmsdcc_get_nr_sg(host));
San Mehat56a8b5b2009-11-21 12:29:46 -0800919
San Mehat9d2bd732009-09-22 16:44:22 -0700920 nc = host->dma.nc;
921
San Mehat9d2bd732009-09-22 16:44:22 -0700922 if (data->flags & MMC_DATA_READ)
923 host->dma.dir = DMA_FROM_DEVICE;
924 else
925 host->dma.dir = DMA_TO_DEVICE;
926
Asutosh Dasaccacd42012-03-08 14:33:17 +0530927 if (!data->host_cookie) {
928 n = msmsdcc_prep_xfer(host, data);
929 if (unlikely(n < 0)) {
930 host->dma.sg = NULL;
931 host->dma.num_ents = 0;
932 return -ENOMEM;
933 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800934 }
San Mehat9d2bd732009-09-22 16:44:22 -0700935
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530936 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
937 host->curr.user_pages = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700938 box = &nc->cmd[0];
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530939 for (i = 0; i < host->dma.num_ents; i++) {
940 len = sg_dma_len(sg);
941 offset = 0;
942
943 do {
944 /* Check if we can do DMA */
945 if (!len || (box_cmd_cnt >= MMC_MAX_DMA_CMDS)) {
946 err = -ENOTSUPP;
947 goto unmap;
948 }
949
950 box->cmd = CMD_MODE_BOX;
951
952 if (len >= MMC_MAX_DMA_BOX_LENGTH) {
953 len = MMC_MAX_DMA_BOX_LENGTH;
954 len -= len % data->blksz;
955 }
956 rows = (len % MCI_FIFOSIZE) ?
957 (len / MCI_FIFOSIZE) + 1 :
958 (len / MCI_FIFOSIZE);
959
960 if (data->flags & MMC_DATA_READ) {
961 box->src_row_addr = msmsdcc_fifo_addr(host);
962 box->dst_row_addr = sg_dma_address(sg) + offset;
963 box->src_dst_len = (MCI_FIFOSIZE << 16) |
964 (MCI_FIFOSIZE);
965 box->row_offset = MCI_FIFOSIZE;
966 box->num_rows = rows * ((1 << 16) + 1);
967 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
968 } else {
969 box->src_row_addr = sg_dma_address(sg) + offset;
970 box->dst_row_addr = msmsdcc_fifo_addr(host);
971 box->src_dst_len = (MCI_FIFOSIZE << 16) |
972 (MCI_FIFOSIZE);
973 box->row_offset = (MCI_FIFOSIZE << 16);
974 box->num_rows = rows * ((1 << 16) + 1);
975 box->cmd |= CMD_DST_CRCI(host->dma.crci);
976 }
977
978 offset += len;
979 len = sg_dma_len(sg) - offset;
980 box++;
981 box_cmd_cnt++;
982 } while (len);
983 sg++;
984 }
985 /* Mark last command */
986 box--;
987 box->cmd |= CMD_LC;
San Mehat9d2bd732009-09-22 16:44:22 -0700988
989 /* location of command block must be 64 bit aligned */
990 BUG_ON(host->dma.cmd_busaddr & 0x07);
991
992 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
993 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
994 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
995 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
996
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530997 /* Flush all data to memory before starting dma */
998 mb();
999
1000unmap:
1001 if (err) {
Asutosh Dasaccacd42012-03-08 14:33:17 +05301002 if (!data->host_cookie)
1003 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
1004 host->dma.num_ents, host->dma.dir);
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05301005 pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
1006 mmc_hostname(host->mmc), err);
San Mehat9d2bd732009-09-22 16:44:22 -07001007 }
1008
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05301009 return err;
San Mehat9d2bd732009-09-22 16:44:22 -07001010}
1011
Asutosh Dasaccacd42012-03-08 14:33:17 +05301012static int msmsdcc_prep_xfer(struct msmsdcc_host *host,
1013 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -08001014{
Asutosh Dasaccacd42012-03-08 14:33:17 +05301015 int rc = 0;
1016 unsigned int dir;
1017
1018 /* Prevent memory corruption */
1019 BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
1020
1021 if (data->flags & MMC_DATA_READ)
1022 dir = DMA_FROM_DEVICE;
1023 else
1024 dir = DMA_TO_DEVICE;
1025
1026 /* Make sg buffers DMA ready */
1027 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
1028 dir);
1029
1030 if (unlikely(rc != data->sg_len)) {
1031 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
1032 mmc_hostname(host->mmc), rc);
1033 rc = -ENOMEM;
1034 goto dma_map_err;
1035 }
1036
1037 pr_debug("%s: %s: %s: sg_len=%d\n",
1038 mmc_hostname(host->mmc), __func__,
1039 dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
1040 data->sg_len);
1041
1042 goto out;
1043
1044dma_map_err:
1045 dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
1046 data->flags);
1047out:
1048 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07001049}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001050#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
1051/**
1052 * Submits data transfer request to SPS driver
1053 *
1054 * This function make sg (scatter gather) data buffers
1055 * DMA ready and then submits them to SPS driver for
1056 * transfer.
1057 *
1058 * @host - Pointer to sdcc host structure
1059 * @data - Pointer to mmc_data structure
1060 *
1061 * @return 0 if success else negative value
1062 */
1063static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
Asutosh Dasaccacd42012-03-08 14:33:17 +05301064 struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -07001065{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001066 int rc = 0;
1067 u32 flags;
1068 int i;
1069 u32 addr, len, data_cnt;
1070 struct scatterlist *sg = data->sg;
1071 struct sps_pipe *sps_pipe_handle;
1072
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001073 host->sps.sg = data->sg;
1074 host->sps.num_ents = data->sg_len;
1075 host->sps.xfer_req_cnt = 0;
1076 if (data->flags & MMC_DATA_READ) {
1077 host->sps.dir = DMA_FROM_DEVICE;
1078 sps_pipe_handle = host->sps.prod.pipe_handle;
1079 } else {
1080 host->sps.dir = DMA_TO_DEVICE;
1081 sps_pipe_handle = host->sps.cons.pipe_handle;
1082 }
1083
Asutosh Dasaccacd42012-03-08 14:33:17 +05301084 if (!data->host_cookie) {
1085 rc = msmsdcc_prep_xfer(host, data);
1086 if (unlikely(rc < 0)) {
1087 host->dma.sg = NULL;
1088 host->dma.num_ents = 0;
1089 goto out;
1090 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001091 }
1092
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001093 for (i = 0; i < data->sg_len; i++) {
1094 /*
1095 * Check if this is the last buffer to transfer?
1096 * If yes then set the INT and EOT flags.
1097 */
1098 len = sg_dma_len(sg);
1099 addr = sg_dma_address(sg);
1100 flags = 0;
1101 while (len > 0) {
1102 if (len > SPS_MAX_DESC_SIZE) {
1103 data_cnt = SPS_MAX_DESC_SIZE;
1104 } else {
1105 data_cnt = len;
1106 if (i == data->sg_len - 1)
1107 flags = SPS_IOVEC_FLAG_INT |
1108 SPS_IOVEC_FLAG_EOT;
1109 }
1110 rc = sps_transfer_one(sps_pipe_handle, addr,
1111 data_cnt, host, flags);
1112 if (rc) {
1113 pr_err("%s: sps_transfer_one() error! rc=%d,"
1114 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
1115 mmc_hostname(host->mmc), rc,
1116 (u32)sps_pipe_handle, (u32)sg, i);
1117 goto dma_map_err;
1118 }
1119 addr += data_cnt;
1120 len -= data_cnt;
1121 host->sps.xfer_req_cnt++;
1122 }
1123 sg++;
1124 }
1125 goto out;
1126
1127dma_map_err:
1128 /* unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +05301129 if (!data->host_cookie)
1130 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
1131 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001132out:
1133 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07001134}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001135#else
1136static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
1137 struct mmc_data *data) { return 0; }
1138#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -07001139
1140static void
San Mehat56a8b5b2009-11-21 12:29:46 -08001141msmsdcc_start_command_deferred(struct msmsdcc_host *host,
1142 struct mmc_command *cmd, u32 *c)
1143{
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301144 DBG(host, "op %02x arg %08x flags %08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001145 cmd->opcode, cmd->arg, cmd->flags);
1146
San Mehat56a8b5b2009-11-21 12:29:46 -08001147 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
1148
1149 if (cmd->flags & MMC_RSP_PRESENT) {
1150 if (cmd->flags & MMC_RSP_136)
1151 *c |= MCI_CPSM_LONGRSP;
1152 *c |= MCI_CPSM_RESPONSE;
1153 }
1154
1155 if (/*interrupt*/0)
1156 *c |= MCI_CPSM_INTERRUPT;
1157
Asutosh Das05049132012-05-09 12:38:15 +05301158 /* DAT_CMD bit should be set for all ADTC */
1159 if (mmc_cmd_type(cmd) == MMC_CMD_ADTC)
San Mehat56a8b5b2009-11-21 12:29:46 -08001160 *c |= MCI_CSPM_DATCMD;
1161
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001162 /* Check if AUTO CMD19 is required or not? */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301163 if (host->tuning_needed &&
1164 !(host->mmc->ios.timing == MMC_TIMING_MMC_HS200)) {
1165
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301166 /*
1167 * For open ended block read operation (without CMD23),
1168 * AUTO_CMD19 bit should be set while sending the READ command.
1169 * For close ended block read operation (with CMD23),
1170 * AUTO_CMD19 bit should be set while sending CMD23.
1171 */
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301172 if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
1173 host->curr.mrq->cmd->opcode ==
1174 MMC_READ_MULTIPLE_BLOCK) ||
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301175 (!host->curr.mrq->sbc &&
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301176 (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
1177 cmd->opcode == MMC_READ_MULTIPLE_BLOCK))) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301178 msmsdcc_enable_cdr_cm_sdc4_dll(host);
1179 *c |= MCI_CSPM_AUTO_CMD19;
1180 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001181 }
1182
Subhash Jadavanif97d2992012-07-13 14:47:47 +05301183 if (cmd->mrq->data && (cmd->mrq->data->flags & MMC_DATA_READ))
1184 writel_relaxed((readl_relaxed(host->base +
1185 MCI_DLL_CONFIG) | MCI_CDR_EN),
1186 host->base + MCI_DLL_CONFIG);
1187 else
1188 /* Clear CDR_EN bit for non read operations */
1189 writel_relaxed((readl_relaxed(host->base +
1190 MCI_DLL_CONFIG) & ~MCI_CDR_EN),
1191 host->base + MCI_DLL_CONFIG);
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05301192
Sujit Reddy Thumma02868752012-06-25 17:22:56 +05301193 if (((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) ||
1194 (cmd->opcode == MMC_SEND_STATUS &&
1195 !(cmd->flags & MMC_CMD_ADTC))) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301196 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001197 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301198 }
1199
San Mehat56a8b5b2009-11-21 12:29:46 -08001200 if (cmd == cmd->mrq->stop)
1201 *c |= MCI_CSPM_MCIABORT;
1202
San Mehat56a8b5b2009-11-21 12:29:46 -08001203 if (host->curr.cmd != NULL) {
Girish K Sa3c76eb2011-10-11 11:44:09 +05301204 pr_err("%s: Overlapping command requests\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001205 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -08001206 }
1207 host->curr.cmd = cmd;
1208}
1209
1210static void
1211msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1212 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001213{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301214 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001215 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001216 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001217 unsigned int pio_irqmask = 0;
1218
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301219 BUG_ON(!data->sg);
1220 BUG_ON(!data->sg_len);
1221
San Mehat9d2bd732009-09-22 16:44:22 -07001222 host->curr.data = data;
1223 host->curr.xfer_size = data->blksz * data->blocks;
1224 host->curr.xfer_remain = host->curr.xfer_size;
1225 host->curr.data_xfered = 0;
1226 host->curr.got_dataend = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301227 host->curr.got_auto_prog_done = false;
San Mehat9d2bd732009-09-22 16:44:22 -07001228
San Mehat9d2bd732009-09-22 16:44:22 -07001229 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1230
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301231 if (host->curr.wait_for_auto_prog_done)
1232 datactrl |= MCI_AUTO_PROG_DONE;
San Mehat9d2bd732009-09-22 16:44:22 -07001233
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05301234 if (msmsdcc_is_dma_possible(host, data)) {
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301235 if (is_dma_mode(host) && !msmsdcc_config_dma(host, data)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001236 datactrl |= MCI_DPSM_DMAENABLE;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301237 } else if (is_sps_mode(host)) {
Krishna Kondad337ddd2012-08-19 11:16:39 -07001238 if (!msmsdcc_sps_start_xfer(host, data)) {
1239 /* Now kick start DML transfer */
1240 mb();
1241 msmsdcc_dml_start_xfer(host, data);
1242 datactrl |= MCI_DPSM_DMAENABLE;
1243 host->sps.busy = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001244 }
1245 }
1246 }
1247
1248 /* Is data transfer in PIO mode required? */
1249 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001250 if (data->flags & MMC_DATA_READ) {
1251 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1252 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1253 pio_irqmask |= MCI_RXDATAAVLBLMASK;
1254 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001255 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1256 MCI_TXFIFOEMPTYMASK;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001257
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001258 msmsdcc_sg_start(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001259 }
1260
1261 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301262 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
Subhash Jadavanif5277752011-10-12 16:47:52 +05301263 else if (host->curr.use_wr_data_pend)
1264 datactrl |= MCI_DATA_PEND;
San Mehat9d2bd732009-09-22 16:44:22 -07001265
San Mehat56a8b5b2009-11-21 12:29:46 -08001266 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001267 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001268 timeout = data->timeout_clks + (unsigned int)clks*2 ;
Subhash Jadavani63540362012-06-12 14:56:04 +05301269 WARN(!timeout,
1270 "%s: data timeout is zero. timeout_ns=0x%x, timeout_clks=0x%x\n",
1271 mmc_hostname(host->mmc), data->timeout_ns, data->timeout_clks);
San Mehat9d2bd732009-09-22 16:44:22 -07001272
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301273 if (is_dma_mode(host) && (datactrl & MCI_DPSM_DMAENABLE)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001274 /* Use ADM (Application Data Mover) HW for Data transfer */
1275 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001276 host->cmd_timeout = timeout;
1277 host->cmd_pio_irqmask = pio_irqmask;
1278 host->cmd_datactrl = datactrl;
1279 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001280
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001281 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1282 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001283 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001284
1285 if (cmd) {
1286 msmsdcc_start_command_deferred(host, cmd, &c);
1287 host->cmd_c = c;
1288 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001289 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1290 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1291 host->base + MMCIMASK0);
1292 mb();
1293 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001294 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001295 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001296 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001297
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001298 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001299
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001300 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1301 (~(MCI_IRQ_PIO))) | pio_irqmask,
1302 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001303 writel_relaxed(datactrl, base + MMCIDATACTRL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001304
1305 if (cmd) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05301306 /* Delay between data/command */
1307 msmsdcc_sync_reg_wr(host);
San Mehat56a8b5b2009-11-21 12:29:46 -08001308 /* Daisy-chain the command if requested */
1309 msmsdcc_start_command(host, cmd, c);
Subhash Jadavanidd432952012-03-28 11:25:56 +05301310 } else {
1311 /*
1312 * We don't need delay after writing to DATA_CTRL
1313 * register if we are not writing to CMD register
1314 * immediately after this. As we already have delay
1315 * before sending the command, we just need mb() here.
1316 */
1317 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001318 }
San Mehat9d2bd732009-09-22 16:44:22 -07001319 }
1320}
1321
1322static void
1323msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1324{
San Mehat56a8b5b2009-11-21 12:29:46 -08001325 msmsdcc_start_command_deferred(host, cmd, &c);
1326 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001327}
1328
1329static void
1330msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1331 unsigned int status)
1332{
1333 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001334 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
Subhash Jadavanib30c9822012-03-27 18:03:16 +05301335 || data->mrq->cmd->opcode == MMC_BUS_TEST_R
1336 || data->mrq->cmd->opcode ==
1337 MMC_SEND_TUNING_BLOCK_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001338 pr_err("%s: Data CRC error\n",
1339 mmc_hostname(host->mmc));
1340 pr_err("%s: opcode 0x%.8x\n", __func__,
1341 data->mrq->cmd->opcode);
1342 pr_err("%s: blksz %d, blocks %d\n", __func__,
1343 data->blksz, data->blocks);
1344 data->error = -EILSEQ;
1345 }
San Mehat9d2bd732009-09-22 16:44:22 -07001346 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001347 /* CRC is optional for the bus test commands, not all
1348 * cards respond back with CRC. However controller
1349 * waits for the CRC and times out. Hence ignore the
1350 * data timeouts during the Bustest.
1351 */
1352 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1353 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301354 pr_err("%s: CMD%d: Data timeout\n",
1355 mmc_hostname(host->mmc),
1356 data->mrq->cmd->opcode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001357 data->error = -ETIMEDOUT;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301358 msmsdcc_dump_sdcc_state(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001359 }
San Mehat9d2bd732009-09-22 16:44:22 -07001360 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001361 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001362 data->error = -EIO;
1363 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001364 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001365 data->error = -EIO;
1366 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001367 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001368 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001369 data->error = -EIO;
1370 }
San Mehat9d2bd732009-09-22 16:44:22 -07001371
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001372 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001373 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001374 host->dummy_52_needed = 0;
1375}
San Mehat9d2bd732009-09-22 16:44:22 -07001376
1377static int
1378msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1379{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001380 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001381 uint32_t *ptr = (uint32_t *) buffer;
1382 int count = 0;
1383
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301384 if (remain % 4)
1385 remain = ((remain >> 2) + 1) << 2;
1386
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001387 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1388
1389 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001390 ptr++;
1391 count += sizeof(uint32_t);
1392
1393 remain -= sizeof(uint32_t);
1394 if (remain == 0)
1395 break;
1396 }
1397 return count;
1398}
1399
1400static int
1401msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001402 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001403{
1404 void __iomem *base = host->base;
1405 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001406 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001407
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001408 while (readl_relaxed(base + MMCISTATUS) &
1409 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1410 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001411
San Mehat9d2bd732009-09-22 16:44:22 -07001412 count = min(remain, maxcnt);
1413
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301414 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1415 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001416 ptr += count;
1417 remain -= count;
1418
1419 if (remain == 0)
1420 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001421 }
1422 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001423
1424 return ptr - buffer;
1425}
1426
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001427/*
1428 * Copy up to a word (4 bytes) between a scatterlist
1429 * and a temporary bounce buffer when the word lies across
1430 * two pages. The temporary buffer can then be read to/
1431 * written from the FIFO once.
1432 */
1433static void _msmsdcc_sg_consume_word(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -07001434{
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001435 struct msmsdcc_pio_data *pio = &host->pio;
1436 unsigned int bytes_avail;
1437
1438 if (host->curr.data->flags & MMC_DATA_READ)
1439 memcpy(pio->sg_miter.addr, pio->bounce_buf,
1440 pio->bounce_buf_len);
1441 else
1442 memcpy(pio->bounce_buf, pio->sg_miter.addr,
1443 pio->bounce_buf_len);
1444
1445 while (pio->bounce_buf_len != 4) {
1446 if (!sg_miter_next(&pio->sg_miter))
1447 break;
1448 bytes_avail = min_t(unsigned int, pio->sg_miter.length,
1449 4 - pio->bounce_buf_len);
1450 if (host->curr.data->flags & MMC_DATA_READ)
1451 memcpy(pio->sg_miter.addr,
1452 &pio->bounce_buf[pio->bounce_buf_len],
1453 bytes_avail);
1454 else
1455 memcpy(&pio->bounce_buf[pio->bounce_buf_len],
1456 pio->sg_miter.addr, bytes_avail);
1457
1458 pio->sg_miter.consumed = bytes_avail;
1459 pio->bounce_buf_len += bytes_avail;
San Mehat9d2bd732009-09-22 16:44:22 -07001460 }
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001461}
1462
1463/*
1464 * Use sg_miter_next to return as many 4-byte aligned
1465 * chunks as possible, using a temporary 4 byte buffer
1466 * for alignment if necessary
1467 */
1468static int msmsdcc_sg_next(struct msmsdcc_host *host, char **buf, int *len)
1469{
1470 struct msmsdcc_pio_data *pio = &host->pio;
1471 unsigned int length, rlength;
1472 char *buffer;
1473
1474 if (!sg_miter_next(&pio->sg_miter))
1475 return 0;
1476
1477 buffer = pio->sg_miter.addr;
1478 length = pio->sg_miter.length;
1479
1480 if (length < host->curr.xfer_remain) {
1481 rlength = round_down(length, 4);
1482 if (rlength) {
1483 /*
1484 * We have a 4-byte aligned chunk.
1485 * The rounding will be reflected by
1486 * a call to msmsdcc_sg_consumed
1487 */
1488 length = rlength;
1489 goto sg_next_end;
1490 }
1491 /*
1492 * We have a length less than 4 bytes. Check to
1493 * see if more buffer is available, and combine
1494 * to make 4 bytes if possible.
1495 */
1496 pio->bounce_buf_len = length;
1497 memset(pio->bounce_buf, 0, 4);
1498
1499 /*
1500 * On a read, get 4 bytes from FIFO, and distribute
1501 * (4-bouce_buf_len) bytes into consecutive
1502 * sgl buffers when msmsdcc_sg_consumed is called
1503 */
1504 if (host->curr.data->flags & MMC_DATA_READ) {
1505 buffer = pio->bounce_buf;
1506 length = 4;
1507 goto sg_next_end;
1508 } else {
1509 _msmsdcc_sg_consume_word(host);
1510 buffer = pio->bounce_buf;
1511 length = pio->bounce_buf_len;
1512 }
1513 }
1514
1515sg_next_end:
1516 *buf = buffer;
1517 *len = length;
1518 return 1;
1519}
1520
1521/*
1522 * Update sg_miter.consumed based on how many bytes were
1523 * consumed. If the bounce buffer was used to read from FIFO,
1524 * redistribute into sgls.
1525 */
1526static void msmsdcc_sg_consumed(struct msmsdcc_host *host,
1527 unsigned int length)
1528{
1529 struct msmsdcc_pio_data *pio = &host->pio;
1530
1531 if (host->curr.data->flags & MMC_DATA_READ) {
1532 if (length > pio->sg_miter.consumed)
1533 /*
1534 * consumed 4 bytes, but sgl
1535 * describes < 4 bytes
1536 */
1537 _msmsdcc_sg_consume_word(host);
1538 else
1539 pio->sg_miter.consumed = length;
1540 } else
1541 if (length < pio->sg_miter.consumed)
1542 pio->sg_miter.consumed = length;
1543}
1544
1545static void msmsdcc_sg_start(struct msmsdcc_host *host)
1546{
1547 unsigned int sg_miter_flags = SG_MITER_ATOMIC;
1548
1549 host->pio.bounce_buf_len = 0;
1550
1551 if (host->curr.data->flags & MMC_DATA_READ)
1552 sg_miter_flags |= SG_MITER_TO_SG;
1553 else
1554 sg_miter_flags |= SG_MITER_FROM_SG;
1555
1556 sg_miter_start(&host->pio.sg_miter, host->curr.data->sg,
1557 host->curr.data->sg_len, sg_miter_flags);
1558}
1559
1560static void msmsdcc_sg_stop(struct msmsdcc_host *host)
1561{
1562 sg_miter_stop(&host->pio.sg_miter);
San Mehat9d2bd732009-09-22 16:44:22 -07001563}
1564
San Mehat1cd22962010-02-03 12:59:29 -08001565static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001566msmsdcc_pio_irq(int irq, void *dev_id)
1567{
1568 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001569 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001570 uint32_t status;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001571 unsigned long flags;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001572 unsigned int remain;
1573 char *buffer;
San Mehat9d2bd732009-09-22 16:44:22 -07001574
Murali Palnati36448a42011-09-02 15:06:18 +05301575 spin_lock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301576
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001577 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001578
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001579 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301580 (MCI_IRQ_PIO)) == 0) {
1581 spin_unlock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301582 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301583 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001584#if IRQ_DEBUG
1585 msmsdcc_print_status(host, "irq1-r", status);
1586#endif
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001587 local_irq_save(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001588
1589 do {
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001590 unsigned int len;
San Mehat9d2bd732009-09-22 16:44:22 -07001591
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001592 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1593 | MCI_RXDATAAVLBL)))
1594 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001595
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001596 if (!msmsdcc_sg_next(host, &buffer, &remain))
1597 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001598
San Mehat9d2bd732009-09-22 16:44:22 -07001599 len = 0;
1600 if (status & MCI_RXACTIVE)
1601 len = msmsdcc_pio_read(host, buffer, remain);
1602 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001603 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001604
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301605 /* len might have aligned to 32bits above */
1606 if (len > remain)
1607 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001608
San Mehat9d2bd732009-09-22 16:44:22 -07001609 host->curr.xfer_remain -= len;
1610 host->curr.data_xfered += len;
1611 remain -= len;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001612 msmsdcc_sg_consumed(host, len);
San Mehat9d2bd732009-09-22 16:44:22 -07001613
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001614 if (remain) /* Done with this page? */
1615 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001616
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001617 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001618 } while (1);
1619
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001620 msmsdcc_sg_stop(host);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001621 local_irq_restore(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001622
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001623 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1624 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1625 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1626 host->base + MMCIMASK0);
1627 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301628 /*
1629 * back to back write to MASK0 register don't need
1630 * synchronization delay.
1631 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001632 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1633 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1634 }
1635 mb();
1636 } else if (!host->curr.xfer_remain) {
1637 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1638 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1639 mb();
1640 }
San Mehat9d2bd732009-09-22 16:44:22 -07001641
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001642 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001643
1644 return IRQ_HANDLED;
1645}
1646
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001647static void
1648msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1649
1650static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1651 struct mmc_data *data)
1652{
1653 u32 loop_cnt = 0;
1654
1655 /*
1656 * For read commands with data less than fifo size, it is possible to
1657 * get DATAEND first and RXDATA_AVAIL might be set later because of
1658 * synchronization delay through the asynchronous RX FIFO. Thus, for
1659 * such cases, even after DATAEND interrupt is received software
1660 * should poll for RXDATA_AVAIL until the requested data is read out
1661 * of FIFO. This change is needed to get around this abnormal but
1662 * sometimes expected behavior of SDCC3 controller.
1663 *
1664 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1665 * after the data is loaded into RX FIFO. This would amount to less
1666 * than a microsecond and thus looping for 1000 times is good enough
1667 * for that delay.
1668 */
1669 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1670 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1671 spin_unlock(&host->lock);
1672 msmsdcc_pio_irq(1, host);
1673 spin_lock(&host->lock);
1674 }
1675 }
1676 if (loop_cnt == 1000) {
1677 pr_info("%s: Timed out while polling for Rx Data\n",
1678 mmc_hostname(host->mmc));
1679 data->error = -ETIMEDOUT;
1680 msmsdcc_reset_and_restore(host);
1681 }
1682}
1683
San Mehat9d2bd732009-09-22 16:44:22 -07001684static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1685{
1686 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001687
1688 host->curr.cmd = NULL;
subhashj8046ae12012-05-02 12:14:52 +05301689 if (mmc_resp_type(cmd))
1690 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1691 /*
1692 * Read rest of the response registers only if
1693 * long response is expected for this command
1694 */
1695 if (mmc_resp_type(cmd) & MMC_RSP_136) {
1696 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1697 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1698 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
1699 }
San Mehat9d2bd732009-09-22 16:44:22 -07001700
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001701 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301702 pr_debug("%s: CMD%d: Command timeout\n",
1703 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001704 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001705 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301706 !host->tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301707 pr_err("%s: CMD%d: Command CRC error\n",
1708 mmc_hostname(host->mmc), cmd->opcode);
1709 msmsdcc_dump_sdcc_state(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001710 cmd->error = -EILSEQ;
1711 }
1712
Subhash Jadavani8706ced2012-05-25 16:09:21 +05301713 if (!cmd->error) {
1714 if (cmd->cmd_timeout_ms > host->curr.req_tout_ms) {
1715 host->curr.req_tout_ms = cmd->cmd_timeout_ms;
1716 mod_timer(&host->req_tout_timer, (jiffies +
1717 msecs_to_jiffies(host->curr.req_tout_ms)));
1718 }
1719 }
1720
San Mehat9d2bd732009-09-22 16:44:22 -07001721 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001722 if (host->curr.data && host->dma.sg &&
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301723 is_dma_mode(host))
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001724 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001725 else if (host->curr.data && host->sps.sg &&
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301726 is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001727 /* Stop current SPS transfer */
1728 msmsdcc_sps_exit_curr_xfer(host);
1729 }
San Mehat9d2bd732009-09-22 16:44:22 -07001730 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301731 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001732 msmsdcc_stop_data(host);
1733 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301734 } else { /* host->data == NULL */
1735 if (!cmd->error && host->prog_enable) {
1736 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001737 host->prog_enable = 0;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301738 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001739 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301740 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301741 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301742 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301743 host->curr.wait_for_auto_prog_done = false;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001744 if (host->dummy_52_needed)
1745 host->dummy_52_needed = 0;
1746 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001747 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301748 msmsdcc_request_end(host, cmd->mrq);
1749 }
1750 }
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301751 } else if (cmd->data) {
Subhash Jadavanif5277752011-10-12 16:47:52 +05301752 if (cmd == host->curr.mrq->sbc)
1753 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1754 else if ((cmd->data->flags & MMC_DATA_WRITE) &&
1755 !host->curr.use_wr_data_pend)
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301756 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001757 }
1758}
1759
San Mehat9d2bd732009-09-22 16:44:22 -07001760static irqreturn_t
1761msmsdcc_irq(int irq, void *dev_id)
1762{
1763 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001764 u32 status;
1765 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001766 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001767
1768 spin_lock(&host->lock);
1769
1770 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001771 struct mmc_command *cmd;
1772 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001773
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001774 if (timer) {
1775 timer = 0;
1776 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001777 }
San Mehat9d2bd732009-09-22 16:44:22 -07001778
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05301779 if (!atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001780 pr_debug("%s: %s: SDIO async irq received\n",
1781 mmc_hostname(host->mmc), __func__);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301782
1783 /*
1784 * Only async interrupt can come when clocks are off,
1785 * disable further interrupts and enable them when
1786 * clocks are on.
1787 */
1788 if (!host->sdcc_irq_disabled) {
1789 disable_irq_nosync(irq);
1790 host->sdcc_irq_disabled = 1;
1791 }
1792
1793 /*
1794 * If mmc_card_wake_sdio_irq() is set, mmc core layer
1795 * will take care of signaling sdio irq during
1796 * mmc_sdio_resume().
1797 */
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301798 if (host->sdcc_suspended) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301799 /*
1800 * This is a wakeup interrupt so hold wakelock
1801 * until SDCC resume is handled.
1802 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001803 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301804 } else {
1805 spin_unlock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301806 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301807 spin_lock(&host->lock);
1808 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301809 ret = 1;
1810 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001811 }
1812
1813 status = readl_relaxed(host->base + MMCISTATUS);
1814
1815 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1816 (~(MCI_IRQ_PIO))) == 0)
San Mehat9d2bd732009-09-22 16:44:22 -07001817 break;
1818
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001819#if IRQ_DEBUG
1820 msmsdcc_print_status(host, "irq0-r", status);
1821#endif
1822 status &= readl_relaxed(host->base + MMCIMASK0);
1823 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301824 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301825 if (host->clk_rate <=
1826 msmsdcc_get_min_sup_clk_rate(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +05301827 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001828#if IRQ_DEBUG
1829 msmsdcc_print_status(host, "irq0-p", status);
1830#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001831
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001832 if (status & MCI_SDIOINTROPE) {
1833 if (host->sdcc_suspending)
1834 wake_lock(&host->sdio_suspend_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301835 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001836 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301837 spin_lock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001838 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001839 data = host->curr.data;
1840
1841 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001842 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1843 MCI_CMDTIMEOUT)) {
1844 if (status & MCI_CMDTIMEOUT)
1845 pr_debug("%s: dummy CMD52 timeout\n",
1846 mmc_hostname(host->mmc));
1847 if (status & MCI_CMDCRCFAIL)
1848 pr_debug("%s: dummy CMD52 CRC failed\n",
1849 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001850 host->dummy_52_sent = 0;
1851 host->dummy_52_needed = 0;
1852 if (data) {
1853 msmsdcc_stop_data(host);
1854 msmsdcc_request_end(host, data->mrq);
1855 }
1856 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001857 spin_unlock(&host->lock);
1858 return IRQ_HANDLED;
1859 }
1860 break;
1861 }
1862
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001863 /*
1864 * Check for proper command response
1865 */
1866 cmd = host->curr.cmd;
1867 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1868 MCI_CMDTIMEOUT | MCI_PROGDONE |
1869 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1870 msmsdcc_do_cmdirq(host, status);
1871 }
1872
Sathish Ambley081d7842011-11-29 11:19:41 -08001873 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001874 /* Check for data errors */
1875 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1876 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1877 msmsdcc_data_err(host, data, status);
1878 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301879 if (host->dma.sg && is_dma_mode(host))
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001880 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301881 else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001882 /* Stop current SPS transfer */
1883 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301884 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001885 msmsdcc_reset_and_restore(host);
1886 if (host->curr.data)
1887 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301888 if (!data->stop || (host->curr.mrq->sbc
1889 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001890 timer |=
1891 msmsdcc_request_end(host,
1892 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301893 else if ((host->curr.mrq->sbc
1894 && data->error) ||
1895 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001896 msmsdcc_start_command(host,
1897 data->stop,
1898 0);
1899 timer = 1;
1900 }
1901 }
1902 }
1903
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301904 /* Check for prog done */
1905 if (host->curr.wait_for_auto_prog_done &&
1906 (status & MCI_PROGDONE))
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301907 host->curr.got_auto_prog_done = true;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301908
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001909 /* Check for data done */
1910 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1911 host->curr.got_dataend = 1;
1912
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301913 if (host->curr.got_dataend &&
1914 (!host->curr.wait_for_auto_prog_done ||
1915 (host->curr.wait_for_auto_prog_done &&
1916 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001917 /*
1918 * If DMA is still in progress, we complete
1919 * via the completion handler
1920 */
1921 if (!host->dma.busy && !host->sps.busy) {
1922 /*
1923 * There appears to be an issue in the
1924 * controller where if you request a
1925 * small block transfer (< fifo size),
1926 * you may get your DATAEND/DATABLKEND
1927 * irq without the PIO data irq.
1928 *
1929 * Check to see if theres still data
1930 * to be read, and simulate a PIO irq.
1931 */
1932 if (data->flags & MMC_DATA_READ)
1933 msmsdcc_wait_for_rxdata(host,
1934 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001935 if (!data->error) {
1936 host->curr.data_xfered =
1937 host->curr.xfer_size;
1938 host->curr.xfer_remain -=
1939 host->curr.xfer_size;
1940 }
1941
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001942 if (!host->dummy_52_needed) {
1943 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301944 if (!data->stop ||
1945 (host->curr.mrq->sbc
1946 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001947 msmsdcc_request_end(
1948 host,
1949 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301950 else if ((host->curr.mrq->sbc
1951 && data->error) ||
1952 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001953 msmsdcc_start_command(
1954 host,
1955 data->stop, 0);
1956 timer = 1;
1957 }
1958 } else {
1959 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001960 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001961 &dummy52cmd,
1962 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001963 }
1964 }
1965 }
1966 }
1967
San Mehat9d2bd732009-09-22 16:44:22 -07001968 ret = 1;
1969 } while (status);
1970
1971 spin_unlock(&host->lock);
1972
San Mehat9d2bd732009-09-22 16:44:22 -07001973 return IRQ_RETVAL(ret);
1974}
1975
1976static void
Asutosh Dasaccacd42012-03-08 14:33:17 +05301977msmsdcc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
1978 bool is_first_request)
1979{
1980 struct msmsdcc_host *host = mmc_priv(mmc);
1981 struct mmc_data *data = mrq->data;
1982 int rc = 0;
1983
1984 if (unlikely(!data)) {
1985 pr_err("%s: %s cannot prepare null data\n", mmc_hostname(mmc),
1986 __func__);
1987 return;
1988 }
1989 if (unlikely(data->host_cookie)) {
1990 /* Very wrong */
1991 data->host_cookie = 0;
1992 pr_err("%s: %s Request reposted for prepare\n",
1993 mmc_hostname(mmc), __func__);
1994 return;
1995 }
1996
1997 if (!msmsdcc_is_dma_possible(host, data))
1998 return;
1999
2000 rc = msmsdcc_prep_xfer(host, data);
2001 if (unlikely(rc < 0)) {
2002 data->host_cookie = 0;
2003 return;
2004 }
2005
2006 data->host_cookie = 1;
2007}
2008
2009static void
2010msmsdcc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, int err)
2011{
2012 struct msmsdcc_host *host = mmc_priv(mmc);
2013 unsigned int dir;
2014 struct mmc_data *data = mrq->data;
2015
2016 if (unlikely(!data)) {
2017 pr_err("%s: %s cannot cleanup null data\n", mmc_hostname(mmc),
2018 __func__);
2019 return;
2020 }
2021 if (data->flags & MMC_DATA_READ)
2022 dir = DMA_FROM_DEVICE;
2023 else
2024 dir = DMA_TO_DEVICE;
2025
2026 if (data->host_cookie)
2027 dma_unmap_sg(mmc_dev(host->mmc), data->sg,
2028 data->sg_len, dir);
2029
2030 data->host_cookie = 0;
2031}
2032
2033static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002034msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
2035{
Subhash Jadavanif5277752011-10-12 16:47:52 +05302036 if (mrq->data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002037 /* Queue/read data, daisy-chain command when data starts */
Subhash Jadavanif5277752011-10-12 16:47:52 +05302038 if ((mrq->data->flags & MMC_DATA_READ) ||
2039 host->curr.use_wr_data_pend)
2040 msmsdcc_start_data(host, mrq->data,
2041 mrq->sbc ? mrq->sbc : mrq->cmd,
2042 0);
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302043 else
Subhash Jadavanif5277752011-10-12 16:47:52 +05302044 msmsdcc_start_command(host,
2045 mrq->sbc ? mrq->sbc : mrq->cmd,
2046 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002047 } else {
2048 msmsdcc_start_command(host, mrq->cmd, 0);
2049 }
2050}
2051
2052static void
San Mehat9d2bd732009-09-22 16:44:22 -07002053msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
2054{
2055 struct msmsdcc_host *host = mmc_priv(mmc);
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302056 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07002057
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002058 /*
2059 * Get the SDIO AL client out of LPM.
2060 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002061 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002062 if (host->plat->is_sdio_al_client)
2063 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002064
Subhash Jadavanib5b07742011-08-29 17:48:07 +05302065 /* check if sps pipe reset is pending? */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05302066 if (is_sps_mode(host) && host->sps.pipe_reset_pending) {
Subhash Jadavanib5b07742011-08-29 17:48:07 +05302067 msmsdcc_sps_pipes_reset_and_restore(host);
2068 host->sps.pipe_reset_pending = false;
2069 }
San Mehat9d2bd732009-09-22 16:44:22 -07002070
2071 spin_lock_irqsave(&host->lock, flags);
2072
San Mehat9d2bd732009-09-22 16:44:22 -07002073 if (host->eject) {
2074 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
2075 mrq->cmd->error = 0;
2076 mrq->data->bytes_xfered = mrq->data->blksz *
2077 mrq->data->blocks;
2078 } else
2079 mrq->cmd->error = -ENOMEDIUM;
2080
2081 spin_unlock_irqrestore(&host->lock, flags);
2082 mmc_request_done(mmc, mrq);
2083 return;
2084 }
2085
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302086 /*
subhashjf181c292012-05-02 13:07:40 +05302087 * Don't start the request if SDCC is not in proper state to handle it
2088 */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302089 if (!host->pwr || !atomic_read(&host->clks_on)
2090 || host->sdcc_irq_disabled) {
subhashjf181c292012-05-02 13:07:40 +05302091 WARN(1, "%s: %s: SDCC is in bad state. don't process"
2092 " new request (CMD%d)\n", mmc_hostname(host->mmc),
2093 __func__, mrq->cmd->opcode);
2094 msmsdcc_dump_sdcc_state(host);
2095 mrq->cmd->error = -EIO;
2096 if (mrq->data) {
2097 mrq->data->error = -EIO;
2098 mrq->data->bytes_xfered = 0;
2099 }
2100 spin_unlock_irqrestore(&host->lock, flags);
2101 mmc_request_done(mmc, mrq);
2102 return;
2103 }
2104
2105 WARN(host->curr.mrq, "%s: %s: New request (CMD%d) received while"
2106 " other request (CMD%d) is in progress\n",
2107 mmc_hostname(host->mmc), __func__,
2108 mrq->cmd->opcode, host->curr.mrq->cmd->opcode);
2109
2110 /*
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302111 * Set timeout value to 10 secs (or more in case of buggy cards)
2112 */
2113 if ((mmc->card) && (mmc->card->quirks & MMC_QUIRK_INAND_DATA_TIMEOUT))
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302114 host->curr.req_tout_ms = 20000;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302115 else
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302116 host->curr.req_tout_ms = MSM_MMC_REQ_TIMEOUT;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302117 /*
2118 * Kick the software request timeout timer here with the timeout
2119 * value identified above
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302120 */
2121 mod_timer(&host->req_tout_timer,
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302122 (jiffies +
2123 msecs_to_jiffies(host->curr.req_tout_ms)));
San Mehat9d2bd732009-09-22 16:44:22 -07002124
San Mehat9d2bd732009-09-22 16:44:22 -07002125 host->curr.mrq = mrq;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302126 if (mrq->sbc) {
2127 mrq->sbc->mrq = mrq;
2128 mrq->sbc->data = mrq->data;
2129 }
2130
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302131 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05302132 if (is_auto_prog_done(host)) {
Sujit Reddy Thummab8e83692012-07-17 15:08:13 +05302133 /*
2134 * Auto-prog done will be enabled for following cases:
2135 * mrq->sbc | mrq->stop
2136 * _____________|________________
2137 * True | Don't care
2138 * False | False (CMD24, ACMD25 use case)
2139 */
2140 if (mrq->sbc || !mrq->stop)
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302141 host->curr.wait_for_auto_prog_done = true;
2142 } else {
2143 if ((mrq->cmd->opcode == SD_IO_RW_EXTENDED) ||
2144 (mrq->cmd->opcode == 54))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002145 host->dummy_52_needed = 1;
2146 }
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302147
Subhash Jadavanif5277752011-10-12 16:47:52 +05302148 if ((mrq->cmd->opcode == MMC_WRITE_BLOCK) ||
2149 (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK))
2150 host->curr.use_wr_data_pend = true;
San Mehat9d2bd732009-09-22 16:44:22 -07002151 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302152
Subhash Jadavanif5277752011-10-12 16:47:52 +05302153 msmsdcc_request_start(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302154
San Mehat9d2bd732009-09-22 16:44:22 -07002155 spin_unlock_irqrestore(&host->lock, flags);
2156}
2157
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002158static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
2159 int min_uV, int max_uV)
2160{
2161 int rc = 0;
2162
2163 if (vreg->set_voltage_sup) {
2164 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
2165 if (rc) {
2166 pr_err("%s: regulator_set_voltage(%s) failed."
2167 " min_uV=%d, max_uV=%d, rc=%d\n",
2168 __func__, vreg->name, min_uV, max_uV, rc);
2169 }
2170 }
2171
2172 return rc;
2173}
2174
Subhash Jadavanibf09d802012-08-11 18:11:57 +05302175static inline int msmsdcc_vreg_get_voltage(struct msm_mmc_reg_data *vreg)
2176{
2177 int rc = 0;
2178
2179 rc = regulator_get_voltage(vreg->reg);
2180 if (rc < 0)
2181 pr_err("%s: regulator_get_voltage(%s) failed. rc=%d\n",
2182 __func__, vreg->name, rc);
2183
2184 return rc;
2185}
2186
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002187static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
2188 int uA_load)
2189{
2190 int rc = 0;
2191
Krishna Kondafea60182011-11-01 16:01:34 -07002192 /* regulators that do not support regulator_set_voltage also
2193 do not support regulator_set_optimum_mode */
2194 if (vreg->set_voltage_sup) {
2195 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
2196 if (rc < 0)
2197 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
2198 "uA_load=%d) failed. rc=%d\n", __func__,
2199 vreg->name, uA_load, rc);
2200 else
2201 /* regulator_set_optimum_mode() can return non zero
2202 * value even for success case.
2203 */
2204 rc = 0;
2205 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002206
2207 return rc;
2208}
2209
2210static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
2211 struct device *dev)
2212{
2213 int rc = 0;
2214
2215 /* check if regulator is already initialized? */
2216 if (vreg->reg)
2217 goto out;
2218
2219 /* Get the regulator handle */
2220 vreg->reg = regulator_get(dev, vreg->name);
2221 if (IS_ERR(vreg->reg)) {
2222 rc = PTR_ERR(vreg->reg);
2223 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
2224 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002225 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002226 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002227
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05302228 if (regulator_count_voltages(vreg->reg) > 0) {
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002229 vreg->set_voltage_sup = 1;
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05302230 /* sanity check */
2231 if (!vreg->high_vol_level || !vreg->hpm_uA) {
2232 pr_err("%s: %s invalid constraints specified\n",
2233 __func__, vreg->name);
2234 rc = -EINVAL;
2235 }
2236 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002237
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002238out:
2239 return rc;
2240}
2241
2242static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
2243{
2244 if (vreg->reg)
2245 regulator_put(vreg->reg);
2246}
2247
2248/* This init function should be called only once for each SDCC slot */
2249static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
2250{
2251 int rc = 0;
2252 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302253 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vdd_io_reg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002254 struct device *dev = mmc_dev(host->mmc);
2255
2256 curr_slot = host->plat->vreg_data;
2257 if (!curr_slot)
2258 goto out;
2259
2260 curr_vdd_reg = curr_slot->vdd_data;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302261 curr_vdd_io_reg = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002262
2263 if (is_init) {
2264 /*
2265 * Get the regulator handle from voltage regulator framework
2266 * and then try to set the voltage level for the regulator
2267 */
2268 if (curr_vdd_reg) {
2269 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
2270 if (rc)
2271 goto out;
2272 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302273 if (curr_vdd_io_reg) {
2274 rc = msmsdcc_vreg_init_reg(curr_vdd_io_reg, dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002275 if (rc)
2276 goto vdd_reg_deinit;
2277 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002278 rc = msmsdcc_vreg_reset(host);
2279 if (rc)
2280 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
2281 host->pdev_id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002282 goto out;
2283 } else {
2284 /* Deregister all regulators from regulator framework */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302285 goto vdd_io_reg_deinit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002286 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302287vdd_io_reg_deinit:
2288 if (curr_vdd_io_reg)
2289 msmsdcc_vreg_deinit_reg(curr_vdd_io_reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002290vdd_reg_deinit:
2291 if (curr_vdd_reg)
2292 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2293out:
2294 return rc;
2295}
2296
2297static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2298{
2299 int rc = 0;
2300
Subhash Jadavanicc922692011-08-01 23:05:01 +05302301 /* Put regulator in HPM (high power mode) */
2302 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2303 if (rc < 0)
2304 goto out;
2305
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002306 if (!vreg->is_enabled) {
2307 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302308 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2309 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002310 if (rc)
2311 goto out;
2312
2313 rc = regulator_enable(vreg->reg);
2314 if (rc) {
2315 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2316 __func__, vreg->name, rc);
2317 goto out;
2318 }
2319 vreg->is_enabled = true;
2320 }
2321
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002322out:
2323 return rc;
2324}
2325
Krishna Konda3c4142d2012-06-27 11:01:56 -07002326static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg, bool is_init)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002327{
2328 int rc = 0;
2329
2330 /* Never disable regulator marked as always_on */
2331 if (vreg->is_enabled && !vreg->always_on) {
2332 rc = regulator_disable(vreg->reg);
2333 if (rc) {
2334 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2335 __func__, vreg->name, rc);
2336 goto out;
2337 }
2338 vreg->is_enabled = false;
2339
2340 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2341 if (rc < 0)
2342 goto out;
2343
2344 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302345 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002346 if (rc)
2347 goto out;
Krishna Konda3c4142d2012-06-27 11:01:56 -07002348 } else if (vreg->is_enabled && vreg->always_on) {
2349 if (!is_init && vreg->lpm_sup) {
2350 /* Put always_on regulator in LPM (low power mode) */
2351 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2352 if (rc < 0)
2353 goto out;
2354 } else if (is_init && vreg->reset_at_init) {
2355 /**
2356 * The regulator might not actually be disabled if it
2357 * is shared and in use by other drivers.
2358 */
2359 rc = regulator_disable(vreg->reg);
2360 if (rc) {
2361 pr_err("%s: regulator_disable(%s) failed at " \
2362 "bootup. rc=%d\n", __func__,
2363 vreg->name, rc);
2364 goto out;
2365 }
2366 vreg->is_enabled = false;
2367 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002368 }
2369out:
2370 return rc;
2371}
2372
Krishna Konda3c4142d2012-06-27 11:01:56 -07002373static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable,
2374 bool is_init)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002375{
2376 int rc = 0, i;
2377 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302378 struct msm_mmc_reg_data *vreg_table[2];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002379
2380 curr_slot = host->plat->vreg_data;
Asutosh Dasebd7d092012-07-09 19:08:26 +05302381 if (!curr_slot) {
2382 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002383 goto out;
Asutosh Dasebd7d092012-07-09 19:08:26 +05302384 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002385
Subhash Jadavani937c7502012-06-01 15:34:46 +05302386 vreg_table[0] = curr_slot->vdd_data;
2387 vreg_table[1] = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002388
2389 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2390 if (vreg_table[i]) {
2391 if (enable)
2392 rc = msmsdcc_vreg_enable(vreg_table[i]);
2393 else
Krishna Konda3c4142d2012-06-27 11:01:56 -07002394 rc = msmsdcc_vreg_disable(vreg_table[i],
2395 is_init);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002396 if (rc)
2397 goto out;
2398 }
2399 }
2400out:
2401 return rc;
2402}
2403
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002404/*
2405 * Reset vreg by ensuring it is off during probe. A call
2406 * to enable vreg is needed to balance disable vreg
2407 */
2408static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2409{
2410 int rc;
2411
Krishna Konda3c4142d2012-06-27 11:01:56 -07002412 rc = msmsdcc_setup_vreg(host, 1, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002413 if (rc)
2414 return rc;
Krishna Konda3c4142d2012-06-27 11:01:56 -07002415 rc = msmsdcc_setup_vreg(host, 0, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002416 return rc;
2417}
2418
Subhash Jadavani937c7502012-06-01 15:34:46 +05302419enum vdd_io_level {
2420 /* set vdd_io_data->low_vol_level */
2421 VDD_IO_LOW,
2422 /* set vdd_io_data->high_vol_level */
2423 VDD_IO_HIGH,
2424 /*
2425 * set whatever there in voltage_level (third argument) of
2426 * msmsdcc_set_vdd_io_vol() function.
2427 */
2428 VDD_IO_SET_LEVEL,
2429};
2430
Subhash Jadavanibf09d802012-08-11 18:11:57 +05302431/*
2432 * This function returns the current VDD IO voltage level.
2433 * Returns negative value if it fails to read the voltage level
2434 * Returns 0 if regulator was disabled or if VDD_IO (and VDD)
2435 * regulator were not defined for host.
2436 */
2437static int msmsdcc_get_vdd_io_vol(struct msmsdcc_host *host)
2438{
2439 int rc = 0;
2440
2441 if (host->plat->vreg_data) {
2442 struct msm_mmc_reg_data *io_reg =
2443 host->plat->vreg_data->vdd_io_data;
2444
2445 /*
2446 * If vdd_io is not defined, then we can consider that
2447 * IO voltage is same as VDD.
2448 */
2449 if (!io_reg)
2450 io_reg = host->plat->vreg_data->vdd_data;
2451
2452 if (io_reg && io_reg->is_enabled)
2453 rc = msmsdcc_vreg_get_voltage(io_reg);
2454 }
2455
2456 return rc;
2457}
2458
2459/*
2460 * This function updates the IO pad power switch bit in MCI_CLK register
2461 * based on currrent IO pad voltage level.
2462 * NOTE: This function assumes that host lock was not taken by caller.
2463 */
2464static void msmsdcc_update_io_pad_pwr_switch(struct msmsdcc_host *host)
2465{
2466 int rc = 0;
2467 unsigned long flags;
2468
2469 if (!is_io_pad_pwr_switch(host))
2470 return;
2471
2472 rc = msmsdcc_get_vdd_io_vol(host);
2473
2474 spin_lock_irqsave(&host->lock, flags);
2475 /*
2476 * Dual voltage pad is the SDCC's (chipset) functionality and not all
2477 * the SDCC instances support the dual voltage pads.
2478 * For dual-voltage pad (1.8v/3.3v), SW should set IO_PAD_PWR_SWITCH
2479 * bit before using the pads in 1.8V mode.
2480 * For regular, not dual-voltage pads (including eMMC 1.2v/1.8v pads),
2481 * IO_PAD_PWR_SWITCH bit is a don't care.
2482 * But we don't have an option to know (by reading some SDCC register)
2483 * that a particular SDCC instance supports dual voltage pads or not,
2484 * so we simply set the IO_PAD_PWR_SWITCH bit for low voltage IO
2485 * (1.8v/1.2v). For regular (not dual-voltage pads), this bit value
2486 * is anyway ignored.
2487 */
2488 if (rc > 0 && rc < 2700000)
2489 host->io_pad_pwr_switch = 1;
2490 else
2491 host->io_pad_pwr_switch = 0;
2492
2493 if (atomic_read(&host->clks_on)) {
2494 if (host->io_pad_pwr_switch)
2495 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2496 IO_PAD_PWR_SWITCH),
2497 host->base + MMCICLOCK);
2498 else
2499 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) &
2500 ~IO_PAD_PWR_SWITCH),
2501 host->base + MMCICLOCK);
2502 msmsdcc_sync_reg_wr(host);
2503 }
2504 spin_unlock_irqrestore(&host->lock, flags);
2505}
2506
Subhash Jadavani937c7502012-06-01 15:34:46 +05302507static int msmsdcc_set_vdd_io_vol(struct msmsdcc_host *host,
2508 enum vdd_io_level level,
2509 unsigned int voltage_level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002510{
2511 int rc = 0;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302512 int set_level;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002513
2514 if (host->plat->vreg_data) {
Subhash Jadavani937c7502012-06-01 15:34:46 +05302515 struct msm_mmc_reg_data *vdd_io_reg =
2516 host->plat->vreg_data->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002517
Subhash Jadavani937c7502012-06-01 15:34:46 +05302518 if (vdd_io_reg && vdd_io_reg->is_enabled) {
2519 switch (level) {
2520 case VDD_IO_LOW:
2521 set_level = vdd_io_reg->low_vol_level;
2522 break;
2523 case VDD_IO_HIGH:
2524 set_level = vdd_io_reg->high_vol_level;
2525 break;
2526 case VDD_IO_SET_LEVEL:
2527 set_level = voltage_level;
2528 break;
2529 default:
2530 pr_err("%s: %s: invalid argument level = %d",
2531 mmc_hostname(host->mmc), __func__,
2532 level);
2533 rc = -EINVAL;
2534 goto out;
2535 }
2536 rc = msmsdcc_vreg_set_voltage(vdd_io_reg,
2537 set_level, set_level);
2538 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002539 }
2540
Subhash Jadavani937c7502012-06-01 15:34:46 +05302541out:
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302542 return rc;
2543}
2544
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002545static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2546{
2547 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2548 return 1;
2549 return 0;
2550}
2551
Asutosh Dasf5298c32012-04-03 14:51:47 +05302552/*
2553 * Any function calling msmsdcc_setup_clocks must
2554 * acquire clk_mutex. May sleep.
2555 */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302556static int msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002557{
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302558 int rc = 0;
2559
2560 if (enable && !atomic_read(&host->clks_on)) {
2561 if (!IS_ERR_OR_NULL(host->bus_clk)) {
2562 rc = clk_prepare_enable(host->bus_clk);
2563 if (rc) {
2564 pr_err("%s: %s: failed to enable the bus-clock with error %d\n",
2565 mmc_hostname(host->mmc), __func__, rc);
2566 goto out;
2567 }
2568 }
2569 if (!IS_ERR(host->pclk)) {
2570 rc = clk_prepare_enable(host->pclk);
2571 if (rc) {
2572 pr_err("%s: %s: failed to enable the pclk with error %d\n",
2573 mmc_hostname(host->mmc), __func__, rc);
2574 goto disable_bus;
2575 }
2576 }
2577 rc = clk_prepare_enable(host->clk);
2578 if (rc) {
2579 pr_err("%s: %s: failed to enable the host-clk with error %d\n",
2580 mmc_hostname(host->mmc), __func__, rc);
2581 goto disable_pclk;
2582 }
Subhash Jadavanidd432952012-03-28 11:25:56 +05302583 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302584 msmsdcc_delay(host);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302585 atomic_set(&host->clks_on, 1);
2586 } else if (!enable && atomic_read(&host->clks_on)) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05302587 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302588 msmsdcc_delay(host);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302589 clk_disable_unprepare(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002590 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302591 clk_disable_unprepare(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05302592 if (!IS_ERR_OR_NULL(host->bus_clk))
2593 clk_disable_unprepare(host->bus_clk);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302594 atomic_set(&host->clks_on, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002595 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302596 goto out;
2597
2598disable_pclk:
2599 if (!IS_ERR_OR_NULL(host->pclk))
2600 clk_disable_unprepare(host->pclk);
2601disable_bus:
2602 if (!IS_ERR_OR_NULL(host->bus_clk))
2603 clk_disable_unprepare(host->bus_clk);
2604out:
2605 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002606}
2607
2608static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2609 unsigned int req_clk)
2610{
2611 unsigned int sel_clk = -1;
2612
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302613 if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
2614 sel_clk = msmsdcc_get_min_sup_clk_rate(host);
2615 goto out;
2616 }
2617
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002618 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2619 unsigned char cnt;
2620
2621 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2622 if (host->plat->sup_clk_table[cnt] > req_clk)
2623 break;
2624 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2625 sel_clk = host->plat->sup_clk_table[cnt];
2626 break;
2627 } else
2628 sel_clk = host->plat->sup_clk_table[cnt];
2629 }
2630 } else {
2631 if ((req_clk < host->plat->msmsdcc_fmax) &&
2632 (req_clk > host->plat->msmsdcc_fmid))
2633 sel_clk = host->plat->msmsdcc_fmid;
2634 else
2635 sel_clk = req_clk;
2636 }
2637
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302638out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002639 return sel_clk;
2640}
2641
2642static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2643 struct msmsdcc_host *host)
2644{
2645 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2646 return host->plat->sup_clk_table[0];
2647 else
2648 return host->plat->msmsdcc_fmin;
2649}
2650
2651static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2652 struct msmsdcc_host *host)
2653{
2654 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2655 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2656 else
2657 return host->plat->msmsdcc_fmax;
2658}
2659
2660static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302661{
2662 struct msm_mmc_gpio_data *curr;
2663 int i, rc = 0;
2664
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002665 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302666 for (i = 0; i < curr->size; i++) {
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05302667 if (!gpio_is_valid(curr->gpio[i].no)) {
2668 rc = -EINVAL;
2669 pr_err("%s: Invalid gpio = %d\n",
2670 mmc_hostname(host->mmc), curr->gpio[i].no);
2671 goto free_gpios;
2672 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302673 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002674 if (curr->gpio[i].is_always_on &&
2675 curr->gpio[i].is_enabled)
2676 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302677 rc = gpio_request(curr->gpio[i].no,
2678 curr->gpio[i].name);
2679 if (rc) {
2680 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2681 mmc_hostname(host->mmc),
2682 curr->gpio[i].no,
2683 curr->gpio[i].name, rc);
2684 goto free_gpios;
2685 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002686 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302687 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002688 if (curr->gpio[i].is_always_on)
2689 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302690 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002691 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302692 }
2693 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002694 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302695
2696free_gpios:
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05302697 for (i--; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302698 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002699 curr->gpio[i].is_enabled = false;
2700 }
2701out:
2702 return rc;
2703}
2704
2705static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2706{
2707 struct msm_mmc_pad_data *curr;
2708 int i;
2709
2710 curr = host->plat->pin_data->pad_data;
2711 for (i = 0; i < curr->drv->size; i++) {
2712 if (enable)
2713 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2714 curr->drv->on[i].val);
2715 else
2716 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2717 curr->drv->off[i].val);
2718 }
2719
2720 for (i = 0; i < curr->pull->size; i++) {
2721 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002722 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002723 curr->pull->on[i].val);
2724 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002725 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002726 curr->pull->off[i].val);
2727 }
2728
2729 return 0;
2730}
2731
2732static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2733{
2734 int rc = 0;
2735
2736 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2737 return 0;
2738
2739 if (host->plat->pin_data->is_gpio)
2740 rc = msmsdcc_setup_gpio(host, enable);
2741 else
2742 rc = msmsdcc_setup_pad(host, enable);
2743
2744 if (!rc)
2745 host->plat->pin_data->cfg_sts = enable;
2746
2747 return rc;
2748}
2749
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302750static int msmsdcc_cfg_mpm_sdiowakeup(struct msmsdcc_host *host,
2751 unsigned mode)
2752{
2753 int ret = 0;
2754 unsigned int pin = host->plat->mpm_sdiowakeup_int;
2755
2756 if (!pin)
2757 return 0;
2758
2759 switch (mode) {
2760 case SDC_DAT1_DISABLE:
2761 ret = msm_mpm_enable_pin(pin, 0);
2762 break;
2763 case SDC_DAT1_ENABLE:
2764 ret = msm_mpm_set_pin_type(pin, IRQ_TYPE_LEVEL_LOW);
2765 ret = msm_mpm_enable_pin(pin, 1);
2766 break;
2767 case SDC_DAT1_ENWAKE:
2768 ret = msm_mpm_set_pin_wake(pin, 1);
2769 break;
2770 case SDC_DAT1_DISWAKE:
2771 ret = msm_mpm_set_pin_wake(pin, 0);
2772 break;
2773 default:
2774 ret = -EINVAL;
2775 break;
2776 }
2777
2778 return ret;
2779}
2780
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302781static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2782{
2783 u32 pwr = 0;
2784 int ret = 0;
2785 struct mmc_host *mmc = host->mmc;
2786
2787 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2788 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2789 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
Krishna Konda3c4142d2012-06-27 11:01:56 -07002790 ret = msmsdcc_setup_vreg(host, !!ios->vdd, false);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302791
2792 if (ret) {
2793 pr_err("%s: Failed to setup voltage regulators\n",
2794 mmc_hostname(host->mmc));
2795 goto out;
2796 }
2797
2798 switch (ios->power_mode) {
2799 case MMC_POWER_OFF:
2800 pwr = MCI_PWR_OFF;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302801 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302802 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05302803 * If VDD IO rail is always on, set low voltage for VDD
2804 * IO rail when slot is not in use (like when card is not
2805 * present or during system suspend).
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302806 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302807 msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Subhash Jadavanibf09d802012-08-11 18:11:57 +05302808 msmsdcc_update_io_pad_pwr_switch(host);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302809 msmsdcc_setup_pins(host, false);
2810 break;
2811 case MMC_POWER_UP:
2812 /* writing PWR_UP bit is redundant */
2813 pwr = MCI_PWR_UP;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302814 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302815
Subhash Jadavani937c7502012-06-01 15:34:46 +05302816 msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Subhash Jadavanibf09d802012-08-11 18:11:57 +05302817 msmsdcc_update_io_pad_pwr_switch(host);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302818 msmsdcc_setup_pins(host, true);
2819 break;
2820 case MMC_POWER_ON:
2821 pwr = MCI_PWR_ON;
2822 break;
2823 }
2824
2825out:
2826 return pwr;
2827}
2828
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002829static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2830{
2831 unsigned int wakeup_irq;
2832
2833 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2834 host->plat->sdiowakeup_irq :
2835 host->core_irqres->start;
2836
2837 if (!host->irq_wake_enabled) {
2838 enable_irq_wake(wakeup_irq);
2839 host->irq_wake_enabled = true;
2840 }
2841}
2842
2843static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2844{
2845 unsigned int wakeup_irq;
2846
2847 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2848 host->plat->sdiowakeup_irq :
2849 host->core_irqres->start;
2850
2851 if (host->irq_wake_enabled) {
2852 disable_irq_wake(wakeup_irq);
2853 host->irq_wake_enabled = false;
2854 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302855}
2856
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05302857/* Returns required bandwidth in Bytes per Sec */
2858static unsigned int msmsdcc_get_bw_required(struct msmsdcc_host *host,
2859 struct mmc_ios *ios)
2860{
2861 unsigned int bw;
2862
2863 bw = host->clk_rate;
2864 /*
2865 * For DDR mode, SDCC controller clock will be at
2866 * the double rate than the actual clock that goes to card.
2867 */
2868 if (ios->bus_width == MMC_BUS_WIDTH_4)
2869 bw /= 2;
2870 else if (ios->bus_width == MMC_BUS_WIDTH_1)
2871 bw /= 8;
2872
2873 return bw;
2874}
2875
2876static int msmsdcc_msm_bus_get_vote_for_bw(struct msmsdcc_host *host,
2877 unsigned int bw)
2878{
2879 unsigned int *table = host->plat->msm_bus_voting_data->bw_vecs;
2880 unsigned int size = host->plat->msm_bus_voting_data->bw_vecs_size;
2881 int i;
2882
2883 if (host->msm_bus_vote.is_max_bw_needed && bw)
2884 return host->msm_bus_vote.max_bw_vote;
2885
2886 for (i = 0; i < size; i++) {
2887 if (bw <= table[i])
2888 break;
2889 }
2890
2891 if (i && (i == size))
2892 i--;
2893
2894 return i;
2895}
2896
2897static int msmsdcc_msm_bus_register(struct msmsdcc_host *host)
2898{
2899 int rc = 0;
2900 struct msm_bus_scale_pdata *use_cases;
2901
2902 if (host->plat->msm_bus_voting_data &&
2903 host->plat->msm_bus_voting_data->use_cases &&
2904 host->plat->msm_bus_voting_data->bw_vecs &&
2905 host->plat->msm_bus_voting_data->bw_vecs_size) {
2906 use_cases = host->plat->msm_bus_voting_data->use_cases;
2907 host->msm_bus_vote.client_handle =
2908 msm_bus_scale_register_client(use_cases);
2909 } else {
2910 return 0;
2911 }
2912
2913 if (!host->msm_bus_vote.client_handle) {
2914 pr_err("%s: msm_bus_scale_register_client() failed\n",
2915 mmc_hostname(host->mmc));
2916 rc = -EFAULT;
2917 } else {
2918 /* cache the vote index for minimum and maximum bandwidth */
2919 host->msm_bus_vote.min_bw_vote =
2920 msmsdcc_msm_bus_get_vote_for_bw(host, 0);
2921 host->msm_bus_vote.max_bw_vote =
2922 msmsdcc_msm_bus_get_vote_for_bw(host, UINT_MAX);
2923 }
2924
2925 return rc;
2926}
2927
2928static void msmsdcc_msm_bus_unregister(struct msmsdcc_host *host)
2929{
2930 if (host->msm_bus_vote.client_handle)
2931 msm_bus_scale_unregister_client(
2932 host->msm_bus_vote.client_handle);
2933}
2934
2935/*
2936 * This function must be called with host lock acquired.
2937 * Caller of this function should also ensure that msm bus client
2938 * handle is not null.
2939 */
2940static inline int msmsdcc_msm_bus_set_vote(struct msmsdcc_host *host,
2941 int vote,
2942 unsigned long flags)
2943{
2944 int rc = 0;
2945
2946 if (vote != host->msm_bus_vote.curr_vote) {
2947 spin_unlock_irqrestore(&host->lock, flags);
2948 rc = msm_bus_scale_client_update_request(
2949 host->msm_bus_vote.client_handle, vote);
2950 if (rc)
2951 pr_err("%s: msm_bus_scale_client_update_request() failed."
2952 " bus_client_handle=0x%x, vote=%d, err=%d\n",
2953 mmc_hostname(host->mmc),
2954 host->msm_bus_vote.client_handle, vote, rc);
2955 spin_lock_irqsave(&host->lock, flags);
2956 if (!rc)
2957 host->msm_bus_vote.curr_vote = vote;
2958 }
2959
2960 return rc;
2961}
2962
2963/*
2964 * Internal work. Work to set 0 bandwidth for msm bus.
2965 */
2966static void msmsdcc_msm_bus_work(struct work_struct *work)
2967{
2968 struct msmsdcc_host *host = container_of(work,
2969 struct msmsdcc_host,
2970 msm_bus_vote.vote_work.work);
2971 unsigned long flags;
2972
2973 if (!host->msm_bus_vote.client_handle)
2974 return;
2975
2976 spin_lock_irqsave(&host->lock, flags);
2977 /* don't vote for 0 bandwidth if any request is in progress */
2978 if (!host->curr.mrq)
2979 msmsdcc_msm_bus_set_vote(host,
2980 host->msm_bus_vote.min_bw_vote, flags);
2981 else
2982 pr_warning("%s: %s: SDCC transfer in progress. skipping"
2983 " bus voting to 0 bandwidth\n",
2984 mmc_hostname(host->mmc), __func__);
2985 spin_unlock_irqrestore(&host->lock, flags);
2986}
2987
2988/*
2989 * This function cancels any scheduled delayed work
2990 * and sets the bus vote based on ios argument.
2991 * If "ios" argument is NULL, bandwidth required is 0 else
2992 * calculate the bandwidth based on ios parameters.
2993 */
2994static void msmsdcc_msm_bus_cancel_work_and_set_vote(
2995 struct msmsdcc_host *host,
2996 struct mmc_ios *ios)
2997{
2998 unsigned long flags;
2999 unsigned int bw;
3000 int vote;
3001
3002 if (!host->msm_bus_vote.client_handle)
3003 return;
3004
3005 bw = ios ? msmsdcc_get_bw_required(host, ios) : 0;
3006
3007 cancel_delayed_work_sync(&host->msm_bus_vote.vote_work);
3008 spin_lock_irqsave(&host->lock, flags);
3009 vote = msmsdcc_msm_bus_get_vote_for_bw(host, bw);
3010 msmsdcc_msm_bus_set_vote(host, vote, flags);
3011 spin_unlock_irqrestore(&host->lock, flags);
3012}
3013
3014/* This function queues a work which will set the bandwidth requiement to 0 */
3015static void msmsdcc_msm_bus_queue_work(struct msmsdcc_host *host)
3016{
3017 unsigned long flags;
3018
3019 if (!host->msm_bus_vote.client_handle)
3020 return;
3021
3022 spin_lock_irqsave(&host->lock, flags);
3023 if (host->msm_bus_vote.min_bw_vote != host->msm_bus_vote.curr_vote)
3024 queue_delayed_work(system_nrt_wq,
3025 &host->msm_bus_vote.vote_work,
3026 msecs_to_jiffies(MSM_MMC_BUS_VOTING_DELAY));
3027 spin_unlock_irqrestore(&host->lock, flags);
3028}
3029
San Mehat9d2bd732009-09-22 16:44:22 -07003030static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303031msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
3032{
3033 struct mmc_host *mmc = host->mmc;
3034
3035 /*
3036 * SDIO_AL clients has different mechanism of handling LPM through
3037 * sdio_al driver itself. The sdio wakeup interrupt is configured as
3038 * part of that. Here, we are interested only in clients like WLAN.
3039 */
3040 if (!(mmc->card && mmc_card_sdio(mmc->card))
3041 || host->plat->is_sdio_al_client)
3042 goto out;
3043
3044 if (!host->sdcc_suspended) {
3045 /*
3046 * When MSM is not in power collapse and we
3047 * are disabling clocks, enable bit 22 in MASK0
3048 * to handle asynchronous SDIO interrupts.
3049 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05303050 if (enable_wakeup_irq) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303051 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303052 mb();
3053 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303054 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303055 msmsdcc_sync_reg_wr(host);
3056 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303057 goto out;
3058 } else if (!mmc_card_wake_sdio_irq(mmc)) {
3059 /*
3060 * Wakeup MSM only if SDIO function drivers set
3061 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
3062 */
3063 goto out;
3064 }
3065
3066 if (enable_wakeup_irq) {
3067 if (!host->plat->sdiowakeup_irq) {
3068 /*
3069 * When there is no gpio line that can be configured
3070 * as wakeup interrupt handle it by configuring
3071 * asynchronous sdio interrupts and DAT1 line.
3072 */
3073 writel_relaxed(MCI_SDIOINTMASK,
3074 host->base + MMCIMASK0);
3075 mb();
Subhash Jadavanic9b85752012-04-13 11:16:49 +05303076 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303077 /* configure sdcc core interrupt as wakeup interrupt */
3078 msmsdcc_enable_irq_wake(host);
3079 } else {
3080 /* Let gpio line handle wakeup interrupt */
3081 writel_relaxed(0, host->base + MMCIMASK0);
3082 mb();
3083 if (host->sdio_wakeupirq_disabled) {
3084 host->sdio_wakeupirq_disabled = 0;
3085 /* configure gpio line as wakeup interrupt */
3086 msmsdcc_enable_irq_wake(host);
3087 enable_irq(host->plat->sdiowakeup_irq);
3088 }
3089 }
3090 } else {
3091 if (!host->plat->sdiowakeup_irq) {
3092 /*
3093 * We may not have cleared bit 22 in the interrupt
3094 * handler as the clocks might be off at that time.
3095 */
3096 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303097 msmsdcc_sync_reg_wr(host);
Subhash Jadavanic9b85752012-04-13 11:16:49 +05303098 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303099 msmsdcc_disable_irq_wake(host);
3100 } else if (!host->sdio_wakeupirq_disabled) {
3101 disable_irq_nosync(host->plat->sdiowakeup_irq);
3102 msmsdcc_disable_irq_wake(host);
3103 host->sdio_wakeupirq_disabled = 1;
3104 }
3105 }
3106out:
3107 return;
San Mehat9d2bd732009-09-22 16:44:22 -07003108}
3109
3110static void
3111msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
3112{
3113 struct msmsdcc_host *host = mmc_priv(mmc);
3114 u32 clk = 0, pwr = 0;
3115 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08003116 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003117 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07003118
Sahitya Tummala7a892482011-01-18 11:22:49 +05303119
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303120 /*
3121 * Disable SDCC core interrupt until set_ios is completed.
3122 * This avoids any race conditions with interrupt raised
3123 * when turning on/off the clocks. One possible
3124 * scenario is SDIO operational interrupt while the clock
3125 * is turned off.
Asutosh Dasf5298c32012-04-03 14:51:47 +05303126 * host->lock is being released intermittently below.
3127 * Thus, prevent concurrent access to host.
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303128 */
3129
Asutosh Dasf5298c32012-04-03 14:51:47 +05303130 mutex_lock(&host->clk_mutex);
3131 DBG(host, "ios->clock = %u\n", ios->clock);
San Mehat9d2bd732009-09-22 16:44:22 -07003132 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303133 if (!host->sdcc_irq_disabled) {
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05303134 disable_irq_nosync(host->core_irqres->start);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303135 host->sdcc_irq_disabled = 1;
3136 }
San Mehatd0719e52009-12-03 10:58:54 -08003137 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07003138
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05303139 /* Make sure sdcc core irq is synchronized */
3140 synchronize_irq(host->core_irqres->start);
3141
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303142 pwr = msmsdcc_setup_pwr(host, ios);
3143
3144 spin_lock_irqsave(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07003145 if (ios->clock) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303146 spin_unlock_irqrestore(&host->lock, flags);
3147 rc = msmsdcc_setup_clocks(host, true);
3148 if (rc)
3149 goto out;
3150 spin_lock_irqsave(&host->lock, flags);
3151 writel_relaxed(host->mci_irqenable, host->base + MMCIMASK0);
3152 mb();
3153 msmsdcc_cfg_sdio_wakeup(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003154 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303155
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003156 /*
3157 * For DDR50 mode, controller needs clock rate to be
3158 * double than what is required on the SD card CLK pin.
Subhash Jadavani2226d262012-10-09 20:01:56 +05303159 *
3160 * Setting DDR timing mode in controller before setting the
3161 * clock rate will make sure that card don't see the double
3162 * clock rate even for very small duration. Some eMMC
3163 * cards seems to lock up if they see clock frequency > 52MHz.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003164 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05303165 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Subhash Jadavani2226d262012-10-09 20:01:56 +05303166 u32 clk;
3167
3168 clk = readl_relaxed(host->base + MMCICLOCK);
3169 clk &= ~(0x7 << 14); /* clear SELECT_IN field */
3170 clk |= (3 << 14); /* set DDR timing mode */
3171 writel_relaxed(clk, host->base + MMCICLOCK);
3172 msmsdcc_sync_reg_wr(host);
3173
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003174 /*
3175 * Make sure that we don't double the clock if
3176 * doubled clock rate is already set
3177 */
3178 if (!host->ddr_doubled_clk_rate ||
3179 (host->ddr_doubled_clk_rate &&
3180 (host->ddr_doubled_clk_rate != ios->clock))) {
3181 host->ddr_doubled_clk_rate =
3182 msmsdcc_get_sup_clk_rate(
3183 host, (ios->clock * 2));
3184 clock = host->ddr_doubled_clk_rate;
3185 }
3186 } else {
3187 host->ddr_doubled_clk_rate = 0;
3188 }
3189
3190 if (clock != host->clk_rate) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05303191 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003192 rc = clk_set_rate(host->clk, clock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303193 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003194 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303195 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003196 mmc_hostname(mmc), clock);
3197 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303198 host->reg_write_delay =
3199 (1 + ((3 * USEC_PER_SEC) /
3200 (host->clk_rate ? host->clk_rate :
3201 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003202 }
3203 /*
3204 * give atleast 2 MCLK cycles delay for clocks
3205 * and SDCC core to stabilize
3206 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05303207 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003208 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003209 clk |= MCI_CLK_ENABLE;
3210 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003211 if (ios->bus_width == MMC_BUS_WIDTH_8)
3212 clk |= MCI_CLK_WIDEBUS_8;
3213 else if (ios->bus_width == MMC_BUS_WIDTH_4)
3214 clk |= MCI_CLK_WIDEBUS_4;
3215 else
3216 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07003217
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003218 if (msmsdcc_is_pwrsave(host))
3219 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07003220
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003221 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07003222
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003223 host->tuning_needed = 0;
3224 /*
3225 * Select the controller timing mode according
3226 * to current bus speed mode
3227 */
Subhash Jadavanif97d2992012-07-13 14:47:47 +05303228 if (host->clk_rate > (100 * 1000 * 1000) &&
3229 (ios->timing == MMC_TIMING_UHS_SDR104 ||
3230 ios->timing == MMC_TIMING_MMC_HS200)) {
3231 /* Card clock frequency must be > 100MHz to enable tuning */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003232 clk |= (4 << 14);
3233 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05303234 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003235 clk |= (3 << 14);
3236 } else {
3237 clk |= (2 << 14); /* feedback clock */
San Mehat9d2bd732009-09-22 16:44:22 -07003238 }
3239
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003240 /* Select free running MCLK as input clock of cm_dll_sdc4 */
3241 clk |= (2 << 23);
San Mehat9d2bd732009-09-22 16:44:22 -07003242
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003243 if (host->io_pad_pwr_switch)
3244 clk |= IO_PAD_PWR_SWITCH;
3245
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303246 /* Don't write into registers if clocks are disabled */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303247 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303248 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
3249 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303250 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003251 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303252 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
3253 host->pwr = pwr;
3254 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303255 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003256 }
San Mehat9d2bd732009-09-22 16:44:22 -07003257 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003258
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303259 if (!(clk & MCI_CLK_ENABLE) && atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303260 msmsdcc_cfg_sdio_wakeup(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303261 spin_unlock_irqrestore(&host->lock, flags);
3262 /*
3263 * May get a wake-up interrupt the instant we disable the
3264 * clocks. This would disable the wake-up interrupt.
3265 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003266 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303267 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003268 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303269
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303270 if (host->tuning_in_progress)
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303271 WARN(!atomic_read(&host->clks_on),
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303272 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303273
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303274 /* Let interrupts be disabled if the host is powered off */
3275 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
3276 enable_irq(host->core_irqres->start);
3277 host->sdcc_irq_disabled = 0;
3278 }
San Mehat4adbbcc2009-11-08 13:00:37 -08003279 spin_unlock_irqrestore(&host->lock, flags);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303280out:
Asutosh Dasf5298c32012-04-03 14:51:47 +05303281 mutex_unlock(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07003282}
3283
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003284int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
3285{
3286 struct msmsdcc_host *host = mmc_priv(mmc);
3287 u32 clk;
3288
3289 clk = readl_relaxed(host->base + MMCICLOCK);
3290 pr_debug("Changing to pwr_save=%d", pwrsave);
3291 if (pwrsave && msmsdcc_is_pwrsave(host))
3292 clk |= MCI_CLK_PWRSAVE;
3293 else
3294 clk &= ~MCI_CLK_PWRSAVE;
3295 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303296 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003297
3298 return 0;
3299}
3300
3301static int msmsdcc_get_ro(struct mmc_host *mmc)
3302{
3303 int status = -ENOSYS;
3304 struct msmsdcc_host *host = mmc_priv(mmc);
3305
3306 if (host->plat->wpswitch) {
3307 status = host->plat->wpswitch(mmc_dev(mmc));
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05303308 } else if (gpio_is_valid(host->plat->wpswitch_gpio)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003309 status = gpio_request(host->plat->wpswitch_gpio,
3310 "SD_WP_Switch");
3311 if (status) {
3312 pr_err("%s: %s: Failed to request GPIO %d\n",
3313 mmc_hostname(mmc), __func__,
3314 host->plat->wpswitch_gpio);
3315 } else {
3316 status = gpio_direction_input(
3317 host->plat->wpswitch_gpio);
3318 if (!status) {
3319 /*
3320 * Wait for atleast 300ms as debounce
3321 * time for GPIO input to stabilize.
3322 */
3323 msleep(300);
3324 status = gpio_get_value_cansleep(
3325 host->plat->wpswitch_gpio);
Sujit Reddy Thumma8f912ea2012-06-22 16:18:43 +05303326 status ^= !host->plat->is_wpswitch_active_low;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003327 }
3328 gpio_free(host->plat->wpswitch_gpio);
3329 }
3330 }
3331
3332 if (status < 0)
3333 status = -ENOSYS;
3334 pr_debug("%s: Card read-only status %d\n", __func__, status);
3335
3336 return status;
San Mehat9d2bd732009-09-22 16:44:22 -07003337}
3338
3339static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
3340{
3341 struct msmsdcc_host *host = mmc_priv(mmc);
3342 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003343
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303344 /*
3345 * We may come here with clocks turned off in that case don't
3346 * attempt to write into MASK0 register. While turning on the
3347 * clocks mci_irqenable will be written to MASK0 register.
3348 */
San Mehat9d2bd732009-09-22 16:44:22 -07003349
3350 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003351 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003352 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303353 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303354 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003355 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303356 mb();
3357 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003358 } else {
3359 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303360 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303361 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003362 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303363 mb();
3364 }
San Mehat9d2bd732009-09-22 16:44:22 -07003365 }
3366 spin_unlock_irqrestore(&host->lock, flags);
3367}
3368
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003369#ifdef CONFIG_PM_RUNTIME
subhashj245831e2012-04-30 18:46:17 +05303370static void msmsdcc_print_rpm_info(struct msmsdcc_host *host)
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003371{
subhashj245831e2012-04-30 18:46:17 +05303372 struct device *dev = mmc_dev(host->mmc);
3373
Subhash Jadavani1371d192012-08-16 18:46:57 +05303374 pr_info("%s: PM: sdcc_suspended=%d, pending_resume=%d, sdcc_suspending=%d\n",
3375 mmc_hostname(host->mmc), host->sdcc_suspended,
3376 host->pending_resume, host->sdcc_suspending);
subhashj245831e2012-04-30 18:46:17 +05303377 pr_info("%s: RPM: runtime_status=%d, usage_count=%d,"
3378 " is_suspended=%d, disable_depth=%d, runtime_error=%d,"
3379 " request_pending=%d, request=%d\n",
3380 mmc_hostname(host->mmc), dev->power.runtime_status,
3381 atomic_read(&dev->power.usage_count),
3382 dev->power.is_suspended, dev->power.disable_depth,
3383 dev->power.runtime_error, dev->power.request_pending,
3384 dev->power.request);
3385}
3386
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003387static int msmsdcc_enable(struct mmc_host *mmc)
3388{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003389 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003390 struct device *dev = mmc->parent;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003391 struct msmsdcc_host *host = mmc_priv(mmc);
3392
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303393 msmsdcc_pm_qos_update_latency(host, 1);
3394
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003395 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303396 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003397
Subhash Jadavani1371d192012-08-16 18:46:57 +05303398 if (host->sdcc_suspended && host->pending_resume) {
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003399 host->pending_resume = false;
3400 pm_runtime_get_noresume(dev);
3401 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303402 goto skip_get_sync;
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003403 }
3404
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303405 if (dev->power.runtime_status == RPM_SUSPENDING) {
3406 if (mmc->suspend_task == current) {
3407 pm_runtime_get_noresume(dev);
3408 goto out;
3409 }
Sujit Reddy Thumma112bd752012-06-20 12:29:45 +05303410 } else if (dev->power.runtime_status == RPM_RESUMING) {
3411 pm_runtime_get_noresume(dev);
3412 goto out;
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303413 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003414
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303415 rc = pm_runtime_get_sync(dev);
3416
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303417skip_get_sync:
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303418 if (rc < 0) {
Subhash Jadavani1371d192012-08-16 18:46:57 +05303419 WARN(1, "%s: %s: failed with error %d\n", mmc_hostname(mmc),
3420 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303421 msmsdcc_print_rpm_info(host);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303422 return rc;
3423 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303424out:
3425 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303426 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003427}
3428
Steve Mucklef132c6c2012-06-06 18:30:57 -07003429static int msmsdcc_disable(struct mmc_host *mmc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003430{
3431 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303432 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003433
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303434 msmsdcc_pm_qos_update_latency(host, 0);
3435
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303436 if (mmc->card && mmc_card_sdio(mmc->card)) {
3437 rc = 0;
3438 goto out;
3439 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303440
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303441 if (host->plat->disable_runtime_pm)
3442 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003443
3444 rc = pm_runtime_put_sync(mmc->parent);
3445
Subhash Jadavani1371d192012-08-16 18:46:57 +05303446 if (rc < 0) {
3447 WARN(1, "%s: %s: failed with error %d\n", mmc_hostname(mmc),
3448 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303449 msmsdcc_print_rpm_info(host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003450 return rc;
3451 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303452
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303453out:
3454 msmsdcc_msm_bus_queue_work(host);
3455 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003456}
3457#else
subhashj245831e2012-04-30 18:46:17 +05303458static void msmsdcc_print_rpm_info(struct msmsdcc_host *host) {}
3459
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303460static int msmsdcc_enable(struct mmc_host *mmc)
3461{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003462 struct device *dev = mmc->parent;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303463 struct msmsdcc_host *host = mmc_priv(mmc);
Sujit Reddy Thumma7f5051c2012-05-04 10:14:07 +05303464 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303465
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303466 msmsdcc_pm_qos_update_latency(host, 1);
3467
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303468 if (mmc->card && mmc_card_sdio(mmc->card)) {
3469 rc = 0;
3470 goto out;
3471 }
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003472
3473 if (host->sdcc_suspended && host->pending_resume) {
3474 host->pending_resume = false;
3475 rc = msmsdcc_runtime_resume(dev);
3476 goto out;
3477 }
3478
Asutosh Dasf5298c32012-04-03 14:51:47 +05303479 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303480 rc = msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303481 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303482
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003483out:
3484 if (rc < 0) {
3485 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3486 __func__, rc);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303487 msmsdcc_pm_qos_update_latency(host, 0);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003488 return rc;
3489 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303490 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303491 return 0;
3492}
3493
Steve Mucklef132c6c2012-06-06 18:30:57 -07003494static int msmsdcc_disable(struct mmc_host *mmc)
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303495{
3496 struct msmsdcc_host *host = mmc_priv(mmc);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303497 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303498
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303499 msmsdcc_pm_qos_update_latency(host, 0);
3500
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303501 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303502 goto out;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303503
Asutosh Dasf5298c32012-04-03 14:51:47 +05303504 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303505 rc = msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303506 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303507
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303508 if (rc) {
3509 msmsdcc_pm_qos_update_latency(host, 1);
3510 return rc;
3511 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303512out:
3513 msmsdcc_msm_bus_queue_work(host);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303514 return rc;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303515}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003516#endif
3517
Subhash Jadavani937c7502012-06-01 15:34:46 +05303518static int msmsdcc_switch_io_voltage(struct mmc_host *mmc,
3519 struct mmc_ios *ios)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003520{
3521 struct msmsdcc_host *host = mmc_priv(mmc);
3522 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303523 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003524
Subhash Jadavani937c7502012-06-01 15:34:46 +05303525 switch (ios->signal_voltage) {
3526 case MMC_SIGNAL_VOLTAGE_330:
3527 /* Set VDD IO to high voltage range (2.7v - 3.6v) */
3528 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Subhash Jadavanibf09d802012-08-11 18:11:57 +05303529 if (!rc)
3530 msmsdcc_update_io_pad_pwr_switch(host);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303531 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303532 case MMC_SIGNAL_VOLTAGE_180:
3533 break;
3534 case MMC_SIGNAL_VOLTAGE_120:
3535 /*
3536 * For eMMC cards, VDD_IO voltage range must be changed
3537 * only if it operates in HS200 SDR 1.2V mode or in
3538 * DDR 1.2V mode.
3539 */
3540 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_SET_LEVEL, 1200000);
Subhash Jadavanibf09d802012-08-11 18:11:57 +05303541 if (!rc)
3542 msmsdcc_update_io_pad_pwr_switch(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003543 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303544 default:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003545 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303546 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003547 goto out;
3548 }
San Mehat9d2bd732009-09-22 16:44:22 -07003549
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003550 /*
3551 * If we are here means voltage switch from high voltage to
3552 * low voltage is required
3553 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303554 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003555
3556 /*
3557 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
3558 * register until they become all zeros.
3559 */
3560 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303561 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003562 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
3563 mmc_hostname(mmc), __func__);
3564 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07003565 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003566
3567 /* Stop SD CLK output. */
3568 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3569 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303570 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003571 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003572
3573 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05303574 * Switch VDD Io from high voltage range (2.7v - 3.6v) to
3575 * low voltage range (1.7v - 1.95v).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003576 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303577 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303578 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003579 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003580
Subhash Jadavanibf09d802012-08-11 18:11:57 +05303581 msmsdcc_update_io_pad_pwr_switch(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003582
3583 /* Wait 5 ms for the voltage regulater in the card to become stable. */
3584 usleep_range(5000, 5500);
3585
3586 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303587 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003588 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3589 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303590 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003591 spin_unlock_irqrestore(&host->lock, flags);
3592
3593 /*
3594 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
3595 * don't become all ones within 1 ms then a Voltage Switch
3596 * sequence has failed and a power cycle to the card is required.
3597 * Otherwise Voltage Switch sequence is completed successfully.
3598 */
3599 usleep_range(1000, 1500);
3600
3601 spin_lock_irqsave(&host->lock, flags);
3602 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
3603 != (0xF << 1)) {
3604 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
3605 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303606 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003607 goto out_unlock;
3608 }
3609
3610out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303611 /* Enable PWRSAVE */
3612 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3613 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303614 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003615 spin_unlock_irqrestore(&host->lock, flags);
3616out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303617 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003618}
3619
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303620static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003621{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003622 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003623
3624 /* Program the MCLK value to MCLK_FREQ bit field */
3625 if (host->clk_rate <= 112000000)
3626 mclk_freq = 0;
3627 else if (host->clk_rate <= 125000000)
3628 mclk_freq = 1;
3629 else if (host->clk_rate <= 137000000)
3630 mclk_freq = 2;
3631 else if (host->clk_rate <= 150000000)
3632 mclk_freq = 3;
3633 else if (host->clk_rate <= 162000000)
3634 mclk_freq = 4;
3635 else if (host->clk_rate <= 175000000)
3636 mclk_freq = 5;
3637 else if (host->clk_rate <= 187000000)
3638 mclk_freq = 6;
3639 else if (host->clk_rate <= 200000000)
3640 mclk_freq = 7;
3641
3642 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3643 & ~(7 << 24)) | (mclk_freq << 24)),
3644 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003645}
3646
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303647/* Initialize the DLL (Programmable Delay Line ) */
3648static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003649{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003650 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303651 unsigned long flags;
3652 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003653
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303654 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003655 /*
3656 * Make sure that clock is always enabled when DLL
3657 * tuning is in progress. Keeping PWRSAVE ON may
3658 * turn off the clock. So let's disable the PWRSAVE
3659 * here and re-enable it once tuning is completed.
3660 */
3661 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3662 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303663 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303664
3665 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3666 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3667 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3668
3669 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3670 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3671 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3672
3673 msmsdcc_cm_sdc4_dll_set_freq(host);
3674
3675 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3676 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3677 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3678
3679 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3680 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3681 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3682
3683 /* Set DLL_EN bit to 1. */
3684 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3685 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3686
3687 /* Set CK_OUT_EN bit to 1. */
3688 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3689 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3690
3691 wait_cnt = 50;
3692 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3693 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3694 /* max. wait for 50us sec for LOCK bit to be set */
3695 if (--wait_cnt == 0) {
3696 pr_err("%s: %s: DLL failed to LOCK\n",
3697 mmc_hostname(host->mmc), __func__);
3698 rc = -ETIMEDOUT;
3699 goto out;
3700 }
3701 /* wait for 1us before polling again */
3702 udelay(1);
3703 }
3704
3705out:
3706 /* re-enable PWRSAVE */
3707 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3708 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303709 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303710 spin_unlock_irqrestore(&host->lock, flags);
3711
3712 return rc;
3713}
3714
3715static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3716 u8 poll)
3717{
3718 int rc = 0;
3719 u32 wait_cnt = 50;
3720 u8 ck_out_en = 0;
3721
3722 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3723 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3724 MCI_CK_OUT_EN);
3725
3726 while (ck_out_en != poll) {
3727 if (--wait_cnt == 0) {
3728 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3729 mmc_hostname(host->mmc), __func__, poll);
3730 rc = -ETIMEDOUT;
3731 goto out;
3732 }
3733 udelay(1);
3734
3735 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3736 MCI_CK_OUT_EN);
3737 }
3738out:
3739 return rc;
3740}
3741
3742/*
3743 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3744 * calibration sequence. This function should be called before
3745 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3746 * commands (CMD17/CMD18).
3747 *
3748 * This function gets called when host spinlock acquired.
3749 */
3750static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3751{
3752 int rc = 0;
3753 u32 config;
3754
3755 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3756 config |= MCI_CDR_EN;
3757 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3758 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3759
3760 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3761 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3762 if (rc)
3763 goto err_out;
3764
3765 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3766 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3767 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3768
3769 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3770 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3771 if (rc)
3772 goto err_out;
3773
3774 goto out;
3775
3776err_out:
3777 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3778out:
3779 return rc;
3780}
3781
3782static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3783 u8 phase)
3784{
3785 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303786 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3787 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3788 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303789 unsigned long flags;
3790 u32 config;
3791
3792 spin_lock_irqsave(&host->lock, flags);
3793
3794 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3795 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3796 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3797 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3798
3799 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3800 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3801 if (rc)
3802 goto err_out;
3803
3804 /*
3805 * Write the selected DLL clock output phase (0 ... 15)
3806 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
3807 */
3808 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3809 & ~(0xF << 20))
3810 | (grey_coded_phase_table[phase] << 20)),
3811 host->base + MCI_DLL_CONFIG);
3812
3813 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3814 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3815 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3816
3817 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3818 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3819 if (rc)
3820 goto err_out;
3821
3822 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3823 config |= MCI_CDR_EN;
3824 config &= ~MCI_CDR_EXT_EN;
3825 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3826 goto out;
3827
3828err_out:
3829 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3830 mmc_hostname(host->mmc), __func__, phase);
3831out:
3832 spin_unlock_irqrestore(&host->lock, flags);
3833 return rc;
3834}
3835
3836/*
3837 * Find out the greatest range of consecuitive selected
3838 * DLL clock output phases that can be used as sampling
3839 * setting for SD3.0 UHS-I card read operation (in SDR104
3840 * timing mode) or for eMMC4.5 card read operation (in HS200
3841 * timing mode).
3842 * Select the 3/4 of the range and configure the DLL with the
3843 * selected DLL clock output phase.
3844*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303845static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303846 u8 *phase_table, u8 total_phases)
3847{
Subhash Jadavani6159c622012-03-15 19:05:55 +05303848 #define MAX_PHASES 16
Subhash Jadavani34187042012-03-02 10:59:49 +05303849 int ret;
Subhash Jadavani6159c622012-03-15 19:05:55 +05303850 u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
3851 u8 phases_per_row[MAX_PHASES] = {0};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303852 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303853 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3854 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303855
Subhash Jadavani6159c622012-03-15 19:05:55 +05303856 if (!total_phases || (total_phases > MAX_PHASES)) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303857 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3858 mmc_hostname(host->mmc), __func__, total_phases);
3859 return -EINVAL;
3860 }
3861
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303862 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303863 ranges[row_index][col_index] = phase_table[cnt];
3864 phases_per_row[row_index] += 1;
3865 col_index++;
3866
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303867 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303868 continue;
3869 /* check if next phase in phase_table is consecutive or not */
3870 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3871 row_index++;
3872 col_index = 0;
3873 }
3874 }
3875
Subhash Jadavani6159c622012-03-15 19:05:55 +05303876 if (row_index >= MAX_PHASES)
3877 return -EINVAL;
3878
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303879 /* Check if phase-0 is present in first valid window? */
3880 if (!ranges[0][0]) {
3881 phase_0_found = true;
3882 phase_0_raw_index = 0;
3883 /* Check if cycle exist between 2 valid windows */
3884 for (cnt = 1; cnt <= row_index; cnt++) {
3885 if (phases_per_row[cnt]) {
Subhash Jadavani6159c622012-03-15 19:05:55 +05303886 for (i = 0; i < phases_per_row[cnt]; i++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303887 if (ranges[cnt][i] == 15) {
3888 phase_15_found = true;
3889 phase_15_raw_index = cnt;
3890 break;
3891 }
3892 }
3893 }
3894 }
3895 }
3896
3897 /* If 2 valid windows form cycle then merge them as single window */
3898 if (phase_0_found && phase_15_found) {
3899 /* number of phases in raw where phase 0 is present */
3900 u8 phases_0 = phases_per_row[phase_0_raw_index];
3901 /* number of phases in raw where phase 15 is present */
3902 u8 phases_15 = phases_per_row[phase_15_raw_index];
3903
Subhash Jadavani6159c622012-03-15 19:05:55 +05303904 if (phases_0 + phases_15 >= MAX_PHASES)
3905 /*
3906 * If there are more than 1 phase windows then total
3907 * number of phases in both the windows should not be
3908 * more than or equal to MAX_PHASES.
3909 */
3910 return -EINVAL;
3911
3912 /* Merge 2 cyclic windows */
3913 i = phases_15;
3914 for (cnt = 0; cnt < phases_0; cnt++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303915 ranges[phase_15_raw_index][i] =
3916 ranges[phase_0_raw_index][cnt];
Subhash Jadavani6159c622012-03-15 19:05:55 +05303917 if (++i >= MAX_PHASES)
3918 break;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303919 }
Subhash Jadavani6159c622012-03-15 19:05:55 +05303920
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303921 phases_per_row[phase_0_raw_index] = 0;
3922 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
3923 }
3924
3925 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303926 if (phases_per_row[cnt] > curr_max) {
3927 curr_max = phases_per_row[cnt];
3928 selected_row_index = cnt;
3929 }
3930 }
3931
Subhash Jadavani6159c622012-03-15 19:05:55 +05303932 i = ((curr_max * 3) / 4);
3933 if (i)
3934 i--;
3935
Subhash Jadavani34187042012-03-02 10:59:49 +05303936 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303937
Subhash Jadavani6159c622012-03-15 19:05:55 +05303938 if (ret >= MAX_PHASES) {
3939 ret = -EINVAL;
3940 pr_err("%s: %s: invalid phase selected=%d\n",
3941 mmc_hostname(host->mmc), __func__, ret);
3942 }
3943
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303944 return ret;
3945}
3946
Girish K Sa3f41692012-02-29 12:00:09 +05303947static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303948{
3949 int rc = 0;
3950 struct msmsdcc_host *host = mmc_priv(mmc);
3951 unsigned long flags;
3952 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303953 const u32 *tuning_block_pattern = tuning_block_64;
3954 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303955
3956 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
3957
3958 /* Tuning is only required for SDR104 modes */
3959 if (!host->tuning_needed) {
3960 rc = 0;
3961 goto exit;
3962 }
3963
3964 spin_lock_irqsave(&host->lock, flags);
3965 WARN(!host->pwr, "SDCC power is turned off\n");
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303966 WARN(!atomic_read(&host->clks_on), "SDCC clocks are turned off\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303967 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
3968
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303969 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303970 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
3971 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
3972 tuning_block_pattern = tuning_block_128;
3973 size = sizeof(tuning_block_128);
3974 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303975 spin_unlock_irqrestore(&host->lock, flags);
3976
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003977 /* first of all reset the tuning block */
3978 rc = msmsdcc_init_cm_sdc4_dll(host);
3979 if (rc)
3980 goto out;
3981
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303982 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003983 if (!data_buf) {
3984 rc = -ENOMEM;
3985 goto out;
3986 }
3987
3988 phase = 0;
3989 do {
3990 struct mmc_command cmd = {0};
3991 struct mmc_data data = {0};
3992 struct mmc_request mrq = {
3993 .cmd = &cmd,
3994 .data = &data
3995 };
3996 struct scatterlist sg;
3997
3998 /* set the phase in delay line hw block */
3999 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
4000 if (rc)
4001 goto kfree;
4002
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304003 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004004 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
4005
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304006 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004007 data.blocks = 1;
4008 data.flags = MMC_DATA_READ;
4009 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
4010
4011 data.sg = &sg;
4012 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304013 sg_init_one(&sg, data_buf, size);
4014 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004015 mmc_wait_for_req(mmc, &mrq);
4016
4017 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304018 !memcmp(data_buf, tuning_block_pattern, size)) {
4019 /* tuning is successful at this tuning point */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004020 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304021 pr_debug("%s: %s: found good phase = %d\n",
4022 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004023 }
4024 } while (++phase < 16);
4025
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004026 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05304027 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304028 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05304029 if (rc < 0)
4030 goto kfree;
4031 else
4032 phase = (u8)rc;
4033
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004034 /*
4035 * Finally set the selected phase in delay
4036 * line hw block.
4037 */
4038 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
4039 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304040 goto kfree;
4041 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
4042 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004043 } else {
4044 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304045 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004046 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304047 msmsdcc_dump_sdcc_state(host);
4048 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004049 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004050
4051kfree:
4052 kfree(data_buf);
4053out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304054 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304055 host->tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304056 spin_unlock_irqrestore(&host->lock, flags);
4057exit:
4058 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004059 return rc;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04004060}
4061
Asutosh Dasebd7d092012-07-09 19:08:26 +05304062/*
4063 * Work around of the unavailability of a power_reset functionality in SD cards
4064 * by turning the OFF & back ON the regulators supplying the SD card.
4065 */
4066void msmsdcc_hw_reset(struct mmc_host *mmc)
4067{
4068 struct mmc_card *card = mmc->card;
4069 struct msmsdcc_host *host = mmc_priv(mmc);
4070 int rc;
4071
4072 /* Write-protection bits would be lost on a hardware reset in emmc */
4073 if (!card || !mmc_card_sd(card))
4074 return;
4075
4076 /*
4077 * Continuing on failing to disable regulator would lead to a panic
4078 * anyway, since the commands would fail and console would be flooded
4079 * with prints, eventually leading to a watchdog bark
4080 */
4081 rc = msmsdcc_setup_vreg(host, false, false);
4082 if (rc) {
4083 pr_err("%s: %s disable regulator: failed: %d\n",
4084 mmc_hostname(mmc), __func__, rc);
4085 BUG_ON(rc);
4086 }
4087
4088 /* 10ms delay for the supply to reach the desired voltage level */
4089 usleep_range(10000, 12000);
4090
4091 /*
4092 * Continuing on failing to enable regulator would lead to a panic
4093 * anyway, since the commands would fail and console would be flooded
4094 * with prints, eventually leading to a watchdog bark
4095 */
4096 rc = msmsdcc_setup_vreg(host, true, false);
4097 if (rc) {
4098 pr_err("%s: %s enable regulator: failed: %d\n",
4099 mmc_hostname(mmc), __func__, rc);
4100 BUG_ON(rc);
4101 }
4102
4103 /* 10ms delay for the supply to reach the desired voltage level */
4104 usleep_range(10000, 12000);
4105}
4106
San Mehat9d2bd732009-09-22 16:44:22 -07004107static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004108 .enable = msmsdcc_enable,
4109 .disable = msmsdcc_disable,
Asutosh Dasaccacd42012-03-08 14:33:17 +05304110 .pre_req = msmsdcc_pre_req,
4111 .post_req = msmsdcc_post_req,
San Mehat9d2bd732009-09-22 16:44:22 -07004112 .request = msmsdcc_request,
4113 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004114 .get_ro = msmsdcc_get_ro,
San Mehat9d2bd732009-09-22 16:44:22 -07004115 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Subhash Jadavani937c7502012-06-01 15:34:46 +05304116 .start_signal_voltage_switch = msmsdcc_switch_io_voltage,
Asutosh Dasebd7d092012-07-09 19:08:26 +05304117 .execute_tuning = msmsdcc_execute_tuning,
4118 .hw_reset = msmsdcc_hw_reset,
San Mehat9d2bd732009-09-22 16:44:22 -07004119};
4120
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004121static unsigned int
4122msmsdcc_slot_status(struct msmsdcc_host *host)
4123{
4124 int status;
4125 unsigned int gpio_no = host->plat->status_gpio;
4126
4127 status = gpio_request(gpio_no, "SD_HW_Detect");
4128 if (status) {
4129 pr_err("%s: %s: Failed to request GPIO %d\n",
4130 mmc_hostname(host->mmc), __func__, gpio_no);
4131 } else {
4132 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08004133 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08004134 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08004135 if (host->plat->is_status_gpio_active_low)
4136 status = !status;
4137 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004138 gpio_free(gpio_no);
4139 }
4140 return status;
4141}
4142
San Mehat9d2bd732009-09-22 16:44:22 -07004143static void
4144msmsdcc_check_status(unsigned long data)
4145{
4146 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4147 unsigned int status;
4148
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05304149 if (host->plat->status || gpio_is_valid(host->plat->status_gpio)) {
Krishna Konda941604a2012-01-10 17:46:34 -08004150 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004151 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004152 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004153 status = msmsdcc_slot_status(host);
4154
Krishna Konda941604a2012-01-10 17:46:34 -08004155 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08004156
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004157 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08004158 if (host->plat->status)
4159 pr_info("%s: Slot status change detected "
4160 "(%d -> %d)\n",
4161 mmc_hostname(host->mmc),
4162 host->oldstat, status);
4163 else if (host->plat->is_status_gpio_active_low)
4164 pr_info("%s: Slot status change detected "
4165 "(%d -> %d) and the card detect GPIO"
4166 " is ACTIVE_LOW\n",
4167 mmc_hostname(host->mmc),
4168 host->oldstat, status);
4169 else
4170 pr_info("%s: Slot status change detected "
4171 "(%d -> %d) and the card detect GPIO"
4172 " is ACTIVE_HIGH\n",
4173 mmc_hostname(host->mmc),
4174 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07004175 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004176 }
4177 host->oldstat = status;
4178 } else {
4179 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07004180 }
San Mehat9d2bd732009-09-22 16:44:22 -07004181}
4182
4183static irqreturn_t
4184msmsdcc_platform_status_irq(int irq, void *dev_id)
4185{
4186 struct msmsdcc_host *host = dev_id;
4187
Girish K Sa3c76eb2011-10-11 11:44:09 +05304188 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07004189 msmsdcc_check_status((unsigned long) host);
4190 return IRQ_HANDLED;
4191}
4192
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004193static irqreturn_t
4194msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
4195{
4196 struct msmsdcc_host *host = dev_id;
4197
4198 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
4199 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304200 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004201 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304202 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004203 wake_lock(&host->sdio_wlock);
4204 msmsdcc_disable_irq_wake(host);
4205 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304206 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004207 }
4208 if (host->plat->is_sdio_al_client) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004209 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304210 spin_unlock(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304211 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304212 goto out_unlocked;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004213 }
4214 spin_unlock(&host->lock);
4215
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304216out_unlocked:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004217 return IRQ_HANDLED;
4218}
4219
San Mehat9d2bd732009-09-22 16:44:22 -07004220static void
4221msmsdcc_status_notify_cb(int card_present, void *dev_id)
4222{
4223 struct msmsdcc_host *host = dev_id;
4224
Girish K Sa3c76eb2011-10-11 11:44:09 +05304225 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07004226 card_present);
4227 msmsdcc_check_status((unsigned long) host);
4228}
4229
San Mehat9d2bd732009-09-22 16:44:22 -07004230static int
4231msmsdcc_init_dma(struct msmsdcc_host *host)
4232{
4233 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
4234 host->dma.host = host;
4235 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004236 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004237
4238 if (!host->dmares)
4239 return -ENODEV;
4240
4241 host->dma.nc = dma_alloc_coherent(NULL,
4242 sizeof(struct msmsdcc_nc_dmadata),
4243 &host->dma.nc_busaddr,
4244 GFP_KERNEL);
4245 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004246 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07004247 return -ENOMEM;
4248 }
4249 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
4250 host->dma.cmd_busaddr = host->dma.nc_busaddr;
4251 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
4252 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
4253 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07004254 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07004255
4256 return 0;
4257}
4258
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004259#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
4260/**
4261 * Allocate and Connect a SDCC peripheral's SPS endpoint
4262 *
4263 * This function allocates endpoint context and
4264 * connect it with memory endpoint by calling
4265 * appropriate SPS driver APIs.
4266 *
4267 * Also registers a SPS callback function with
4268 * SPS driver
4269 *
4270 * This function should only be called once typically
4271 * during driver probe.
4272 *
4273 * @host - Pointer to sdcc host structure
4274 * @ep - Pointer to sps endpoint data structure
4275 * @is_produce - 1 means Producer endpoint
4276 * 0 means Consumer endpoint
4277 *
4278 * @return - 0 if successful else negative value.
4279 *
4280 */
4281static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
4282 struct msmsdcc_sps_ep_conn_data *ep,
4283 bool is_producer)
4284{
4285 int rc = 0;
4286 struct sps_pipe *sps_pipe_handle;
4287 struct sps_connect *sps_config = &ep->config;
4288 struct sps_register_event *sps_event = &ep->event;
4289
4290 /* Allocate endpoint context */
4291 sps_pipe_handle = sps_alloc_endpoint();
4292 if (!sps_pipe_handle) {
4293 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
4294 mmc_hostname(host->mmc), is_producer);
4295 rc = -ENOMEM;
4296 goto out;
4297 }
4298
4299 /* Get default connection configuration for an endpoint */
4300 rc = sps_get_config(sps_pipe_handle, sps_config);
4301 if (rc) {
4302 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
4303 " rc=%d", mmc_hostname(host->mmc),
4304 (u32)sps_pipe_handle, rc);
4305 goto get_config_err;
4306 }
4307
4308 /* Modify the default connection configuration */
4309 if (is_producer) {
4310 /*
4311 * For SDCC producer transfer, source should be
4312 * SDCC peripheral where as destination should
4313 * be system memory.
4314 */
4315 sps_config->source = host->sps.bam_handle;
4316 sps_config->destination = SPS_DEV_HANDLE_MEM;
4317 /* Producer pipe will handle this connection */
4318 sps_config->mode = SPS_MODE_SRC;
4319 sps_config->options =
4320 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4321 } else {
4322 /*
4323 * For SDCC consumer transfer, source should be
4324 * system memory where as destination should
4325 * SDCC peripheral
4326 */
4327 sps_config->source = SPS_DEV_HANDLE_MEM;
4328 sps_config->destination = host->sps.bam_handle;
4329 sps_config->mode = SPS_MODE_DEST;
4330 sps_config->options =
4331 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4332 }
4333
4334 /* Producer pipe index */
4335 sps_config->src_pipe_index = host->sps.src_pipe_index;
4336 /* Consumer pipe index */
4337 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
4338 /*
4339 * This event thresold value is only significant for BAM-to-BAM
4340 * transfer. It's ignored for BAM-to-System mode transfer.
4341 */
4342 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304343
4344 /* Allocate maximum descriptor fifo size */
4345 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
4346 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004347 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
4348 sps_config->desc.size,
4349 &sps_config->desc.phys_base,
4350 GFP_KERNEL);
4351
Pratibhasagar V00b94332011-10-18 14:57:27 +05304352 if (!sps_config->desc.base) {
4353 rc = -ENOMEM;
4354 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
4355 , mmc_hostname(host->mmc));
4356 goto get_config_err;
4357 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004358 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
4359
4360 /* Establish connection between peripheral and memory endpoint */
4361 rc = sps_connect(sps_pipe_handle, sps_config);
4362 if (rc) {
4363 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4364 " rc=%d", mmc_hostname(host->mmc),
4365 (u32)sps_pipe_handle, rc);
4366 goto sps_connect_err;
4367 }
4368
4369 sps_event->mode = SPS_TRIGGER_CALLBACK;
4370 sps_event->options = SPS_O_EOT;
4371 sps_event->callback = msmsdcc_sps_complete_cb;
4372 sps_event->xfer_done = NULL;
4373 sps_event->user = (void *)host;
4374
4375 /* Register callback event for EOT (End of transfer) event. */
4376 rc = sps_register_event(sps_pipe_handle, sps_event);
4377 if (rc) {
4378 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4379 " rc=%d", mmc_hostname(host->mmc),
4380 (u32)sps_pipe_handle, rc);
4381 goto reg_event_err;
4382 }
4383 /* Now save the sps pipe handle */
4384 ep->pipe_handle = sps_pipe_handle;
4385 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
4386 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
4387 __func__, is_producer ? "READ" : "WRITE",
4388 (u32)sps_pipe_handle, sps_config->desc.phys_base);
4389 goto out;
4390
4391reg_event_err:
4392 sps_disconnect(sps_pipe_handle);
4393sps_connect_err:
4394 dma_free_coherent(mmc_dev(host->mmc),
4395 sps_config->desc.size,
4396 sps_config->desc.base,
4397 sps_config->desc.phys_base);
4398get_config_err:
4399 sps_free_endpoint(sps_pipe_handle);
4400out:
4401 return rc;
4402}
4403
4404/**
4405 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
4406 *
4407 * This function disconnect endpoint and deallocates
4408 * endpoint context.
4409 *
4410 * This function should only be called once typically
4411 * during driver remove.
4412 *
4413 * @host - Pointer to sdcc host structure
4414 * @ep - Pointer to sps endpoint data structure
4415 *
4416 */
4417static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
4418 struct msmsdcc_sps_ep_conn_data *ep)
4419{
4420 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4421 struct sps_connect *sps_config = &ep->config;
4422 struct sps_register_event *sps_event = &ep->event;
4423
4424 sps_event->xfer_done = NULL;
4425 sps_event->callback = NULL;
4426 sps_register_event(sps_pipe_handle, sps_event);
4427 sps_disconnect(sps_pipe_handle);
4428 dma_free_coherent(mmc_dev(host->mmc),
4429 sps_config->desc.size,
4430 sps_config->desc.base,
4431 sps_config->desc.phys_base);
4432 sps_free_endpoint(sps_pipe_handle);
4433}
4434
4435/**
4436 * Reset SDCC peripheral's SPS endpoint
4437 *
4438 * This function disconnects an endpoint.
4439 *
4440 * This function should be called for reseting
4441 * SPS endpoint when data transfer error is
4442 * encountered during data transfer. This
4443 * can be considered as soft reset to endpoint.
4444 *
4445 * This function should only be called if
4446 * msmsdcc_sps_init() is already called.
4447 *
4448 * @host - Pointer to sdcc host structure
4449 * @ep - Pointer to sps endpoint data structure
4450 *
4451 * @return - 0 if successful else negative value.
4452 */
4453static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
4454 struct msmsdcc_sps_ep_conn_data *ep)
4455{
4456 int rc = 0;
4457 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4458
4459 rc = sps_disconnect(sps_pipe_handle);
4460 if (rc) {
4461 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
4462 " rc=%d", mmc_hostname(host->mmc), __func__,
4463 (u32)sps_pipe_handle, rc);
4464 goto out;
4465 }
4466 out:
4467 return rc;
4468}
4469
4470/**
4471 * Restore SDCC peripheral's SPS endpoint
4472 *
4473 * This function connects an endpoint.
4474 *
4475 * This function should be called for restoring
4476 * SPS endpoint after data transfer error is
4477 * encountered during data transfer. This
4478 * can be considered as soft reset to endpoint.
4479 *
4480 * This function should only be called if
4481 * msmsdcc_sps_reset_ep() is called before.
4482 *
4483 * @host - Pointer to sdcc host structure
4484 * @ep - Pointer to sps endpoint data structure
4485 *
4486 * @return - 0 if successful else negative value.
4487 */
4488static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
4489 struct msmsdcc_sps_ep_conn_data *ep)
4490{
4491 int rc = 0;
4492 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4493 struct sps_connect *sps_config = &ep->config;
4494 struct sps_register_event *sps_event = &ep->event;
4495
4496 /* Establish connection between peripheral and memory endpoint */
4497 rc = sps_connect(sps_pipe_handle, sps_config);
4498 if (rc) {
4499 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
4500 " rc=%d", mmc_hostname(host->mmc), __func__,
4501 (u32)sps_pipe_handle, rc);
4502 goto out;
4503 }
4504
4505 /* Register callback event for EOT (End of transfer) event. */
4506 rc = sps_register_event(sps_pipe_handle, sps_event);
4507 if (rc) {
4508 pr_err("%s: %s: sps_register_event() failed!!!"
4509 " pipe_handle=0x%x, rc=%d",
4510 mmc_hostname(host->mmc), __func__,
4511 (u32)sps_pipe_handle, rc);
4512 goto reg_event_err;
4513 }
4514 goto out;
4515
4516reg_event_err:
4517 sps_disconnect(sps_pipe_handle);
4518out:
4519 return rc;
4520}
4521
4522/**
Krishna Konda5af8f972012-05-14 16:15:24 -07004523 * Handle BAM device's global error condition
4524 *
4525 * This is an error handler for the SDCC bam device
4526 *
4527 * This function is registered as a callback with SPS-BAM
4528 * driver and will called in case there are an errors for
4529 * the SDCC BAM deivce. Any error conditions in the BAM
4530 * device are global and will be result in this function
4531 * being called once per device.
4532 *
4533 * This function will be called from the sps driver's
4534 * interrupt context.
4535 *
4536 * @sps_cb_case - indicates what error it is
4537 * @user - Pointer to sdcc host structure
4538 */
4539static void
4540msmsdcc_sps_bam_global_irq_cb(enum sps_callback_case sps_cb_case, void *user)
4541{
4542 struct msmsdcc_host *host = (struct msmsdcc_host *)user;
4543 struct mmc_request *mrq;
4544 unsigned long flags;
4545 int32_t error = 0;
4546
4547 BUG_ON(!host);
4548 BUG_ON(!is_sps_mode(host));
4549
4550 if (sps_cb_case == SPS_CALLBACK_BAM_ERROR_IRQ) {
4551 /**
4552 * Reset the all endpoints along with reseting the sps device.
4553 */
4554 host->sps.pipe_reset_pending = true;
4555 host->sps.reset_device = true;
4556
4557 pr_err("%s: BAM Global ERROR IRQ happened\n",
4558 mmc_hostname(host->mmc));
4559 error = EAGAIN;
4560 } else if (sps_cb_case == SPS_CALLBACK_BAM_HRESP_ERR_IRQ) {
4561 /**
4562 * This means that there was an AHB access error and
4563 * the address we are trying to read/write is something
4564 * we dont have priviliges to do so.
4565 */
4566 pr_err("%s: BAM HRESP_ERR_IRQ happened\n",
4567 mmc_hostname(host->mmc));
4568 error = EACCES;
4569 } else {
4570 /**
4571 * This should not have happened ideally. If this happens
4572 * there is some seriously wrong.
4573 */
4574 pr_err("%s: BAM global IRQ callback received, type:%d\n",
4575 mmc_hostname(host->mmc), (u32) sps_cb_case);
4576 error = EIO;
4577 }
4578
4579 spin_lock_irqsave(&host->lock, flags);
4580
4581 mrq = host->curr.mrq;
4582
4583 if (mrq && mrq->cmd) {
4584 msmsdcc_dump_sdcc_state(host);
4585
4586 if (!mrq->cmd->error)
4587 mrq->cmd->error = -error;
4588 if (host->curr.data) {
4589 if (mrq->data && !mrq->data->error)
4590 mrq->data->error = -error;
4591 host->curr.data_xfered = 0;
4592 if (host->sps.sg && is_sps_mode(host)) {
4593 /* Stop current SPS transfer */
4594 msmsdcc_sps_exit_curr_xfer(host);
4595 } else {
4596 /* this condition should not have happened */
4597 pr_err("%s: something is seriously wrong. "\
4598 "Funtion: %s, line: %d\n",
4599 mmc_hostname(host->mmc),
4600 __func__, __LINE__);
4601 }
4602 } else {
4603 /* this condition should not have happened */
4604 pr_err("%s: something is seriously wrong. Funtion: "\
4605 "%s, line: %d\n", mmc_hostname(host->mmc),
4606 __func__, __LINE__);
4607 }
4608 }
4609 spin_unlock_irqrestore(&host->lock, flags);
4610}
4611
4612/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004613 * Initialize SPS HW connected with SDCC core
4614 *
4615 * This function register BAM HW resources with
4616 * SPS driver and then initialize 2 SPS endpoints
4617 *
4618 * This function should only be called once typically
4619 * during driver probe.
4620 *
4621 * @host - Pointer to sdcc host structure
4622 *
4623 * @return - 0 if successful else negative value.
4624 *
4625 */
4626static int msmsdcc_sps_init(struct msmsdcc_host *host)
4627{
4628 int rc = 0;
4629 struct sps_bam_props bam = {0};
4630
4631 host->bam_base = ioremap(host->bam_memres->start,
4632 resource_size(host->bam_memres));
4633 if (!host->bam_base) {
4634 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
4635 " size=0x%x", mmc_hostname(host->mmc),
4636 host->bam_memres->start,
4637 (host->bam_memres->end -
4638 host->bam_memres->start));
4639 rc = -ENOMEM;
4640 goto out;
4641 }
4642
4643 bam.phys_addr = host->bam_memres->start;
4644 bam.virt_addr = host->bam_base;
4645 /*
4646 * This event thresold value is only significant for BAM-to-BAM
4647 * transfer. It's ignored for BAM-to-System mode transfer.
4648 */
4649 bam.event_threshold = 0x10; /* Pipe event threshold */
4650 /*
4651 * This threshold controls when the BAM publish
4652 * the descriptor size on the sideband interface.
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304653 * SPS HW will be used for data transfer size even
4654 * less than SDCC FIFO size. So let's set BAM summing
4655 * thresold to SPS_MIN_XFER_SIZE bytes.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004656 */
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304657 bam.summing_threshold = SPS_MIN_XFER_SIZE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004658 /* SPS driver wll handle the SDCC BAM IRQ */
4659 bam.irq = (u32)host->bam_irqres->start;
4660 bam.manage = SPS_BAM_MGR_LOCAL;
Krishna Konda5af8f972012-05-14 16:15:24 -07004661 bam.callback = msmsdcc_sps_bam_global_irq_cb;
4662 bam.user = (void *)host;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004663
4664 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
4665 (u32)bam.phys_addr);
4666 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
4667 (u32)bam.virt_addr);
4668
4669 /* Register SDCC Peripheral BAM device to SPS driver */
4670 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
4671 if (rc) {
4672 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
4673 mmc_hostname(host->mmc), rc);
4674 goto reg_bam_err;
4675 }
4676 pr_info("%s: BAM device registered. bam_handle=0x%x",
4677 mmc_hostname(host->mmc), host->sps.bam_handle);
4678
4679 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
4680 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
4681
4682 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
4683 SPS_PROD_PERIPHERAL);
4684 if (rc)
4685 goto sps_reset_err;
4686 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
4687 SPS_CONS_PERIPHERAL);
4688 if (rc)
4689 goto cons_conn_err;
4690
4691 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
4692 mmc_hostname(host->mmc),
4693 (unsigned long long)host->bam_memres->start,
4694 (unsigned int)host->bam_irqres->start);
4695 goto out;
4696
4697cons_conn_err:
4698 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4699sps_reset_err:
4700 sps_deregister_bam_device(host->sps.bam_handle);
4701reg_bam_err:
4702 iounmap(host->bam_base);
4703out:
4704 return rc;
4705}
4706
4707/**
4708 * De-initialize SPS HW connected with SDCC core
4709 *
4710 * This function deinitialize SPS endpoints and then
4711 * deregisters BAM resources from SPS driver.
4712 *
4713 * This function should only be called once typically
4714 * during driver remove.
4715 *
4716 * @host - Pointer to sdcc host structure
4717 *
4718 */
4719static void msmsdcc_sps_exit(struct msmsdcc_host *host)
4720{
4721 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
4722 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4723 sps_deregister_bam_device(host->sps.bam_handle);
4724 iounmap(host->bam_base);
4725}
4726#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
4727
4728static ssize_t
4729show_polling(struct device *dev, struct device_attribute *attr, char *buf)
4730{
4731 struct mmc_host *mmc = dev_get_drvdata(dev);
4732 struct msmsdcc_host *host = mmc_priv(mmc);
4733 int poll;
4734 unsigned long flags;
4735
4736 spin_lock_irqsave(&host->lock, flags);
4737 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
4738 spin_unlock_irqrestore(&host->lock, flags);
4739
4740 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
4741}
4742
4743static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05304744store_polling(struct device *dev, struct device_attribute *attr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004745 const char *buf, size_t count)
4746{
4747 struct mmc_host *mmc = dev_get_drvdata(dev);
4748 struct msmsdcc_host *host = mmc_priv(mmc);
4749 int value;
4750 unsigned long flags;
4751
4752 sscanf(buf, "%d", &value);
4753
4754 spin_lock_irqsave(&host->lock, flags);
4755 if (value) {
4756 mmc->caps |= MMC_CAP_NEEDS_POLL;
4757 mmc_detect_change(host->mmc, 0);
4758 } else {
4759 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4760 }
4761#ifdef CONFIG_HAS_EARLYSUSPEND
4762 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
4763#endif
4764 spin_unlock_irqrestore(&host->lock, flags);
4765 return count;
4766}
4767
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304768static ssize_t
4769show_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
4770 char *buf)
4771{
4772 struct mmc_host *mmc = dev_get_drvdata(dev);
4773 struct msmsdcc_host *host = mmc_priv(mmc);
4774
4775 return snprintf(buf, PAGE_SIZE, "%u\n",
4776 host->msm_bus_vote.is_max_bw_needed);
4777}
4778
4779static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05304780store_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304781 const char *buf, size_t count)
4782{
4783 struct mmc_host *mmc = dev_get_drvdata(dev);
4784 struct msmsdcc_host *host = mmc_priv(mmc);
4785 uint32_t value;
4786 unsigned long flags;
4787
4788 if (!kstrtou32(buf, 0, &value)) {
4789 spin_lock_irqsave(&host->lock, flags);
4790 host->msm_bus_vote.is_max_bw_needed = !!value;
4791 spin_unlock_irqrestore(&host->lock, flags);
4792 }
4793
4794 return count;
4795}
4796
Pratibhasagar V13d1d032012-07-09 20:12:38 +05304797static ssize_t
4798show_idle_timeout(struct device *dev, struct device_attribute *attr,
4799 char *buf)
4800{
4801 struct mmc_host *mmc = dev_get_drvdata(dev);
4802 struct msmsdcc_host *host = mmc_priv(mmc);
4803
4804 return snprintf(buf, PAGE_SIZE, "%u (Min 5 sec)\n",
4805 host->idle_tout_ms / 1000);
4806}
4807
4808static ssize_t
4809store_idle_timeout(struct device *dev, struct device_attribute *attr,
4810 const char *buf, size_t count)
4811{
4812 struct mmc_host *mmc = dev_get_drvdata(dev);
4813 struct msmsdcc_host *host = mmc_priv(mmc);
4814 unsigned int long flags;
4815 int timeout; /* in secs */
4816
4817 if (!kstrtou32(buf, 0, &timeout)
4818 && (timeout > MSM_MMC_DEFAULT_IDLE_TIMEOUT / 1000)) {
4819 spin_lock_irqsave(&host->lock, flags);
4820 host->idle_tout_ms = timeout * 1000;
4821 spin_unlock_irqrestore(&host->lock, flags);
4822 }
4823 return count;
4824}
4825
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004826#ifdef CONFIG_HAS_EARLYSUSPEND
4827static void msmsdcc_early_suspend(struct early_suspend *h)
4828{
4829 struct msmsdcc_host *host =
4830 container_of(h, struct msmsdcc_host, early_suspend);
4831 unsigned long flags;
4832
4833 spin_lock_irqsave(&host->lock, flags);
4834 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
4835 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4836 spin_unlock_irqrestore(&host->lock, flags);
4837};
4838static void msmsdcc_late_resume(struct early_suspend *h)
4839{
4840 struct msmsdcc_host *host =
4841 container_of(h, struct msmsdcc_host, early_suspend);
4842 unsigned long flags;
4843
4844 if (host->polling_enabled) {
4845 spin_lock_irqsave(&host->lock, flags);
4846 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
4847 mmc_detect_change(host->mmc, 0);
4848 spin_unlock_irqrestore(&host->lock, flags);
4849 }
4850};
4851#endif
4852
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304853static void msmsdcc_print_regs(const char *name, void __iomem *base,
4854 u32 phys_base, unsigned int no_of_regs)
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304855{
4856 unsigned int i;
4857
4858 if (!base)
4859 return;
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304860
4861 pr_info("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
4862 " =====\n", name, phys_base, (u32)base);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304863 for (i = 0; i < no_of_regs; i = i + 4) {
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304864 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
4865 (u32)readl_relaxed(base + i*4),
4866 (u32)readl_relaxed(base + ((i+1)*4)),
4867 (u32)readl_relaxed(base + ((i+2)*4)),
4868 (u32)readl_relaxed(base + ((i+3)*4)));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304869 }
4870}
4871
4872static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
4873{
4874 /* Dump current state of SDCC clocks, power and irq */
4875 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304876 (host->pwr ? "ON" : "OFF"));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304877 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304878 mmc_hostname(host->mmc),
4879 (atomic_read(&host->clks_on) ? "ON" : "OFF"),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304880 (u32)clk_get_rate(host->clk));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304881 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
4882 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
4883
4884 /* Now dump SDCC registers. Don't print FIFO registers */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304885 if (atomic_read(&host->clks_on))
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304886 msmsdcc_print_regs("SDCC-CORE", host->base,
4887 host->core_memres->start, 28);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304888
4889 if (host->curr.data) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304890 if (!msmsdcc_is_dma_possible(host, host->curr.data))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304891 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304892 else if (is_dma_mode(host))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304893 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
4894 mmc_hostname(host->mmc), host->dma.busy,
4895 host->dma.channel, host->dma.crci);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304896 else if (is_sps_mode(host)) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304897 if (host->sps.busy && atomic_read(&host->clks_on))
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304898 msmsdcc_print_regs("SDCC-DML", host->dml_base,
4899 host->dml_memres->start,
4900 16);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304901 pr_info("%s: SPS mode: busy=%d\n",
4902 mmc_hostname(host->mmc), host->sps.busy);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304903 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304904
4905 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
4906 mmc_hostname(host->mmc), host->curr.xfer_size,
4907 host->curr.data_xfered, host->curr.xfer_remain);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304908 }
4909
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304910 pr_info("%s: got_dataend=%d, prog_enable=%d,"
Subhash Jadavani8706ced2012-05-25 16:09:21 +05304911 " wait_for_auto_prog_done=%d, got_auto_prog_done=%d,"
4912 " req_tout_ms=%d\n", mmc_hostname(host->mmc),
4913 host->curr.got_dataend, host->prog_enable,
4914 host->curr.wait_for_auto_prog_done,
4915 host->curr.got_auto_prog_done, host->curr.req_tout_ms);
subhashj245831e2012-04-30 18:46:17 +05304916 msmsdcc_print_rpm_info(host);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304917}
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304918
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004919static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
4920{
4921 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4922 struct mmc_request *mrq;
4923 unsigned long flags;
4924
4925 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004926 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004927 pr_info("%s: %s: dummy CMD52 timeout\n",
4928 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004929 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004930 }
4931
4932 mrq = host->curr.mrq;
4933
4934 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304935 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
4936 mrq->cmd->opcode);
4937 msmsdcc_dump_sdcc_state(host);
4938
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004939 if (!mrq->cmd->error)
4940 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304941 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004942 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004943 if (mrq->data && !mrq->data->error)
4944 mrq->data->error = -ETIMEDOUT;
4945 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304946 if (host->dma.sg && is_dma_mode(host)) {
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07004947 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304948 } else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004949 /* Stop current SPS transfer */
4950 msmsdcc_sps_exit_curr_xfer(host);
4951 } else {
4952 msmsdcc_reset_and_restore(host);
4953 msmsdcc_stop_data(host);
4954 if (mrq->data && mrq->data->stop)
4955 msmsdcc_start_command(host,
4956 mrq->data->stop, 0);
4957 else
4958 msmsdcc_request_end(host, mrq);
4959 }
4960 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304961 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05304962 host->curr.wait_for_auto_prog_done = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004963 msmsdcc_reset_and_restore(host);
4964 msmsdcc_request_end(host, mrq);
4965 }
4966 }
4967 spin_unlock_irqrestore(&host->lock, flags);
4968}
4969
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05304970/*
4971 * msmsdcc_dt_get_array - Wrapper fn to read an array of 32 bit integers
4972 *
4973 * @dev: device node from which the property value is to be read.
4974 * @prop_name: name of the property to be searched.
4975 * @out_array: filled array returned to caller
4976 * @len: filled array size returned to caller
4977 * @size: expected size of the array
4978 *
4979 * If expected "size" doesn't match with "len" an error is returned. If
4980 * expected size is zero, the length of actual array is returned provided
4981 * return value is zero.
4982 *
4983 * RETURNS:
4984 * zero on success, negative error if failed.
4985 */
4986static int msmsdcc_dt_get_array(struct device *dev, const char *prop_name,
4987 u32 **out_array, int *len, int size)
4988{
4989 int ret = 0;
4990 u32 *array = NULL;
4991 struct device_node *np = dev->of_node;
4992
4993 if (of_get_property(np, prop_name, len)) {
4994 size_t sz;
4995 sz = *len = *len / sizeof(*array);
4996
4997 if (sz > 0 && !(size > 0 && (sz != size))) {
4998 array = devm_kzalloc(dev, sz * sizeof(*array),
4999 GFP_KERNEL);
5000 if (!array) {
5001 dev_err(dev, "%s: no memory\n", prop_name);
5002 ret = -ENOMEM;
5003 goto out;
5004 }
5005
5006 ret = of_property_read_u32_array(np, prop_name,
5007 array, sz);
5008 if (ret < 0) {
5009 dev_err(dev, "%s: error reading array %d\n",
5010 prop_name, ret);
5011 goto out;
5012 }
5013 } else {
5014 dev_err(dev, "%s invalid size\n", prop_name);
5015 ret = -EINVAL;
5016 goto out;
5017 }
5018 } else {
5019 dev_err(dev, "%s not specified\n", prop_name);
5020 ret = -EINVAL;
5021 goto out;
5022 }
5023 *out_array = array;
5024out:
5025 if (ret)
5026 *len = 0;
5027 return ret;
5028}
5029
5030static int msmsdcc_dt_get_pad_pull_info(struct device *dev, int id,
5031 struct msm_mmc_pad_pull_data **pad_pull_data)
5032{
5033 int ret = 0, base = 0, len, i;
5034 u32 *tmp;
5035 struct msm_mmc_pad_pull_data *pull_data;
5036 struct msm_mmc_pad_pull *pull;
5037
5038 switch (id) {
5039 case 1:
5040 base = TLMM_PULL_SDC1_CLK;
5041 break;
5042 case 2:
5043 base = TLMM_PULL_SDC2_CLK;
5044 break;
5045 case 3:
5046 base = TLMM_PULL_SDC3_CLK;
5047 break;
5048 case 4:
5049 base = TLMM_PULL_SDC4_CLK;
5050 break;
5051 default:
5052 dev_err(dev, "%s: Invalid slot id\n", __func__);
5053 ret = -EINVAL;
5054 goto err;
5055 }
5056
5057 pull_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_pull_data),
5058 GFP_KERNEL);
5059 if (!pull_data) {
5060 dev_err(dev, "No memory msm_mmc_pad_pull_data\n");
5061 ret = -ENOMEM;
5062 goto err;
5063 }
5064 pull_data->size = 3; /* array size for clk, cmd, data */
5065
5066 /* Allocate on, off configs for clk, cmd, data */
5067 pull = devm_kzalloc(dev, 2 * pull_data->size *\
5068 sizeof(struct msm_mmc_pad_pull), GFP_KERNEL);
5069 if (!pull) {
5070 dev_err(dev, "No memory for msm_mmc_pad_pull\n");
5071 ret = -ENOMEM;
5072 goto err;
5073 }
5074 pull_data->on = pull;
5075 pull_data->off = pull + pull_data->size;
5076
5077 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-pull-on",
5078 &tmp, &len, pull_data->size);
5079 if (!ret) {
5080 for (i = 0; i < len; i++) {
5081 pull_data->on[i].no = base + i;
5082 pull_data->on[i].val = tmp[i];
5083 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5084 i, pull_data->on[i].val);
5085 }
5086 } else {
5087 goto err;
5088 }
5089
5090 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-pull-off",
5091 &tmp, &len, pull_data->size);
5092 if (!ret) {
5093 for (i = 0; i < len; i++) {
5094 pull_data->off[i].no = base + i;
5095 pull_data->off[i].val = tmp[i];
5096 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5097 i, pull_data->off[i].val);
5098 }
5099 } else {
5100 goto err;
5101 }
5102
5103 *pad_pull_data = pull_data;
5104err:
5105 return ret;
5106}
5107
5108static int msmsdcc_dt_get_pad_drv_info(struct device *dev, int id,
5109 struct msm_mmc_pad_drv_data **pad_drv_data)
5110{
5111 int ret = 0, base = 0, len, i;
5112 u32 *tmp;
5113 struct msm_mmc_pad_drv_data *drv_data;
5114 struct msm_mmc_pad_drv *drv;
5115
5116 switch (id) {
5117 case 1:
5118 base = TLMM_HDRV_SDC1_CLK;
5119 break;
5120 case 2:
5121 base = TLMM_HDRV_SDC2_CLK;
5122 break;
5123 case 3:
5124 base = TLMM_HDRV_SDC3_CLK;
5125 break;
5126 case 4:
5127 base = TLMM_HDRV_SDC4_CLK;
5128 break;
5129 default:
5130 dev_err(dev, "%s: Invalid slot id\n", __func__);
5131 ret = -EINVAL;
5132 goto err;
5133 }
5134
5135 drv_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_drv_data),
5136 GFP_KERNEL);
5137 if (!drv_data) {
5138 dev_err(dev, "No memory for msm_mmc_pad_drv_data\n");
5139 ret = -ENOMEM;
5140 goto err;
5141 }
5142 drv_data->size = 3; /* array size for clk, cmd, data */
5143
5144 /* Allocate on, off configs for clk, cmd, data */
5145 drv = devm_kzalloc(dev, 2 * drv_data->size *\
5146 sizeof(struct msm_mmc_pad_drv), GFP_KERNEL);
5147 if (!drv) {
5148 dev_err(dev, "No memory msm_mmc_pad_drv\n");
5149 ret = -ENOMEM;
5150 goto err;
5151 }
5152 drv_data->on = drv;
5153 drv_data->off = drv + drv_data->size;
5154
5155 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-drv-on",
5156 &tmp, &len, drv_data->size);
5157 if (!ret) {
5158 for (i = 0; i < len; i++) {
5159 drv_data->on[i].no = base + i;
5160 drv_data->on[i].val = tmp[i];
5161 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5162 i, drv_data->on[i].val);
5163 }
5164 } else {
5165 goto err;
5166 }
5167
5168 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-drv-off",
5169 &tmp, &len, drv_data->size);
5170 if (!ret) {
5171 for (i = 0; i < len; i++) {
5172 drv_data->off[i].no = base + i;
5173 drv_data->off[i].val = tmp[i];
5174 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5175 i, drv_data->off[i].val);
5176 }
5177 } else {
5178 goto err;
5179 }
5180
5181 *pad_drv_data = drv_data;
5182err:
5183 return ret;
5184}
5185
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305186static void msmsdcc_dt_get_cd_wp_gpio(struct device *dev,
5187 struct mmc_platform_data *pdata)
5188{
5189 enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
5190 struct device_node *np = dev->of_node;
5191
5192 pdata->status_gpio = of_get_named_gpio_flags(np,
5193 "cd-gpios", 0, &flags);
5194 if (gpio_is_valid(pdata->status_gpio)) {
5195 pdata->status_irq = gpio_to_irq(pdata->status_gpio);
5196 pdata->is_status_gpio_active_low = flags & OF_GPIO_ACTIVE_LOW;
5197 }
5198
5199 pdata->wpswitch_gpio = of_get_named_gpio_flags(np,
5200 "wp-gpios", 0, &flags);
5201 if (gpio_is_valid(pdata->wpswitch_gpio))
5202 pdata->is_wpswitch_active_low = flags & OF_GPIO_ACTIVE_LOW;
5203}
5204
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305205static int msmsdcc_dt_parse_gpio_info(struct device *dev,
5206 struct mmc_platform_data *pdata)
5207{
5208 int ret = 0, id = 0, cnt, i;
5209 struct msm_mmc_pin_data *pin_data;
5210 struct device_node *np = dev->of_node;
5211
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305212 msmsdcc_dt_get_cd_wp_gpio(dev, pdata);
5213
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305214 pin_data = devm_kzalloc(dev, sizeof(*pin_data), GFP_KERNEL);
5215 if (!pin_data) {
5216 dev_err(dev, "No memory for pin_data\n");
5217 ret = -ENOMEM;
5218 goto err;
5219 }
5220
5221 cnt = of_gpio_count(np);
5222 if (cnt > 0) {
5223 pin_data->is_gpio = true;
5224
5225 pin_data->gpio_data = devm_kzalloc(dev,
5226 sizeof(struct msm_mmc_gpio_data), GFP_KERNEL);
5227 if (!pin_data->gpio_data) {
5228 dev_err(dev, "No memory for gpio_data\n");
5229 ret = -ENOMEM;
5230 goto err;
5231 }
5232 pin_data->gpio_data->size = cnt;
5233 pin_data->gpio_data->gpio = devm_kzalloc(dev,
5234 cnt * sizeof(struct msm_mmc_gpio), GFP_KERNEL);
5235 if (!pin_data->gpio_data->gpio) {
5236 dev_err(dev, "No memory for gpio\n");
5237 ret = -ENOMEM;
5238 goto err;
5239 }
5240
5241 for (i = 0; i < cnt; i++) {
5242 const char *name = NULL;
5243 char result[32];
5244 pin_data->gpio_data->gpio[i].no = of_get_gpio(np, i);
5245 of_property_read_string_index(np,
5246 "qcom,sdcc-gpio-names", i, &name);
5247
5248 snprintf(result, 32, "%s-%s",
5249 dev_name(dev), name ? name : "?");
5250 pin_data->gpio_data->gpio[i].name = result;
5251 dev_dbg(dev, "%s: gpio[%s] = %d\n", __func__,
5252 pin_data->gpio_data->gpio[i].name,
5253 pin_data->gpio_data->gpio[i].no);
5254 }
5255 } else {
5256 pin_data->pad_data = devm_kzalloc(dev,
5257 sizeof(struct msm_mmc_pad_data), GFP_KERNEL);
5258 if (!pin_data->pad_data) {
5259 dev_err(dev, "No memory for pin_data->pad_data\n");
5260 ret = -ENOMEM;
5261 goto err;
5262 }
5263
5264 of_property_read_u32(np, "cell-index", &id);
5265
5266 ret = msmsdcc_dt_get_pad_pull_info(dev, id,
5267 &pin_data->pad_data->pull);
5268 if (ret)
5269 goto err;
5270 ret = msmsdcc_dt_get_pad_drv_info(dev, id,
5271 &pin_data->pad_data->drv);
5272 if (ret)
5273 goto err;
5274 }
5275
5276 pdata->pin_data = pin_data;
5277err:
5278 if (ret)
5279 dev_err(dev, "%s failed with err %d\n", __func__, ret);
5280 return ret;
5281}
5282
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305283#define MAX_PROP_SIZE 32
5284static int msmsdcc_dt_parse_vreg_info(struct device *dev,
5285 struct msm_mmc_reg_data **vreg_data, const char *vreg_name)
5286{
5287 int len, ret = 0;
5288 const __be32 *prop;
5289 char prop_name[MAX_PROP_SIZE];
5290 struct msm_mmc_reg_data *vreg;
5291 struct device_node *np = dev->of_node;
5292
5293 snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", vreg_name);
5294 if (of_parse_phandle(np, prop_name, 0)) {
5295 vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
5296 if (!vreg) {
5297 dev_err(dev, "No memory for vreg: %s\n", vreg_name);
5298 ret = -ENOMEM;
5299 goto err;
5300 }
5301
5302 vreg->name = vreg_name;
5303
5304 snprintf(prop_name, MAX_PROP_SIZE,
5305 "qcom,sdcc-%s-always_on", vreg_name);
5306 if (of_get_property(np, prop_name, NULL))
5307 vreg->always_on = true;
5308
5309 snprintf(prop_name, MAX_PROP_SIZE,
5310 "qcom,sdcc-%s-lpm_sup", vreg_name);
5311 if (of_get_property(np, prop_name, NULL))
5312 vreg->lpm_sup = true;
5313
5314 snprintf(prop_name, MAX_PROP_SIZE,
5315 "qcom,sdcc-%s-voltage_level", vreg_name);
5316 prop = of_get_property(np, prop_name, &len);
5317 if (!prop || (len != (2 * sizeof(__be32)))) {
5318 dev_warn(dev, "%s %s property\n",
5319 prop ? "invalid format" : "no", prop_name);
5320 } else {
5321 vreg->low_vol_level = be32_to_cpup(&prop[0]);
5322 vreg->high_vol_level = be32_to_cpup(&prop[1]);
5323 }
5324
5325 snprintf(prop_name, MAX_PROP_SIZE,
5326 "qcom,sdcc-%s-current_level", vreg_name);
5327 prop = of_get_property(np, prop_name, &len);
5328 if (!prop || (len != (2 * sizeof(__be32)))) {
5329 dev_warn(dev, "%s %s property\n",
5330 prop ? "invalid format" : "no", prop_name);
5331 } else {
5332 vreg->lpm_uA = be32_to_cpup(&prop[0]);
5333 vreg->hpm_uA = be32_to_cpup(&prop[1]);
5334 }
5335
5336 *vreg_data = vreg;
5337 dev_dbg(dev, "%s: %s %s vol=[%d %d]uV, curr=[%d %d]uA\n",
5338 vreg->name, vreg->always_on ? "always_on," : "",
5339 vreg->lpm_sup ? "lpm_sup," : "", vreg->low_vol_level,
5340 vreg->high_vol_level, vreg->lpm_uA, vreg->hpm_uA);
5341 }
5342
5343err:
5344 return ret;
5345}
5346
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305347static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
5348{
5349 int i, ret;
5350 struct mmc_platform_data *pdata;
5351 struct device_node *np = dev->of_node;
Devin Kim9ccbff52012-07-16 20:55:14 -07005352 u32 bus_width = 0, current_limit = 0;
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305353 u32 *clk_table, *sup_voltages;
Devin Kim9ccbff52012-07-16 20:55:14 -07005354 int clk_table_len, sup_volt_len, len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305355
5356 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
5357 if (!pdata) {
5358 dev_err(dev, "could not allocate memory for platform data\n");
5359 goto err;
5360 }
5361
5362 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
5363 if (bus_width == 8) {
5364 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
5365 } else if (bus_width == 4) {
5366 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
5367 } else {
5368 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
5369 pdata->mmc_bus_width = 0;
5370 }
5371
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305372 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-sup-voltages",
5373 &sup_voltages, &sup_volt_len, 0);
5374 if (!ret) {
5375 for (i = 0; i < sup_volt_len; i += 2) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305376 u32 mask;
5377
5378 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
5379 sup_voltages[i + 1]);
5380 if (!mask)
5381 dev_err(dev, "Invalide voltage range %d\n", i);
5382 pdata->ocr_mask |= mask;
5383 }
5384 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305385 }
5386
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305387 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-clk-rates",
5388 &clk_table, &clk_table_len, 0);
5389 if (!ret) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305390 pdata->sup_clk_table = clk_table;
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305391 pdata->sup_clk_cnt = clk_table_len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305392 }
5393
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305394 pdata->vreg_data = devm_kzalloc(dev,
5395 sizeof(struct msm_mmc_slot_reg_data), GFP_KERNEL);
5396 if (!pdata->vreg_data) {
5397 dev_err(dev, "could not allocate memory for vreg_data\n");
5398 goto err;
5399 }
5400
5401 if (msmsdcc_dt_parse_vreg_info(dev,
5402 &pdata->vreg_data->vdd_data, "vdd"))
5403 goto err;
5404
5405 if (msmsdcc_dt_parse_vreg_info(dev,
5406 &pdata->vreg_data->vdd_io_data, "vdd-io"))
5407 goto err;
5408
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305409 if (msmsdcc_dt_parse_gpio_info(dev, pdata))
5410 goto err;
5411
Devin Kim9ccbff52012-07-16 20:55:14 -07005412 len = of_property_count_strings(np, "qcom,sdcc-bus-speed-mode");
5413
5414 for (i = 0; i < len; i++) {
5415 const char *name = NULL;
5416
5417 of_property_read_string_index(np,
5418 "qcom,sdcc-bus-speed-mode", i, &name);
5419 if (!name)
5420 continue;
5421
5422 if (!strncmp(name, "SDR12", sizeof("SDR12")))
5423 pdata->uhs_caps |= MMC_CAP_UHS_SDR12;
5424 else if (!strncmp(name, "SDR25", sizeof("SDR25")))
5425 pdata->uhs_caps |= MMC_CAP_UHS_SDR25;
5426 else if (!strncmp(name, "SDR50", sizeof("SDR50")))
5427 pdata->uhs_caps |= MMC_CAP_UHS_SDR50;
5428 else if (!strncmp(name, "DDR50", sizeof("DDR50")))
5429 pdata->uhs_caps |= MMC_CAP_UHS_DDR50;
5430 else if (!strncmp(name, "SDR104", sizeof("SDR104")))
5431 pdata->uhs_caps |= MMC_CAP_UHS_SDR104;
5432 else if (!strncmp(name, "HS200_1p8v", sizeof("HS200_1p8v")))
5433 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_8V_SDR;
5434 else if (!strncmp(name, "HS200_1p2v", sizeof("HS200_1p2v")))
5435 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_2V_SDR;
5436 else if (!strncmp(name, "DDR_1p8v", sizeof("DDR_1p8v")))
5437 pdata->uhs_caps |= MMC_CAP_1_8V_DDR
5438 | MMC_CAP_UHS_DDR50;
5439 else if (!strncmp(name, "DDR_1p2v", sizeof("DDR_1p2v")))
5440 pdata->uhs_caps |= MMC_CAP_1_2V_DDR
5441 | MMC_CAP_UHS_DDR50;
5442 }
5443
5444 of_property_read_u32(np, "qcom,sdcc-current-limit", &current_limit);
5445 if (current_limit == 800)
5446 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_800;
5447 else if (current_limit == 600)
5448 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_600;
5449 else if (current_limit == 400)
5450 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_400;
5451 else if (current_limit == 200)
5452 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_200;
5453
5454 if (of_get_property(np, "qcom,sdcc-xpc", NULL))
5455 pdata->xpc_cap = true;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305456 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
5457 pdata->nonremovable = true;
5458 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
5459 pdata->disable_cmd23 = true;
5460
5461 return pdata;
5462err:
5463 return NULL;
5464}
5465
San Mehat9d2bd732009-09-22 16:44:22 -07005466static int
5467msmsdcc_probe(struct platform_device *pdev)
5468{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305469 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07005470 struct msmsdcc_host *host;
5471 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005472 unsigned long flags;
5473 struct resource *core_irqres = NULL;
5474 struct resource *bam_irqres = NULL;
5475 struct resource *core_memres = NULL;
5476 struct resource *dml_memres = NULL;
5477 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07005478 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07005479 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05305480 int ret = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07005481
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305482 if (pdev->dev.of_node) {
5483 plat = msmsdcc_populate_pdata(&pdev->dev);
5484 of_property_read_u32((&pdev->dev)->of_node,
5485 "cell-index", &pdev->id);
5486 } else {
5487 plat = pdev->dev.platform_data;
5488 }
San Mehat9d2bd732009-09-22 16:44:22 -07005489
5490 /* must have platform data */
5491 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005492 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005493 ret = -EINVAL;
5494 goto out;
5495 }
5496
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005497 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07005498 return -EINVAL;
5499
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305500 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
5501 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
5502 return -EINVAL;
5503 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005504
San Mehat9d2bd732009-09-22 16:44:22 -07005505 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005506 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005507 return -ENXIO;
5508 }
5509
Sujit Reddy Thumma1dfac2c2012-07-30 10:15:39 +05305510 core_memres = platform_get_resource_byname(pdev,
5511 IORESOURCE_MEM, "core_mem");
5512 bam_memres = platform_get_resource_byname(pdev,
5513 IORESOURCE_MEM, "bam_mem");
5514 dml_memres = platform_get_resource_byname(pdev,
5515 IORESOURCE_MEM, "dml_mem");
5516 core_irqres = platform_get_resource_byname(pdev,
5517 IORESOURCE_IRQ, "core_irq");
5518 bam_irqres = platform_get_resource_byname(pdev,
5519 IORESOURCE_IRQ, "bam_irq");
5520 dmares = platform_get_resource_byname(pdev,
5521 IORESOURCE_DMA, "dma_chnl");
5522 dma_crci_res = platform_get_resource_byname(pdev,
5523 IORESOURCE_DMA, "dma_crci");
San Mehat9d2bd732009-09-22 16:44:22 -07005524
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005525 if (!core_irqres || !core_memres) {
5526 pr_err("%s: Invalid sdcc core resource\n", __func__);
5527 return -ENXIO;
5528 }
5529
5530 /*
5531 * Both BAM and DML memory resource should be preset.
5532 * BAM IRQ resource should also be present.
5533 */
5534 if ((bam_memres && !dml_memres) ||
5535 (!bam_memres && dml_memres) ||
5536 ((bam_memres && dml_memres) && !bam_irqres)) {
5537 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005538 return -ENXIO;
5539 }
5540
5541 /*
5542 * Setup our host structure
5543 */
San Mehat9d2bd732009-09-22 16:44:22 -07005544 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
5545 if (!mmc) {
5546 ret = -ENOMEM;
5547 goto out;
5548 }
5549
5550 host = mmc_priv(mmc);
5551 host->pdev_id = pdev->id;
5552 host->plat = plat;
5553 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08005554 host->curr.cmd = NULL;
Sahitya Tummala19207f02011-05-02 18:10:01 +05305555
Sahitya Tummalad9df3272011-08-19 16:50:46 +05305556 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305557 set_hw_caps(host, MSMSDCC_SPS_BAM_SUP);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005558 else if (dmares)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305559 set_hw_caps(host, MSMSDCC_DMA_SUP);
San Mehat9d2bd732009-09-22 16:44:22 -07005560
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005561 host->base = ioremap(core_memres->start,
5562 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07005563 if (!host->base) {
5564 ret = -ENOMEM;
Sahitya Tummaladce7c752011-05-02 18:06:05 +05305565 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005566 }
5567
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005568 host->core_irqres = core_irqres;
5569 host->bam_irqres = bam_irqres;
5570 host->core_memres = core_memres;
5571 host->dml_memres = dml_memres;
5572 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07005573 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07005574 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07005575 spin_lock_init(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305576 mutex_init(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07005577
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005578#ifdef CONFIG_MMC_EMBEDDED_SDIO
5579 if (plat->embedded_sdio)
5580 mmc_set_embedded_sdio_data(mmc,
5581 &plat->embedded_sdio->cis,
5582 &plat->embedded_sdio->cccr,
5583 plat->embedded_sdio->funcs,
5584 plat->embedded_sdio->num_funcs);
5585#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005586
Sahitya Tummala62612cf2010-12-08 15:03:03 +05305587 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
5588 (unsigned long)host);
5589
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005590 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
5591 (unsigned long)host);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305592 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005593 /* Setup DMA */
Subhash Jadavani190657c2011-05-02 18:10:40 +05305594 ret = msmsdcc_init_dma(host);
5595 if (ret)
5596 goto ioremap_free;
5597 } else {
5598 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07005599 host->dma.crci = -1;
Subhash Jadavani190657c2011-05-02 18:10:40 +05305600 }
San Mehat9d2bd732009-09-22 16:44:22 -07005601
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005602 /*
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305603 * Setup SDCC bus voter clock.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005604 */
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305605 host->bus_clk = clk_get(&pdev->dev, "bus_clk");
5606 if (!IS_ERR_OR_NULL(host->bus_clk)) {
5607 /* Vote for max. clk rate for max. performance */
5608 ret = clk_set_rate(host->bus_clk, INT_MAX);
5609 if (ret)
5610 goto bus_clk_put;
5611 ret = clk_prepare_enable(host->bus_clk);
5612 if (ret)
5613 goto bus_clk_put;
San Mehat9d2bd732009-09-22 16:44:22 -07005614 }
5615
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005616 /*
5617 * Setup main peripheral bus clock
5618 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07005619 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005620 if (!IS_ERR(host->pclk)) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305621 ret = clk_prepare_enable(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005622 if (ret)
5623 goto pclk_put;
5624
5625 host->pclk_rate = clk_get_rate(host->pclk);
5626 }
5627
5628 /*
5629 * Setup SDC MMC clock
5630 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07005631 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07005632 if (IS_ERR(host->clk)) {
5633 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005634 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07005635 }
5636
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005637 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
Sahitya Tummala514d9ed2011-05-02 18:07:01 +05305638 if (ret) {
5639 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
5640 goto clk_put;
5641 }
5642
Asutosh Dasf5298c32012-04-03 14:51:47 +05305643 ret = clk_prepare_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07005644 if (ret)
5645 goto clk_put;
5646
San Mehat9d2bd732009-09-22 16:44:22 -07005647 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05305648 if (!host->clk_rate)
5649 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05305650
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305651 set_default_hw_caps(host);
5652
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05305653 /*
5654 * Set the register write delay according to min. clock frequency
5655 * supported and update later when the host->clk_rate changes.
5656 */
5657 host->reg_write_delay =
5658 (1 + ((3 * USEC_PER_SEC) /
5659 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005660
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305661 atomic_set(&host->clks_on, 1);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05305662 /* Apply Hard reset to SDCC to put it in power on default state */
5663 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005664
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005665#define MSM_MMC_DEFAULT_CPUDMA_LATENCY 200 /* usecs */
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305666 /* pm qos request to prevent apps idle power collapse */
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005667 if (host->plat->cpu_dma_latency)
5668 host->cpu_dma_latency = host->plat->cpu_dma_latency;
5669 else
5670 host->cpu_dma_latency = MSM_MMC_DEFAULT_CPUDMA_LATENCY;
5671 pm_qos_add_request(&host->pm_qos_req_dma,
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305672 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
5673
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305674 ret = msmsdcc_msm_bus_register(host);
5675 if (ret)
5676 goto pm_qos_remove;
5677
5678 if (host->msm_bus_vote.client_handle)
5679 INIT_DELAYED_WORK(&host->msm_bus_vote.vote_work,
5680 msmsdcc_msm_bus_work);
5681
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005682 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07005683 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005684 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07005685 goto clk_disable;
5686 }
5687
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005688
5689 /* Clocks has to be running before accessing SPS/DML HW blocks */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305690 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005691 /* Initialize SPS */
5692 ret = msmsdcc_sps_init(host);
5693 if (ret)
5694 goto vreg_deinit;
5695 /* Initialize DML */
5696 ret = msmsdcc_dml_init(host);
5697 if (ret)
5698 goto sps_exit;
5699 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05305700 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07005701
San Mehat9d2bd732009-09-22 16:44:22 -07005702 /*
5703 * Setup MMC host structure
5704 */
5705 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005706 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
5707 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005708 mmc->ocr_avail = plat->ocr_mask;
Sujit Reddy Thumma0e05f022012-06-11 19:44:18 +05305709 mmc->clkgate_delay = MSM_MMC_CLK_GATE_DELAY;
5710
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005711 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
5712 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07005713 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05305714 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
Asutosh Dasebd7d092012-07-09 19:08:26 +05305715 mmc->caps |= MMC_CAP_HW_RESET;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05305716 /*
5717 * If we send the CMD23 before multi block write/read command
5718 * then we need not to send CMD12 at the end of the transfer.
5719 * If we don't send the CMD12 then only way to detect the PROG_DONE
5720 * status is to use the AUTO_PROG_DONE status provided by SDCC4
5721 * controller. So let's enable the CMD23 for SDCC4 only.
5722 */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305723 if (!plat->disable_cmd23 && is_auto_prog_done(host))
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05305724 mmc->caps |= MMC_CAP_CMD23;
San Mehat9d2bd732009-09-22 16:44:22 -07005725
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005726 mmc->caps |= plat->uhs_caps;
Devin Kim9ccbff52012-07-16 20:55:14 -07005727 mmc->caps2 |= plat->uhs_caps2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005728 /*
5729 * XPC controls the maximum current in the default speed mode of SDXC
5730 * card. XPC=0 means 100mA (max.) but speed class is not supported.
5731 * XPC=1 means 150mA (max.) and speed class is supported.
5732 */
5733 if (plat->xpc_cap)
5734 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
5735 MMC_CAP_SET_XPC_180);
5736
Devin Kim9b67ee02012-07-16 21:13:05 -07005737 /* packed write */
5738 mmc->caps2 |= plat->packed_write;
5739
Subhash Jadavani6bb34a82012-04-18 13:18:40 +05305740 mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
Yaniv Gardi14098552012-06-04 10:56:03 +03005741 mmc->caps2 |= MMC_CAP2_SANITIZE;
5742
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005743 if (plat->nonremovable)
5744 mmc->caps |= MMC_CAP_NONREMOVABLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005745 mmc->caps |= MMC_CAP_SDIO_IRQ;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005746
Konstantin Dorfman9db69fc2012-06-01 14:04:45 +03005747 mmc->caps2 |= MMC_CAP2_INIT_BKOPS | MMC_CAP2_BKOPS;
5748
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005749 if (plat->is_sdio_al_client)
5750 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07005751
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305752 mmc->max_segs = msmsdcc_get_nr_sg(host);
5753 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
5754 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07005755
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305756 mmc->max_req_size = MMC_MAX_REQ_SIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07005757 mmc->max_seg_size = mmc->max_req_size;
5758
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005759 writel_relaxed(0, host->base + MMCIMASK0);
5760 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05305761 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005762
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005763 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
5764 mb();
5765 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07005766
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005767 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
5768 DRIVER_NAME " (cmd)", host);
5769 if (ret)
5770 goto dml_exit;
5771
5772 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
5773 DRIVER_NAME " (pio)", host);
5774 if (ret)
5775 goto irq_free;
5776
5777 /*
5778 * Enable SDCC IRQ only when host is powered on. Otherwise, this
5779 * IRQ is un-necessarily being monitored by MPM (Modem power
5780 * management block) during idle-power collapse. The MPM will be
5781 * configured to monitor the DATA1 GPIO line with level-low trigger
5782 * and thus depending on the GPIO status, it prevents TCXO shutdown
5783 * during idle-power collapse.
5784 */
5785 disable_irq(core_irqres->start);
5786 host->sdcc_irq_disabled = 1;
5787
5788 if (plat->sdiowakeup_irq) {
5789 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5790 mmc_hostname(mmc));
5791 ret = request_irq(plat->sdiowakeup_irq,
5792 msmsdcc_platform_sdiowakeup_irq,
5793 IRQF_SHARED | IRQF_TRIGGER_LOW,
5794 DRIVER_NAME "sdiowakeup", host);
5795 if (ret) {
5796 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
5797 plat->sdiowakeup_irq, ret);
5798 goto pio_irq_free;
5799 } else {
5800 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305801 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005802 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305803 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005804 }
5805 spin_unlock_irqrestore(&host->lock, flags);
5806 }
5807 }
5808
Subhash Jadavanic9b85752012-04-13 11:16:49 +05305809 if (host->plat->mpm_sdiowakeup_int) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005810 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5811 mmc_hostname(mmc));
5812 }
5813
5814 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
5815 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005816 /*
5817 * Setup card detect change
5818 */
5819
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305820 if (!plat->status_gpio)
5821 plat->status_gpio = -ENOENT;
5822 if (!plat->wpswitch_gpio)
5823 plat->wpswitch_gpio = -ENOENT;
5824
5825 if (plat->status || gpio_is_valid(plat->status_gpio)) {
Krishna Konda941604a2012-01-10 17:46:34 -08005826 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005827 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08005828 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005829 host->oldstat = msmsdcc_slot_status(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005830
Krishna Konda941604a2012-01-10 17:46:34 -08005831 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005832 }
San Mehat9d2bd732009-09-22 16:44:22 -07005833
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005834 if (plat->status_irq) {
5835 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07005836 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005837 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07005838 DRIVER_NAME " (slot)",
5839 host);
5840 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005841 pr_err("Unable to get slot IRQ %d (%d)\n",
5842 plat->status_irq, ret);
5843 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005844 }
5845 } else if (plat->register_status_notify) {
5846 plat->register_status_notify(msmsdcc_status_notify_cb, host);
5847 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005848 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07005849 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005850
5851 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005852
5853 ret = pm_runtime_set_active(&(pdev)->dev);
5854 if (ret < 0)
5855 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
5856 __func__, ret);
5857 /*
5858 * There is no notion of suspend/resume for SD/MMC/SDIO
5859 * cards. So host can be suspended/resumed with out
5860 * worrying about its children.
5861 */
5862 pm_suspend_ignore_children(&(pdev)->dev, true);
5863
5864 /*
5865 * MMC/SD/SDIO bus suspend/resume operations are defined
5866 * only for the slots that will be used for non-removable
5867 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
5868 * defined. Otherwise, they simply become card removal and
5869 * insertion events during suspend and resume respectively.
5870 * Hence, enable run-time PM only for slots for which bus
5871 * suspend/resume operations are defined.
5872 */
5873#ifdef CONFIG_MMC_UNSAFE_RESUME
5874 /*
5875 * If this capability is set, MMC core will enable/disable host
5876 * for every claim/release operation on a host. We use this
5877 * notification to increment/decrement runtime pm usage count.
5878 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005879 pm_runtime_enable(&(pdev)->dev);
5880#else
5881 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005882 pm_runtime_enable(&(pdev)->dev);
5883 }
5884#endif
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305885 host->idle_tout_ms = MSM_MMC_DEFAULT_IDLE_TIMEOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005886 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
5887 (unsigned long)host);
5888
San Mehat9d2bd732009-09-22 16:44:22 -07005889 mmc_add_host(mmc);
5890
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005891#ifdef CONFIG_HAS_EARLYSUSPEND
5892 host->early_suspend.suspend = msmsdcc_early_suspend;
5893 host->early_suspend.resume = msmsdcc_late_resume;
5894 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
5895 register_early_suspend(&host->early_suspend);
5896#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005897
Krishna Konda25786ec2011-07-25 16:21:36 -07005898 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
5899 " dmacrcri %d\n", mmc_hostname(mmc),
5900 (unsigned long long)core_memres->start,
5901 (unsigned int) core_irqres->start,
5902 (unsigned int) plat->status_irq, host->dma.channel,
5903 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005904
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305905 pr_info("%s: Controller capabilities: 0x%.8x\n",
5906 mmc_hostname(mmc), host->hw_caps);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005907 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
5908 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
5909 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
5910 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
5911 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
5912 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
5913 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
5914 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
5915 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
5916 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
5917 host->eject);
5918 pr_info("%s: Power save feature enable = %d\n",
5919 mmc_hostname(mmc), msmsdcc_pwrsave);
5920
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305921 if (is_dma_mode(host) && host->dma.channel != -1
Krishna Konda25786ec2011-07-25 16:21:36 -07005922 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005923 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005924 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005925 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005926 mmc_hostname(mmc), host->dma.cmd_busaddr,
5927 host->dma.cmdptr_busaddr);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305928 } else if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005929 pr_info("%s: SPS-BAM data transfer mode available\n",
5930 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005931 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005932 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005933
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005934#if defined(CONFIG_DEBUG_FS)
5935 msmsdcc_dbg_createhost(host);
5936#endif
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305937
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305938 host->max_bus_bw.show = show_sdcc_to_mem_max_bus_bw;
5939 host->max_bus_bw.store = store_sdcc_to_mem_max_bus_bw;
5940 sysfs_attr_init(&host->max_bus_bw.attr);
5941 host->max_bus_bw.attr.name = "max_bus_bw";
5942 host->max_bus_bw.attr.mode = S_IRUGO | S_IWUSR;
5943 ret = device_create_file(&pdev->dev, &host->max_bus_bw);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305944 if (ret)
5945 goto platform_irq_free;
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305946
5947 if (!plat->status_irq) {
5948 host->polling.show = show_polling;
5949 host->polling.store = store_polling;
5950 sysfs_attr_init(&host->polling.attr);
5951 host->polling.attr.name = "polling";
5952 host->polling.attr.mode = S_IRUGO | S_IWUSR;
5953 ret = device_create_file(&pdev->dev, &host->polling);
5954 if (ret)
5955 goto remove_max_bus_bw_file;
5956 }
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305957 host->idle_timeout.show = show_idle_timeout;
5958 host->idle_timeout.store = store_idle_timeout;
5959 sysfs_attr_init(&host->idle_timeout.attr);
5960 host->idle_timeout.attr.name = "idle_timeout";
5961 host->idle_timeout.attr.mode = S_IRUGO | S_IWUSR;
5962 ret = device_create_file(&pdev->dev, &host->idle_timeout);
5963 if (ret)
5964 goto remove_polling_file;
San Mehat9d2bd732009-09-22 16:44:22 -07005965 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005966
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305967 remove_polling_file:
5968 if (!plat->status_irq)
5969 device_remove_file(&pdev->dev, &host->polling);
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305970 remove_max_bus_bw_file:
5971 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005972 platform_irq_free:
5973 del_timer_sync(&host->req_tout_timer);
5974 pm_runtime_disable(&(pdev)->dev);
5975 pm_runtime_set_suspended(&(pdev)->dev);
5976
5977 if (plat->status_irq)
5978 free_irq(plat->status_irq, host);
5979 sdiowakeup_irq_free:
5980 wake_lock_destroy(&host->sdio_suspend_wlock);
5981 if (plat->sdiowakeup_irq)
5982 free_irq(plat->sdiowakeup_irq, host);
5983 pio_irq_free:
5984 if (plat->sdiowakeup_irq)
5985 wake_lock_destroy(&host->sdio_wlock);
5986 free_irq(core_irqres->start, host);
5987 irq_free:
5988 free_irq(core_irqres->start, host);
5989 dml_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305990 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005991 msmsdcc_dml_exit(host);
5992 sps_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305993 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005994 msmsdcc_sps_exit(host);
5995 vreg_deinit:
5996 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07005997 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005998 clk_disable(host->clk);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305999 msmsdcc_msm_bus_unregister(host);
6000 pm_qos_remove:
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006001 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306002 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07006003 clk_put:
6004 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006005 pclk_disable:
6006 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05306007 clk_disable_unprepare(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07006008 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006009 if (!IS_ERR(host->pclk))
6010 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05306011 if (!IS_ERR_OR_NULL(host->bus_clk))
6012 clk_disable_unprepare(host->bus_clk);
6013 bus_clk_put:
6014 if (!IS_ERR_OR_NULL(host->bus_clk))
6015 clk_put(host->bus_clk);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306016 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006017 if (host->dmares)
6018 dma_free_coherent(NULL,
6019 sizeof(struct msmsdcc_nc_dmadata),
6020 host->dma.nc, host->dma.nc_busaddr);
6021 }
6022 ioremap_free:
Sahitya Tummaladce7c752011-05-02 18:06:05 +05306023 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07006024 host_free:
6025 mmc_free_host(mmc);
6026 out:
6027 return ret;
6028}
6029
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006030static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07006031{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006032 struct mmc_host *mmc = mmc_get_drvdata(pdev);
6033 struct mmc_platform_data *plat;
6034 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07006035
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006036 if (!mmc)
6037 return -ENXIO;
6038
6039 if (pm_runtime_suspended(&(pdev)->dev))
6040 pm_runtime_resume(&(pdev)->dev);
6041
6042 host = mmc_priv(mmc);
6043
6044 DBG(host, "Removing SDCC device = %d\n", pdev->id);
6045 plat = host->plat;
6046
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306047 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006048 if (!plat->status_irq)
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306049 device_remove_file(&pdev->dev, &host->polling);
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306050 device_remove_file(&pdev->dev, &host->idle_timeout);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006051
6052 del_timer_sync(&host->req_tout_timer);
6053 tasklet_kill(&host->dma_tlet);
6054 tasklet_kill(&host->sps.tlet);
6055 mmc_remove_host(mmc);
6056
6057 if (plat->status_irq)
6058 free_irq(plat->status_irq, host);
6059
6060 wake_lock_destroy(&host->sdio_suspend_wlock);
6061 if (plat->sdiowakeup_irq) {
6062 wake_lock_destroy(&host->sdio_wlock);
6063 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
6064 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07006065 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006066
6067 free_irq(host->core_irqres->start, host);
6068 free_irq(host->core_irqres->start, host);
6069
6070 clk_put(host->clk);
6071 if (!IS_ERR(host->pclk))
6072 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05306073 if (!IS_ERR_OR_NULL(host->bus_clk))
6074 clk_put(host->bus_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006075
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006076 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306077 pm_qos_remove_request(&host->pm_qos_req_dma);
6078
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306079 if (host->msm_bus_vote.client_handle) {
6080 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
6081 msmsdcc_msm_bus_unregister(host);
6082 }
6083
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006084 msmsdcc_vreg_init(host, false);
6085
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306086 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006087 if (host->dmares)
6088 dma_free_coherent(NULL,
6089 sizeof(struct msmsdcc_nc_dmadata),
6090 host->dma.nc, host->dma.nc_busaddr);
6091 }
6092
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306093 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006094 msmsdcc_dml_exit(host);
6095 msmsdcc_sps_exit(host);
6096 }
6097
6098 iounmap(host->base);
6099 mmc_free_host(mmc);
6100
6101#ifdef CONFIG_HAS_EARLYSUSPEND
6102 unregister_early_suspend(&host->early_suspend);
6103#endif
6104 pm_runtime_disable(&(pdev)->dev);
6105 pm_runtime_set_suspended(&(pdev)->dev);
6106
6107 return 0;
6108}
6109
6110#ifdef CONFIG_MSM_SDIO_AL
6111int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
6112{
6113 struct msmsdcc_host *host = mmc_priv(mmc);
6114 unsigned long flags;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306115 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006116
Asutosh Dasf5298c32012-04-03 14:51:47 +05306117 mutex_lock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006118 spin_lock_irqsave(&host->lock, flags);
6119 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
6120 enable ? "En" : "Dis");
6121
6122 if (enable) {
6123 if (!host->sdcc_irq_disabled) {
6124 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05306125 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006126 host->sdcc_irq_disabled = 1;
6127 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306128 rc = msmsdcc_setup_clocks(host, false);
6129 if (rc)
6130 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006131
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05306132 if (host->plat->sdio_lpm_gpio_setup &&
6133 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006134 spin_unlock_irqrestore(&host->lock, flags);
6135 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
6136 spin_lock_irqsave(&host->lock, flags);
6137 host->sdio_gpio_lpm = 1;
6138 }
6139
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306140 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006141 msmsdcc_enable_irq_wake(host);
6142 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306143 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006144 }
6145 } else {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306146 rc = msmsdcc_setup_clocks(host, true);
6147 if (rc)
6148 goto out;
6149
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306150 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006151 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306152 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006153 msmsdcc_disable_irq_wake(host);
6154 }
6155
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05306156 if (host->plat->sdio_lpm_gpio_setup &&
6157 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006158 spin_unlock_irqrestore(&host->lock, flags);
6159 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
6160 spin_lock_irqsave(&host->lock, flags);
6161 host->sdio_gpio_lpm = 0;
6162 }
6163
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306164 if (host->sdcc_irq_disabled && atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006165 writel_relaxed(host->mci_irqenable,
6166 host->base + MMCIMASK0);
6167 mb();
6168 enable_irq(host->core_irqres->start);
6169 host->sdcc_irq_disabled = 0;
6170 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006171 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306172out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006173 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05306174 mutex_unlock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306175 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006176}
6177#else
6178int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
6179{
6180 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07006181}
6182#endif
6183
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006184#ifdef CONFIG_PM
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306185#ifdef CONFIG_MMC_CLKGATE
6186static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6187{
6188 struct mmc_host *mmc = host->mmc;
6189 unsigned long flags;
6190
6191 mmc_host_clk_hold(mmc);
6192 spin_lock_irqsave(&mmc->clk_lock, flags);
6193 mmc->clk_old = mmc->ios.clock;
6194 mmc->ios.clock = 0;
6195 mmc->clk_gated = true;
6196 spin_unlock_irqrestore(&mmc->clk_lock, flags);
6197 mmc_set_ios(mmc);
6198 mmc_host_clk_release(mmc);
6199}
6200
6201static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6202{
6203 struct mmc_host *mmc = host->mmc;
6204
6205 mmc_host_clk_hold(mmc);
6206 mmc->ios.clock = host->clk_rate;
6207 mmc_set_ios(mmc);
6208 mmc_host_clk_release(mmc);
6209}
6210#else
6211static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6212{
6213 struct mmc_host *mmc = host->mmc;
6214
6215 mmc->ios.clock = 0;
6216 mmc_set_ios(mmc);
6217}
6218
6219static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6220{
6221 struct mmc_host *mmc = host->mmc;
6222
6223 mmc->ios.clock = host->clk_rate;
6224 mmc_set_ios(mmc);
6225}
6226#endif
6227
San Mehat9d2bd732009-09-22 16:44:22 -07006228static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006229msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006230{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006231 struct mmc_host *mmc = dev_get_drvdata(dev);
6232 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006233 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306234 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07006235
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306236 if (host->plat->is_sdio_al_client) {
6237 rc = 0;
6238 goto out;
San Mehat9d2bd732009-09-22 16:44:22 -07006239 }
San Mehat9d2bd732009-09-22 16:44:22 -07006240
Sahitya Tummala7661a452011-07-18 13:28:35 +05306241 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006242 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006243 host->sdcc_suspending = 1;
6244 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07006245
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006246 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006247 * MMC core thinks that host is disabled by now since
6248 * runtime suspend is scheduled after msmsdcc_disable()
6249 * is called. Thus, MMC core will try to enable the host
6250 * while suspending it. This results in a synchronous
6251 * runtime resume request while in runtime suspending
6252 * context and hence inorder to complete this resume
6253 * requet, it will wait for suspend to be complete,
6254 * but runtime suspend also can not proceed further
6255 * until the host is resumed. Thus, it leads to a hang.
6256 * Hence, increase the pm usage count before suspending
6257 * the host so that any resume requests after this will
6258 * simple become pm usage counter increment operations.
6259 */
6260 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306261 /* If there is pending detect work abort runtime suspend */
6262 if (unlikely(work_busy(&mmc->detect.work)))
6263 rc = -EAGAIN;
6264 else
6265 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006266 pm_runtime_put_noidle(dev);
6267
6268 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306269 spin_lock_irqsave(&host->lock, flags);
6270 host->sdcc_suspended = true;
6271 spin_unlock_irqrestore(&host->lock, flags);
6272 if (mmc->card && mmc_card_sdio(mmc->card) &&
6273 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006274 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306275 * If SDIO function driver doesn't want
6276 * to power off the card, atleast turn off
6277 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006278 */
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306279 msmsdcc_gate_clock(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006280 }
6281 }
6282 host->sdcc_suspending = 0;
6283 mmc->suspend_task = NULL;
6284 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
6285 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006286 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306287 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306288out:
6289 /* set bus bandwidth to 0 immediately */
6290 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
San Mehat9d2bd732009-09-22 16:44:22 -07006291 return rc;
6292}
6293
6294static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006295msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006296{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006297 struct mmc_host *mmc = dev_get_drvdata(dev);
6298 struct msmsdcc_host *host = mmc_priv(mmc);
6299 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07006300
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006301 if (host->plat->is_sdio_al_client)
6302 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07006303
Sahitya Tummala7661a452011-07-18 13:28:35 +05306304 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006305 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306306 if (mmc->card && mmc_card_sdio(mmc->card) &&
6307 mmc_card_keep_power(mmc)) {
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306308 msmsdcc_ungate_clock(host);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05306309 }
San Mehat9d2bd732009-09-22 16:44:22 -07006310
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006311 mmc_resume_host(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006312
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006313 /*
6314 * FIXME: Clearing of flags must be handled in clients
6315 * resume handler.
6316 */
6317 spin_lock_irqsave(&host->lock, flags);
6318 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306319 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006320 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07006321
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006322 /*
6323 * After resuming the host wait for sometime so that
6324 * the SDIO work will be processed.
6325 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306326 if (mmc->card && mmc_card_sdio(mmc->card)) {
Subhash Jadavanic9b85752012-04-13 11:16:49 +05306327 if ((host->plat->mpm_sdiowakeup_int ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006328 host->plat->sdiowakeup_irq) &&
6329 wake_lock_active(&host->sdio_wlock))
6330 wake_lock_timeout(&host->sdio_wlock, 1);
6331 }
6332
6333 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006334 }
Subhash Jadavani1371d192012-08-16 18:46:57 +05306335 host->pending_resume = false;
Sahitya Tummala7661a452011-07-18 13:28:35 +05306336 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006337 return 0;
6338}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006339
6340static int msmsdcc_runtime_idle(struct device *dev)
6341{
6342 struct mmc_host *mmc = dev_get_drvdata(dev);
6343 struct msmsdcc_host *host = mmc_priv(mmc);
6344
6345 if (host->plat->is_sdio_al_client)
6346 return 0;
6347
6348 /* Idle timeout is not configurable for now */
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306349 pm_schedule_suspend(dev, host->idle_tout_ms);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006350
6351 return -EAGAIN;
6352}
6353
6354static int msmsdcc_pm_suspend(struct device *dev)
6355{
6356 struct mmc_host *mmc = dev_get_drvdata(dev);
6357 struct msmsdcc_host *host = mmc_priv(mmc);
6358 int rc = 0;
6359
6360 if (host->plat->is_sdio_al_client)
6361 return 0;
6362
6363
6364 if (host->plat->status_irq)
6365 disable_irq(host->plat->status_irq);
6366
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006367 if (!pm_runtime_suspended(dev))
6368 rc = msmsdcc_runtime_suspend(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006369
6370 return rc;
6371}
6372
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306373static int msmsdcc_suspend_noirq(struct device *dev)
6374{
6375 struct mmc_host *mmc = dev_get_drvdata(dev);
6376 struct msmsdcc_host *host = mmc_priv(mmc);
6377 int rc = 0;
6378
6379 /*
6380 * After platform suspend there may be active request
6381 * which might have enabled clocks. For example, in SDIO
6382 * case, ksdioirq thread might have scheduled after sdcc
6383 * suspend but before system freeze. In that case abort
6384 * suspend and retry instead of keeping the clocks on
6385 * during suspend and not allowing TCXO.
6386 */
6387
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306388 if (atomic_read(&host->clks_on) && !host->plat->is_sdio_al_client) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306389 pr_warn("%s: clocks are on after suspend, aborting system "
6390 "suspend\n", mmc_hostname(mmc));
6391 rc = -EAGAIN;
6392 }
6393
6394 return rc;
6395}
6396
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006397static int msmsdcc_pm_resume(struct device *dev)
6398{
6399 struct mmc_host *mmc = dev_get_drvdata(dev);
6400 struct msmsdcc_host *host = mmc_priv(mmc);
6401 int rc = 0;
6402
6403 if (host->plat->is_sdio_al_client)
6404 return 0;
6405
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006406 if (mmc->card && mmc_card_sdio(mmc->card))
Sahitya Tummalafb486372011-09-02 19:01:49 +05306407 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavani1371d192012-08-16 18:46:57 +05306408 /*
6409 * As runtime PM is enabled before calling the device's platform resume
6410 * callback, we use the pm_runtime_suspended API to know if SDCC is
6411 * really runtime suspended or not and set the pending_resume flag only
6412 * if its not runtime suspended.
6413 */
6414 else if (!pm_runtime_suspended(dev))
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006415 host->pending_resume = true;
6416
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006417 if (host->plat->status_irq) {
6418 msmsdcc_check_status((unsigned long)host);
6419 enable_irq(host->plat->status_irq);
6420 }
6421
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006422 return rc;
6423}
6424
Daniel Walker08ecfde2010-06-23 12:32:20 -07006425#else
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006426static int msmsdcc_runtime_suspend(struct device *dev)
6427{
6428 return 0;
6429}
6430static int msmsdcc_runtime_idle(struct device *dev)
6431{
6432 return 0;
6433}
6434static int msmsdcc_pm_suspend(struct device *dev)
6435{
6436 return 0;
6437}
6438static int msmsdcc_pm_resume(struct device *dev)
6439{
6440 return 0;
6441}
6442static int msmsdcc_suspend_noirq(struct device *dev)
6443{
6444 return 0;
6445}
6446static int msmsdcc_runtime_resume(struct device *dev)
6447{
6448 return 0;
6449}
Daniel Walker08ecfde2010-06-23 12:32:20 -07006450#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006451
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006452static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
6453 .runtime_suspend = msmsdcc_runtime_suspend,
6454 .runtime_resume = msmsdcc_runtime_resume,
6455 .runtime_idle = msmsdcc_runtime_idle,
6456 .suspend = msmsdcc_pm_suspend,
6457 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306458 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006459};
6460
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306461static const struct of_device_id msmsdcc_dt_match[] = {
6462 {.compatible = "qcom,msm-sdcc"},
6463
6464};
6465MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
6466
San Mehat9d2bd732009-09-22 16:44:22 -07006467static struct platform_driver msmsdcc_driver = {
6468 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006469 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07006470 .driver = {
6471 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006472 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306473 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07006474 },
6475};
6476
6477static int __init msmsdcc_init(void)
6478{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006479#if defined(CONFIG_DEBUG_FS)
6480 int ret = 0;
6481 ret = msmsdcc_dbg_init();
6482 if (ret) {
6483 pr_err("Failed to create debug fs dir \n");
6484 return ret;
6485 }
6486#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006487 return platform_driver_register(&msmsdcc_driver);
6488}
San Mehat9d2bd732009-09-22 16:44:22 -07006489
San Mehat9d2bd732009-09-22 16:44:22 -07006490static void __exit msmsdcc_exit(void)
6491{
6492 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006493
6494#if defined(CONFIG_DEBUG_FS)
6495 debugfs_remove(debugfs_file);
6496 debugfs_remove(debugfs_dir);
6497#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006498}
6499
6500module_init(msmsdcc_init);
6501module_exit(msmsdcc_exit);
6502
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006503MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07006504MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006505
6506#if defined(CONFIG_DEBUG_FS)
6507
6508static int
6509msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
6510{
6511 file->private_data = inode->i_private;
6512 return 0;
6513}
6514
6515static ssize_t
6516msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
6517 size_t count, loff_t *ppos)
6518{
6519 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08006520 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006521 int max, i;
6522
6523 i = 0;
6524 max = sizeof(buf) - 1;
6525
6526 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
6527 host->curr.cmd, host->curr.data);
6528 if (host->curr.cmd) {
6529 struct mmc_command *cmd = host->curr.cmd;
6530
6531 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
6532 cmd->opcode, cmd->arg, cmd->flags);
6533 }
6534 if (host->curr.data) {
6535 struct mmc_data *data = host->curr.data;
6536 i += scnprintf(buf + i, max - i,
6537 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
6538 data->timeout_ns, data->timeout_clks,
6539 data->blksz, data->blocks, data->error,
6540 data->flags);
6541 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
6542 host->curr.xfer_size, host->curr.xfer_remain,
6543 host->curr.data_xfered, host->dma.sg);
6544 }
6545
6546 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
6547}
6548
6549static const struct file_operations msmsdcc_dbg_state_ops = {
6550 .read = msmsdcc_dbg_state_read,
6551 .open = msmsdcc_dbg_state_open,
6552};
6553
6554static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
6555{
6556 if (debugfs_dir) {
6557 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
6558 0644, debugfs_dir, host,
6559 &msmsdcc_dbg_state_ops);
6560 }
6561}
6562
6563static int __init msmsdcc_dbg_init(void)
6564{
6565 int err;
6566
6567 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
6568 if (IS_ERR(debugfs_dir)) {
6569 err = PTR_ERR(debugfs_dir);
6570 debugfs_dir = NULL;
6571 return err;
6572 }
6573
6574 return 0;
6575}
6576#endif