blob: dbd6a16f1563331c213516258647db904adc6587 [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;
Pratibhasagar Vbe4e3132012-09-20 19:46:11 +05301764 struct mmc_host *mmc = host->mmc;
San Mehat9d2bd732009-09-22 16:44:22 -07001765 u32 status;
1766 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001767 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001768
1769 spin_lock(&host->lock);
1770
1771 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001772 struct mmc_command *cmd;
1773 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001774
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001775 if (timer) {
1776 timer = 0;
1777 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001778 }
San Mehat9d2bd732009-09-22 16:44:22 -07001779
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05301780 if (!atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001781 pr_debug("%s: %s: SDIO async irq received\n",
1782 mmc_hostname(host->mmc), __func__);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301783
1784 /*
1785 * Only async interrupt can come when clocks are off,
1786 * disable further interrupts and enable them when
1787 * clocks are on.
1788 */
1789 if (!host->sdcc_irq_disabled) {
1790 disable_irq_nosync(irq);
1791 host->sdcc_irq_disabled = 1;
1792 }
1793
1794 /*
1795 * If mmc_card_wake_sdio_irq() is set, mmc core layer
1796 * will take care of signaling sdio irq during
1797 * mmc_sdio_resume().
1798 */
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301799 if (host->sdcc_suspended) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301800 /*
1801 * This is a wakeup interrupt so hold wakelock
1802 * until SDCC resume is handled.
1803 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001804 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301805 } else {
Pratibhasagar Vbe4e3132012-09-20 19:46:11 +05301806 if (!mmc->card || !mmc_card_sdio(mmc->card)) {
1807 WARN(1, "%s: SDCC core interrupt received for non-SDIO cards when SDCC clocks are off\n",
1808 mmc_hostname(mmc));
1809 ret = 1;
1810 break;
1811 }
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301812 spin_unlock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301813 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301814 spin_lock(&host->lock);
1815 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301816 ret = 1;
1817 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001818 }
1819
1820 status = readl_relaxed(host->base + MMCISTATUS);
1821
1822 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1823 (~(MCI_IRQ_PIO))) == 0)
San Mehat9d2bd732009-09-22 16:44:22 -07001824 break;
1825
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001826#if IRQ_DEBUG
1827 msmsdcc_print_status(host, "irq0-r", status);
1828#endif
1829 status &= readl_relaxed(host->base + MMCIMASK0);
1830 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301831 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301832 if (host->clk_rate <=
1833 msmsdcc_get_min_sup_clk_rate(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +05301834 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001835#if IRQ_DEBUG
1836 msmsdcc_print_status(host, "irq0-p", status);
1837#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001838
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001839 if (status & MCI_SDIOINTROPE) {
Pratibhasagar Vbe4e3132012-09-20 19:46:11 +05301840 if (!mmc->card || mmc_card_sdio(mmc->card)) {
1841 WARN(1, "%s: SDIO interrupt received for non-SDIO card\n",
1842 mmc_hostname(mmc));
1843 ret = 1;
1844 break;
1845 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001846 if (host->sdcc_suspending)
1847 wake_lock(&host->sdio_suspend_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301848 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001849 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301850 spin_lock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001851 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001852 data = host->curr.data;
1853
1854 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001855 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1856 MCI_CMDTIMEOUT)) {
1857 if (status & MCI_CMDTIMEOUT)
1858 pr_debug("%s: dummy CMD52 timeout\n",
1859 mmc_hostname(host->mmc));
1860 if (status & MCI_CMDCRCFAIL)
1861 pr_debug("%s: dummy CMD52 CRC failed\n",
1862 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001863 host->dummy_52_sent = 0;
1864 host->dummy_52_needed = 0;
1865 if (data) {
1866 msmsdcc_stop_data(host);
1867 msmsdcc_request_end(host, data->mrq);
1868 }
1869 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001870 spin_unlock(&host->lock);
1871 return IRQ_HANDLED;
1872 }
1873 break;
1874 }
1875
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001876 /*
1877 * Check for proper command response
1878 */
1879 cmd = host->curr.cmd;
1880 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1881 MCI_CMDTIMEOUT | MCI_PROGDONE |
1882 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1883 msmsdcc_do_cmdirq(host, status);
1884 }
1885
Sathish Ambley081d7842011-11-29 11:19:41 -08001886 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001887 /* Check for data errors */
1888 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1889 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1890 msmsdcc_data_err(host, data, status);
1891 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301892 if (host->dma.sg && is_dma_mode(host))
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001893 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301894 else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001895 /* Stop current SPS transfer */
1896 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301897 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001898 msmsdcc_reset_and_restore(host);
1899 if (host->curr.data)
1900 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301901 if (!data->stop || (host->curr.mrq->sbc
1902 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001903 timer |=
1904 msmsdcc_request_end(host,
1905 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301906 else if ((host->curr.mrq->sbc
1907 && data->error) ||
1908 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001909 msmsdcc_start_command(host,
1910 data->stop,
1911 0);
1912 timer = 1;
1913 }
1914 }
1915 }
1916
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301917 /* Check for prog done */
1918 if (host->curr.wait_for_auto_prog_done &&
1919 (status & MCI_PROGDONE))
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301920 host->curr.got_auto_prog_done = true;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301921
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001922 /* Check for data done */
1923 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1924 host->curr.got_dataend = 1;
1925
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301926 if (host->curr.got_dataend &&
1927 (!host->curr.wait_for_auto_prog_done ||
1928 (host->curr.wait_for_auto_prog_done &&
1929 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001930 /*
1931 * If DMA is still in progress, we complete
1932 * via the completion handler
1933 */
1934 if (!host->dma.busy && !host->sps.busy) {
1935 /*
1936 * There appears to be an issue in the
1937 * controller where if you request a
1938 * small block transfer (< fifo size),
1939 * you may get your DATAEND/DATABLKEND
1940 * irq without the PIO data irq.
1941 *
1942 * Check to see if theres still data
1943 * to be read, and simulate a PIO irq.
1944 */
1945 if (data->flags & MMC_DATA_READ)
1946 msmsdcc_wait_for_rxdata(host,
1947 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001948 if (!data->error) {
1949 host->curr.data_xfered =
1950 host->curr.xfer_size;
1951 host->curr.xfer_remain -=
1952 host->curr.xfer_size;
1953 }
1954
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001955 if (!host->dummy_52_needed) {
1956 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301957 if (!data->stop ||
1958 (host->curr.mrq->sbc
1959 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001960 msmsdcc_request_end(
1961 host,
1962 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301963 else if ((host->curr.mrq->sbc
1964 && data->error) ||
1965 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001966 msmsdcc_start_command(
1967 host,
1968 data->stop, 0);
1969 timer = 1;
1970 }
1971 } else {
1972 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001973 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001974 &dummy52cmd,
1975 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001976 }
1977 }
1978 }
1979 }
1980
San Mehat9d2bd732009-09-22 16:44:22 -07001981 ret = 1;
1982 } while (status);
1983
1984 spin_unlock(&host->lock);
1985
San Mehat9d2bd732009-09-22 16:44:22 -07001986 return IRQ_RETVAL(ret);
1987}
1988
1989static void
Asutosh Dasaccacd42012-03-08 14:33:17 +05301990msmsdcc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
1991 bool is_first_request)
1992{
1993 struct msmsdcc_host *host = mmc_priv(mmc);
1994 struct mmc_data *data = mrq->data;
1995 int rc = 0;
1996
1997 if (unlikely(!data)) {
1998 pr_err("%s: %s cannot prepare null data\n", mmc_hostname(mmc),
1999 __func__);
2000 return;
2001 }
2002 if (unlikely(data->host_cookie)) {
2003 /* Very wrong */
2004 data->host_cookie = 0;
2005 pr_err("%s: %s Request reposted for prepare\n",
2006 mmc_hostname(mmc), __func__);
2007 return;
2008 }
2009
2010 if (!msmsdcc_is_dma_possible(host, data))
2011 return;
2012
2013 rc = msmsdcc_prep_xfer(host, data);
2014 if (unlikely(rc < 0)) {
2015 data->host_cookie = 0;
2016 return;
2017 }
2018
2019 data->host_cookie = 1;
2020}
2021
2022static void
2023msmsdcc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, int err)
2024{
2025 struct msmsdcc_host *host = mmc_priv(mmc);
2026 unsigned int dir;
2027 struct mmc_data *data = mrq->data;
2028
2029 if (unlikely(!data)) {
2030 pr_err("%s: %s cannot cleanup null data\n", mmc_hostname(mmc),
2031 __func__);
2032 return;
2033 }
2034 if (data->flags & MMC_DATA_READ)
2035 dir = DMA_FROM_DEVICE;
2036 else
2037 dir = DMA_TO_DEVICE;
2038
2039 if (data->host_cookie)
2040 dma_unmap_sg(mmc_dev(host->mmc), data->sg,
2041 data->sg_len, dir);
2042
2043 data->host_cookie = 0;
2044}
2045
2046static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002047msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
2048{
Subhash Jadavanif5277752011-10-12 16:47:52 +05302049 if (mrq->data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002050 /* Queue/read data, daisy-chain command when data starts */
Subhash Jadavanif5277752011-10-12 16:47:52 +05302051 if ((mrq->data->flags & MMC_DATA_READ) ||
2052 host->curr.use_wr_data_pend)
2053 msmsdcc_start_data(host, mrq->data,
2054 mrq->sbc ? mrq->sbc : mrq->cmd,
2055 0);
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302056 else
Subhash Jadavanif5277752011-10-12 16:47:52 +05302057 msmsdcc_start_command(host,
2058 mrq->sbc ? mrq->sbc : mrq->cmd,
2059 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002060 } else {
2061 msmsdcc_start_command(host, mrq->cmd, 0);
2062 }
2063}
2064
2065static void
San Mehat9d2bd732009-09-22 16:44:22 -07002066msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
2067{
2068 struct msmsdcc_host *host = mmc_priv(mmc);
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302069 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07002070
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002071 /*
2072 * Get the SDIO AL client out of LPM.
2073 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002074 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002075 if (host->plat->is_sdio_al_client)
2076 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002077
Subhash Jadavanib5b07742011-08-29 17:48:07 +05302078 /* check if sps pipe reset is pending? */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05302079 if (is_sps_mode(host) && host->sps.pipe_reset_pending) {
Subhash Jadavanib5b07742011-08-29 17:48:07 +05302080 msmsdcc_sps_pipes_reset_and_restore(host);
2081 host->sps.pipe_reset_pending = false;
2082 }
San Mehat9d2bd732009-09-22 16:44:22 -07002083
2084 spin_lock_irqsave(&host->lock, flags);
2085
San Mehat9d2bd732009-09-22 16:44:22 -07002086 if (host->eject) {
2087 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
2088 mrq->cmd->error = 0;
2089 mrq->data->bytes_xfered = mrq->data->blksz *
2090 mrq->data->blocks;
2091 } else
2092 mrq->cmd->error = -ENOMEDIUM;
2093
2094 spin_unlock_irqrestore(&host->lock, flags);
2095 mmc_request_done(mmc, mrq);
2096 return;
2097 }
2098
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302099 /*
subhashjf181c292012-05-02 13:07:40 +05302100 * Don't start the request if SDCC is not in proper state to handle it
2101 */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302102 if (!host->pwr || !atomic_read(&host->clks_on)
2103 || host->sdcc_irq_disabled) {
subhashjf181c292012-05-02 13:07:40 +05302104 WARN(1, "%s: %s: SDCC is in bad state. don't process"
2105 " new request (CMD%d)\n", mmc_hostname(host->mmc),
2106 __func__, mrq->cmd->opcode);
2107 msmsdcc_dump_sdcc_state(host);
2108 mrq->cmd->error = -EIO;
2109 if (mrq->data) {
2110 mrq->data->error = -EIO;
2111 mrq->data->bytes_xfered = 0;
2112 }
2113 spin_unlock_irqrestore(&host->lock, flags);
2114 mmc_request_done(mmc, mrq);
2115 return;
2116 }
2117
2118 WARN(host->curr.mrq, "%s: %s: New request (CMD%d) received while"
2119 " other request (CMD%d) is in progress\n",
2120 mmc_hostname(host->mmc), __func__,
2121 mrq->cmd->opcode, host->curr.mrq->cmd->opcode);
2122
2123 /*
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302124 * Set timeout value to 10 secs (or more in case of buggy cards)
2125 */
2126 if ((mmc->card) && (mmc->card->quirks & MMC_QUIRK_INAND_DATA_TIMEOUT))
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302127 host->curr.req_tout_ms = 20000;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302128 else
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302129 host->curr.req_tout_ms = MSM_MMC_REQ_TIMEOUT;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302130 /*
2131 * Kick the software request timeout timer here with the timeout
2132 * value identified above
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302133 */
2134 mod_timer(&host->req_tout_timer,
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302135 (jiffies +
2136 msecs_to_jiffies(host->curr.req_tout_ms)));
San Mehat9d2bd732009-09-22 16:44:22 -07002137
San Mehat9d2bd732009-09-22 16:44:22 -07002138 host->curr.mrq = mrq;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302139 if (mrq->sbc) {
2140 mrq->sbc->mrq = mrq;
2141 mrq->sbc->data = mrq->data;
2142 }
2143
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302144 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05302145 if (is_auto_prog_done(host)) {
Sujit Reddy Thummab8e83692012-07-17 15:08:13 +05302146 /*
2147 * Auto-prog done will be enabled for following cases:
2148 * mrq->sbc | mrq->stop
2149 * _____________|________________
2150 * True | Don't care
2151 * False | False (CMD24, ACMD25 use case)
2152 */
2153 if (mrq->sbc || !mrq->stop)
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302154 host->curr.wait_for_auto_prog_done = true;
2155 } else {
2156 if ((mrq->cmd->opcode == SD_IO_RW_EXTENDED) ||
2157 (mrq->cmd->opcode == 54))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002158 host->dummy_52_needed = 1;
2159 }
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302160
Subhash Jadavanif5277752011-10-12 16:47:52 +05302161 if ((mrq->cmd->opcode == MMC_WRITE_BLOCK) ||
2162 (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK))
2163 host->curr.use_wr_data_pend = true;
San Mehat9d2bd732009-09-22 16:44:22 -07002164 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302165
Subhash Jadavanif5277752011-10-12 16:47:52 +05302166 msmsdcc_request_start(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302167
San Mehat9d2bd732009-09-22 16:44:22 -07002168 spin_unlock_irqrestore(&host->lock, flags);
2169}
2170
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002171static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
2172 int min_uV, int max_uV)
2173{
2174 int rc = 0;
2175
2176 if (vreg->set_voltage_sup) {
2177 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
2178 if (rc) {
2179 pr_err("%s: regulator_set_voltage(%s) failed."
2180 " min_uV=%d, max_uV=%d, rc=%d\n",
2181 __func__, vreg->name, min_uV, max_uV, rc);
2182 }
2183 }
2184
2185 return rc;
2186}
2187
Subhash Jadavanibf09d802012-08-11 18:11:57 +05302188static inline int msmsdcc_vreg_get_voltage(struct msm_mmc_reg_data *vreg)
2189{
2190 int rc = 0;
2191
2192 rc = regulator_get_voltage(vreg->reg);
2193 if (rc < 0)
2194 pr_err("%s: regulator_get_voltage(%s) failed. rc=%d\n",
2195 __func__, vreg->name, rc);
2196
2197 return rc;
2198}
2199
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002200static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
2201 int uA_load)
2202{
2203 int rc = 0;
2204
Krishna Kondafea60182011-11-01 16:01:34 -07002205 /* regulators that do not support regulator_set_voltage also
2206 do not support regulator_set_optimum_mode */
2207 if (vreg->set_voltage_sup) {
2208 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
2209 if (rc < 0)
2210 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
2211 "uA_load=%d) failed. rc=%d\n", __func__,
2212 vreg->name, uA_load, rc);
2213 else
2214 /* regulator_set_optimum_mode() can return non zero
2215 * value even for success case.
2216 */
2217 rc = 0;
2218 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002219
2220 return rc;
2221}
2222
2223static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
2224 struct device *dev)
2225{
2226 int rc = 0;
2227
2228 /* check if regulator is already initialized? */
2229 if (vreg->reg)
2230 goto out;
2231
2232 /* Get the regulator handle */
2233 vreg->reg = regulator_get(dev, vreg->name);
2234 if (IS_ERR(vreg->reg)) {
2235 rc = PTR_ERR(vreg->reg);
2236 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
2237 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002238 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002239 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002240
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05302241 if (regulator_count_voltages(vreg->reg) > 0) {
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002242 vreg->set_voltage_sup = 1;
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05302243 /* sanity check */
2244 if (!vreg->high_vol_level || !vreg->hpm_uA) {
2245 pr_err("%s: %s invalid constraints specified\n",
2246 __func__, vreg->name);
2247 rc = -EINVAL;
2248 }
2249 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002250
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002251out:
2252 return rc;
2253}
2254
2255static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
2256{
2257 if (vreg->reg)
2258 regulator_put(vreg->reg);
2259}
2260
2261/* This init function should be called only once for each SDCC slot */
2262static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
2263{
2264 int rc = 0;
2265 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302266 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vdd_io_reg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002267 struct device *dev = mmc_dev(host->mmc);
2268
2269 curr_slot = host->plat->vreg_data;
2270 if (!curr_slot)
2271 goto out;
2272
2273 curr_vdd_reg = curr_slot->vdd_data;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302274 curr_vdd_io_reg = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002275
2276 if (is_init) {
2277 /*
2278 * Get the regulator handle from voltage regulator framework
2279 * and then try to set the voltage level for the regulator
2280 */
2281 if (curr_vdd_reg) {
2282 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
2283 if (rc)
2284 goto out;
2285 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302286 if (curr_vdd_io_reg) {
2287 rc = msmsdcc_vreg_init_reg(curr_vdd_io_reg, dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002288 if (rc)
2289 goto vdd_reg_deinit;
2290 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002291 rc = msmsdcc_vreg_reset(host);
2292 if (rc)
2293 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
2294 host->pdev_id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002295 goto out;
2296 } else {
2297 /* Deregister all regulators from regulator framework */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302298 goto vdd_io_reg_deinit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002299 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302300vdd_io_reg_deinit:
2301 if (curr_vdd_io_reg)
2302 msmsdcc_vreg_deinit_reg(curr_vdd_io_reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002303vdd_reg_deinit:
2304 if (curr_vdd_reg)
2305 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2306out:
2307 return rc;
2308}
2309
2310static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2311{
2312 int rc = 0;
2313
Subhash Jadavanicc922692011-08-01 23:05:01 +05302314 /* Put regulator in HPM (high power mode) */
2315 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2316 if (rc < 0)
2317 goto out;
2318
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002319 if (!vreg->is_enabled) {
2320 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302321 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2322 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002323 if (rc)
2324 goto out;
2325
2326 rc = regulator_enable(vreg->reg);
2327 if (rc) {
2328 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2329 __func__, vreg->name, rc);
2330 goto out;
2331 }
2332 vreg->is_enabled = true;
2333 }
2334
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002335out:
2336 return rc;
2337}
2338
Krishna Konda3c4142d2012-06-27 11:01:56 -07002339static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg, bool is_init)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002340{
2341 int rc = 0;
2342
2343 /* Never disable regulator marked as always_on */
2344 if (vreg->is_enabled && !vreg->always_on) {
2345 rc = regulator_disable(vreg->reg);
2346 if (rc) {
2347 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2348 __func__, vreg->name, rc);
2349 goto out;
2350 }
2351 vreg->is_enabled = false;
2352
2353 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2354 if (rc < 0)
2355 goto out;
2356
2357 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302358 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002359 if (rc)
2360 goto out;
Krishna Konda3c4142d2012-06-27 11:01:56 -07002361 } else if (vreg->is_enabled && vreg->always_on) {
2362 if (!is_init && vreg->lpm_sup) {
2363 /* Put always_on regulator in LPM (low power mode) */
2364 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2365 if (rc < 0)
2366 goto out;
2367 } else if (is_init && vreg->reset_at_init) {
2368 /**
2369 * The regulator might not actually be disabled if it
2370 * is shared and in use by other drivers.
2371 */
2372 rc = regulator_disable(vreg->reg);
2373 if (rc) {
2374 pr_err("%s: regulator_disable(%s) failed at " \
2375 "bootup. rc=%d\n", __func__,
2376 vreg->name, rc);
2377 goto out;
2378 }
2379 vreg->is_enabled = false;
2380 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002381 }
2382out:
2383 return rc;
2384}
2385
Krishna Konda3c4142d2012-06-27 11:01:56 -07002386static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable,
2387 bool is_init)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002388{
2389 int rc = 0, i;
2390 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302391 struct msm_mmc_reg_data *vreg_table[2];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002392
2393 curr_slot = host->plat->vreg_data;
Asutosh Dasebd7d092012-07-09 19:08:26 +05302394 if (!curr_slot) {
2395 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002396 goto out;
Asutosh Dasebd7d092012-07-09 19:08:26 +05302397 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002398
Subhash Jadavani937c7502012-06-01 15:34:46 +05302399 vreg_table[0] = curr_slot->vdd_data;
2400 vreg_table[1] = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002401
2402 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2403 if (vreg_table[i]) {
2404 if (enable)
2405 rc = msmsdcc_vreg_enable(vreg_table[i]);
2406 else
Krishna Konda3c4142d2012-06-27 11:01:56 -07002407 rc = msmsdcc_vreg_disable(vreg_table[i],
2408 is_init);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002409 if (rc)
2410 goto out;
2411 }
2412 }
2413out:
2414 return rc;
2415}
2416
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002417/*
2418 * Reset vreg by ensuring it is off during probe. A call
2419 * to enable vreg is needed to balance disable vreg
2420 */
2421static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2422{
2423 int rc;
2424
Krishna Konda3c4142d2012-06-27 11:01:56 -07002425 rc = msmsdcc_setup_vreg(host, 1, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002426 if (rc)
2427 return rc;
Krishna Konda3c4142d2012-06-27 11:01:56 -07002428 rc = msmsdcc_setup_vreg(host, 0, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002429 return rc;
2430}
2431
Subhash Jadavani937c7502012-06-01 15:34:46 +05302432enum vdd_io_level {
2433 /* set vdd_io_data->low_vol_level */
2434 VDD_IO_LOW,
2435 /* set vdd_io_data->high_vol_level */
2436 VDD_IO_HIGH,
2437 /*
2438 * set whatever there in voltage_level (third argument) of
2439 * msmsdcc_set_vdd_io_vol() function.
2440 */
2441 VDD_IO_SET_LEVEL,
2442};
2443
Subhash Jadavanibf09d802012-08-11 18:11:57 +05302444/*
2445 * This function returns the current VDD IO voltage level.
2446 * Returns negative value if it fails to read the voltage level
2447 * Returns 0 if regulator was disabled or if VDD_IO (and VDD)
2448 * regulator were not defined for host.
2449 */
2450static int msmsdcc_get_vdd_io_vol(struct msmsdcc_host *host)
2451{
2452 int rc = 0;
2453
2454 if (host->plat->vreg_data) {
2455 struct msm_mmc_reg_data *io_reg =
2456 host->plat->vreg_data->vdd_io_data;
2457
2458 /*
2459 * If vdd_io is not defined, then we can consider that
2460 * IO voltage is same as VDD.
2461 */
2462 if (!io_reg)
2463 io_reg = host->plat->vreg_data->vdd_data;
2464
2465 if (io_reg && io_reg->is_enabled)
2466 rc = msmsdcc_vreg_get_voltage(io_reg);
2467 }
2468
2469 return rc;
2470}
2471
2472/*
2473 * This function updates the IO pad power switch bit in MCI_CLK register
2474 * based on currrent IO pad voltage level.
2475 * NOTE: This function assumes that host lock was not taken by caller.
2476 */
2477static void msmsdcc_update_io_pad_pwr_switch(struct msmsdcc_host *host)
2478{
2479 int rc = 0;
2480 unsigned long flags;
2481
2482 if (!is_io_pad_pwr_switch(host))
2483 return;
2484
2485 rc = msmsdcc_get_vdd_io_vol(host);
2486
2487 spin_lock_irqsave(&host->lock, flags);
2488 /*
2489 * Dual voltage pad is the SDCC's (chipset) functionality and not all
2490 * the SDCC instances support the dual voltage pads.
2491 * For dual-voltage pad (1.8v/3.3v), SW should set IO_PAD_PWR_SWITCH
2492 * bit before using the pads in 1.8V mode.
2493 * For regular, not dual-voltage pads (including eMMC 1.2v/1.8v pads),
2494 * IO_PAD_PWR_SWITCH bit is a don't care.
2495 * But we don't have an option to know (by reading some SDCC register)
2496 * that a particular SDCC instance supports dual voltage pads or not,
2497 * so we simply set the IO_PAD_PWR_SWITCH bit for low voltage IO
2498 * (1.8v/1.2v). For regular (not dual-voltage pads), this bit value
2499 * is anyway ignored.
2500 */
2501 if (rc > 0 && rc < 2700000)
2502 host->io_pad_pwr_switch = 1;
2503 else
2504 host->io_pad_pwr_switch = 0;
2505
2506 if (atomic_read(&host->clks_on)) {
2507 if (host->io_pad_pwr_switch)
2508 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2509 IO_PAD_PWR_SWITCH),
2510 host->base + MMCICLOCK);
2511 else
2512 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) &
2513 ~IO_PAD_PWR_SWITCH),
2514 host->base + MMCICLOCK);
2515 msmsdcc_sync_reg_wr(host);
2516 }
2517 spin_unlock_irqrestore(&host->lock, flags);
2518}
2519
Subhash Jadavani937c7502012-06-01 15:34:46 +05302520static int msmsdcc_set_vdd_io_vol(struct msmsdcc_host *host,
2521 enum vdd_io_level level,
2522 unsigned int voltage_level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002523{
2524 int rc = 0;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302525 int set_level;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002526
2527 if (host->plat->vreg_data) {
Subhash Jadavani937c7502012-06-01 15:34:46 +05302528 struct msm_mmc_reg_data *vdd_io_reg =
2529 host->plat->vreg_data->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002530
Subhash Jadavani937c7502012-06-01 15:34:46 +05302531 if (vdd_io_reg && vdd_io_reg->is_enabled) {
2532 switch (level) {
2533 case VDD_IO_LOW:
2534 set_level = vdd_io_reg->low_vol_level;
2535 break;
2536 case VDD_IO_HIGH:
2537 set_level = vdd_io_reg->high_vol_level;
2538 break;
2539 case VDD_IO_SET_LEVEL:
2540 set_level = voltage_level;
2541 break;
2542 default:
2543 pr_err("%s: %s: invalid argument level = %d",
2544 mmc_hostname(host->mmc), __func__,
2545 level);
2546 rc = -EINVAL;
2547 goto out;
2548 }
2549 rc = msmsdcc_vreg_set_voltage(vdd_io_reg,
2550 set_level, set_level);
2551 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002552 }
2553
Subhash Jadavani937c7502012-06-01 15:34:46 +05302554out:
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302555 return rc;
2556}
2557
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002558static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2559{
2560 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2561 return 1;
2562 return 0;
2563}
2564
Asutosh Dasf5298c32012-04-03 14:51:47 +05302565/*
2566 * Any function calling msmsdcc_setup_clocks must
2567 * acquire clk_mutex. May sleep.
2568 */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302569static int msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002570{
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302571 int rc = 0;
2572
2573 if (enable && !atomic_read(&host->clks_on)) {
2574 if (!IS_ERR_OR_NULL(host->bus_clk)) {
2575 rc = clk_prepare_enable(host->bus_clk);
2576 if (rc) {
2577 pr_err("%s: %s: failed to enable the bus-clock with error %d\n",
2578 mmc_hostname(host->mmc), __func__, rc);
2579 goto out;
2580 }
2581 }
2582 if (!IS_ERR(host->pclk)) {
2583 rc = clk_prepare_enable(host->pclk);
2584 if (rc) {
2585 pr_err("%s: %s: failed to enable the pclk with error %d\n",
2586 mmc_hostname(host->mmc), __func__, rc);
2587 goto disable_bus;
2588 }
2589 }
2590 rc = clk_prepare_enable(host->clk);
2591 if (rc) {
2592 pr_err("%s: %s: failed to enable the host-clk with error %d\n",
2593 mmc_hostname(host->mmc), __func__, rc);
2594 goto disable_pclk;
2595 }
Subhash Jadavanidd432952012-03-28 11:25:56 +05302596 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302597 msmsdcc_delay(host);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302598 atomic_set(&host->clks_on, 1);
2599 } else if (!enable && atomic_read(&host->clks_on)) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05302600 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302601 msmsdcc_delay(host);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302602 clk_disable_unprepare(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002603 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302604 clk_disable_unprepare(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05302605 if (!IS_ERR_OR_NULL(host->bus_clk))
2606 clk_disable_unprepare(host->bus_clk);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302607 atomic_set(&host->clks_on, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002608 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302609 goto out;
2610
2611disable_pclk:
2612 if (!IS_ERR_OR_NULL(host->pclk))
2613 clk_disable_unprepare(host->pclk);
2614disable_bus:
2615 if (!IS_ERR_OR_NULL(host->bus_clk))
2616 clk_disable_unprepare(host->bus_clk);
2617out:
2618 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002619}
2620
2621static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2622 unsigned int req_clk)
2623{
2624 unsigned int sel_clk = -1;
2625
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302626 if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
2627 sel_clk = msmsdcc_get_min_sup_clk_rate(host);
2628 goto out;
2629 }
2630
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002631 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2632 unsigned char cnt;
2633
2634 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2635 if (host->plat->sup_clk_table[cnt] > req_clk)
2636 break;
2637 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2638 sel_clk = host->plat->sup_clk_table[cnt];
2639 break;
2640 } else
2641 sel_clk = host->plat->sup_clk_table[cnt];
2642 }
2643 } else {
2644 if ((req_clk < host->plat->msmsdcc_fmax) &&
2645 (req_clk > host->plat->msmsdcc_fmid))
2646 sel_clk = host->plat->msmsdcc_fmid;
2647 else
2648 sel_clk = req_clk;
2649 }
2650
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302651out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002652 return sel_clk;
2653}
2654
2655static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2656 struct msmsdcc_host *host)
2657{
2658 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2659 return host->plat->sup_clk_table[0];
2660 else
2661 return host->plat->msmsdcc_fmin;
2662}
2663
2664static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2665 struct msmsdcc_host *host)
2666{
2667 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2668 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2669 else
2670 return host->plat->msmsdcc_fmax;
2671}
2672
2673static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302674{
2675 struct msm_mmc_gpio_data *curr;
2676 int i, rc = 0;
2677
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002678 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302679 for (i = 0; i < curr->size; i++) {
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05302680 if (!gpio_is_valid(curr->gpio[i].no)) {
2681 rc = -EINVAL;
2682 pr_err("%s: Invalid gpio = %d\n",
2683 mmc_hostname(host->mmc), curr->gpio[i].no);
2684 goto free_gpios;
2685 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302686 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002687 if (curr->gpio[i].is_always_on &&
2688 curr->gpio[i].is_enabled)
2689 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302690 rc = gpio_request(curr->gpio[i].no,
2691 curr->gpio[i].name);
2692 if (rc) {
2693 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2694 mmc_hostname(host->mmc),
2695 curr->gpio[i].no,
2696 curr->gpio[i].name, rc);
2697 goto free_gpios;
2698 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002699 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302700 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002701 if (curr->gpio[i].is_always_on)
2702 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302703 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002704 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302705 }
2706 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002707 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302708
2709free_gpios:
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05302710 for (i--; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302711 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002712 curr->gpio[i].is_enabled = false;
2713 }
2714out:
2715 return rc;
2716}
2717
2718static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2719{
2720 struct msm_mmc_pad_data *curr;
2721 int i;
2722
2723 curr = host->plat->pin_data->pad_data;
2724 for (i = 0; i < curr->drv->size; i++) {
2725 if (enable)
2726 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2727 curr->drv->on[i].val);
2728 else
2729 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2730 curr->drv->off[i].val);
2731 }
2732
2733 for (i = 0; i < curr->pull->size; i++) {
2734 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002735 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002736 curr->pull->on[i].val);
2737 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002738 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002739 curr->pull->off[i].val);
2740 }
2741
2742 return 0;
2743}
2744
2745static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2746{
2747 int rc = 0;
2748
2749 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2750 return 0;
2751
2752 if (host->plat->pin_data->is_gpio)
2753 rc = msmsdcc_setup_gpio(host, enable);
2754 else
2755 rc = msmsdcc_setup_pad(host, enable);
2756
2757 if (!rc)
2758 host->plat->pin_data->cfg_sts = enable;
2759
2760 return rc;
2761}
2762
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302763static int msmsdcc_cfg_mpm_sdiowakeup(struct msmsdcc_host *host,
2764 unsigned mode)
2765{
2766 int ret = 0;
2767 unsigned int pin = host->plat->mpm_sdiowakeup_int;
2768
2769 if (!pin)
2770 return 0;
2771
2772 switch (mode) {
2773 case SDC_DAT1_DISABLE:
2774 ret = msm_mpm_enable_pin(pin, 0);
2775 break;
2776 case SDC_DAT1_ENABLE:
2777 ret = msm_mpm_set_pin_type(pin, IRQ_TYPE_LEVEL_LOW);
2778 ret = msm_mpm_enable_pin(pin, 1);
2779 break;
2780 case SDC_DAT1_ENWAKE:
2781 ret = msm_mpm_set_pin_wake(pin, 1);
2782 break;
2783 case SDC_DAT1_DISWAKE:
2784 ret = msm_mpm_set_pin_wake(pin, 0);
2785 break;
2786 default:
2787 ret = -EINVAL;
2788 break;
2789 }
2790
2791 return ret;
2792}
2793
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302794static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2795{
2796 u32 pwr = 0;
2797 int ret = 0;
2798 struct mmc_host *mmc = host->mmc;
2799
2800 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2801 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2802 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
Krishna Konda3c4142d2012-06-27 11:01:56 -07002803 ret = msmsdcc_setup_vreg(host, !!ios->vdd, false);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302804
2805 if (ret) {
2806 pr_err("%s: Failed to setup voltage regulators\n",
2807 mmc_hostname(host->mmc));
2808 goto out;
2809 }
2810
2811 switch (ios->power_mode) {
2812 case MMC_POWER_OFF:
2813 pwr = MCI_PWR_OFF;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302814 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302815 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05302816 * If VDD IO rail is always on, set low voltage for VDD
2817 * IO rail when slot is not in use (like when card is not
2818 * present or during system suspend).
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302819 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302820 msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Subhash Jadavanibf09d802012-08-11 18:11:57 +05302821 msmsdcc_update_io_pad_pwr_switch(host);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302822 msmsdcc_setup_pins(host, false);
Pratibhasagar Vbe4e3132012-09-20 19:46:11 +05302823 /*
2824 * Reset the mask to prevent hitting any pending interrupts
2825 * after powering up the card again.
2826 */
2827 if (atomic_read(&host->clks_on)) {
2828 writel_relaxed(0, host->base + MMCIMASK0);
2829 mb();
2830 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302831 break;
2832 case MMC_POWER_UP:
2833 /* writing PWR_UP bit is redundant */
2834 pwr = MCI_PWR_UP;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302835 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302836
Subhash Jadavani937c7502012-06-01 15:34:46 +05302837 msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Subhash Jadavanibf09d802012-08-11 18:11:57 +05302838 msmsdcc_update_io_pad_pwr_switch(host);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302839 msmsdcc_setup_pins(host, true);
2840 break;
2841 case MMC_POWER_ON:
2842 pwr = MCI_PWR_ON;
2843 break;
2844 }
2845
2846out:
2847 return pwr;
2848}
2849
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002850static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2851{
2852 unsigned int wakeup_irq;
2853
2854 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2855 host->plat->sdiowakeup_irq :
2856 host->core_irqres->start;
2857
2858 if (!host->irq_wake_enabled) {
2859 enable_irq_wake(wakeup_irq);
2860 host->irq_wake_enabled = true;
2861 }
2862}
2863
2864static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2865{
2866 unsigned int wakeup_irq;
2867
2868 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2869 host->plat->sdiowakeup_irq :
2870 host->core_irqres->start;
2871
2872 if (host->irq_wake_enabled) {
2873 disable_irq_wake(wakeup_irq);
2874 host->irq_wake_enabled = false;
2875 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302876}
2877
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05302878/* Returns required bandwidth in Bytes per Sec */
2879static unsigned int msmsdcc_get_bw_required(struct msmsdcc_host *host,
2880 struct mmc_ios *ios)
2881{
2882 unsigned int bw;
2883
2884 bw = host->clk_rate;
2885 /*
2886 * For DDR mode, SDCC controller clock will be at
2887 * the double rate than the actual clock that goes to card.
2888 */
2889 if (ios->bus_width == MMC_BUS_WIDTH_4)
2890 bw /= 2;
2891 else if (ios->bus_width == MMC_BUS_WIDTH_1)
2892 bw /= 8;
2893
2894 return bw;
2895}
2896
2897static int msmsdcc_msm_bus_get_vote_for_bw(struct msmsdcc_host *host,
2898 unsigned int bw)
2899{
2900 unsigned int *table = host->plat->msm_bus_voting_data->bw_vecs;
2901 unsigned int size = host->plat->msm_bus_voting_data->bw_vecs_size;
2902 int i;
2903
2904 if (host->msm_bus_vote.is_max_bw_needed && bw)
2905 return host->msm_bus_vote.max_bw_vote;
2906
2907 for (i = 0; i < size; i++) {
2908 if (bw <= table[i])
2909 break;
2910 }
2911
2912 if (i && (i == size))
2913 i--;
2914
2915 return i;
2916}
2917
2918static int msmsdcc_msm_bus_register(struct msmsdcc_host *host)
2919{
2920 int rc = 0;
2921 struct msm_bus_scale_pdata *use_cases;
2922
2923 if (host->plat->msm_bus_voting_data &&
2924 host->plat->msm_bus_voting_data->use_cases &&
2925 host->plat->msm_bus_voting_data->bw_vecs &&
2926 host->plat->msm_bus_voting_data->bw_vecs_size) {
2927 use_cases = host->plat->msm_bus_voting_data->use_cases;
2928 host->msm_bus_vote.client_handle =
2929 msm_bus_scale_register_client(use_cases);
2930 } else {
2931 return 0;
2932 }
2933
2934 if (!host->msm_bus_vote.client_handle) {
2935 pr_err("%s: msm_bus_scale_register_client() failed\n",
2936 mmc_hostname(host->mmc));
2937 rc = -EFAULT;
2938 } else {
2939 /* cache the vote index for minimum and maximum bandwidth */
2940 host->msm_bus_vote.min_bw_vote =
2941 msmsdcc_msm_bus_get_vote_for_bw(host, 0);
2942 host->msm_bus_vote.max_bw_vote =
2943 msmsdcc_msm_bus_get_vote_for_bw(host, UINT_MAX);
2944 }
2945
2946 return rc;
2947}
2948
2949static void msmsdcc_msm_bus_unregister(struct msmsdcc_host *host)
2950{
2951 if (host->msm_bus_vote.client_handle)
2952 msm_bus_scale_unregister_client(
2953 host->msm_bus_vote.client_handle);
2954}
2955
2956/*
2957 * This function must be called with host lock acquired.
2958 * Caller of this function should also ensure that msm bus client
2959 * handle is not null.
2960 */
2961static inline int msmsdcc_msm_bus_set_vote(struct msmsdcc_host *host,
2962 int vote,
2963 unsigned long flags)
2964{
2965 int rc = 0;
2966
2967 if (vote != host->msm_bus_vote.curr_vote) {
2968 spin_unlock_irqrestore(&host->lock, flags);
2969 rc = msm_bus_scale_client_update_request(
2970 host->msm_bus_vote.client_handle, vote);
2971 if (rc)
2972 pr_err("%s: msm_bus_scale_client_update_request() failed."
2973 " bus_client_handle=0x%x, vote=%d, err=%d\n",
2974 mmc_hostname(host->mmc),
2975 host->msm_bus_vote.client_handle, vote, rc);
2976 spin_lock_irqsave(&host->lock, flags);
2977 if (!rc)
2978 host->msm_bus_vote.curr_vote = vote;
2979 }
2980
2981 return rc;
2982}
2983
2984/*
2985 * Internal work. Work to set 0 bandwidth for msm bus.
2986 */
2987static void msmsdcc_msm_bus_work(struct work_struct *work)
2988{
2989 struct msmsdcc_host *host = container_of(work,
2990 struct msmsdcc_host,
2991 msm_bus_vote.vote_work.work);
2992 unsigned long flags;
2993
2994 if (!host->msm_bus_vote.client_handle)
2995 return;
2996
2997 spin_lock_irqsave(&host->lock, flags);
2998 /* don't vote for 0 bandwidth if any request is in progress */
2999 if (!host->curr.mrq)
3000 msmsdcc_msm_bus_set_vote(host,
3001 host->msm_bus_vote.min_bw_vote, flags);
3002 else
3003 pr_warning("%s: %s: SDCC transfer in progress. skipping"
3004 " bus voting to 0 bandwidth\n",
3005 mmc_hostname(host->mmc), __func__);
3006 spin_unlock_irqrestore(&host->lock, flags);
3007}
3008
3009/*
3010 * This function cancels any scheduled delayed work
3011 * and sets the bus vote based on ios argument.
3012 * If "ios" argument is NULL, bandwidth required is 0 else
3013 * calculate the bandwidth based on ios parameters.
3014 */
3015static void msmsdcc_msm_bus_cancel_work_and_set_vote(
3016 struct msmsdcc_host *host,
3017 struct mmc_ios *ios)
3018{
3019 unsigned long flags;
3020 unsigned int bw;
3021 int vote;
3022
3023 if (!host->msm_bus_vote.client_handle)
3024 return;
3025
3026 bw = ios ? msmsdcc_get_bw_required(host, ios) : 0;
3027
3028 cancel_delayed_work_sync(&host->msm_bus_vote.vote_work);
3029 spin_lock_irqsave(&host->lock, flags);
3030 vote = msmsdcc_msm_bus_get_vote_for_bw(host, bw);
3031 msmsdcc_msm_bus_set_vote(host, vote, flags);
3032 spin_unlock_irqrestore(&host->lock, flags);
3033}
3034
3035/* This function queues a work which will set the bandwidth requiement to 0 */
3036static void msmsdcc_msm_bus_queue_work(struct msmsdcc_host *host)
3037{
3038 unsigned long flags;
3039
3040 if (!host->msm_bus_vote.client_handle)
3041 return;
3042
3043 spin_lock_irqsave(&host->lock, flags);
3044 if (host->msm_bus_vote.min_bw_vote != host->msm_bus_vote.curr_vote)
3045 queue_delayed_work(system_nrt_wq,
3046 &host->msm_bus_vote.vote_work,
3047 msecs_to_jiffies(MSM_MMC_BUS_VOTING_DELAY));
3048 spin_unlock_irqrestore(&host->lock, flags);
3049}
3050
San Mehat9d2bd732009-09-22 16:44:22 -07003051static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303052msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
3053{
3054 struct mmc_host *mmc = host->mmc;
3055
3056 /*
3057 * SDIO_AL clients has different mechanism of handling LPM through
3058 * sdio_al driver itself. The sdio wakeup interrupt is configured as
3059 * part of that. Here, we are interested only in clients like WLAN.
3060 */
3061 if (!(mmc->card && mmc_card_sdio(mmc->card))
3062 || host->plat->is_sdio_al_client)
3063 goto out;
3064
3065 if (!host->sdcc_suspended) {
3066 /*
3067 * When MSM is not in power collapse and we
3068 * are disabling clocks, enable bit 22 in MASK0
3069 * to handle asynchronous SDIO interrupts.
3070 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05303071 if (enable_wakeup_irq) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303072 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303073 mb();
3074 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303075 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303076 msmsdcc_sync_reg_wr(host);
3077 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303078 goto out;
3079 } else if (!mmc_card_wake_sdio_irq(mmc)) {
3080 /*
3081 * Wakeup MSM only if SDIO function drivers set
3082 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
3083 */
3084 goto out;
3085 }
3086
3087 if (enable_wakeup_irq) {
3088 if (!host->plat->sdiowakeup_irq) {
3089 /*
3090 * When there is no gpio line that can be configured
3091 * as wakeup interrupt handle it by configuring
3092 * asynchronous sdio interrupts and DAT1 line.
3093 */
3094 writel_relaxed(MCI_SDIOINTMASK,
3095 host->base + MMCIMASK0);
3096 mb();
Subhash Jadavanic9b85752012-04-13 11:16:49 +05303097 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303098 /* configure sdcc core interrupt as wakeup interrupt */
3099 msmsdcc_enable_irq_wake(host);
3100 } else {
3101 /* Let gpio line handle wakeup interrupt */
3102 writel_relaxed(0, host->base + MMCIMASK0);
3103 mb();
3104 if (host->sdio_wakeupirq_disabled) {
3105 host->sdio_wakeupirq_disabled = 0;
3106 /* configure gpio line as wakeup interrupt */
3107 msmsdcc_enable_irq_wake(host);
3108 enable_irq(host->plat->sdiowakeup_irq);
3109 }
3110 }
3111 } else {
3112 if (!host->plat->sdiowakeup_irq) {
3113 /*
3114 * We may not have cleared bit 22 in the interrupt
3115 * handler as the clocks might be off at that time.
3116 */
3117 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303118 msmsdcc_sync_reg_wr(host);
Subhash Jadavanic9b85752012-04-13 11:16:49 +05303119 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303120 msmsdcc_disable_irq_wake(host);
3121 } else if (!host->sdio_wakeupirq_disabled) {
3122 disable_irq_nosync(host->plat->sdiowakeup_irq);
3123 msmsdcc_disable_irq_wake(host);
3124 host->sdio_wakeupirq_disabled = 1;
3125 }
3126 }
3127out:
3128 return;
San Mehat9d2bd732009-09-22 16:44:22 -07003129}
3130
3131static void
3132msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
3133{
3134 struct msmsdcc_host *host = mmc_priv(mmc);
3135 u32 clk = 0, pwr = 0;
3136 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08003137 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003138 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07003139
Sahitya Tummala7a892482011-01-18 11:22:49 +05303140
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303141 /*
3142 * Disable SDCC core interrupt until set_ios is completed.
3143 * This avoids any race conditions with interrupt raised
3144 * when turning on/off the clocks. One possible
3145 * scenario is SDIO operational interrupt while the clock
3146 * is turned off.
Asutosh Dasf5298c32012-04-03 14:51:47 +05303147 * host->lock is being released intermittently below.
3148 * Thus, prevent concurrent access to host.
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303149 */
3150
Asutosh Dasf5298c32012-04-03 14:51:47 +05303151 mutex_lock(&host->clk_mutex);
3152 DBG(host, "ios->clock = %u\n", ios->clock);
San Mehat9d2bd732009-09-22 16:44:22 -07003153 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303154 if (!host->sdcc_irq_disabled) {
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05303155 disable_irq_nosync(host->core_irqres->start);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303156 host->sdcc_irq_disabled = 1;
3157 }
San Mehatd0719e52009-12-03 10:58:54 -08003158 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07003159
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05303160 /* Make sure sdcc core irq is synchronized */
3161 synchronize_irq(host->core_irqres->start);
3162
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303163 pwr = msmsdcc_setup_pwr(host, ios);
3164
3165 spin_lock_irqsave(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07003166 if (ios->clock) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303167 spin_unlock_irqrestore(&host->lock, flags);
3168 rc = msmsdcc_setup_clocks(host, true);
3169 if (rc)
3170 goto out;
3171 spin_lock_irqsave(&host->lock, flags);
3172 writel_relaxed(host->mci_irqenable, host->base + MMCIMASK0);
3173 mb();
3174 msmsdcc_cfg_sdio_wakeup(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003175 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303176
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003177 /*
3178 * For DDR50 mode, controller needs clock rate to be
3179 * double than what is required on the SD card CLK pin.
Subhash Jadavani2226d262012-10-09 20:01:56 +05303180 *
3181 * Setting DDR timing mode in controller before setting the
3182 * clock rate will make sure that card don't see the double
3183 * clock rate even for very small duration. Some eMMC
3184 * cards seems to lock up if they see clock frequency > 52MHz.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003185 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05303186 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Subhash Jadavani2226d262012-10-09 20:01:56 +05303187 u32 clk;
3188
3189 clk = readl_relaxed(host->base + MMCICLOCK);
3190 clk &= ~(0x7 << 14); /* clear SELECT_IN field */
3191 clk |= (3 << 14); /* set DDR timing mode */
3192 writel_relaxed(clk, host->base + MMCICLOCK);
3193 msmsdcc_sync_reg_wr(host);
3194
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003195 /*
3196 * Make sure that we don't double the clock if
3197 * doubled clock rate is already set
3198 */
3199 if (!host->ddr_doubled_clk_rate ||
3200 (host->ddr_doubled_clk_rate &&
3201 (host->ddr_doubled_clk_rate != ios->clock))) {
3202 host->ddr_doubled_clk_rate =
3203 msmsdcc_get_sup_clk_rate(
3204 host, (ios->clock * 2));
3205 clock = host->ddr_doubled_clk_rate;
3206 }
3207 } else {
3208 host->ddr_doubled_clk_rate = 0;
3209 }
3210
3211 if (clock != host->clk_rate) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05303212 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003213 rc = clk_set_rate(host->clk, clock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303214 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003215 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303216 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003217 mmc_hostname(mmc), clock);
3218 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303219 host->reg_write_delay =
3220 (1 + ((3 * USEC_PER_SEC) /
3221 (host->clk_rate ? host->clk_rate :
3222 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003223 }
3224 /*
3225 * give atleast 2 MCLK cycles delay for clocks
3226 * and SDCC core to stabilize
3227 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05303228 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003229 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003230 clk |= MCI_CLK_ENABLE;
3231 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003232 if (ios->bus_width == MMC_BUS_WIDTH_8)
3233 clk |= MCI_CLK_WIDEBUS_8;
3234 else if (ios->bus_width == MMC_BUS_WIDTH_4)
3235 clk |= MCI_CLK_WIDEBUS_4;
3236 else
3237 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07003238
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003239 if (msmsdcc_is_pwrsave(host))
3240 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07003241
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003242 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07003243
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003244 host->tuning_needed = 0;
3245 /*
3246 * Select the controller timing mode according
3247 * to current bus speed mode
3248 */
Subhash Jadavanif97d2992012-07-13 14:47:47 +05303249 if (host->clk_rate > (100 * 1000 * 1000) &&
3250 (ios->timing == MMC_TIMING_UHS_SDR104 ||
3251 ios->timing == MMC_TIMING_MMC_HS200)) {
3252 /* Card clock frequency must be > 100MHz to enable tuning */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003253 clk |= (4 << 14);
3254 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05303255 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003256 clk |= (3 << 14);
3257 } else {
3258 clk |= (2 << 14); /* feedback clock */
San Mehat9d2bd732009-09-22 16:44:22 -07003259 }
3260
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003261 /* Select free running MCLK as input clock of cm_dll_sdc4 */
3262 clk |= (2 << 23);
San Mehat9d2bd732009-09-22 16:44:22 -07003263
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003264 if (host->io_pad_pwr_switch)
3265 clk |= IO_PAD_PWR_SWITCH;
3266
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303267 /* Don't write into registers if clocks are disabled */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303268 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303269 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
3270 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303271 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003272 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303273 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
3274 host->pwr = pwr;
3275 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303276 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003277 }
San Mehat9d2bd732009-09-22 16:44:22 -07003278 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003279
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303280 if (!(clk & MCI_CLK_ENABLE) && atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303281 msmsdcc_cfg_sdio_wakeup(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303282 spin_unlock_irqrestore(&host->lock, flags);
3283 /*
3284 * May get a wake-up interrupt the instant we disable the
3285 * clocks. This would disable the wake-up interrupt.
3286 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003287 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303288 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003289 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303290
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303291 if (host->tuning_in_progress)
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303292 WARN(!atomic_read(&host->clks_on),
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303293 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303294
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303295 /* Let interrupts be disabled if the host is powered off */
3296 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
3297 enable_irq(host->core_irqres->start);
3298 host->sdcc_irq_disabled = 0;
3299 }
San Mehat4adbbcc2009-11-08 13:00:37 -08003300 spin_unlock_irqrestore(&host->lock, flags);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303301out:
Asutosh Dasf5298c32012-04-03 14:51:47 +05303302 mutex_unlock(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07003303}
3304
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003305int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
3306{
3307 struct msmsdcc_host *host = mmc_priv(mmc);
3308 u32 clk;
3309
3310 clk = readl_relaxed(host->base + MMCICLOCK);
3311 pr_debug("Changing to pwr_save=%d", pwrsave);
3312 if (pwrsave && msmsdcc_is_pwrsave(host))
3313 clk |= MCI_CLK_PWRSAVE;
3314 else
3315 clk &= ~MCI_CLK_PWRSAVE;
3316 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303317 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003318
3319 return 0;
3320}
3321
3322static int msmsdcc_get_ro(struct mmc_host *mmc)
3323{
3324 int status = -ENOSYS;
3325 struct msmsdcc_host *host = mmc_priv(mmc);
3326
3327 if (host->plat->wpswitch) {
3328 status = host->plat->wpswitch(mmc_dev(mmc));
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05303329 } else if (gpio_is_valid(host->plat->wpswitch_gpio)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003330 status = gpio_request(host->plat->wpswitch_gpio,
3331 "SD_WP_Switch");
3332 if (status) {
3333 pr_err("%s: %s: Failed to request GPIO %d\n",
3334 mmc_hostname(mmc), __func__,
3335 host->plat->wpswitch_gpio);
3336 } else {
3337 status = gpio_direction_input(
3338 host->plat->wpswitch_gpio);
3339 if (!status) {
3340 /*
3341 * Wait for atleast 300ms as debounce
3342 * time for GPIO input to stabilize.
3343 */
3344 msleep(300);
3345 status = gpio_get_value_cansleep(
3346 host->plat->wpswitch_gpio);
Sujit Reddy Thumma8f912ea2012-06-22 16:18:43 +05303347 status ^= !host->plat->is_wpswitch_active_low;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003348 }
3349 gpio_free(host->plat->wpswitch_gpio);
3350 }
3351 }
3352
3353 if (status < 0)
3354 status = -ENOSYS;
3355 pr_debug("%s: Card read-only status %d\n", __func__, status);
3356
3357 return status;
San Mehat9d2bd732009-09-22 16:44:22 -07003358}
3359
3360static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
3361{
3362 struct msmsdcc_host *host = mmc_priv(mmc);
3363 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003364
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303365 /*
3366 * We may come here with clocks turned off in that case don't
3367 * attempt to write into MASK0 register. While turning on the
3368 * clocks mci_irqenable will be written to MASK0 register.
3369 */
San Mehat9d2bd732009-09-22 16:44:22 -07003370
3371 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003372 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003373 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303374 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303375 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003376 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303377 mb();
3378 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003379 } else {
3380 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303381 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303382 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003383 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303384 mb();
3385 }
San Mehat9d2bd732009-09-22 16:44:22 -07003386 }
3387 spin_unlock_irqrestore(&host->lock, flags);
3388}
3389
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003390#ifdef CONFIG_PM_RUNTIME
subhashj245831e2012-04-30 18:46:17 +05303391static void msmsdcc_print_rpm_info(struct msmsdcc_host *host)
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003392{
subhashj245831e2012-04-30 18:46:17 +05303393 struct device *dev = mmc_dev(host->mmc);
3394
Subhash Jadavani1371d192012-08-16 18:46:57 +05303395 pr_info("%s: PM: sdcc_suspended=%d, pending_resume=%d, sdcc_suspending=%d\n",
3396 mmc_hostname(host->mmc), host->sdcc_suspended,
3397 host->pending_resume, host->sdcc_suspending);
subhashj245831e2012-04-30 18:46:17 +05303398 pr_info("%s: RPM: runtime_status=%d, usage_count=%d,"
3399 " is_suspended=%d, disable_depth=%d, runtime_error=%d,"
3400 " request_pending=%d, request=%d\n",
3401 mmc_hostname(host->mmc), dev->power.runtime_status,
3402 atomic_read(&dev->power.usage_count),
3403 dev->power.is_suspended, dev->power.disable_depth,
3404 dev->power.runtime_error, dev->power.request_pending,
3405 dev->power.request);
3406}
3407
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003408static int msmsdcc_enable(struct mmc_host *mmc)
3409{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003410 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003411 struct device *dev = mmc->parent;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003412 struct msmsdcc_host *host = mmc_priv(mmc);
3413
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303414 msmsdcc_pm_qos_update_latency(host, 1);
3415
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003416 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303417 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003418
Subhash Jadavani1371d192012-08-16 18:46:57 +05303419 if (host->sdcc_suspended && host->pending_resume) {
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003420 host->pending_resume = false;
3421 pm_runtime_get_noresume(dev);
3422 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303423 goto skip_get_sync;
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003424 }
3425
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303426 if (dev->power.runtime_status == RPM_SUSPENDING) {
3427 if (mmc->suspend_task == current) {
3428 pm_runtime_get_noresume(dev);
3429 goto out;
3430 }
Sujit Reddy Thumma112bd752012-06-20 12:29:45 +05303431 } else if (dev->power.runtime_status == RPM_RESUMING) {
3432 pm_runtime_get_noresume(dev);
3433 goto out;
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303434 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003435
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303436 rc = pm_runtime_get_sync(dev);
3437
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303438skip_get_sync:
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303439 if (rc < 0) {
Subhash Jadavani1371d192012-08-16 18:46:57 +05303440 WARN(1, "%s: %s: failed with error %d\n", mmc_hostname(mmc),
3441 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303442 msmsdcc_print_rpm_info(host);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303443 return rc;
3444 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303445out:
3446 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303447 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003448}
3449
Steve Mucklef132c6c2012-06-06 18:30:57 -07003450static int msmsdcc_disable(struct mmc_host *mmc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003451{
3452 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303453 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003454
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303455 msmsdcc_pm_qos_update_latency(host, 0);
3456
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303457 if (mmc->card && mmc_card_sdio(mmc->card)) {
3458 rc = 0;
3459 goto out;
3460 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303461
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303462 if (host->plat->disable_runtime_pm)
3463 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003464
3465 rc = pm_runtime_put_sync(mmc->parent);
3466
Subhash Jadavani1371d192012-08-16 18:46:57 +05303467 if (rc < 0) {
3468 WARN(1, "%s: %s: failed with error %d\n", mmc_hostname(mmc),
3469 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303470 msmsdcc_print_rpm_info(host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003471 return rc;
3472 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303473
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303474out:
3475 msmsdcc_msm_bus_queue_work(host);
3476 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003477}
3478#else
subhashj245831e2012-04-30 18:46:17 +05303479static void msmsdcc_print_rpm_info(struct msmsdcc_host *host) {}
3480
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303481static int msmsdcc_enable(struct mmc_host *mmc)
3482{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003483 struct device *dev = mmc->parent;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303484 struct msmsdcc_host *host = mmc_priv(mmc);
Sujit Reddy Thumma7f5051c2012-05-04 10:14:07 +05303485 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303486
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303487 msmsdcc_pm_qos_update_latency(host, 1);
3488
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303489 if (mmc->card && mmc_card_sdio(mmc->card)) {
3490 rc = 0;
3491 goto out;
3492 }
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003493
3494 if (host->sdcc_suspended && host->pending_resume) {
3495 host->pending_resume = false;
3496 rc = msmsdcc_runtime_resume(dev);
3497 goto out;
3498 }
3499
Asutosh Dasf5298c32012-04-03 14:51:47 +05303500 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303501 rc = msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303502 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303503
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003504out:
3505 if (rc < 0) {
3506 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3507 __func__, rc);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303508 msmsdcc_pm_qos_update_latency(host, 0);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003509 return rc;
3510 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303511 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303512 return 0;
3513}
3514
Steve Mucklef132c6c2012-06-06 18:30:57 -07003515static int msmsdcc_disable(struct mmc_host *mmc)
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303516{
3517 struct msmsdcc_host *host = mmc_priv(mmc);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303518 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303519
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303520 msmsdcc_pm_qos_update_latency(host, 0);
3521
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303522 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303523 goto out;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303524
Asutosh Dasf5298c32012-04-03 14:51:47 +05303525 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303526 rc = msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303527 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303528
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303529 if (rc) {
3530 msmsdcc_pm_qos_update_latency(host, 1);
3531 return rc;
3532 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303533out:
3534 msmsdcc_msm_bus_queue_work(host);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303535 return rc;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303536}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003537#endif
3538
Subhash Jadavani937c7502012-06-01 15:34:46 +05303539static int msmsdcc_switch_io_voltage(struct mmc_host *mmc,
3540 struct mmc_ios *ios)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003541{
3542 struct msmsdcc_host *host = mmc_priv(mmc);
3543 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303544 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003545
Subhash Jadavani937c7502012-06-01 15:34:46 +05303546 switch (ios->signal_voltage) {
3547 case MMC_SIGNAL_VOLTAGE_330:
3548 /* Set VDD IO to high voltage range (2.7v - 3.6v) */
3549 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Subhash Jadavanibf09d802012-08-11 18:11:57 +05303550 if (!rc)
3551 msmsdcc_update_io_pad_pwr_switch(host);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303552 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303553 case MMC_SIGNAL_VOLTAGE_180:
3554 break;
3555 case MMC_SIGNAL_VOLTAGE_120:
3556 /*
3557 * For eMMC cards, VDD_IO voltage range must be changed
3558 * only if it operates in HS200 SDR 1.2V mode or in
3559 * DDR 1.2V mode.
3560 */
3561 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_SET_LEVEL, 1200000);
Subhash Jadavanibf09d802012-08-11 18:11:57 +05303562 if (!rc)
3563 msmsdcc_update_io_pad_pwr_switch(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003564 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303565 default:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003566 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303567 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003568 goto out;
3569 }
San Mehat9d2bd732009-09-22 16:44:22 -07003570
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003571 /*
3572 * If we are here means voltage switch from high voltage to
3573 * low voltage is required
3574 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303575 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003576
3577 /*
3578 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
3579 * register until they become all zeros.
3580 */
3581 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303582 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003583 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
3584 mmc_hostname(mmc), __func__);
3585 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07003586 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003587
3588 /* Stop SD CLK output. */
3589 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3590 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303591 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003592 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003593
3594 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05303595 * Switch VDD Io from high voltage range (2.7v - 3.6v) to
3596 * low voltage range (1.7v - 1.95v).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003597 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303598 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303599 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003600 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003601
Subhash Jadavanibf09d802012-08-11 18:11:57 +05303602 msmsdcc_update_io_pad_pwr_switch(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003603
3604 /* Wait 5 ms for the voltage regulater in the card to become stable. */
3605 usleep_range(5000, 5500);
3606
3607 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303608 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003609 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3610 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303611 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003612 spin_unlock_irqrestore(&host->lock, flags);
3613
3614 /*
3615 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
3616 * don't become all ones within 1 ms then a Voltage Switch
3617 * sequence has failed and a power cycle to the card is required.
3618 * Otherwise Voltage Switch sequence is completed successfully.
3619 */
3620 usleep_range(1000, 1500);
3621
3622 spin_lock_irqsave(&host->lock, flags);
3623 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
3624 != (0xF << 1)) {
3625 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
3626 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303627 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003628 goto out_unlock;
3629 }
3630
3631out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303632 /* Enable PWRSAVE */
3633 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3634 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303635 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003636 spin_unlock_irqrestore(&host->lock, flags);
3637out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303638 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003639}
3640
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303641static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003642{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003643 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003644
3645 /* Program the MCLK value to MCLK_FREQ bit field */
3646 if (host->clk_rate <= 112000000)
3647 mclk_freq = 0;
3648 else if (host->clk_rate <= 125000000)
3649 mclk_freq = 1;
3650 else if (host->clk_rate <= 137000000)
3651 mclk_freq = 2;
3652 else if (host->clk_rate <= 150000000)
3653 mclk_freq = 3;
3654 else if (host->clk_rate <= 162000000)
3655 mclk_freq = 4;
3656 else if (host->clk_rate <= 175000000)
3657 mclk_freq = 5;
3658 else if (host->clk_rate <= 187000000)
3659 mclk_freq = 6;
3660 else if (host->clk_rate <= 200000000)
3661 mclk_freq = 7;
3662
3663 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3664 & ~(7 << 24)) | (mclk_freq << 24)),
3665 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003666}
3667
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303668/* Initialize the DLL (Programmable Delay Line ) */
3669static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003670{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003671 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303672 unsigned long flags;
3673 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003674
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303675 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003676 /*
3677 * Make sure that clock is always enabled when DLL
3678 * tuning is in progress. Keeping PWRSAVE ON may
3679 * turn off the clock. So let's disable the PWRSAVE
3680 * here and re-enable it once tuning is completed.
3681 */
3682 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3683 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303684 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303685
3686 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3687 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3688 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3689
3690 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3691 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3692 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3693
3694 msmsdcc_cm_sdc4_dll_set_freq(host);
3695
3696 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3697 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3698 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3699
3700 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3701 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3702 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3703
3704 /* Set DLL_EN bit to 1. */
3705 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3706 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3707
3708 /* Set CK_OUT_EN bit to 1. */
3709 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3710 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3711
3712 wait_cnt = 50;
3713 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3714 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3715 /* max. wait for 50us sec for LOCK bit to be set */
3716 if (--wait_cnt == 0) {
3717 pr_err("%s: %s: DLL failed to LOCK\n",
3718 mmc_hostname(host->mmc), __func__);
3719 rc = -ETIMEDOUT;
3720 goto out;
3721 }
3722 /* wait for 1us before polling again */
3723 udelay(1);
3724 }
3725
3726out:
3727 /* re-enable PWRSAVE */
3728 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3729 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303730 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303731 spin_unlock_irqrestore(&host->lock, flags);
3732
3733 return rc;
3734}
3735
3736static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3737 u8 poll)
3738{
3739 int rc = 0;
3740 u32 wait_cnt = 50;
3741 u8 ck_out_en = 0;
3742
3743 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3744 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3745 MCI_CK_OUT_EN);
3746
3747 while (ck_out_en != poll) {
3748 if (--wait_cnt == 0) {
3749 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3750 mmc_hostname(host->mmc), __func__, poll);
3751 rc = -ETIMEDOUT;
3752 goto out;
3753 }
3754 udelay(1);
3755
3756 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3757 MCI_CK_OUT_EN);
3758 }
3759out:
3760 return rc;
3761}
3762
3763/*
3764 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3765 * calibration sequence. This function should be called before
3766 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3767 * commands (CMD17/CMD18).
3768 *
3769 * This function gets called when host spinlock acquired.
3770 */
3771static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3772{
3773 int rc = 0;
3774 u32 config;
3775
3776 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3777 config |= MCI_CDR_EN;
3778 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3779 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3780
3781 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3782 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3783 if (rc)
3784 goto err_out;
3785
3786 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3787 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3788 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3789
3790 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3791 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3792 if (rc)
3793 goto err_out;
3794
3795 goto out;
3796
3797err_out:
3798 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3799out:
3800 return rc;
3801}
3802
3803static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3804 u8 phase)
3805{
3806 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303807 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3808 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3809 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303810 unsigned long flags;
3811 u32 config;
3812
3813 spin_lock_irqsave(&host->lock, flags);
3814
3815 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3816 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3817 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3818 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3819
3820 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3821 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3822 if (rc)
3823 goto err_out;
3824
3825 /*
3826 * Write the selected DLL clock output phase (0 ... 15)
3827 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
3828 */
3829 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3830 & ~(0xF << 20))
3831 | (grey_coded_phase_table[phase] << 20)),
3832 host->base + MCI_DLL_CONFIG);
3833
3834 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3835 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3836 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3837
3838 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3839 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3840 if (rc)
3841 goto err_out;
3842
3843 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3844 config |= MCI_CDR_EN;
3845 config &= ~MCI_CDR_EXT_EN;
3846 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3847 goto out;
3848
3849err_out:
3850 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3851 mmc_hostname(host->mmc), __func__, phase);
3852out:
3853 spin_unlock_irqrestore(&host->lock, flags);
3854 return rc;
3855}
3856
3857/*
3858 * Find out the greatest range of consecuitive selected
3859 * DLL clock output phases that can be used as sampling
3860 * setting for SD3.0 UHS-I card read operation (in SDR104
3861 * timing mode) or for eMMC4.5 card read operation (in HS200
3862 * timing mode).
3863 * Select the 3/4 of the range and configure the DLL with the
3864 * selected DLL clock output phase.
3865*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303866static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303867 u8 *phase_table, u8 total_phases)
3868{
Subhash Jadavani6159c622012-03-15 19:05:55 +05303869 #define MAX_PHASES 16
Subhash Jadavani34187042012-03-02 10:59:49 +05303870 int ret;
Subhash Jadavani6159c622012-03-15 19:05:55 +05303871 u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
3872 u8 phases_per_row[MAX_PHASES] = {0};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303873 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303874 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3875 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303876
Subhash Jadavani6159c622012-03-15 19:05:55 +05303877 if (!total_phases || (total_phases > MAX_PHASES)) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303878 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3879 mmc_hostname(host->mmc), __func__, total_phases);
3880 return -EINVAL;
3881 }
3882
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303883 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303884 ranges[row_index][col_index] = phase_table[cnt];
3885 phases_per_row[row_index] += 1;
3886 col_index++;
3887
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303888 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303889 continue;
3890 /* check if next phase in phase_table is consecutive or not */
3891 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3892 row_index++;
3893 col_index = 0;
3894 }
3895 }
3896
Subhash Jadavani6159c622012-03-15 19:05:55 +05303897 if (row_index >= MAX_PHASES)
3898 return -EINVAL;
3899
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303900 /* Check if phase-0 is present in first valid window? */
3901 if (!ranges[0][0]) {
3902 phase_0_found = true;
3903 phase_0_raw_index = 0;
3904 /* Check if cycle exist between 2 valid windows */
3905 for (cnt = 1; cnt <= row_index; cnt++) {
3906 if (phases_per_row[cnt]) {
Subhash Jadavani6159c622012-03-15 19:05:55 +05303907 for (i = 0; i < phases_per_row[cnt]; i++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303908 if (ranges[cnt][i] == 15) {
3909 phase_15_found = true;
3910 phase_15_raw_index = cnt;
3911 break;
3912 }
3913 }
3914 }
3915 }
3916 }
3917
3918 /* If 2 valid windows form cycle then merge them as single window */
3919 if (phase_0_found && phase_15_found) {
3920 /* number of phases in raw where phase 0 is present */
3921 u8 phases_0 = phases_per_row[phase_0_raw_index];
3922 /* number of phases in raw where phase 15 is present */
3923 u8 phases_15 = phases_per_row[phase_15_raw_index];
3924
Subhash Jadavani6159c622012-03-15 19:05:55 +05303925 if (phases_0 + phases_15 >= MAX_PHASES)
3926 /*
3927 * If there are more than 1 phase windows then total
3928 * number of phases in both the windows should not be
3929 * more than or equal to MAX_PHASES.
3930 */
3931 return -EINVAL;
3932
3933 /* Merge 2 cyclic windows */
3934 i = phases_15;
3935 for (cnt = 0; cnt < phases_0; cnt++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303936 ranges[phase_15_raw_index][i] =
3937 ranges[phase_0_raw_index][cnt];
Subhash Jadavani6159c622012-03-15 19:05:55 +05303938 if (++i >= MAX_PHASES)
3939 break;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303940 }
Subhash Jadavani6159c622012-03-15 19:05:55 +05303941
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303942 phases_per_row[phase_0_raw_index] = 0;
3943 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
3944 }
3945
3946 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303947 if (phases_per_row[cnt] > curr_max) {
3948 curr_max = phases_per_row[cnt];
3949 selected_row_index = cnt;
3950 }
3951 }
3952
Subhash Jadavani6159c622012-03-15 19:05:55 +05303953 i = ((curr_max * 3) / 4);
3954 if (i)
3955 i--;
3956
Subhash Jadavani34187042012-03-02 10:59:49 +05303957 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303958
Subhash Jadavani6159c622012-03-15 19:05:55 +05303959 if (ret >= MAX_PHASES) {
3960 ret = -EINVAL;
3961 pr_err("%s: %s: invalid phase selected=%d\n",
3962 mmc_hostname(host->mmc), __func__, ret);
3963 }
3964
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303965 return ret;
3966}
3967
Girish K Sa3f41692012-02-29 12:00:09 +05303968static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303969{
3970 int rc = 0;
3971 struct msmsdcc_host *host = mmc_priv(mmc);
3972 unsigned long flags;
3973 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303974 const u32 *tuning_block_pattern = tuning_block_64;
3975 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303976
3977 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
3978
3979 /* Tuning is only required for SDR104 modes */
3980 if (!host->tuning_needed) {
3981 rc = 0;
3982 goto exit;
3983 }
3984
3985 spin_lock_irqsave(&host->lock, flags);
3986 WARN(!host->pwr, "SDCC power is turned off\n");
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303987 WARN(!atomic_read(&host->clks_on), "SDCC clocks are turned off\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303988 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
3989
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303990 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303991 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
3992 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
3993 tuning_block_pattern = tuning_block_128;
3994 size = sizeof(tuning_block_128);
3995 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303996 spin_unlock_irqrestore(&host->lock, flags);
3997
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003998 /* first of all reset the tuning block */
3999 rc = msmsdcc_init_cm_sdc4_dll(host);
4000 if (rc)
4001 goto out;
4002
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304003 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004004 if (!data_buf) {
4005 rc = -ENOMEM;
4006 goto out;
4007 }
4008
4009 phase = 0;
4010 do {
4011 struct mmc_command cmd = {0};
4012 struct mmc_data data = {0};
4013 struct mmc_request mrq = {
4014 .cmd = &cmd,
4015 .data = &data
4016 };
4017 struct scatterlist sg;
4018
4019 /* set the phase in delay line hw block */
4020 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
4021 if (rc)
4022 goto kfree;
4023
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304024 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004025 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
4026
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304027 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004028 data.blocks = 1;
4029 data.flags = MMC_DATA_READ;
4030 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
4031
4032 data.sg = &sg;
4033 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304034 sg_init_one(&sg, data_buf, size);
4035 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004036 mmc_wait_for_req(mmc, &mrq);
4037
4038 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304039 !memcmp(data_buf, tuning_block_pattern, size)) {
4040 /* tuning is successful at this tuning point */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004041 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304042 pr_debug("%s: %s: found good phase = %d\n",
4043 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004044 }
4045 } while (++phase < 16);
4046
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004047 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05304048 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304049 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05304050 if (rc < 0)
4051 goto kfree;
4052 else
4053 phase = (u8)rc;
4054
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004055 /*
4056 * Finally set the selected phase in delay
4057 * line hw block.
4058 */
4059 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
4060 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304061 goto kfree;
4062 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
4063 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004064 } else {
4065 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304066 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004067 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304068 msmsdcc_dump_sdcc_state(host);
4069 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004070 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004071
4072kfree:
4073 kfree(data_buf);
4074out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304075 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304076 host->tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304077 spin_unlock_irqrestore(&host->lock, flags);
4078exit:
4079 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004080 return rc;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04004081}
4082
Asutosh Dasebd7d092012-07-09 19:08:26 +05304083/*
4084 * Work around of the unavailability of a power_reset functionality in SD cards
4085 * by turning the OFF & back ON the regulators supplying the SD card.
4086 */
4087void msmsdcc_hw_reset(struct mmc_host *mmc)
4088{
4089 struct mmc_card *card = mmc->card;
4090 struct msmsdcc_host *host = mmc_priv(mmc);
4091 int rc;
4092
4093 /* Write-protection bits would be lost on a hardware reset in emmc */
4094 if (!card || !mmc_card_sd(card))
4095 return;
4096
4097 /*
4098 * Continuing on failing to disable regulator would lead to a panic
4099 * anyway, since the commands would fail and console would be flooded
4100 * with prints, eventually leading to a watchdog bark
4101 */
4102 rc = msmsdcc_setup_vreg(host, false, false);
4103 if (rc) {
4104 pr_err("%s: %s disable regulator: failed: %d\n",
4105 mmc_hostname(mmc), __func__, rc);
4106 BUG_ON(rc);
4107 }
4108
4109 /* 10ms delay for the supply to reach the desired voltage level */
4110 usleep_range(10000, 12000);
4111
4112 /*
4113 * Continuing on failing to enable regulator would lead to a panic
4114 * anyway, since the commands would fail and console would be flooded
4115 * with prints, eventually leading to a watchdog bark
4116 */
4117 rc = msmsdcc_setup_vreg(host, true, false);
4118 if (rc) {
4119 pr_err("%s: %s enable regulator: failed: %d\n",
4120 mmc_hostname(mmc), __func__, rc);
4121 BUG_ON(rc);
4122 }
4123
4124 /* 10ms delay for the supply to reach the desired voltage level */
4125 usleep_range(10000, 12000);
4126}
4127
San Mehat9d2bd732009-09-22 16:44:22 -07004128static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004129 .enable = msmsdcc_enable,
4130 .disable = msmsdcc_disable,
Asutosh Dasaccacd42012-03-08 14:33:17 +05304131 .pre_req = msmsdcc_pre_req,
4132 .post_req = msmsdcc_post_req,
San Mehat9d2bd732009-09-22 16:44:22 -07004133 .request = msmsdcc_request,
4134 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004135 .get_ro = msmsdcc_get_ro,
San Mehat9d2bd732009-09-22 16:44:22 -07004136 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Subhash Jadavani937c7502012-06-01 15:34:46 +05304137 .start_signal_voltage_switch = msmsdcc_switch_io_voltage,
Asutosh Dasebd7d092012-07-09 19:08:26 +05304138 .execute_tuning = msmsdcc_execute_tuning,
4139 .hw_reset = msmsdcc_hw_reset,
San Mehat9d2bd732009-09-22 16:44:22 -07004140};
4141
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004142static unsigned int
4143msmsdcc_slot_status(struct msmsdcc_host *host)
4144{
4145 int status;
4146 unsigned int gpio_no = host->plat->status_gpio;
4147
4148 status = gpio_request(gpio_no, "SD_HW_Detect");
4149 if (status) {
4150 pr_err("%s: %s: Failed to request GPIO %d\n",
4151 mmc_hostname(host->mmc), __func__, gpio_no);
4152 } else {
4153 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08004154 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08004155 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08004156 if (host->plat->is_status_gpio_active_low)
4157 status = !status;
4158 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004159 gpio_free(gpio_no);
4160 }
4161 return status;
4162}
4163
San Mehat9d2bd732009-09-22 16:44:22 -07004164static void
4165msmsdcc_check_status(unsigned long data)
4166{
4167 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4168 unsigned int status;
4169
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05304170 if (host->plat->status || gpio_is_valid(host->plat->status_gpio)) {
Krishna Konda941604a2012-01-10 17:46:34 -08004171 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004172 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004173 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004174 status = msmsdcc_slot_status(host);
4175
Krishna Konda941604a2012-01-10 17:46:34 -08004176 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08004177
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004178 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08004179 if (host->plat->status)
4180 pr_info("%s: Slot status change detected "
4181 "(%d -> %d)\n",
4182 mmc_hostname(host->mmc),
4183 host->oldstat, status);
4184 else if (host->plat->is_status_gpio_active_low)
4185 pr_info("%s: Slot status change detected "
4186 "(%d -> %d) and the card detect GPIO"
4187 " is ACTIVE_LOW\n",
4188 mmc_hostname(host->mmc),
4189 host->oldstat, status);
4190 else
4191 pr_info("%s: Slot status change detected "
4192 "(%d -> %d) and the card detect GPIO"
4193 " is ACTIVE_HIGH\n",
4194 mmc_hostname(host->mmc),
4195 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07004196 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004197 }
4198 host->oldstat = status;
4199 } else {
4200 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07004201 }
San Mehat9d2bd732009-09-22 16:44:22 -07004202}
4203
4204static irqreturn_t
4205msmsdcc_platform_status_irq(int irq, void *dev_id)
4206{
4207 struct msmsdcc_host *host = dev_id;
4208
Girish K Sa3c76eb2011-10-11 11:44:09 +05304209 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07004210 msmsdcc_check_status((unsigned long) host);
4211 return IRQ_HANDLED;
4212}
4213
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004214static irqreturn_t
4215msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
4216{
4217 struct msmsdcc_host *host = dev_id;
4218
4219 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
4220 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304221 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004222 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304223 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004224 wake_lock(&host->sdio_wlock);
4225 msmsdcc_disable_irq_wake(host);
4226 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304227 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004228 }
4229 if (host->plat->is_sdio_al_client) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004230 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304231 spin_unlock(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304232 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304233 goto out_unlocked;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004234 }
4235 spin_unlock(&host->lock);
4236
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304237out_unlocked:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004238 return IRQ_HANDLED;
4239}
4240
San Mehat9d2bd732009-09-22 16:44:22 -07004241static void
4242msmsdcc_status_notify_cb(int card_present, void *dev_id)
4243{
4244 struct msmsdcc_host *host = dev_id;
4245
Girish K Sa3c76eb2011-10-11 11:44:09 +05304246 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07004247 card_present);
4248 msmsdcc_check_status((unsigned long) host);
4249}
4250
San Mehat9d2bd732009-09-22 16:44:22 -07004251static int
4252msmsdcc_init_dma(struct msmsdcc_host *host)
4253{
4254 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
4255 host->dma.host = host;
4256 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004257 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004258
4259 if (!host->dmares)
4260 return -ENODEV;
4261
4262 host->dma.nc = dma_alloc_coherent(NULL,
4263 sizeof(struct msmsdcc_nc_dmadata),
4264 &host->dma.nc_busaddr,
4265 GFP_KERNEL);
4266 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004267 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07004268 return -ENOMEM;
4269 }
4270 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
4271 host->dma.cmd_busaddr = host->dma.nc_busaddr;
4272 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
4273 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
4274 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07004275 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07004276
4277 return 0;
4278}
4279
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004280#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
4281/**
4282 * Allocate and Connect a SDCC peripheral's SPS endpoint
4283 *
4284 * This function allocates endpoint context and
4285 * connect it with memory endpoint by calling
4286 * appropriate SPS driver APIs.
4287 *
4288 * Also registers a SPS callback function with
4289 * SPS driver
4290 *
4291 * This function should only be called once typically
4292 * during driver probe.
4293 *
4294 * @host - Pointer to sdcc host structure
4295 * @ep - Pointer to sps endpoint data structure
4296 * @is_produce - 1 means Producer endpoint
4297 * 0 means Consumer endpoint
4298 *
4299 * @return - 0 if successful else negative value.
4300 *
4301 */
4302static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
4303 struct msmsdcc_sps_ep_conn_data *ep,
4304 bool is_producer)
4305{
4306 int rc = 0;
4307 struct sps_pipe *sps_pipe_handle;
4308 struct sps_connect *sps_config = &ep->config;
4309 struct sps_register_event *sps_event = &ep->event;
4310
4311 /* Allocate endpoint context */
4312 sps_pipe_handle = sps_alloc_endpoint();
4313 if (!sps_pipe_handle) {
4314 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
4315 mmc_hostname(host->mmc), is_producer);
4316 rc = -ENOMEM;
4317 goto out;
4318 }
4319
4320 /* Get default connection configuration for an endpoint */
4321 rc = sps_get_config(sps_pipe_handle, sps_config);
4322 if (rc) {
4323 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
4324 " rc=%d", mmc_hostname(host->mmc),
4325 (u32)sps_pipe_handle, rc);
4326 goto get_config_err;
4327 }
4328
4329 /* Modify the default connection configuration */
4330 if (is_producer) {
4331 /*
4332 * For SDCC producer transfer, source should be
4333 * SDCC peripheral where as destination should
4334 * be system memory.
4335 */
4336 sps_config->source = host->sps.bam_handle;
4337 sps_config->destination = SPS_DEV_HANDLE_MEM;
4338 /* Producer pipe will handle this connection */
4339 sps_config->mode = SPS_MODE_SRC;
4340 sps_config->options =
4341 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4342 } else {
4343 /*
4344 * For SDCC consumer transfer, source should be
4345 * system memory where as destination should
4346 * SDCC peripheral
4347 */
4348 sps_config->source = SPS_DEV_HANDLE_MEM;
4349 sps_config->destination = host->sps.bam_handle;
4350 sps_config->mode = SPS_MODE_DEST;
4351 sps_config->options =
4352 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4353 }
4354
4355 /* Producer pipe index */
4356 sps_config->src_pipe_index = host->sps.src_pipe_index;
4357 /* Consumer pipe index */
4358 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
4359 /*
4360 * This event thresold value is only significant for BAM-to-BAM
4361 * transfer. It's ignored for BAM-to-System mode transfer.
4362 */
4363 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304364
4365 /* Allocate maximum descriptor fifo size */
4366 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
4367 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004368 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
4369 sps_config->desc.size,
4370 &sps_config->desc.phys_base,
4371 GFP_KERNEL);
4372
Pratibhasagar V00b94332011-10-18 14:57:27 +05304373 if (!sps_config->desc.base) {
4374 rc = -ENOMEM;
4375 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
4376 , mmc_hostname(host->mmc));
4377 goto get_config_err;
4378 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004379 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
4380
4381 /* Establish connection between peripheral and memory endpoint */
4382 rc = sps_connect(sps_pipe_handle, sps_config);
4383 if (rc) {
4384 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4385 " rc=%d", mmc_hostname(host->mmc),
4386 (u32)sps_pipe_handle, rc);
4387 goto sps_connect_err;
4388 }
4389
4390 sps_event->mode = SPS_TRIGGER_CALLBACK;
4391 sps_event->options = SPS_O_EOT;
4392 sps_event->callback = msmsdcc_sps_complete_cb;
4393 sps_event->xfer_done = NULL;
4394 sps_event->user = (void *)host;
4395
4396 /* Register callback event for EOT (End of transfer) event. */
4397 rc = sps_register_event(sps_pipe_handle, sps_event);
4398 if (rc) {
4399 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4400 " rc=%d", mmc_hostname(host->mmc),
4401 (u32)sps_pipe_handle, rc);
4402 goto reg_event_err;
4403 }
4404 /* Now save the sps pipe handle */
4405 ep->pipe_handle = sps_pipe_handle;
4406 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
4407 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
4408 __func__, is_producer ? "READ" : "WRITE",
4409 (u32)sps_pipe_handle, sps_config->desc.phys_base);
4410 goto out;
4411
4412reg_event_err:
4413 sps_disconnect(sps_pipe_handle);
4414sps_connect_err:
4415 dma_free_coherent(mmc_dev(host->mmc),
4416 sps_config->desc.size,
4417 sps_config->desc.base,
4418 sps_config->desc.phys_base);
4419get_config_err:
4420 sps_free_endpoint(sps_pipe_handle);
4421out:
4422 return rc;
4423}
4424
4425/**
4426 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
4427 *
4428 * This function disconnect endpoint and deallocates
4429 * endpoint context.
4430 *
4431 * This function should only be called once typically
4432 * during driver remove.
4433 *
4434 * @host - Pointer to sdcc host structure
4435 * @ep - Pointer to sps endpoint data structure
4436 *
4437 */
4438static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
4439 struct msmsdcc_sps_ep_conn_data *ep)
4440{
4441 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4442 struct sps_connect *sps_config = &ep->config;
4443 struct sps_register_event *sps_event = &ep->event;
4444
4445 sps_event->xfer_done = NULL;
4446 sps_event->callback = NULL;
4447 sps_register_event(sps_pipe_handle, sps_event);
4448 sps_disconnect(sps_pipe_handle);
4449 dma_free_coherent(mmc_dev(host->mmc),
4450 sps_config->desc.size,
4451 sps_config->desc.base,
4452 sps_config->desc.phys_base);
4453 sps_free_endpoint(sps_pipe_handle);
4454}
4455
4456/**
4457 * Reset SDCC peripheral's SPS endpoint
4458 *
4459 * This function disconnects an endpoint.
4460 *
4461 * This function should be called for reseting
4462 * SPS endpoint when data transfer error is
4463 * encountered during data transfer. This
4464 * can be considered as soft reset to endpoint.
4465 *
4466 * This function should only be called if
4467 * msmsdcc_sps_init() is already called.
4468 *
4469 * @host - Pointer to sdcc host structure
4470 * @ep - Pointer to sps endpoint data structure
4471 *
4472 * @return - 0 if successful else negative value.
4473 */
4474static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
4475 struct msmsdcc_sps_ep_conn_data *ep)
4476{
4477 int rc = 0;
4478 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4479
4480 rc = sps_disconnect(sps_pipe_handle);
4481 if (rc) {
4482 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
4483 " rc=%d", mmc_hostname(host->mmc), __func__,
4484 (u32)sps_pipe_handle, rc);
4485 goto out;
4486 }
4487 out:
4488 return rc;
4489}
4490
4491/**
4492 * Restore SDCC peripheral's SPS endpoint
4493 *
4494 * This function connects an endpoint.
4495 *
4496 * This function should be called for restoring
4497 * SPS endpoint after data transfer error is
4498 * encountered during data transfer. This
4499 * can be considered as soft reset to endpoint.
4500 *
4501 * This function should only be called if
4502 * msmsdcc_sps_reset_ep() is called before.
4503 *
4504 * @host - Pointer to sdcc host structure
4505 * @ep - Pointer to sps endpoint data structure
4506 *
4507 * @return - 0 if successful else negative value.
4508 */
4509static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
4510 struct msmsdcc_sps_ep_conn_data *ep)
4511{
4512 int rc = 0;
4513 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4514 struct sps_connect *sps_config = &ep->config;
4515 struct sps_register_event *sps_event = &ep->event;
4516
4517 /* Establish connection between peripheral and memory endpoint */
4518 rc = sps_connect(sps_pipe_handle, sps_config);
4519 if (rc) {
4520 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
4521 " rc=%d", mmc_hostname(host->mmc), __func__,
4522 (u32)sps_pipe_handle, rc);
4523 goto out;
4524 }
4525
4526 /* Register callback event for EOT (End of transfer) event. */
4527 rc = sps_register_event(sps_pipe_handle, sps_event);
4528 if (rc) {
4529 pr_err("%s: %s: sps_register_event() failed!!!"
4530 " pipe_handle=0x%x, rc=%d",
4531 mmc_hostname(host->mmc), __func__,
4532 (u32)sps_pipe_handle, rc);
4533 goto reg_event_err;
4534 }
4535 goto out;
4536
4537reg_event_err:
4538 sps_disconnect(sps_pipe_handle);
4539out:
4540 return rc;
4541}
4542
4543/**
Krishna Konda5af8f972012-05-14 16:15:24 -07004544 * Handle BAM device's global error condition
4545 *
4546 * This is an error handler for the SDCC bam device
4547 *
4548 * This function is registered as a callback with SPS-BAM
4549 * driver and will called in case there are an errors for
4550 * the SDCC BAM deivce. Any error conditions in the BAM
4551 * device are global and will be result in this function
4552 * being called once per device.
4553 *
4554 * This function will be called from the sps driver's
4555 * interrupt context.
4556 *
4557 * @sps_cb_case - indicates what error it is
4558 * @user - Pointer to sdcc host structure
4559 */
4560static void
4561msmsdcc_sps_bam_global_irq_cb(enum sps_callback_case sps_cb_case, void *user)
4562{
4563 struct msmsdcc_host *host = (struct msmsdcc_host *)user;
4564 struct mmc_request *mrq;
4565 unsigned long flags;
4566 int32_t error = 0;
4567
4568 BUG_ON(!host);
4569 BUG_ON(!is_sps_mode(host));
4570
4571 if (sps_cb_case == SPS_CALLBACK_BAM_ERROR_IRQ) {
4572 /**
4573 * Reset the all endpoints along with reseting the sps device.
4574 */
4575 host->sps.pipe_reset_pending = true;
4576 host->sps.reset_device = true;
4577
4578 pr_err("%s: BAM Global ERROR IRQ happened\n",
4579 mmc_hostname(host->mmc));
4580 error = EAGAIN;
4581 } else if (sps_cb_case == SPS_CALLBACK_BAM_HRESP_ERR_IRQ) {
4582 /**
4583 * This means that there was an AHB access error and
4584 * the address we are trying to read/write is something
4585 * we dont have priviliges to do so.
4586 */
4587 pr_err("%s: BAM HRESP_ERR_IRQ happened\n",
4588 mmc_hostname(host->mmc));
4589 error = EACCES;
4590 } else {
4591 /**
4592 * This should not have happened ideally. If this happens
4593 * there is some seriously wrong.
4594 */
4595 pr_err("%s: BAM global IRQ callback received, type:%d\n",
4596 mmc_hostname(host->mmc), (u32) sps_cb_case);
4597 error = EIO;
4598 }
4599
4600 spin_lock_irqsave(&host->lock, flags);
4601
4602 mrq = host->curr.mrq;
4603
4604 if (mrq && mrq->cmd) {
4605 msmsdcc_dump_sdcc_state(host);
4606
4607 if (!mrq->cmd->error)
4608 mrq->cmd->error = -error;
4609 if (host->curr.data) {
4610 if (mrq->data && !mrq->data->error)
4611 mrq->data->error = -error;
4612 host->curr.data_xfered = 0;
4613 if (host->sps.sg && is_sps_mode(host)) {
4614 /* Stop current SPS transfer */
4615 msmsdcc_sps_exit_curr_xfer(host);
4616 } else {
4617 /* this condition should not have happened */
4618 pr_err("%s: something is seriously wrong. "\
4619 "Funtion: %s, line: %d\n",
4620 mmc_hostname(host->mmc),
4621 __func__, __LINE__);
4622 }
4623 } else {
4624 /* this condition should not have happened */
4625 pr_err("%s: something is seriously wrong. Funtion: "\
4626 "%s, line: %d\n", mmc_hostname(host->mmc),
4627 __func__, __LINE__);
4628 }
4629 }
4630 spin_unlock_irqrestore(&host->lock, flags);
4631}
4632
4633/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004634 * Initialize SPS HW connected with SDCC core
4635 *
4636 * This function register BAM HW resources with
4637 * SPS driver and then initialize 2 SPS endpoints
4638 *
4639 * This function should only be called once typically
4640 * during driver probe.
4641 *
4642 * @host - Pointer to sdcc host structure
4643 *
4644 * @return - 0 if successful else negative value.
4645 *
4646 */
4647static int msmsdcc_sps_init(struct msmsdcc_host *host)
4648{
4649 int rc = 0;
4650 struct sps_bam_props bam = {0};
4651
4652 host->bam_base = ioremap(host->bam_memres->start,
4653 resource_size(host->bam_memres));
4654 if (!host->bam_base) {
4655 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
4656 " size=0x%x", mmc_hostname(host->mmc),
4657 host->bam_memres->start,
4658 (host->bam_memres->end -
4659 host->bam_memres->start));
4660 rc = -ENOMEM;
4661 goto out;
4662 }
4663
4664 bam.phys_addr = host->bam_memres->start;
4665 bam.virt_addr = host->bam_base;
4666 /*
4667 * This event thresold value is only significant for BAM-to-BAM
4668 * transfer. It's ignored for BAM-to-System mode transfer.
4669 */
4670 bam.event_threshold = 0x10; /* Pipe event threshold */
4671 /*
4672 * This threshold controls when the BAM publish
4673 * the descriptor size on the sideband interface.
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304674 * SPS HW will be used for data transfer size even
4675 * less than SDCC FIFO size. So let's set BAM summing
4676 * thresold to SPS_MIN_XFER_SIZE bytes.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004677 */
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304678 bam.summing_threshold = SPS_MIN_XFER_SIZE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004679 /* SPS driver wll handle the SDCC BAM IRQ */
4680 bam.irq = (u32)host->bam_irqres->start;
4681 bam.manage = SPS_BAM_MGR_LOCAL;
Krishna Konda5af8f972012-05-14 16:15:24 -07004682 bam.callback = msmsdcc_sps_bam_global_irq_cb;
4683 bam.user = (void *)host;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004684
4685 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
4686 (u32)bam.phys_addr);
4687 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
4688 (u32)bam.virt_addr);
4689
4690 /* Register SDCC Peripheral BAM device to SPS driver */
4691 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
4692 if (rc) {
4693 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
4694 mmc_hostname(host->mmc), rc);
4695 goto reg_bam_err;
4696 }
4697 pr_info("%s: BAM device registered. bam_handle=0x%x",
4698 mmc_hostname(host->mmc), host->sps.bam_handle);
4699
4700 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
4701 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
4702
4703 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
4704 SPS_PROD_PERIPHERAL);
4705 if (rc)
4706 goto sps_reset_err;
4707 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
4708 SPS_CONS_PERIPHERAL);
4709 if (rc)
4710 goto cons_conn_err;
4711
4712 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
4713 mmc_hostname(host->mmc),
4714 (unsigned long long)host->bam_memres->start,
4715 (unsigned int)host->bam_irqres->start);
4716 goto out;
4717
4718cons_conn_err:
4719 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4720sps_reset_err:
4721 sps_deregister_bam_device(host->sps.bam_handle);
4722reg_bam_err:
4723 iounmap(host->bam_base);
4724out:
4725 return rc;
4726}
4727
4728/**
4729 * De-initialize SPS HW connected with SDCC core
4730 *
4731 * This function deinitialize SPS endpoints and then
4732 * deregisters BAM resources from SPS driver.
4733 *
4734 * This function should only be called once typically
4735 * during driver remove.
4736 *
4737 * @host - Pointer to sdcc host structure
4738 *
4739 */
4740static void msmsdcc_sps_exit(struct msmsdcc_host *host)
4741{
4742 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
4743 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4744 sps_deregister_bam_device(host->sps.bam_handle);
4745 iounmap(host->bam_base);
4746}
4747#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
4748
4749static ssize_t
4750show_polling(struct device *dev, struct device_attribute *attr, char *buf)
4751{
4752 struct mmc_host *mmc = dev_get_drvdata(dev);
4753 struct msmsdcc_host *host = mmc_priv(mmc);
4754 int poll;
4755 unsigned long flags;
4756
4757 spin_lock_irqsave(&host->lock, flags);
4758 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
4759 spin_unlock_irqrestore(&host->lock, flags);
4760
4761 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
4762}
4763
4764static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05304765store_polling(struct device *dev, struct device_attribute *attr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004766 const char *buf, size_t count)
4767{
4768 struct mmc_host *mmc = dev_get_drvdata(dev);
4769 struct msmsdcc_host *host = mmc_priv(mmc);
4770 int value;
4771 unsigned long flags;
4772
4773 sscanf(buf, "%d", &value);
4774
4775 spin_lock_irqsave(&host->lock, flags);
4776 if (value) {
4777 mmc->caps |= MMC_CAP_NEEDS_POLL;
4778 mmc_detect_change(host->mmc, 0);
4779 } else {
4780 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4781 }
4782#ifdef CONFIG_HAS_EARLYSUSPEND
4783 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
4784#endif
4785 spin_unlock_irqrestore(&host->lock, flags);
4786 return count;
4787}
4788
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304789static ssize_t
4790show_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
4791 char *buf)
4792{
4793 struct mmc_host *mmc = dev_get_drvdata(dev);
4794 struct msmsdcc_host *host = mmc_priv(mmc);
4795
4796 return snprintf(buf, PAGE_SIZE, "%u\n",
4797 host->msm_bus_vote.is_max_bw_needed);
4798}
4799
4800static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05304801store_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304802 const char *buf, size_t count)
4803{
4804 struct mmc_host *mmc = dev_get_drvdata(dev);
4805 struct msmsdcc_host *host = mmc_priv(mmc);
4806 uint32_t value;
4807 unsigned long flags;
4808
4809 if (!kstrtou32(buf, 0, &value)) {
4810 spin_lock_irqsave(&host->lock, flags);
4811 host->msm_bus_vote.is_max_bw_needed = !!value;
4812 spin_unlock_irqrestore(&host->lock, flags);
4813 }
4814
4815 return count;
4816}
4817
Pratibhasagar V13d1d032012-07-09 20:12:38 +05304818static ssize_t
4819show_idle_timeout(struct device *dev, struct device_attribute *attr,
4820 char *buf)
4821{
4822 struct mmc_host *mmc = dev_get_drvdata(dev);
4823 struct msmsdcc_host *host = mmc_priv(mmc);
4824
4825 return snprintf(buf, PAGE_SIZE, "%u (Min 5 sec)\n",
4826 host->idle_tout_ms / 1000);
4827}
4828
4829static ssize_t
4830store_idle_timeout(struct device *dev, struct device_attribute *attr,
4831 const char *buf, size_t count)
4832{
4833 struct mmc_host *mmc = dev_get_drvdata(dev);
4834 struct msmsdcc_host *host = mmc_priv(mmc);
4835 unsigned int long flags;
4836 int timeout; /* in secs */
4837
4838 if (!kstrtou32(buf, 0, &timeout)
4839 && (timeout > MSM_MMC_DEFAULT_IDLE_TIMEOUT / 1000)) {
4840 spin_lock_irqsave(&host->lock, flags);
4841 host->idle_tout_ms = timeout * 1000;
4842 spin_unlock_irqrestore(&host->lock, flags);
4843 }
4844 return count;
4845}
4846
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004847#ifdef CONFIG_HAS_EARLYSUSPEND
4848static void msmsdcc_early_suspend(struct early_suspend *h)
4849{
4850 struct msmsdcc_host *host =
4851 container_of(h, struct msmsdcc_host, early_suspend);
4852 unsigned long flags;
4853
4854 spin_lock_irqsave(&host->lock, flags);
4855 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
4856 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4857 spin_unlock_irqrestore(&host->lock, flags);
4858};
4859static void msmsdcc_late_resume(struct early_suspend *h)
4860{
4861 struct msmsdcc_host *host =
4862 container_of(h, struct msmsdcc_host, early_suspend);
4863 unsigned long flags;
4864
4865 if (host->polling_enabled) {
4866 spin_lock_irqsave(&host->lock, flags);
4867 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
4868 mmc_detect_change(host->mmc, 0);
4869 spin_unlock_irqrestore(&host->lock, flags);
4870 }
4871};
4872#endif
4873
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304874static void msmsdcc_print_regs(const char *name, void __iomem *base,
4875 u32 phys_base, unsigned int no_of_regs)
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304876{
4877 unsigned int i;
4878
4879 if (!base)
4880 return;
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304881
4882 pr_info("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
4883 " =====\n", name, phys_base, (u32)base);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304884 for (i = 0; i < no_of_regs; i = i + 4) {
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304885 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
4886 (u32)readl_relaxed(base + i*4),
4887 (u32)readl_relaxed(base + ((i+1)*4)),
4888 (u32)readl_relaxed(base + ((i+2)*4)),
4889 (u32)readl_relaxed(base + ((i+3)*4)));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304890 }
4891}
4892
4893static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
4894{
4895 /* Dump current state of SDCC clocks, power and irq */
4896 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304897 (host->pwr ? "ON" : "OFF"));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304898 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304899 mmc_hostname(host->mmc),
4900 (atomic_read(&host->clks_on) ? "ON" : "OFF"),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304901 (u32)clk_get_rate(host->clk));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304902 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
4903 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
4904
4905 /* Now dump SDCC registers. Don't print FIFO registers */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304906 if (atomic_read(&host->clks_on))
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304907 msmsdcc_print_regs("SDCC-CORE", host->base,
4908 host->core_memres->start, 28);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304909
4910 if (host->curr.data) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304911 if (!msmsdcc_is_dma_possible(host, host->curr.data))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304912 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304913 else if (is_dma_mode(host))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304914 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
4915 mmc_hostname(host->mmc), host->dma.busy,
4916 host->dma.channel, host->dma.crci);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304917 else if (is_sps_mode(host)) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304918 if (host->sps.busy && atomic_read(&host->clks_on))
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304919 msmsdcc_print_regs("SDCC-DML", host->dml_base,
4920 host->dml_memres->start,
4921 16);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304922 pr_info("%s: SPS mode: busy=%d\n",
4923 mmc_hostname(host->mmc), host->sps.busy);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304924 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304925
4926 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
4927 mmc_hostname(host->mmc), host->curr.xfer_size,
4928 host->curr.data_xfered, host->curr.xfer_remain);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304929 }
4930
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304931 pr_info("%s: got_dataend=%d, prog_enable=%d,"
Subhash Jadavani8706ced2012-05-25 16:09:21 +05304932 " wait_for_auto_prog_done=%d, got_auto_prog_done=%d,"
4933 " req_tout_ms=%d\n", mmc_hostname(host->mmc),
4934 host->curr.got_dataend, host->prog_enable,
4935 host->curr.wait_for_auto_prog_done,
4936 host->curr.got_auto_prog_done, host->curr.req_tout_ms);
subhashj245831e2012-04-30 18:46:17 +05304937 msmsdcc_print_rpm_info(host);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304938}
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304939
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004940static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
4941{
4942 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4943 struct mmc_request *mrq;
4944 unsigned long flags;
4945
4946 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004947 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004948 pr_info("%s: %s: dummy CMD52 timeout\n",
4949 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004950 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004951 }
4952
4953 mrq = host->curr.mrq;
4954
4955 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304956 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
4957 mrq->cmd->opcode);
4958 msmsdcc_dump_sdcc_state(host);
4959
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004960 if (!mrq->cmd->error)
4961 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304962 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004963 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004964 if (mrq->data && !mrq->data->error)
4965 mrq->data->error = -ETIMEDOUT;
4966 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304967 if (host->dma.sg && is_dma_mode(host)) {
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07004968 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304969 } else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004970 /* Stop current SPS transfer */
4971 msmsdcc_sps_exit_curr_xfer(host);
4972 } else {
4973 msmsdcc_reset_and_restore(host);
4974 msmsdcc_stop_data(host);
4975 if (mrq->data && mrq->data->stop)
4976 msmsdcc_start_command(host,
4977 mrq->data->stop, 0);
4978 else
4979 msmsdcc_request_end(host, mrq);
4980 }
4981 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304982 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05304983 host->curr.wait_for_auto_prog_done = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004984 msmsdcc_reset_and_restore(host);
4985 msmsdcc_request_end(host, mrq);
4986 }
4987 }
4988 spin_unlock_irqrestore(&host->lock, flags);
4989}
4990
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05304991/*
4992 * msmsdcc_dt_get_array - Wrapper fn to read an array of 32 bit integers
4993 *
4994 * @dev: device node from which the property value is to be read.
4995 * @prop_name: name of the property to be searched.
4996 * @out_array: filled array returned to caller
4997 * @len: filled array size returned to caller
4998 * @size: expected size of the array
4999 *
5000 * If expected "size" doesn't match with "len" an error is returned. If
5001 * expected size is zero, the length of actual array is returned provided
5002 * return value is zero.
5003 *
5004 * RETURNS:
5005 * zero on success, negative error if failed.
5006 */
5007static int msmsdcc_dt_get_array(struct device *dev, const char *prop_name,
5008 u32 **out_array, int *len, int size)
5009{
5010 int ret = 0;
5011 u32 *array = NULL;
5012 struct device_node *np = dev->of_node;
5013
5014 if (of_get_property(np, prop_name, len)) {
5015 size_t sz;
5016 sz = *len = *len / sizeof(*array);
5017
5018 if (sz > 0 && !(size > 0 && (sz != size))) {
5019 array = devm_kzalloc(dev, sz * sizeof(*array),
5020 GFP_KERNEL);
5021 if (!array) {
5022 dev_err(dev, "%s: no memory\n", prop_name);
5023 ret = -ENOMEM;
5024 goto out;
5025 }
5026
5027 ret = of_property_read_u32_array(np, prop_name,
5028 array, sz);
5029 if (ret < 0) {
5030 dev_err(dev, "%s: error reading array %d\n",
5031 prop_name, ret);
5032 goto out;
5033 }
5034 } else {
5035 dev_err(dev, "%s invalid size\n", prop_name);
5036 ret = -EINVAL;
5037 goto out;
5038 }
5039 } else {
5040 dev_err(dev, "%s not specified\n", prop_name);
5041 ret = -EINVAL;
5042 goto out;
5043 }
5044 *out_array = array;
5045out:
5046 if (ret)
5047 *len = 0;
5048 return ret;
5049}
5050
5051static int msmsdcc_dt_get_pad_pull_info(struct device *dev, int id,
5052 struct msm_mmc_pad_pull_data **pad_pull_data)
5053{
5054 int ret = 0, base = 0, len, i;
5055 u32 *tmp;
5056 struct msm_mmc_pad_pull_data *pull_data;
5057 struct msm_mmc_pad_pull *pull;
5058
5059 switch (id) {
5060 case 1:
5061 base = TLMM_PULL_SDC1_CLK;
5062 break;
5063 case 2:
5064 base = TLMM_PULL_SDC2_CLK;
5065 break;
5066 case 3:
5067 base = TLMM_PULL_SDC3_CLK;
5068 break;
5069 case 4:
5070 base = TLMM_PULL_SDC4_CLK;
5071 break;
5072 default:
5073 dev_err(dev, "%s: Invalid slot id\n", __func__);
5074 ret = -EINVAL;
5075 goto err;
5076 }
5077
5078 pull_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_pull_data),
5079 GFP_KERNEL);
5080 if (!pull_data) {
5081 dev_err(dev, "No memory msm_mmc_pad_pull_data\n");
5082 ret = -ENOMEM;
5083 goto err;
5084 }
5085 pull_data->size = 3; /* array size for clk, cmd, data */
5086
5087 /* Allocate on, off configs for clk, cmd, data */
5088 pull = devm_kzalloc(dev, 2 * pull_data->size *\
5089 sizeof(struct msm_mmc_pad_pull), GFP_KERNEL);
5090 if (!pull) {
5091 dev_err(dev, "No memory for msm_mmc_pad_pull\n");
5092 ret = -ENOMEM;
5093 goto err;
5094 }
5095 pull_data->on = pull;
5096 pull_data->off = pull + pull_data->size;
5097
5098 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-pull-on",
5099 &tmp, &len, pull_data->size);
5100 if (!ret) {
5101 for (i = 0; i < len; i++) {
5102 pull_data->on[i].no = base + i;
5103 pull_data->on[i].val = tmp[i];
5104 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5105 i, pull_data->on[i].val);
5106 }
5107 } else {
5108 goto err;
5109 }
5110
5111 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-pull-off",
5112 &tmp, &len, pull_data->size);
5113 if (!ret) {
5114 for (i = 0; i < len; i++) {
5115 pull_data->off[i].no = base + i;
5116 pull_data->off[i].val = tmp[i];
5117 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5118 i, pull_data->off[i].val);
5119 }
5120 } else {
5121 goto err;
5122 }
5123
5124 *pad_pull_data = pull_data;
5125err:
5126 return ret;
5127}
5128
5129static int msmsdcc_dt_get_pad_drv_info(struct device *dev, int id,
5130 struct msm_mmc_pad_drv_data **pad_drv_data)
5131{
5132 int ret = 0, base = 0, len, i;
5133 u32 *tmp;
5134 struct msm_mmc_pad_drv_data *drv_data;
5135 struct msm_mmc_pad_drv *drv;
5136
5137 switch (id) {
5138 case 1:
5139 base = TLMM_HDRV_SDC1_CLK;
5140 break;
5141 case 2:
5142 base = TLMM_HDRV_SDC2_CLK;
5143 break;
5144 case 3:
5145 base = TLMM_HDRV_SDC3_CLK;
5146 break;
5147 case 4:
5148 base = TLMM_HDRV_SDC4_CLK;
5149 break;
5150 default:
5151 dev_err(dev, "%s: Invalid slot id\n", __func__);
5152 ret = -EINVAL;
5153 goto err;
5154 }
5155
5156 drv_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_drv_data),
5157 GFP_KERNEL);
5158 if (!drv_data) {
5159 dev_err(dev, "No memory for msm_mmc_pad_drv_data\n");
5160 ret = -ENOMEM;
5161 goto err;
5162 }
5163 drv_data->size = 3; /* array size for clk, cmd, data */
5164
5165 /* Allocate on, off configs for clk, cmd, data */
5166 drv = devm_kzalloc(dev, 2 * drv_data->size *\
5167 sizeof(struct msm_mmc_pad_drv), GFP_KERNEL);
5168 if (!drv) {
5169 dev_err(dev, "No memory msm_mmc_pad_drv\n");
5170 ret = -ENOMEM;
5171 goto err;
5172 }
5173 drv_data->on = drv;
5174 drv_data->off = drv + drv_data->size;
5175
5176 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-drv-on",
5177 &tmp, &len, drv_data->size);
5178 if (!ret) {
5179 for (i = 0; i < len; i++) {
5180 drv_data->on[i].no = base + i;
5181 drv_data->on[i].val = tmp[i];
5182 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5183 i, drv_data->on[i].val);
5184 }
5185 } else {
5186 goto err;
5187 }
5188
5189 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-drv-off",
5190 &tmp, &len, drv_data->size);
5191 if (!ret) {
5192 for (i = 0; i < len; i++) {
5193 drv_data->off[i].no = base + i;
5194 drv_data->off[i].val = tmp[i];
5195 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5196 i, drv_data->off[i].val);
5197 }
5198 } else {
5199 goto err;
5200 }
5201
5202 *pad_drv_data = drv_data;
5203err:
5204 return ret;
5205}
5206
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305207static void msmsdcc_dt_get_cd_wp_gpio(struct device *dev,
5208 struct mmc_platform_data *pdata)
5209{
5210 enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
5211 struct device_node *np = dev->of_node;
5212
5213 pdata->status_gpio = of_get_named_gpio_flags(np,
5214 "cd-gpios", 0, &flags);
5215 if (gpio_is_valid(pdata->status_gpio)) {
5216 pdata->status_irq = gpio_to_irq(pdata->status_gpio);
5217 pdata->is_status_gpio_active_low = flags & OF_GPIO_ACTIVE_LOW;
5218 }
5219
5220 pdata->wpswitch_gpio = of_get_named_gpio_flags(np,
5221 "wp-gpios", 0, &flags);
5222 if (gpio_is_valid(pdata->wpswitch_gpio))
5223 pdata->is_wpswitch_active_low = flags & OF_GPIO_ACTIVE_LOW;
5224}
5225
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305226static int msmsdcc_dt_parse_gpio_info(struct device *dev,
5227 struct mmc_platform_data *pdata)
5228{
5229 int ret = 0, id = 0, cnt, i;
5230 struct msm_mmc_pin_data *pin_data;
5231 struct device_node *np = dev->of_node;
5232
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305233 msmsdcc_dt_get_cd_wp_gpio(dev, pdata);
5234
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305235 pin_data = devm_kzalloc(dev, sizeof(*pin_data), GFP_KERNEL);
5236 if (!pin_data) {
5237 dev_err(dev, "No memory for pin_data\n");
5238 ret = -ENOMEM;
5239 goto err;
5240 }
5241
5242 cnt = of_gpio_count(np);
5243 if (cnt > 0) {
5244 pin_data->is_gpio = true;
5245
5246 pin_data->gpio_data = devm_kzalloc(dev,
5247 sizeof(struct msm_mmc_gpio_data), GFP_KERNEL);
5248 if (!pin_data->gpio_data) {
5249 dev_err(dev, "No memory for gpio_data\n");
5250 ret = -ENOMEM;
5251 goto err;
5252 }
5253 pin_data->gpio_data->size = cnt;
5254 pin_data->gpio_data->gpio = devm_kzalloc(dev,
5255 cnt * sizeof(struct msm_mmc_gpio), GFP_KERNEL);
5256 if (!pin_data->gpio_data->gpio) {
5257 dev_err(dev, "No memory for gpio\n");
5258 ret = -ENOMEM;
5259 goto err;
5260 }
5261
5262 for (i = 0; i < cnt; i++) {
5263 const char *name = NULL;
5264 char result[32];
5265 pin_data->gpio_data->gpio[i].no = of_get_gpio(np, i);
5266 of_property_read_string_index(np,
5267 "qcom,sdcc-gpio-names", i, &name);
5268
5269 snprintf(result, 32, "%s-%s",
5270 dev_name(dev), name ? name : "?");
5271 pin_data->gpio_data->gpio[i].name = result;
5272 dev_dbg(dev, "%s: gpio[%s] = %d\n", __func__,
5273 pin_data->gpio_data->gpio[i].name,
5274 pin_data->gpio_data->gpio[i].no);
5275 }
5276 } else {
5277 pin_data->pad_data = devm_kzalloc(dev,
5278 sizeof(struct msm_mmc_pad_data), GFP_KERNEL);
5279 if (!pin_data->pad_data) {
5280 dev_err(dev, "No memory for pin_data->pad_data\n");
5281 ret = -ENOMEM;
5282 goto err;
5283 }
5284
5285 of_property_read_u32(np, "cell-index", &id);
5286
5287 ret = msmsdcc_dt_get_pad_pull_info(dev, id,
5288 &pin_data->pad_data->pull);
5289 if (ret)
5290 goto err;
5291 ret = msmsdcc_dt_get_pad_drv_info(dev, id,
5292 &pin_data->pad_data->drv);
5293 if (ret)
5294 goto err;
5295 }
5296
5297 pdata->pin_data = pin_data;
5298err:
5299 if (ret)
5300 dev_err(dev, "%s failed with err %d\n", __func__, ret);
5301 return ret;
5302}
5303
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305304#define MAX_PROP_SIZE 32
5305static int msmsdcc_dt_parse_vreg_info(struct device *dev,
5306 struct msm_mmc_reg_data **vreg_data, const char *vreg_name)
5307{
5308 int len, ret = 0;
5309 const __be32 *prop;
5310 char prop_name[MAX_PROP_SIZE];
5311 struct msm_mmc_reg_data *vreg;
5312 struct device_node *np = dev->of_node;
5313
5314 snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", vreg_name);
5315 if (of_parse_phandle(np, prop_name, 0)) {
5316 vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
5317 if (!vreg) {
5318 dev_err(dev, "No memory for vreg: %s\n", vreg_name);
5319 ret = -ENOMEM;
5320 goto err;
5321 }
5322
5323 vreg->name = vreg_name;
5324
5325 snprintf(prop_name, MAX_PROP_SIZE,
5326 "qcom,sdcc-%s-always_on", vreg_name);
5327 if (of_get_property(np, prop_name, NULL))
5328 vreg->always_on = true;
5329
5330 snprintf(prop_name, MAX_PROP_SIZE,
5331 "qcom,sdcc-%s-lpm_sup", vreg_name);
5332 if (of_get_property(np, prop_name, NULL))
5333 vreg->lpm_sup = true;
5334
5335 snprintf(prop_name, MAX_PROP_SIZE,
5336 "qcom,sdcc-%s-voltage_level", vreg_name);
5337 prop = of_get_property(np, prop_name, &len);
5338 if (!prop || (len != (2 * sizeof(__be32)))) {
5339 dev_warn(dev, "%s %s property\n",
5340 prop ? "invalid format" : "no", prop_name);
5341 } else {
5342 vreg->low_vol_level = be32_to_cpup(&prop[0]);
5343 vreg->high_vol_level = be32_to_cpup(&prop[1]);
5344 }
5345
5346 snprintf(prop_name, MAX_PROP_SIZE,
5347 "qcom,sdcc-%s-current_level", vreg_name);
5348 prop = of_get_property(np, prop_name, &len);
5349 if (!prop || (len != (2 * sizeof(__be32)))) {
5350 dev_warn(dev, "%s %s property\n",
5351 prop ? "invalid format" : "no", prop_name);
5352 } else {
5353 vreg->lpm_uA = be32_to_cpup(&prop[0]);
5354 vreg->hpm_uA = be32_to_cpup(&prop[1]);
5355 }
5356
5357 *vreg_data = vreg;
5358 dev_dbg(dev, "%s: %s %s vol=[%d %d]uV, curr=[%d %d]uA\n",
5359 vreg->name, vreg->always_on ? "always_on," : "",
5360 vreg->lpm_sup ? "lpm_sup," : "", vreg->low_vol_level,
5361 vreg->high_vol_level, vreg->lpm_uA, vreg->hpm_uA);
5362 }
5363
5364err:
5365 return ret;
5366}
5367
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305368static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
5369{
5370 int i, ret;
5371 struct mmc_platform_data *pdata;
5372 struct device_node *np = dev->of_node;
Devin Kim9ccbff52012-07-16 20:55:14 -07005373 u32 bus_width = 0, current_limit = 0;
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305374 u32 *clk_table, *sup_voltages;
Devin Kim9ccbff52012-07-16 20:55:14 -07005375 int clk_table_len, sup_volt_len, len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305376
5377 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
5378 if (!pdata) {
5379 dev_err(dev, "could not allocate memory for platform data\n");
5380 goto err;
5381 }
5382
5383 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
5384 if (bus_width == 8) {
5385 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
5386 } else if (bus_width == 4) {
5387 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
5388 } else {
5389 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
5390 pdata->mmc_bus_width = 0;
5391 }
5392
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305393 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-sup-voltages",
5394 &sup_voltages, &sup_volt_len, 0);
5395 if (!ret) {
5396 for (i = 0; i < sup_volt_len; i += 2) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305397 u32 mask;
5398
5399 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
5400 sup_voltages[i + 1]);
5401 if (!mask)
5402 dev_err(dev, "Invalide voltage range %d\n", i);
5403 pdata->ocr_mask |= mask;
5404 }
5405 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305406 }
5407
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305408 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-clk-rates",
5409 &clk_table, &clk_table_len, 0);
5410 if (!ret) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305411 pdata->sup_clk_table = clk_table;
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305412 pdata->sup_clk_cnt = clk_table_len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305413 }
5414
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305415 pdata->vreg_data = devm_kzalloc(dev,
5416 sizeof(struct msm_mmc_slot_reg_data), GFP_KERNEL);
5417 if (!pdata->vreg_data) {
5418 dev_err(dev, "could not allocate memory for vreg_data\n");
5419 goto err;
5420 }
5421
5422 if (msmsdcc_dt_parse_vreg_info(dev,
5423 &pdata->vreg_data->vdd_data, "vdd"))
5424 goto err;
5425
5426 if (msmsdcc_dt_parse_vreg_info(dev,
5427 &pdata->vreg_data->vdd_io_data, "vdd-io"))
5428 goto err;
5429
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305430 if (msmsdcc_dt_parse_gpio_info(dev, pdata))
5431 goto err;
5432
Devin Kim9ccbff52012-07-16 20:55:14 -07005433 len = of_property_count_strings(np, "qcom,sdcc-bus-speed-mode");
5434
5435 for (i = 0; i < len; i++) {
5436 const char *name = NULL;
5437
5438 of_property_read_string_index(np,
5439 "qcom,sdcc-bus-speed-mode", i, &name);
5440 if (!name)
5441 continue;
5442
5443 if (!strncmp(name, "SDR12", sizeof("SDR12")))
5444 pdata->uhs_caps |= MMC_CAP_UHS_SDR12;
5445 else if (!strncmp(name, "SDR25", sizeof("SDR25")))
5446 pdata->uhs_caps |= MMC_CAP_UHS_SDR25;
5447 else if (!strncmp(name, "SDR50", sizeof("SDR50")))
5448 pdata->uhs_caps |= MMC_CAP_UHS_SDR50;
5449 else if (!strncmp(name, "DDR50", sizeof("DDR50")))
5450 pdata->uhs_caps |= MMC_CAP_UHS_DDR50;
5451 else if (!strncmp(name, "SDR104", sizeof("SDR104")))
5452 pdata->uhs_caps |= MMC_CAP_UHS_SDR104;
5453 else if (!strncmp(name, "HS200_1p8v", sizeof("HS200_1p8v")))
5454 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_8V_SDR;
5455 else if (!strncmp(name, "HS200_1p2v", sizeof("HS200_1p2v")))
5456 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_2V_SDR;
5457 else if (!strncmp(name, "DDR_1p8v", sizeof("DDR_1p8v")))
5458 pdata->uhs_caps |= MMC_CAP_1_8V_DDR
5459 | MMC_CAP_UHS_DDR50;
5460 else if (!strncmp(name, "DDR_1p2v", sizeof("DDR_1p2v")))
5461 pdata->uhs_caps |= MMC_CAP_1_2V_DDR
5462 | MMC_CAP_UHS_DDR50;
5463 }
5464
5465 of_property_read_u32(np, "qcom,sdcc-current-limit", &current_limit);
5466 if (current_limit == 800)
5467 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_800;
5468 else if (current_limit == 600)
5469 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_600;
5470 else if (current_limit == 400)
5471 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_400;
5472 else if (current_limit == 200)
5473 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_200;
5474
5475 if (of_get_property(np, "qcom,sdcc-xpc", NULL))
5476 pdata->xpc_cap = true;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305477 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
5478 pdata->nonremovable = true;
5479 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
5480 pdata->disable_cmd23 = true;
5481
5482 return pdata;
5483err:
5484 return NULL;
5485}
5486
San Mehat9d2bd732009-09-22 16:44:22 -07005487static int
5488msmsdcc_probe(struct platform_device *pdev)
5489{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305490 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07005491 struct msmsdcc_host *host;
5492 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005493 unsigned long flags;
5494 struct resource *core_irqres = NULL;
5495 struct resource *bam_irqres = NULL;
5496 struct resource *core_memres = NULL;
5497 struct resource *dml_memres = NULL;
5498 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07005499 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07005500 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05305501 int ret = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07005502
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305503 if (pdev->dev.of_node) {
5504 plat = msmsdcc_populate_pdata(&pdev->dev);
5505 of_property_read_u32((&pdev->dev)->of_node,
5506 "cell-index", &pdev->id);
5507 } else {
5508 plat = pdev->dev.platform_data;
5509 }
San Mehat9d2bd732009-09-22 16:44:22 -07005510
5511 /* must have platform data */
5512 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005513 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005514 ret = -EINVAL;
5515 goto out;
5516 }
5517
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005518 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07005519 return -EINVAL;
5520
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305521 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
5522 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
5523 return -EINVAL;
5524 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005525
San Mehat9d2bd732009-09-22 16:44:22 -07005526 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005527 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005528 return -ENXIO;
5529 }
5530
Sujit Reddy Thumma1dfac2c2012-07-30 10:15:39 +05305531 core_memres = platform_get_resource_byname(pdev,
5532 IORESOURCE_MEM, "core_mem");
5533 bam_memres = platform_get_resource_byname(pdev,
5534 IORESOURCE_MEM, "bam_mem");
5535 dml_memres = platform_get_resource_byname(pdev,
5536 IORESOURCE_MEM, "dml_mem");
5537 core_irqres = platform_get_resource_byname(pdev,
5538 IORESOURCE_IRQ, "core_irq");
5539 bam_irqres = platform_get_resource_byname(pdev,
5540 IORESOURCE_IRQ, "bam_irq");
5541 dmares = platform_get_resource_byname(pdev,
5542 IORESOURCE_DMA, "dma_chnl");
5543 dma_crci_res = platform_get_resource_byname(pdev,
5544 IORESOURCE_DMA, "dma_crci");
San Mehat9d2bd732009-09-22 16:44:22 -07005545
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005546 if (!core_irqres || !core_memres) {
5547 pr_err("%s: Invalid sdcc core resource\n", __func__);
5548 return -ENXIO;
5549 }
5550
5551 /*
5552 * Both BAM and DML memory resource should be preset.
5553 * BAM IRQ resource should also be present.
5554 */
5555 if ((bam_memres && !dml_memres) ||
5556 (!bam_memres && dml_memres) ||
5557 ((bam_memres && dml_memres) && !bam_irqres)) {
5558 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005559 return -ENXIO;
5560 }
5561
5562 /*
5563 * Setup our host structure
5564 */
San Mehat9d2bd732009-09-22 16:44:22 -07005565 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
5566 if (!mmc) {
5567 ret = -ENOMEM;
5568 goto out;
5569 }
5570
5571 host = mmc_priv(mmc);
5572 host->pdev_id = pdev->id;
5573 host->plat = plat;
5574 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08005575 host->curr.cmd = NULL;
Sahitya Tummala19207f02011-05-02 18:10:01 +05305576
Sahitya Tummalad9df3272011-08-19 16:50:46 +05305577 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305578 set_hw_caps(host, MSMSDCC_SPS_BAM_SUP);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005579 else if (dmares)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305580 set_hw_caps(host, MSMSDCC_DMA_SUP);
San Mehat9d2bd732009-09-22 16:44:22 -07005581
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005582 host->base = ioremap(core_memres->start,
5583 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07005584 if (!host->base) {
5585 ret = -ENOMEM;
Sahitya Tummaladce7c752011-05-02 18:06:05 +05305586 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005587 }
5588
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005589 host->core_irqres = core_irqres;
5590 host->bam_irqres = bam_irqres;
5591 host->core_memres = core_memres;
5592 host->dml_memres = dml_memres;
5593 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07005594 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07005595 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07005596 spin_lock_init(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305597 mutex_init(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07005598
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005599#ifdef CONFIG_MMC_EMBEDDED_SDIO
5600 if (plat->embedded_sdio)
5601 mmc_set_embedded_sdio_data(mmc,
5602 &plat->embedded_sdio->cis,
5603 &plat->embedded_sdio->cccr,
5604 plat->embedded_sdio->funcs,
5605 plat->embedded_sdio->num_funcs);
5606#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005607
Sahitya Tummala62612cf2010-12-08 15:03:03 +05305608 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
5609 (unsigned long)host);
5610
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005611 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
5612 (unsigned long)host);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305613 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005614 /* Setup DMA */
Subhash Jadavani190657c2011-05-02 18:10:40 +05305615 ret = msmsdcc_init_dma(host);
5616 if (ret)
5617 goto ioremap_free;
5618 } else {
5619 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07005620 host->dma.crci = -1;
Subhash Jadavani190657c2011-05-02 18:10:40 +05305621 }
San Mehat9d2bd732009-09-22 16:44:22 -07005622
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005623 /*
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305624 * Setup SDCC bus voter clock.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005625 */
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305626 host->bus_clk = clk_get(&pdev->dev, "bus_clk");
5627 if (!IS_ERR_OR_NULL(host->bus_clk)) {
5628 /* Vote for max. clk rate for max. performance */
5629 ret = clk_set_rate(host->bus_clk, INT_MAX);
5630 if (ret)
5631 goto bus_clk_put;
5632 ret = clk_prepare_enable(host->bus_clk);
5633 if (ret)
5634 goto bus_clk_put;
San Mehat9d2bd732009-09-22 16:44:22 -07005635 }
5636
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005637 /*
5638 * Setup main peripheral bus clock
5639 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07005640 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005641 if (!IS_ERR(host->pclk)) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305642 ret = clk_prepare_enable(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005643 if (ret)
5644 goto pclk_put;
5645
5646 host->pclk_rate = clk_get_rate(host->pclk);
5647 }
5648
5649 /*
5650 * Setup SDC MMC clock
5651 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07005652 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07005653 if (IS_ERR(host->clk)) {
5654 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005655 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07005656 }
5657
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005658 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
Sahitya Tummala514d9ed2011-05-02 18:07:01 +05305659 if (ret) {
5660 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
5661 goto clk_put;
5662 }
5663
Asutosh Dasf5298c32012-04-03 14:51:47 +05305664 ret = clk_prepare_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07005665 if (ret)
5666 goto clk_put;
5667
San Mehat9d2bd732009-09-22 16:44:22 -07005668 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05305669 if (!host->clk_rate)
5670 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05305671
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305672 set_default_hw_caps(host);
5673
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05305674 /*
5675 * Set the register write delay according to min. clock frequency
5676 * supported and update later when the host->clk_rate changes.
5677 */
5678 host->reg_write_delay =
5679 (1 + ((3 * USEC_PER_SEC) /
5680 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005681
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305682 atomic_set(&host->clks_on, 1);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05305683 /* Apply Hard reset to SDCC to put it in power on default state */
5684 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005685
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005686#define MSM_MMC_DEFAULT_CPUDMA_LATENCY 200 /* usecs */
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305687 /* pm qos request to prevent apps idle power collapse */
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005688 if (host->plat->cpu_dma_latency)
5689 host->cpu_dma_latency = host->plat->cpu_dma_latency;
5690 else
5691 host->cpu_dma_latency = MSM_MMC_DEFAULT_CPUDMA_LATENCY;
5692 pm_qos_add_request(&host->pm_qos_req_dma,
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305693 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
5694
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305695 ret = msmsdcc_msm_bus_register(host);
5696 if (ret)
5697 goto pm_qos_remove;
5698
5699 if (host->msm_bus_vote.client_handle)
5700 INIT_DELAYED_WORK(&host->msm_bus_vote.vote_work,
5701 msmsdcc_msm_bus_work);
5702
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005703 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07005704 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005705 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07005706 goto clk_disable;
5707 }
5708
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005709
5710 /* Clocks has to be running before accessing SPS/DML HW blocks */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305711 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005712 /* Initialize SPS */
5713 ret = msmsdcc_sps_init(host);
5714 if (ret)
5715 goto vreg_deinit;
5716 /* Initialize DML */
5717 ret = msmsdcc_dml_init(host);
5718 if (ret)
5719 goto sps_exit;
5720 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05305721 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07005722
San Mehat9d2bd732009-09-22 16:44:22 -07005723 /*
5724 * Setup MMC host structure
5725 */
5726 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005727 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
5728 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005729 mmc->ocr_avail = plat->ocr_mask;
Sujit Reddy Thumma0e05f022012-06-11 19:44:18 +05305730 mmc->clkgate_delay = MSM_MMC_CLK_GATE_DELAY;
5731
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005732 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
5733 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07005734 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05305735 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
Asutosh Dasebd7d092012-07-09 19:08:26 +05305736 mmc->caps |= MMC_CAP_HW_RESET;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05305737 /*
5738 * If we send the CMD23 before multi block write/read command
5739 * then we need not to send CMD12 at the end of the transfer.
5740 * If we don't send the CMD12 then only way to detect the PROG_DONE
5741 * status is to use the AUTO_PROG_DONE status provided by SDCC4
5742 * controller. So let's enable the CMD23 for SDCC4 only.
5743 */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305744 if (!plat->disable_cmd23 && is_auto_prog_done(host))
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05305745 mmc->caps |= MMC_CAP_CMD23;
San Mehat9d2bd732009-09-22 16:44:22 -07005746
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005747 mmc->caps |= plat->uhs_caps;
Devin Kim9ccbff52012-07-16 20:55:14 -07005748 mmc->caps2 |= plat->uhs_caps2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005749 /*
5750 * XPC controls the maximum current in the default speed mode of SDXC
5751 * card. XPC=0 means 100mA (max.) but speed class is not supported.
5752 * XPC=1 means 150mA (max.) and speed class is supported.
5753 */
5754 if (plat->xpc_cap)
5755 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
5756 MMC_CAP_SET_XPC_180);
5757
Devin Kim9b67ee02012-07-16 21:13:05 -07005758 /* packed write */
5759 mmc->caps2 |= plat->packed_write;
5760
Subhash Jadavani6bb34a82012-04-18 13:18:40 +05305761 mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
Yaniv Gardi14098552012-06-04 10:56:03 +03005762 mmc->caps2 |= MMC_CAP2_SANITIZE;
Maya Erezd0ed5ae2012-11-01 21:39:00 +02005763 mmc->caps2 |= MMC_CAP2_INIT_BKOPS;
Yaniv Gardi14098552012-06-04 10:56:03 +03005764
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005765 if (plat->nonremovable)
5766 mmc->caps |= MMC_CAP_NONREMOVABLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005767 mmc->caps |= MMC_CAP_SDIO_IRQ;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005768
5769 if (plat->is_sdio_al_client)
5770 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07005771
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305772 mmc->max_segs = msmsdcc_get_nr_sg(host);
5773 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
5774 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07005775
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305776 mmc->max_req_size = MMC_MAX_REQ_SIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07005777 mmc->max_seg_size = mmc->max_req_size;
5778
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005779 writel_relaxed(0, host->base + MMCIMASK0);
5780 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05305781 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005782
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005783 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
5784 mb();
5785 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07005786
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005787 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
5788 DRIVER_NAME " (cmd)", host);
5789 if (ret)
5790 goto dml_exit;
5791
5792 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
5793 DRIVER_NAME " (pio)", host);
5794 if (ret)
5795 goto irq_free;
5796
5797 /*
5798 * Enable SDCC IRQ only when host is powered on. Otherwise, this
5799 * IRQ is un-necessarily being monitored by MPM (Modem power
5800 * management block) during idle-power collapse. The MPM will be
5801 * configured to monitor the DATA1 GPIO line with level-low trigger
5802 * and thus depending on the GPIO status, it prevents TCXO shutdown
5803 * during idle-power collapse.
5804 */
5805 disable_irq(core_irqres->start);
5806 host->sdcc_irq_disabled = 1;
5807
5808 if (plat->sdiowakeup_irq) {
5809 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5810 mmc_hostname(mmc));
5811 ret = request_irq(plat->sdiowakeup_irq,
5812 msmsdcc_platform_sdiowakeup_irq,
5813 IRQF_SHARED | IRQF_TRIGGER_LOW,
5814 DRIVER_NAME "sdiowakeup", host);
5815 if (ret) {
5816 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
5817 plat->sdiowakeup_irq, ret);
5818 goto pio_irq_free;
5819 } else {
5820 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305821 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005822 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305823 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005824 }
5825 spin_unlock_irqrestore(&host->lock, flags);
5826 }
5827 }
5828
Subhash Jadavanic9b85752012-04-13 11:16:49 +05305829 if (host->plat->mpm_sdiowakeup_int) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005830 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5831 mmc_hostname(mmc));
5832 }
5833
5834 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
5835 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005836 /*
5837 * Setup card detect change
5838 */
5839
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305840 if (!plat->status_gpio)
5841 plat->status_gpio = -ENOENT;
5842 if (!plat->wpswitch_gpio)
5843 plat->wpswitch_gpio = -ENOENT;
5844
5845 if (plat->status || gpio_is_valid(plat->status_gpio)) {
Krishna Konda941604a2012-01-10 17:46:34 -08005846 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005847 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08005848 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005849 host->oldstat = msmsdcc_slot_status(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005850
Krishna Konda941604a2012-01-10 17:46:34 -08005851 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005852 }
San Mehat9d2bd732009-09-22 16:44:22 -07005853
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005854 if (plat->status_irq) {
5855 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07005856 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005857 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07005858 DRIVER_NAME " (slot)",
5859 host);
5860 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005861 pr_err("Unable to get slot IRQ %d (%d)\n",
5862 plat->status_irq, ret);
5863 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005864 }
5865 } else if (plat->register_status_notify) {
5866 plat->register_status_notify(msmsdcc_status_notify_cb, host);
5867 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005868 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07005869 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005870
5871 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005872
5873 ret = pm_runtime_set_active(&(pdev)->dev);
5874 if (ret < 0)
5875 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
5876 __func__, ret);
5877 /*
5878 * There is no notion of suspend/resume for SD/MMC/SDIO
5879 * cards. So host can be suspended/resumed with out
5880 * worrying about its children.
5881 */
5882 pm_suspend_ignore_children(&(pdev)->dev, true);
5883
5884 /*
5885 * MMC/SD/SDIO bus suspend/resume operations are defined
5886 * only for the slots that will be used for non-removable
5887 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
5888 * defined. Otherwise, they simply become card removal and
5889 * insertion events during suspend and resume respectively.
5890 * Hence, enable run-time PM only for slots for which bus
5891 * suspend/resume operations are defined.
5892 */
5893#ifdef CONFIG_MMC_UNSAFE_RESUME
5894 /*
5895 * If this capability is set, MMC core will enable/disable host
5896 * for every claim/release operation on a host. We use this
5897 * notification to increment/decrement runtime pm usage count.
5898 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005899 pm_runtime_enable(&(pdev)->dev);
5900#else
5901 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005902 pm_runtime_enable(&(pdev)->dev);
5903 }
5904#endif
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305905 host->idle_tout_ms = MSM_MMC_DEFAULT_IDLE_TIMEOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005906 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
5907 (unsigned long)host);
5908
San Mehat9d2bd732009-09-22 16:44:22 -07005909 mmc_add_host(mmc);
5910
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005911#ifdef CONFIG_HAS_EARLYSUSPEND
5912 host->early_suspend.suspend = msmsdcc_early_suspend;
5913 host->early_suspend.resume = msmsdcc_late_resume;
5914 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
5915 register_early_suspend(&host->early_suspend);
5916#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005917
Krishna Konda25786ec2011-07-25 16:21:36 -07005918 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
5919 " dmacrcri %d\n", mmc_hostname(mmc),
5920 (unsigned long long)core_memres->start,
5921 (unsigned int) core_irqres->start,
5922 (unsigned int) plat->status_irq, host->dma.channel,
5923 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005924
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305925 pr_info("%s: Controller capabilities: 0x%.8x\n",
5926 mmc_hostname(mmc), host->hw_caps);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005927 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
5928 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
5929 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
5930 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
5931 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
5932 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
5933 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
5934 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
5935 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
5936 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
5937 host->eject);
5938 pr_info("%s: Power save feature enable = %d\n",
5939 mmc_hostname(mmc), msmsdcc_pwrsave);
5940
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305941 if (is_dma_mode(host) && host->dma.channel != -1
Krishna Konda25786ec2011-07-25 16:21:36 -07005942 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005943 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005944 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005945 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005946 mmc_hostname(mmc), host->dma.cmd_busaddr,
5947 host->dma.cmdptr_busaddr);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305948 } else if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005949 pr_info("%s: SPS-BAM data transfer mode available\n",
5950 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005951 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005952 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005953
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005954#if defined(CONFIG_DEBUG_FS)
5955 msmsdcc_dbg_createhost(host);
5956#endif
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305957
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305958 host->max_bus_bw.show = show_sdcc_to_mem_max_bus_bw;
5959 host->max_bus_bw.store = store_sdcc_to_mem_max_bus_bw;
5960 sysfs_attr_init(&host->max_bus_bw.attr);
5961 host->max_bus_bw.attr.name = "max_bus_bw";
5962 host->max_bus_bw.attr.mode = S_IRUGO | S_IWUSR;
5963 ret = device_create_file(&pdev->dev, &host->max_bus_bw);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305964 if (ret)
5965 goto platform_irq_free;
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305966
5967 if (!plat->status_irq) {
5968 host->polling.show = show_polling;
5969 host->polling.store = store_polling;
5970 sysfs_attr_init(&host->polling.attr);
5971 host->polling.attr.name = "polling";
5972 host->polling.attr.mode = S_IRUGO | S_IWUSR;
5973 ret = device_create_file(&pdev->dev, &host->polling);
5974 if (ret)
5975 goto remove_max_bus_bw_file;
5976 }
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305977 host->idle_timeout.show = show_idle_timeout;
5978 host->idle_timeout.store = store_idle_timeout;
5979 sysfs_attr_init(&host->idle_timeout.attr);
5980 host->idle_timeout.attr.name = "idle_timeout";
5981 host->idle_timeout.attr.mode = S_IRUGO | S_IWUSR;
5982 ret = device_create_file(&pdev->dev, &host->idle_timeout);
5983 if (ret)
5984 goto remove_polling_file;
San Mehat9d2bd732009-09-22 16:44:22 -07005985 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005986
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305987 remove_polling_file:
5988 if (!plat->status_irq)
5989 device_remove_file(&pdev->dev, &host->polling);
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305990 remove_max_bus_bw_file:
5991 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005992 platform_irq_free:
5993 del_timer_sync(&host->req_tout_timer);
5994 pm_runtime_disable(&(pdev)->dev);
5995 pm_runtime_set_suspended(&(pdev)->dev);
5996
5997 if (plat->status_irq)
5998 free_irq(plat->status_irq, host);
5999 sdiowakeup_irq_free:
6000 wake_lock_destroy(&host->sdio_suspend_wlock);
6001 if (plat->sdiowakeup_irq)
6002 free_irq(plat->sdiowakeup_irq, host);
6003 pio_irq_free:
6004 if (plat->sdiowakeup_irq)
6005 wake_lock_destroy(&host->sdio_wlock);
6006 free_irq(core_irqres->start, host);
6007 irq_free:
6008 free_irq(core_irqres->start, host);
6009 dml_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306010 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006011 msmsdcc_dml_exit(host);
6012 sps_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306013 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006014 msmsdcc_sps_exit(host);
6015 vreg_deinit:
6016 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07006017 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006018 clk_disable(host->clk);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306019 msmsdcc_msm_bus_unregister(host);
6020 pm_qos_remove:
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006021 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306022 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07006023 clk_put:
6024 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006025 pclk_disable:
6026 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05306027 clk_disable_unprepare(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07006028 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006029 if (!IS_ERR(host->pclk))
6030 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05306031 if (!IS_ERR_OR_NULL(host->bus_clk))
6032 clk_disable_unprepare(host->bus_clk);
6033 bus_clk_put:
6034 if (!IS_ERR_OR_NULL(host->bus_clk))
6035 clk_put(host->bus_clk);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306036 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006037 if (host->dmares)
6038 dma_free_coherent(NULL,
6039 sizeof(struct msmsdcc_nc_dmadata),
6040 host->dma.nc, host->dma.nc_busaddr);
6041 }
6042 ioremap_free:
Sahitya Tummaladce7c752011-05-02 18:06:05 +05306043 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07006044 host_free:
6045 mmc_free_host(mmc);
6046 out:
6047 return ret;
6048}
6049
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006050static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07006051{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006052 struct mmc_host *mmc = mmc_get_drvdata(pdev);
6053 struct mmc_platform_data *plat;
6054 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07006055
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006056 if (!mmc)
6057 return -ENXIO;
6058
6059 if (pm_runtime_suspended(&(pdev)->dev))
6060 pm_runtime_resume(&(pdev)->dev);
6061
6062 host = mmc_priv(mmc);
6063
6064 DBG(host, "Removing SDCC device = %d\n", pdev->id);
6065 plat = host->plat;
6066
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306067 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006068 if (!plat->status_irq)
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306069 device_remove_file(&pdev->dev, &host->polling);
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306070 device_remove_file(&pdev->dev, &host->idle_timeout);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006071
6072 del_timer_sync(&host->req_tout_timer);
6073 tasklet_kill(&host->dma_tlet);
6074 tasklet_kill(&host->sps.tlet);
6075 mmc_remove_host(mmc);
6076
6077 if (plat->status_irq)
6078 free_irq(plat->status_irq, host);
6079
6080 wake_lock_destroy(&host->sdio_suspend_wlock);
6081 if (plat->sdiowakeup_irq) {
6082 wake_lock_destroy(&host->sdio_wlock);
6083 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
6084 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07006085 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006086
6087 free_irq(host->core_irqres->start, host);
6088 free_irq(host->core_irqres->start, host);
6089
6090 clk_put(host->clk);
6091 if (!IS_ERR(host->pclk))
6092 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05306093 if (!IS_ERR_OR_NULL(host->bus_clk))
6094 clk_put(host->bus_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006095
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006096 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306097 pm_qos_remove_request(&host->pm_qos_req_dma);
6098
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306099 if (host->msm_bus_vote.client_handle) {
6100 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
6101 msmsdcc_msm_bus_unregister(host);
6102 }
6103
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006104 msmsdcc_vreg_init(host, false);
6105
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306106 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006107 if (host->dmares)
6108 dma_free_coherent(NULL,
6109 sizeof(struct msmsdcc_nc_dmadata),
6110 host->dma.nc, host->dma.nc_busaddr);
6111 }
6112
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306113 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006114 msmsdcc_dml_exit(host);
6115 msmsdcc_sps_exit(host);
6116 }
6117
6118 iounmap(host->base);
6119 mmc_free_host(mmc);
6120
6121#ifdef CONFIG_HAS_EARLYSUSPEND
6122 unregister_early_suspend(&host->early_suspend);
6123#endif
6124 pm_runtime_disable(&(pdev)->dev);
6125 pm_runtime_set_suspended(&(pdev)->dev);
6126
6127 return 0;
6128}
6129
6130#ifdef CONFIG_MSM_SDIO_AL
6131int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
6132{
6133 struct msmsdcc_host *host = mmc_priv(mmc);
6134 unsigned long flags;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306135 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006136
Asutosh Dasf5298c32012-04-03 14:51:47 +05306137 mutex_lock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006138 spin_lock_irqsave(&host->lock, flags);
6139 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
6140 enable ? "En" : "Dis");
6141
6142 if (enable) {
6143 if (!host->sdcc_irq_disabled) {
6144 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05306145 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006146 host->sdcc_irq_disabled = 1;
6147 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306148 rc = msmsdcc_setup_clocks(host, false);
6149 if (rc)
6150 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006151
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05306152 if (host->plat->sdio_lpm_gpio_setup &&
6153 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006154 spin_unlock_irqrestore(&host->lock, flags);
6155 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
6156 spin_lock_irqsave(&host->lock, flags);
6157 host->sdio_gpio_lpm = 1;
6158 }
6159
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306160 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006161 msmsdcc_enable_irq_wake(host);
6162 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306163 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006164 }
6165 } else {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306166 rc = msmsdcc_setup_clocks(host, true);
6167 if (rc)
6168 goto out;
6169
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306170 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006171 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306172 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006173 msmsdcc_disable_irq_wake(host);
6174 }
6175
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05306176 if (host->plat->sdio_lpm_gpio_setup &&
6177 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006178 spin_unlock_irqrestore(&host->lock, flags);
6179 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
6180 spin_lock_irqsave(&host->lock, flags);
6181 host->sdio_gpio_lpm = 0;
6182 }
6183
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306184 if (host->sdcc_irq_disabled && atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006185 writel_relaxed(host->mci_irqenable,
6186 host->base + MMCIMASK0);
6187 mb();
6188 enable_irq(host->core_irqres->start);
6189 host->sdcc_irq_disabled = 0;
6190 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006191 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306192out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006193 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05306194 mutex_unlock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306195 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006196}
6197#else
6198int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
6199{
6200 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07006201}
6202#endif
6203
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006204#ifdef CONFIG_PM
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306205#ifdef CONFIG_MMC_CLKGATE
6206static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6207{
6208 struct mmc_host *mmc = host->mmc;
6209 unsigned long flags;
6210
6211 mmc_host_clk_hold(mmc);
6212 spin_lock_irqsave(&mmc->clk_lock, flags);
6213 mmc->clk_old = mmc->ios.clock;
6214 mmc->ios.clock = 0;
6215 mmc->clk_gated = true;
6216 spin_unlock_irqrestore(&mmc->clk_lock, flags);
6217 mmc_set_ios(mmc);
6218 mmc_host_clk_release(mmc);
6219}
6220
6221static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6222{
6223 struct mmc_host *mmc = host->mmc;
6224
6225 mmc_host_clk_hold(mmc);
6226 mmc->ios.clock = host->clk_rate;
6227 mmc_set_ios(mmc);
6228 mmc_host_clk_release(mmc);
6229}
6230#else
6231static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6232{
6233 struct mmc_host *mmc = host->mmc;
6234
6235 mmc->ios.clock = 0;
6236 mmc_set_ios(mmc);
6237}
6238
6239static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6240{
6241 struct mmc_host *mmc = host->mmc;
6242
6243 mmc->ios.clock = host->clk_rate;
6244 mmc_set_ios(mmc);
6245}
6246#endif
6247
San Mehat9d2bd732009-09-22 16:44:22 -07006248static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006249msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006250{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006251 struct mmc_host *mmc = dev_get_drvdata(dev);
6252 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006253 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306254 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07006255
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306256 if (host->plat->is_sdio_al_client) {
6257 rc = 0;
6258 goto out;
San Mehat9d2bd732009-09-22 16:44:22 -07006259 }
San Mehat9d2bd732009-09-22 16:44:22 -07006260
Sahitya Tummala7661a452011-07-18 13:28:35 +05306261 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006262 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006263 host->sdcc_suspending = 1;
6264 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07006265
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006266 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006267 * MMC core thinks that host is disabled by now since
6268 * runtime suspend is scheduled after msmsdcc_disable()
6269 * is called. Thus, MMC core will try to enable the host
6270 * while suspending it. This results in a synchronous
6271 * runtime resume request while in runtime suspending
6272 * context and hence inorder to complete this resume
6273 * requet, it will wait for suspend to be complete,
6274 * but runtime suspend also can not proceed further
6275 * until the host is resumed. Thus, it leads to a hang.
6276 * Hence, increase the pm usage count before suspending
6277 * the host so that any resume requests after this will
6278 * simple become pm usage counter increment operations.
6279 */
6280 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306281 /* If there is pending detect work abort runtime suspend */
6282 if (unlikely(work_busy(&mmc->detect.work)))
6283 rc = -EAGAIN;
6284 else
6285 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006286 pm_runtime_put_noidle(dev);
6287
6288 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306289 spin_lock_irqsave(&host->lock, flags);
6290 host->sdcc_suspended = true;
6291 spin_unlock_irqrestore(&host->lock, flags);
6292 if (mmc->card && mmc_card_sdio(mmc->card) &&
6293 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006294 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306295 * If SDIO function driver doesn't want
6296 * to power off the card, atleast turn off
6297 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006298 */
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306299 msmsdcc_gate_clock(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006300 }
6301 }
6302 host->sdcc_suspending = 0;
6303 mmc->suspend_task = NULL;
6304 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
6305 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006306 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306307 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306308out:
6309 /* set bus bandwidth to 0 immediately */
6310 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
San Mehat9d2bd732009-09-22 16:44:22 -07006311 return rc;
6312}
6313
6314static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006315msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006316{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006317 struct mmc_host *mmc = dev_get_drvdata(dev);
6318 struct msmsdcc_host *host = mmc_priv(mmc);
6319 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07006320
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006321 if (host->plat->is_sdio_al_client)
6322 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07006323
Sahitya Tummala7661a452011-07-18 13:28:35 +05306324 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006325 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306326 if (mmc->card && mmc_card_sdio(mmc->card) &&
6327 mmc_card_keep_power(mmc)) {
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306328 msmsdcc_ungate_clock(host);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05306329 }
San Mehat9d2bd732009-09-22 16:44:22 -07006330
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006331 mmc_resume_host(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006332
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006333 /*
6334 * FIXME: Clearing of flags must be handled in clients
6335 * resume handler.
6336 */
6337 spin_lock_irqsave(&host->lock, flags);
6338 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306339 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006340 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07006341
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006342 /*
6343 * After resuming the host wait for sometime so that
6344 * the SDIO work will be processed.
6345 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306346 if (mmc->card && mmc_card_sdio(mmc->card)) {
Subhash Jadavanic9b85752012-04-13 11:16:49 +05306347 if ((host->plat->mpm_sdiowakeup_int ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006348 host->plat->sdiowakeup_irq) &&
6349 wake_lock_active(&host->sdio_wlock))
6350 wake_lock_timeout(&host->sdio_wlock, 1);
6351 }
6352
6353 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006354 }
Subhash Jadavani1371d192012-08-16 18:46:57 +05306355 host->pending_resume = false;
Sahitya Tummala7661a452011-07-18 13:28:35 +05306356 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006357 return 0;
6358}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006359
6360static int msmsdcc_runtime_idle(struct device *dev)
6361{
6362 struct mmc_host *mmc = dev_get_drvdata(dev);
6363 struct msmsdcc_host *host = mmc_priv(mmc);
6364
6365 if (host->plat->is_sdio_al_client)
6366 return 0;
6367
6368 /* Idle timeout is not configurable for now */
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306369 pm_schedule_suspend(dev, host->idle_tout_ms);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006370
6371 return -EAGAIN;
6372}
6373
6374static int msmsdcc_pm_suspend(struct device *dev)
6375{
6376 struct mmc_host *mmc = dev_get_drvdata(dev);
6377 struct msmsdcc_host *host = mmc_priv(mmc);
6378 int rc = 0;
6379
6380 if (host->plat->is_sdio_al_client)
6381 return 0;
6382
6383
6384 if (host->plat->status_irq)
6385 disable_irq(host->plat->status_irq);
6386
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006387 if (!pm_runtime_suspended(dev))
6388 rc = msmsdcc_runtime_suspend(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006389
6390 return rc;
6391}
6392
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306393static int msmsdcc_suspend_noirq(struct device *dev)
6394{
6395 struct mmc_host *mmc = dev_get_drvdata(dev);
6396 struct msmsdcc_host *host = mmc_priv(mmc);
6397 int rc = 0;
6398
6399 /*
6400 * After platform suspend there may be active request
6401 * which might have enabled clocks. For example, in SDIO
6402 * case, ksdioirq thread might have scheduled after sdcc
6403 * suspend but before system freeze. In that case abort
6404 * suspend and retry instead of keeping the clocks on
6405 * during suspend and not allowing TCXO.
6406 */
6407
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306408 if (atomic_read(&host->clks_on) && !host->plat->is_sdio_al_client) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306409 pr_warn("%s: clocks are on after suspend, aborting system "
6410 "suspend\n", mmc_hostname(mmc));
6411 rc = -EAGAIN;
6412 }
6413
6414 return rc;
6415}
6416
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006417static int msmsdcc_pm_resume(struct device *dev)
6418{
6419 struct mmc_host *mmc = dev_get_drvdata(dev);
6420 struct msmsdcc_host *host = mmc_priv(mmc);
6421 int rc = 0;
6422
6423 if (host->plat->is_sdio_al_client)
6424 return 0;
6425
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006426 if (mmc->card && mmc_card_sdio(mmc->card))
Sahitya Tummalafb486372011-09-02 19:01:49 +05306427 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavani1371d192012-08-16 18:46:57 +05306428 /*
6429 * As runtime PM is enabled before calling the device's platform resume
6430 * callback, we use the pm_runtime_suspended API to know if SDCC is
6431 * really runtime suspended or not and set the pending_resume flag only
6432 * if its not runtime suspended.
6433 */
6434 else if (!pm_runtime_suspended(dev))
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006435 host->pending_resume = true;
6436
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006437 if (host->plat->status_irq) {
6438 msmsdcc_check_status((unsigned long)host);
6439 enable_irq(host->plat->status_irq);
6440 }
6441
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006442 return rc;
6443}
6444
Daniel Walker08ecfde2010-06-23 12:32:20 -07006445#else
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006446static int msmsdcc_runtime_suspend(struct device *dev)
6447{
6448 return 0;
6449}
6450static int msmsdcc_runtime_idle(struct device *dev)
6451{
6452 return 0;
6453}
6454static int msmsdcc_pm_suspend(struct device *dev)
6455{
6456 return 0;
6457}
6458static int msmsdcc_pm_resume(struct device *dev)
6459{
6460 return 0;
6461}
6462static int msmsdcc_suspend_noirq(struct device *dev)
6463{
6464 return 0;
6465}
6466static int msmsdcc_runtime_resume(struct device *dev)
6467{
6468 return 0;
6469}
Daniel Walker08ecfde2010-06-23 12:32:20 -07006470#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006471
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006472static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
6473 .runtime_suspend = msmsdcc_runtime_suspend,
6474 .runtime_resume = msmsdcc_runtime_resume,
6475 .runtime_idle = msmsdcc_runtime_idle,
6476 .suspend = msmsdcc_pm_suspend,
6477 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306478 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006479};
6480
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306481static const struct of_device_id msmsdcc_dt_match[] = {
6482 {.compatible = "qcom,msm-sdcc"},
6483
6484};
6485MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
6486
San Mehat9d2bd732009-09-22 16:44:22 -07006487static struct platform_driver msmsdcc_driver = {
6488 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006489 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07006490 .driver = {
6491 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006492 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306493 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07006494 },
6495};
6496
6497static int __init msmsdcc_init(void)
6498{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006499#if defined(CONFIG_DEBUG_FS)
6500 int ret = 0;
6501 ret = msmsdcc_dbg_init();
6502 if (ret) {
6503 pr_err("Failed to create debug fs dir \n");
6504 return ret;
6505 }
6506#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006507 return platform_driver_register(&msmsdcc_driver);
6508}
San Mehat9d2bd732009-09-22 16:44:22 -07006509
San Mehat9d2bd732009-09-22 16:44:22 -07006510static void __exit msmsdcc_exit(void)
6511{
6512 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006513
6514#if defined(CONFIG_DEBUG_FS)
6515 debugfs_remove(debugfs_file);
6516 debugfs_remove(debugfs_dir);
6517#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006518}
6519
6520module_init(msmsdcc_init);
6521module_exit(msmsdcc_exit);
6522
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006523MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07006524MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006525
6526#if defined(CONFIG_DEBUG_FS)
6527
6528static int
6529msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
6530{
6531 file->private_data = inode->i_private;
6532 return 0;
6533}
6534
6535static ssize_t
6536msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
6537 size_t count, loff_t *ppos)
6538{
6539 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08006540 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006541 int max, i;
6542
6543 i = 0;
6544 max = sizeof(buf) - 1;
6545
6546 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
6547 host->curr.cmd, host->curr.data);
6548 if (host->curr.cmd) {
6549 struct mmc_command *cmd = host->curr.cmd;
6550
6551 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
6552 cmd->opcode, cmd->arg, cmd->flags);
6553 }
6554 if (host->curr.data) {
6555 struct mmc_data *data = host->curr.data;
6556 i += scnprintf(buf + i, max - i,
6557 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
6558 data->timeout_ns, data->timeout_clks,
6559 data->blksz, data->blocks, data->error,
6560 data->flags);
6561 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
6562 host->curr.xfer_size, host->curr.xfer_remain,
6563 host->curr.data_xfered, host->dma.sg);
6564 }
6565
6566 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
6567}
6568
6569static const struct file_operations msmsdcc_dbg_state_ops = {
6570 .read = msmsdcc_dbg_state_read,
6571 .open = msmsdcc_dbg_state_open,
6572};
6573
6574static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
6575{
6576 if (debugfs_dir) {
6577 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
6578 0644, debugfs_dir, host,
6579 &msmsdcc_dbg_state_ops);
6580 }
6581}
6582
6583static int __init msmsdcc_dbg_init(void)
6584{
6585 int err;
6586
6587 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
6588 if (IS_ERR(debugfs_dir)) {
6589 err = PTR_ERR(debugfs_dir);
6590 debugfs_dir = NULL;
6591 return err;
6592 }
6593
6594 return 0;
6595}
6596#endif